"use strict"; /** * Test script to validate Dutchie GraphQL API access and capture response structure */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); // @ts-ignore - node-fetch type declaration not installed const node_fetch_1 = __importDefault(require("node-fetch")); const GRAPHQL_HASHES = { ConsumerDispensaries: '0a5bfa6ca1d64ae47bcccb7c8077c87147cbc4e6982c17ceec97a2a4948b311b', GetAddressBasedDispensaryData: '13461f73abf7268770dfd05fe7e10c523084b2bb916a929c08efe3d87531977b', FilteredProducts: 'ee29c060826dc41c527e470e9ae502c9b2c169720faa0a9f5d25e1b9a530a4a0', MenuFiltersV2: '2f0b3233b8a2426b391649ca3f0f7a5d43b9aefd683f6286d7261a2517e3568e', FilteredSpecials: '0dfb85a4fc138c55a076d4d11bf6d1a25f7cbd511428e1cf5a5b863b3eb23f25', }; async function fetchProducts(dispensaryId, page = 0, perPage = 25) { const session = 'crawlsy-session-' + Date.now(); const variables = { includeEnterpriseSpecials: false, productsFilter: { dispensaryId, pricingType: 'rec', Status: null, // null to include all (in-stock and out-of-stock) types: [], useCache: true, isDefaultSort: true, sortBy: 'popularSortIdx', sortDirection: 1, bypassOnlineThresholds: true, isKioskMenu: false, removeProductsBelowOptionThresholds: false }, page, perPage }; const qs = new URLSearchParams({ operationName: 'FilteredProducts', variables: JSON.stringify(variables), extensions: JSON.stringify({ persistedQuery: { version: 1, sha256Hash: GRAPHQL_HASHES.FilteredProducts } }) }); const res = await (0, node_fetch_1.default)(`https://dutchie.com/api-3/graphql?${qs.toString()}`, { headers: { 'x-dutchie-session': session, 'apollographql-client-name': 'Marketplace (production)', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' } }); if (!res.ok) { const text = await res.text(); console.error('HTTP Status:', res.status); console.error('Response:', text.substring(0, 500)); throw new Error(`HTTP ${res.status}: ${text.substring(0, 200)}`); } return res.json(); } async function resolveDispensaryId(cName) { const session = 'crawlsy-session-' + Date.now(); const variables = { input: { dispensaryId: cName } }; const qs = new URLSearchParams({ operationName: 'GetAddressBasedDispensaryData', variables: JSON.stringify(variables), extensions: JSON.stringify({ persistedQuery: { version: 1, sha256Hash: GRAPHQL_HASHES.GetAddressBasedDispensaryData } }) }); const res = await (0, node_fetch_1.default)(`https://dutchie.com/graphql?${qs.toString()}`, { headers: { 'x-dutchie-session': session, 'apollographql-client-name': 'Marketplace (production)', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } }); if (!res.ok) { console.error('Failed to resolve dispensary ID:', res.status); return null; } const data = await res.json(); return data?.data?.getAddressBasedDispensaryData?.dispensaryData?.dispensaryId || null; } function enumerateFields(obj, prefix = '') { const fields = []; for (const [key, value] of Object.entries(obj)) { const path = prefix ? `${prefix}.${key}` : key; if (value === null) { fields.push(`${path}: null`); } else if (Array.isArray(value)) { fields.push(`${path}: Array[${value.length}]`); if (value.length > 0 && typeof value[0] === 'object') { const subFields = enumerateFields(value[0], `${path}[0]`); fields.push(...subFields); } } else if (typeof value === 'object') { fields.push(`${path}: Object`); const subFields = enumerateFields(value, path); fields.push(...subFields); } else { const typeStr = typeof value; const preview = String(value).substring(0, 50); fields.push(`${path}: ${typeStr} = "${preview}"`); } } return fields; } async function main() { console.log('='.repeat(80)); console.log('DUTCHIE GRAPHQL API TEST'); console.log('='.repeat(80)); const cName = 'AZ-Deeply-Rooted'; // Step 1: Resolve dispensary ID console.log(`\n1. Resolving dispensary ID for "${cName}"...`); const dispensaryId = await resolveDispensaryId(cName); const finalDispensaryId = dispensaryId || '6405ef617056e8014d79101b'; // Fallback to known ID if (!dispensaryId) { console.log(' Failed to resolve via API, using hardcoded ID: 6405ef617056e8014d79101b'); } console.log(` Final ID: ${finalDispensaryId}`); // Step 2: Fetch first page of products console.log('\n2. Fetching products (page 0, perPage 5)...'); const result = await fetchProducts(finalDispensaryId, 0, 5); if (result.errors) { console.error('\nGraphQL Errors:'); console.error(JSON.stringify(result.errors, null, 2)); return; } const products = result?.data?.filteredProducts?.products || []; console.log(` Found ${products.length} products in this page`); if (products.length === 0) { console.log('No products returned. Full response:'); console.log(JSON.stringify(result, null, 2)); return; } // Step 3: Enumerate all fields from first product console.log('\n3. PRODUCT FIELD STRUCTURE (from first product):'); console.log('-'.repeat(80)); const product = products[0]; const fields = enumerateFields(product); fields.forEach(f => console.log(` ${f}`)); // Step 4: Show full sample product JSON console.log('\n4. FULL SAMPLE PRODUCT JSON:'); console.log('-'.repeat(80)); console.log(JSON.stringify(product, null, 2)); // Step 5: Summary of key fields for schema design console.log('\n5. KEY FIELDS FOR SCHEMA DESIGN:'); console.log('-'.repeat(80)); const keyFields = [ { field: 'id', value: product.id }, { field: 'name', value: product.name }, { field: 'slug', value: product.slug }, { field: 'brand', value: product.brand }, { field: 'brandId', value: product.brandId }, { field: 'type', value: product.type }, { field: 'category', value: product.category }, { field: 'subcategory', value: product.subcategory }, { field: 'strainType', value: product.strainType }, { field: 'THCContent', value: product.THCContent }, { field: 'CBDContent', value: product.CBDContent }, { field: 'description', value: product.description?.substring(0, 100) + '...' }, { field: 'image', value: product.image }, { field: 'options.length', value: product.options?.length }, { field: 'pricing', value: product.pricing }, { field: 'terpenes.length', value: product.terpenes?.length }, { field: 'effects.length', value: product.effects?.length }, ]; keyFields.forEach(({ field, value }) => { console.log(` ${field}: ${JSON.stringify(value)}`); }); // Step 6: Show an option (variant) if available if (product.options && product.options.length > 0) { console.log('\n6. SAMPLE OPTION/VARIANT:'); console.log('-'.repeat(80)); console.log(JSON.stringify(product.options[0], null, 2)); } } main().catch(console.error);