{"_id":"@fluentcommerce/fc-connect-sdk","_rev":"285-64e4ee230d9d64e51e2773444e149c45","name":"@fluentcommerce/fc-connect-sdk","dist-tags":{"latest":"0.1.56"},"versions":{"0.1.48":{"name":"@fluentcommerce/fc-connect-sdk","version":"0.1.48","keywords":["fluent","commerce","sdk","integration","inventory","batch","graphql"],"author":{"name":"Fluent Commerce"},"license":"MIT","_id":"@fluentcommerce/fc-connect-sdk@0.1.48","maintainers":[{"name":"sagirish","email":"sagirish@gmail.com"}],"bin":{"fc-connect":"bin/fc-connect.js","fc-connect-validate-schema":"bin/validate-schema.js","fc-connect-analyze-coverage":"bin/analyze-coverage.js","fc-connect-introspect-schema":"bin/introspect-schema.js","fc-connect-generate-query-mapping":"bin/generate-query-mapping.js","fc-connect-analyze-source-structure":"bin/analyze-source-structure.js","fc-connect-generate-mutation-mapping":"bin/generate-mutation-mapping.js"},"dist":{"shasum":"840dae81aeb77b58ac9b20e5757b0168f57511d7","tarball":"https://registry.npmjs.org/@fluentcommerce/fc-connect-sdk/-/fc-connect-sdk-0.1.48.tgz","fileCount":1164,"integrity":"sha512-pugl+LgX6InTQpZbZ2iGqqm7HJCUo3p3kIFizVE3uS7DCHT2No9YXKbet3eRD0ohIma0u8lIM1Q47/2AIj3q3g==","signatures":[{"sig":"MEQCIFjrnwgz/+bYT+r9yPWLIymI+hwJ+IEdIDV6ufUSCEqCAiAuqd+OfnBggqPjBqxHkhgtD66JZBoWJlgALOkuw2kKtw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13023725},"main":"dist/cjs/index.js","type":"module","types":"dist/cjs/index.d.ts","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"5f1a9a6448f5e35a1334a2b3e6f61de3a2066c24","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"jest","build":"npm run clean && npm run build:cjs && npm run fix:cjs && npm run build:esm && npm run fix:esm && npm run build:types","clean":"rm -rf dist || echo No dist folder to clean","fix:cjs":"node scripts/fix-cjs-package.cjs","fix:esm":"node scripts/fix-esm-imports.cjs","prepare":"npm run build","ai:queue":"node scripts/generate-ai-queue.cjs","docs:all":"npm run docs:pdf","docs:pdf":"node scripts/generate-pdfs.cjs","lint:fix":"eslint src --ext .ts --fix","test:cov":"jest --coverage --coverageReporters=json-summary --coverageReporters=lcov --coverageReporters=text --reporters=default --reporters=jest-junit","validate":"npm run lint && npm run test -- --testPathIgnorePatterns=\"integration|webhook-validation|xml-parser|xml-error-handling|xml-path-resolver\" && npm run build","build:cjs":"tsc -p tsconfig.json","build:esm":"tsc -p tsconfig.esm.json","test:deno":"node scripts/analyze-deno-compat.cjs","test:watch":"jest --watch","build:types":"tsc -p tsconfig.types.json","docs:rename":"node scripts/rename-docs-with-category.cjs","versori:info":"npm view @versori/run --json","test:coverage":"jest --coverage","validate:full":"npm run lint && npm test && npm run test:integration:live && npm run test:deno:live && npm run build","versori:audit":"npm audit | grep @versori || echo 'No @versori packages found in audit'","versori:check":"npm view @versori/run version","prepublishOnly":"node scripts/prepublish.cjs","test:deno:live":"bash scripts/test-deno-local.sh","docs:rename:dry":"node scripts/rename-docs-with-category.cjs --dry-run","versori:monitor":"node scripts/versori-monitor.cjs","docs:token-count":"node scripts/count-tokens.cjs","validate:exports":"node scripts/validate-exports.mjs","versori:detailed":"node scripts/versori-monitor.cjs --detailed","versori:outdated":"npm outdated @versori/run || true","versori:security":"node scripts/versori-monitor.cjs --security-only","versori:versions":"node scripts/versori-monitor.cjs --version-only","docs:fix-encoding":"node scripts/fix-emoji-encoding.mjs","fixtures:generate":"tsx tests/fixtures/generate-fixtures.ts","docs:inject-tokens":"node scripts/inject-tokens.cjs","validate:templates":"node scripts/validate-templates.cjs","versori:consistency":"node scripts/versori-monitor.cjs --consistency-only","docs:fix-encoding:dry":"node scripts/fix-emoji-encoding.mjs --dry-run","test:integration:live":"jest --config jest.config.integration.cjs"},"_npmUser":{"name":"sagirish","email":"sagirish@gmail.com"},"jest-junit":{"outputName":"junit.xml","outputDirectory":"artifacts"},"_npmVersion":"10.9.3","description":"Fluent Commerce SDK - Deno & Node.js Compatible","directories":{},"_nodeVersion":"22.20.0","dependencies":{"ssh2":"^1.17.0","graphql":"^16.9.0","csv-parse":"^5.6.0","hyparquet":"^1.3.0","parquetjs":"^0.11.2","fast-xml-parser":"^5.2.5","ssh2-sftp-client":"^12.0.1","@aws-sdk/client-s3":"^3.879.0","@aws-sdk/credential-providers":"^3.879.0","@aws-sdk/s3-request-presigner":"^3.886.0"},"_hasShrinkwrap":false,"devDependencies":{"ora":"^5.4.1","tsx":"^4.20.6","glob":"^11.0.3","jest":"^29.7.0","uuid":"^13.0.0","chalk":"^4.1.2","dotenv":"^17.2.2","eslint":"^8.57.0","marked":"^14.1.4","p-limit":"^3.1.0","ts-jest":"^29.1.0","ts-node":"^10.9.0","prettier":"^3.2.0","puppeteer":"^23.11.1","jest-junit":"^16.0.0","typescript":"^5.9.2","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/ssh2":"^1.15.5","@versori/run":"^0.4.4","highlight.js":"^11.11.1","markdown-pdf":"^11.0.0","markdownlint-cli":"^0.45.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.0","@types/ssh2-sftp-client":"^9.0.5","@typescript-eslint/parser":"^7.0.0","@typescript-eslint/eslint-plugin":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/fc-connect-sdk_0.1.48_1763576239986_0.6482901766568867","host":"s3://npm-registry-packages-npm-production"}},"0.1.51":{"name":"@fluentcommerce/fc-connect-sdk","version":"0.1.51","keywords":["fluent","commerce","sdk","integration","inventory","batch","graphql"],"author":{"name":"Fluent Commerce"},"license":"MIT","_id":"@fluentcommerce/fc-connect-sdk@0.1.51","maintainers":[{"name":"sagirish","email":"sagirish@gmail.com"}],"bin":{"fc-connect":"bin/fc-connect.js","fc-connect-validate-schema":"bin/validate-schema.js","fc-connect-analyze-coverage":"bin/analyze-coverage.js","fc-connect-introspect-schema":"bin/introspect-schema.js","fc-connect-generate-query-mapping":"bin/generate-query-mapping.js","fc-connect-analyze-source-structure":"bin/analyze-source-structure.js","fc-connect-generate-mutation-mapping":"bin/generate-mutation-mapping.js"},"dist":{"shasum":"65beb7d19b9773be7444c7d51146d914cc1c861e","tarball":"https://registry.npmjs.org/@fluentcommerce/fc-connect-sdk/-/fc-connect-sdk-0.1.51.tgz","fileCount":1157,"integrity":"sha512-qMeZgx0Hi+SwmWPqTsehLtEySXFCnu+3NAm+pBpu8avORzdsKPf5lzWLIBbNZIljERFWw+9eS+cb2MJf97sAqg==","signatures":[{"sig":"MEUCIQCJlYCuBUY8wdg1CilfnP5YXNa2RGaZx0LthfWtpBbbggIgatsJtFuRDUxe3rJkbJi1NIUlmJWh2R7rk7BU0QGZw6c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":12904840},"main":"dist/cjs/index.js","type":"module","types":"dist/cjs/index.d.ts","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"24a0f4b574e38c2ceab09bf408b626c75e50336a","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"jest","build":"npm run clean && npm run build:cjs && npm run fix:cjs && npm run build:esm && npm run fix:esm && npm run build:types","clean":"rm -rf dist || echo No dist folder to clean","fix:cjs":"node scripts/fix-cjs-package.cjs","fix:esm":"node scripts/fix-esm-imports.cjs","prepare":"npm run build","ai:queue":"node scripts/generate-ai-queue.cjs","docs:all":"npm run docs:pdf","docs:pdf":"node scripts/generate-pdfs.cjs","lint:fix":"eslint src --ext .ts --fix","test:cov":"jest --coverage --coverageReporters=json-summary --coverageReporters=lcov --coverageReporters=text --reporters=default --reporters=jest-junit","validate":"npm run lint && npm run test -- --testPathIgnorePatterns=\"integration|webhook-validation|xml-parser|xml-error-handling|xml-path-resolver\" && npm run build","build:cjs":"tsc -p tsconfig.json","build:esm":"tsc -p tsconfig.esm.json","test:deno":"node scripts/analyze-deno-compat.cjs","test:watch":"jest --watch","build:types":"tsc -p tsconfig.types.json","docs:rename":"node scripts/rename-docs-with-category.cjs","security:fix":"node security-audit/safe-fix.cjs","versori:info":"npm view @versori/run --json","security:full":"npm run security:check && npm run security:snyk","security:snyk":"node security-audit/snyk-setup.cjs","test:coverage":"jest --coverage","validate:full":"npm run lint && npm test && npm run test:integration:live && npm run test:deno:live && npm run build","versori:audit":"npm audit | grep @versori || echo 'No @versori packages found in audit'","versori:check":"npm view @versori/run version","prepublishOnly":"node scripts/prepublish.cjs","security:audit":"node security-audit/security-audit.cjs","security:check":"npm run security:audit:npm && npm run security:audit","test:deno:live":"bash scripts/test-deno-local.sh","docs:rename:dry":"node scripts/rename-docs-with-category.cjs --dry-run","versori:monitor":"node scripts/versori-monitor.cjs","docs:token-count":"node scripts/count-tokens.cjs","validate:exports":"node scripts/validate-exports.mjs","versori:detailed":"node scripts/versori-monitor.cjs --detailed","versori:outdated":"npm outdated @versori/run || true","versori:security":"node scripts/versori-monitor.cjs --security-only","versori:versions":"node scripts/versori-monitor.cjs --version-only","docs:fix-encoding":"node scripts/fix-emoji-encoding.mjs","fixtures:generate":"tsx tests/fixtures/generate-fixtures.ts","security:fix:high":"node security-audit/safe-fix.cjs high","docs:inject-tokens":"node scripts/inject-tokens.cjs","security:audit:npm":"npm audit --audit-level=moderate","security:snyk:test":"snyk test","validate:templates":"node scripts/validate-templates.cjs","security:audit:json":"npm audit --json > artifacts/security-audit-$(date +%Y%m%d).json || true","versori:consistency":"node scripts/versori-monitor.cjs --consistency-only","security:snyk:report":"snyk test --json > artifacts/snyk-report-$(date +%Y%m%d).json","docs:fix-encoding:dry":"node scripts/fix-emoji-encoding.mjs --dry-run","security:fix:critical":"node security-audit/safe-fix.cjs critical","security:snyk:monitor":"snyk monitor","test:integration:live":"jest --config jest.config.integration.cjs"},"_npmUser":{"name":"sagirish","email":"sagirish@gmail.com"},"jest-junit":{"outputName":"junit.xml","outputDirectory":"artifacts"},"_npmVersion":"10.9.3","description":"Fluent Commerce SDK - Deno & Node.js Compatible","directories":{},"_nodeVersion":"22.20.0","dependencies":{"ssh2":"^1.17.0","graphql":"^16.9.0","csv-parse":"^5.6.0","hyparquet":"^1.3.0","@dsnp/parquetjs":"^1.8.7","fast-xml-parser":"^5.2.5","ssh2-sftp-client":"^12.0.1","@aws-sdk/client-s3":"^3.879.0","@aws-sdk/credential-providers":"^3.879.0","@aws-sdk/s3-request-presigner":"^3.886.0"},"_hasShrinkwrap":false,"devDependencies":{"ora":"^5.4.1","tsx":"^4.20.6","glob":"^11.0.3","jest":"^29.7.0","uuid":"^13.0.0","chalk":"^4.1.2","dotenv":"^17.2.2","eslint":"^8.57.0","marked":"^14.1.4","p-limit":"^3.1.0","ts-jest":"^29.1.0","ts-node":"^10.9.0","prettier":"^3.2.0","puppeteer":"^23.11.1","jest-junit":"^16.0.0","typescript":"^5.9.2","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/ssh2":"^1.15.5","@versori/run":"^0.4.4","highlight.js":"^11.11.1","markdownlint-cli":"^0.46.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.0","@types/ssh2-sftp-client":"^9.0.5","@typescript-eslint/parser":"^7.0.0","@typescript-eslint/eslint-plugin":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/fc-connect-sdk_0.1.51_1768308398635_0.6286109796292856","host":"s3://npm-registry-packages-npm-production"}},"0.1.52":{"name":"@fluentcommerce/fc-connect-sdk","version":"0.1.52","keywords":["fluent","commerce","sdk","integration","inventory","batch","graphql"],"author":{"name":"Fluent Commerce"},"license":"MIT","_id":"@fluentcommerce/fc-connect-sdk@0.1.52","maintainers":[{"name":"sagirish","email":"sagirish@gmail.com"}],"bin":{"fc-connect":"bin/fc-connect.js","fc-connect-validate-schema":"bin/validate-schema.js","fc-connect-analyze-coverage":"bin/analyze-coverage.js","fc-connect-introspect-schema":"bin/introspect-schema.js","fc-connect-generate-query-mapping":"bin/generate-query-mapping.js","fc-connect-analyze-source-structure":"bin/analyze-source-structure.js","fc-connect-generate-mutation-mapping":"bin/generate-mutation-mapping.js"},"dist":{"shasum":"3044e710a9a10576182f0ca7cea95a6da8841cf7","tarball":"https://registry.npmjs.org/@fluentcommerce/fc-connect-sdk/-/fc-connect-sdk-0.1.52.tgz","fileCount":1157,"integrity":"sha512-W3Ei/xOeq/79+Xyd2VEsCFWTT8cP3XcNSO56Az8k7+KGwUYP2ZhbDsp6CSl0MJqJ1bpXfl3hCQ0cNpFZ8Yynow==","signatures":[{"sig":"MEQCIF7spyWdMenlglOEY2aV/JNBsVjLfAate7mHLHlnJaYZAiAuJtNtZX6qPlcxbePf27vQuN4St9SA/EEgh6QqrlIBHg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":12954111},"main":"dist/cjs/index.js","type":"module","types":"dist/cjs/index.d.ts","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"20347a50e48a05525ce9a0c19827cc78bf12bcb3","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"jest","build":"npm run clean && npm run build:cjs && npm run fix:cjs && npm run build:esm && npm run fix:esm && npm run build:types","clean":"rm -rf dist || echo No dist folder to clean","fix:cjs":"node scripts/fix-cjs-package.cjs","fix:esm":"node scripts/fix-esm-imports.cjs","prepare":"npm run build","ai:queue":"node scripts/generate-ai-queue.cjs","docs:all":"npm run docs:pdf","docs:pdf":"node scripts/generate-pdfs.cjs","lint:fix":"eslint src --ext .ts --fix","test:cov":"jest --coverage --coverageReporters=json-summary --coverageReporters=lcov --coverageReporters=text --reporters=default --reporters=jest-junit","validate":"npm run lint && npm run test -- --testPathIgnorePatterns=\"integration|webhook-validation|xml-parser|xml-error-handling|xml-path-resolver\" && npm run build","build:cjs":"tsc -p tsconfig.json","build:esm":"tsc -p tsconfig.esm.json","test:deno":"node scripts/analyze-deno-compat.cjs","test:watch":"jest --watch","build:types":"tsc -p tsconfig.types.json","docs:rename":"node scripts/rename-docs-with-category.cjs","security:fix":"node security-audit/safe-fix.cjs","versori:info":"npm view @versori/run --json","security:full":"npm run security:check && npm run security:snyk","security:snyk":"node security-audit/snyk-setup.cjs","test:coverage":"jest --coverage","validate:full":"npm run lint && npm test && npm run test:integration:live && npm run test:deno:live && npm run build","versori:audit":"npm audit | grep @versori || echo 'No @versori packages found in audit'","versori:check":"npm view @versori/run version","prepublishOnly":"node scripts/prepublish.cjs","security:audit":"node security-audit/security-audit.cjs","security:check":"npm run security:audit:npm && npm run security:audit","test:deno:live":"bash scripts/test-deno-local.sh","docs:rename:dry":"node scripts/rename-docs-with-category.cjs --dry-run","versori:monitor":"node scripts/versori-monitor.cjs","docs:token-count":"node scripts/count-tokens.cjs","validate:exports":"node scripts/validate-exports.mjs","versori:detailed":"node scripts/versori-monitor.cjs --detailed","versori:outdated":"npm outdated @versori/run || true","versori:security":"node scripts/versori-monitor.cjs --security-only","versori:versions":"node scripts/versori-monitor.cjs --version-only","docs:fix-encoding":"node scripts/fix-emoji-encoding.mjs","fixtures:generate":"tsx tests/fixtures/generate-fixtures.ts","security:fix:high":"node security-audit/safe-fix.cjs high","docs:inject-tokens":"node scripts/inject-tokens.cjs","security:audit:npm":"npm audit --audit-level=moderate","security:snyk:test":"snyk test","validate:templates":"node scripts/validate-templates.cjs","security:audit:json":"npm audit --json > artifacts/security-audit-$(date +%Y%m%d).json || true","versori:consistency":"node scripts/versori-monitor.cjs --consistency-only","security:snyk:report":"snyk test --json > artifacts/snyk-report-$(date +%Y%m%d).json","docs:fix-encoding:dry":"node scripts/fix-emoji-encoding.mjs --dry-run","security:fix:critical":"node security-audit/safe-fix.cjs critical","security:snyk:monitor":"snyk monitor","test:integration:live":"jest --config jest.config.integration.cjs"},"_npmUser":{"name":"sagirish","email":"sagirish@gmail.com"},"jest-junit":{"outputName":"junit.xml","outputDirectory":"artifacts"},"_npmVersion":"10.9.3","description":"Fluent Commerce SDK - Deno & Node.js Compatible","directories":{},"_nodeVersion":"22.20.0","dependencies":{"ssh2":"^1.17.0","graphql":"^16.9.0","csv-parse":"^5.6.0","hyparquet":"^1.3.0","@dsnp/parquetjs":"^1.8.7","fast-xml-parser":"^5.2.5","ssh2-sftp-client":"^12.0.1","@aws-sdk/client-s3":"^3.879.0","@aws-sdk/credential-providers":"^3.879.0","@aws-sdk/s3-request-presigner":"^3.886.0"},"_hasShrinkwrap":false,"devDependencies":{"ora":"^5.4.1","tsx":"^4.20.6","glob":"^11.0.3","jest":"^29.7.0","uuid":"^13.0.0","chalk":"^4.1.2","dotenv":"^17.2.2","eslint":"^8.57.0","marked":"^14.1.4","p-limit":"^3.1.0","ts-jest":"^29.1.0","ts-node":"^10.9.0","prettier":"^3.2.0","puppeteer":"^23.11.1","jest-junit":"^16.0.0","typescript":"^5.9.2","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/ssh2":"^1.15.5","@versori/run":"^0.4.18","highlight.js":"^11.11.1","markdownlint-cli":"^0.46.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.0","@types/ssh2-sftp-client":"^9.0.5","@typescript-eslint/parser":"^7.0.0","@typescript-eslint/eslint-plugin":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/fc-connect-sdk_0.1.52_1771175346425_0.981515175709774","host":"s3://npm-registry-packages-npm-production"}},"0.1.53":{"name":"@fluentcommerce/fc-connect-sdk","version":"0.1.53","keywords":["fluent","commerce","sdk","integration","inventory","batch","graphql"],"author":{"name":"Fluent Commerce"},"license":"MIT","_id":"@fluentcommerce/fc-connect-sdk@0.1.53","maintainers":[{"name":"sagirish","email":"sagirish@gmail.com"}],"bin":{"fc-connect":"bin/fc-connect.js","fc-connect-validate-schema":"bin/validate-schema.js","fc-connect-analyze-coverage":"bin/analyze-coverage.js","fc-connect-introspect-schema":"bin/introspect-schema.js","fc-connect-generate-query-mapping":"bin/generate-query-mapping.js","fc-connect-analyze-source-structure":"bin/analyze-source-structure.js","fc-connect-generate-mutation-mapping":"bin/generate-mutation-mapping.js"},"dist":{"shasum":"a90440d1bc6ebb1a3f89797d6ae0fef754cf8c90","tarball":"https://registry.npmjs.org/@fluentcommerce/fc-connect-sdk/-/fc-connect-sdk-0.1.53.tgz","fileCount":1157,"integrity":"sha512-POnEAbqzvCnBqaicM28N1okTTHqnKAmKdQkz7DEZLSAqOuK3UfGz5ZK5Z+ahpbWMh4yHWwenjwXoh6ehIStJZA==","signatures":[{"sig":"MEUCIC564K/ywJa5SpHqPNRq2L4klMPEDkG1JoXZqw/DuloCAiEAhavRQdUUXUl1IpT/sDshRxGbpHPavQotX75y7MaajPw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":12955204},"main":"dist/cjs/index.js","type":"module","types":"dist/cjs/index.d.ts","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"20347a50e48a05525ce9a0c19827cc78bf12bcb3","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"jest","build":"npm run clean && npm run build:cjs && npm run fix:cjs && npm run build:esm && npm run fix:esm && npm run build:types","clean":"rm -rf dist || echo No dist folder to clean","fix:cjs":"node scripts/fix-cjs-package.cjs","fix:esm":"node scripts/fix-esm-imports.cjs","prepare":"npm run build","ai:queue":"node scripts/generate-ai-queue.cjs","docs:all":"npm run docs:pdf","docs:pdf":"node scripts/generate-pdfs.cjs","lint:fix":"eslint src --ext .ts --fix","test:cov":"jest --coverage --coverageReporters=json-summary --coverageReporters=lcov --coverageReporters=text --reporters=default --reporters=jest-junit","validate":"npm run lint && npm run test -- --testPathIgnorePatterns=\"integration|webhook-validation|xml-parser|xml-error-handling|xml-path-resolver\" && npm run build","build:cjs":"tsc -p tsconfig.json","build:esm":"tsc -p tsconfig.esm.json","test:deno":"node scripts/analyze-deno-compat.cjs","test:watch":"jest --watch","build:types":"tsc -p tsconfig.types.json","docs:rename":"node scripts/rename-docs-with-category.cjs","security:fix":"node security-audit/safe-fix.cjs","versori:info":"npm view @versori/run --json","security:full":"npm run security:check && npm run security:snyk","security:snyk":"node security-audit/snyk-setup.cjs","test:coverage":"jest --coverage","validate:full":"npm run lint && npm test && npm run test:integration:live && npm run test:deno:live && npm run build","versori:audit":"npm audit | grep @versori || echo 'No @versori packages found in audit'","versori:check":"npm view @versori/run version","prepublishOnly":"node scripts/prepublish.cjs","security:audit":"node security-audit/security-audit.cjs","security:check":"npm run security:audit:npm && npm run security:audit","test:deno:live":"bash scripts/test-deno-local.sh","docs:rename:dry":"node scripts/rename-docs-with-category.cjs --dry-run","versori:monitor":"node scripts/versori-monitor.cjs","docs:token-count":"node scripts/count-tokens.cjs","validate:exports":"node scripts/validate-exports.mjs","versori:detailed":"node scripts/versori-monitor.cjs --detailed","versori:outdated":"npm outdated @versori/run || true","versori:security":"node scripts/versori-monitor.cjs --security-only","versori:versions":"node scripts/versori-monitor.cjs --version-only","docs:fix-encoding":"node scripts/fix-emoji-encoding.mjs","fixtures:generate":"tsx tests/fixtures/generate-fixtures.ts","security:fix:high":"node security-audit/safe-fix.cjs high","docs:inject-tokens":"node scripts/inject-tokens.cjs","security:audit:npm":"npm audit --audit-level=moderate","security:snyk:test":"snyk test","validate:templates":"node scripts/validate-templates.cjs","security:audit:json":"npm audit --json > artifacts/security-audit-$(date +%Y%m%d).json || true","versori:consistency":"node scripts/versori-monitor.cjs --consistency-only","security:snyk:report":"snyk test --json > artifacts/snyk-report-$(date +%Y%m%d).json","docs:fix-encoding:dry":"node scripts/fix-emoji-encoding.mjs --dry-run","security:fix:critical":"node security-audit/safe-fix.cjs critical","security:snyk:monitor":"snyk monitor","test:integration:live":"jest --config jest.config.integration.cjs"},"_npmUser":{"name":"sagirish","email":"sagirish@gmail.com"},"jest-junit":{"outputName":"junit.xml","outputDirectory":"artifacts"},"_npmVersion":"10.9.3","description":"Fluent Commerce SDK - Deno & Node.js Compatible","directories":{},"_nodeVersion":"22.20.0","dependencies":{"ssh2":"^1.17.0","graphql":"^16.9.0","csv-parse":"^5.6.0","hyparquet":"^1.3.0","@dsnp/parquetjs":"^1.8.7","fast-xml-parser":"^5.2.5","ssh2-sftp-client":"^12.0.1","@aws-sdk/client-s3":"^3.879.0","@aws-sdk/credential-providers":"^3.879.0","@aws-sdk/s3-request-presigner":"^3.886.0"},"_hasShrinkwrap":false,"devDependencies":{"ora":"^5.4.1","tsx":"^4.20.6","glob":"^11.0.3","jest":"^29.7.0","uuid":"^13.0.0","chalk":"^4.1.2","dotenv":"^17.2.2","eslint":"^8.57.0","marked":"^14.1.4","p-limit":"^3.1.0","ts-jest":"^29.1.0","ts-node":"^10.9.0","prettier":"^3.2.0","puppeteer":"^23.11.1","jest-junit":"^16.0.0","typescript":"^5.9.2","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/ssh2":"^1.15.5","@versori/run":"^0.4.18","highlight.js":"^11.11.1","markdownlint-cli":"^0.46.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.0","@types/ssh2-sftp-client":"^9.0.5","@typescript-eslint/parser":"^7.0.0","@typescript-eslint/eslint-plugin":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/fc-connect-sdk_0.1.53_1771260322891_0.02355412786938338","host":"s3://npm-registry-packages-npm-production"}},"0.1.54":{"name":"@fluentcommerce/fc-connect-sdk","version":"0.1.54","keywords":["fluent","commerce","sdk","integration","inventory","batch","graphql"],"author":{"name":"Fluent Commerce"},"license":"MIT","_id":"@fluentcommerce/fc-connect-sdk@0.1.54","maintainers":[{"name":"sagirish","email":"sagirish@gmail.com"}],"bin":{"fc-connect":"bin/fc-connect.js","fc-connect-validate-schema":"bin/validate-schema.js","fc-connect-analyze-coverage":"bin/analyze-coverage.js","fc-connect-introspect-schema":"bin/introspect-schema.js","fc-connect-generate-query-mapping":"bin/generate-query-mapping.js","fc-connect-analyze-source-structure":"bin/analyze-source-structure.js","fc-connect-generate-mutation-mapping":"bin/generate-mutation-mapping.js"},"dist":{"shasum":"3da47c47499754874aa7ac75ab8d84c02fd08cc3","tarball":"https://registry.npmjs.org/@fluentcommerce/fc-connect-sdk/-/fc-connect-sdk-0.1.54.tgz","fileCount":1168,"integrity":"sha512-VhotrHOtIBA+wUprqBCi/x/JlDJMEmaZ7G8wDk84kS/8Csamc73UISWzWvXE5naOsnmMnBHUusFe4ByqjYcrcw==","signatures":[{"sig":"MEYCIQCdxYUC+Dc/2S909tBDQ3AdR0P8OkNlYcng26FdUYWZnwIhAP32tnOaJCkb4L/kQO7r7J573eRVIIT1VO0u9qjJOS7C","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":12997753},"main":"dist/cjs/index.js","type":"module","types":"dist/cjs/index.d.ts","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"20347a50e48a05525ce9a0c19827cc78bf12bcb3","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"jest","build":"npm run clean && npm run build:cjs && npm run fix:cjs && npm run build:esm && npm run fix:esm && npm run build:types","clean":"rm -rf dist || echo No dist folder to clean","fix:cjs":"node scripts/fix-cjs-package.cjs","fix:esm":"node scripts/fix-esm-imports.cjs","prepare":"npm run build","ai:queue":"node scripts/generate-ai-queue.cjs","docs:all":"npm run docs:pdf","docs:pdf":"node scripts/generate-pdfs.cjs","lint:fix":"eslint src --ext .ts --fix","test:cov":"jest --coverage --coverageReporters=json-summary --coverageReporters=lcov --coverageReporters=text --reporters=default --reporters=jest-junit","validate":"npm run lint && npm run test -- --testPathIgnorePatterns=\"integration|webhook-validation|xml-parser|xml-error-handling|xml-path-resolver\" && npm run build","build:cjs":"tsc -p tsconfig.json","build:esm":"tsc -p tsconfig.esm.json","test:deno":"node scripts/analyze-deno-compat.cjs","test:watch":"jest --watch","build:types":"tsc -p tsconfig.types.json","docs:rename":"node scripts/rename-docs-with-category.cjs","security:fix":"node security-audit/safe-fix.cjs","versori:info":"npm view @versori/run --json","security:full":"npm run security:check && npm run security:snyk","security:snyk":"node security-audit/snyk-setup.cjs","test:coverage":"jest --coverage","validate:full":"npm run lint && npm test && npm run test:integration:live && npm run test:deno:live && npm run build","versori:audit":"npm audit | grep @versori || echo 'No @versori packages found in audit'","versori:check":"npm view @versori/run version","prepublishOnly":"node scripts/prepublish.cjs","security:audit":"node security-audit/security-audit.cjs","security:check":"npm run security:audit:npm && npm run security:audit","test:deno:live":"bash scripts/test-deno-local.sh","docs:rename:dry":"node scripts/rename-docs-with-category.cjs --dry-run","versori:monitor":"node scripts/versori-monitor.cjs","docs:token-count":"node scripts/count-tokens.cjs","validate:exports":"node scripts/validate-exports.mjs","versori:detailed":"node scripts/versori-monitor.cjs --detailed","versori:outdated":"npm outdated @versori/run || true","versori:security":"node scripts/versori-monitor.cjs --security-only","versori:versions":"node scripts/versori-monitor.cjs --version-only","docs:fix-encoding":"node scripts/fix-emoji-encoding.mjs","fixtures:generate":"tsx tests/fixtures/generate-fixtures.ts","security:fix:high":"node security-audit/safe-fix.cjs high","docs:inject-tokens":"node scripts/inject-tokens.cjs","security:audit:npm":"npm audit --audit-level=moderate","security:snyk:test":"snyk test","validate:templates":"node scripts/validate-templates.cjs","security:audit:json":"npm audit --json > artifacts/security-audit-$(date +%Y%m%d).json || true","versori:consistency":"node scripts/versori-monitor.cjs --consistency-only","security:snyk:report":"snyk test --json > artifacts/snyk-report-$(date +%Y%m%d).json","docs:fix-encoding:dry":"node scripts/fix-emoji-encoding.mjs --dry-run","security:fix:critical":"node security-audit/safe-fix.cjs critical","security:snyk:monitor":"snyk monitor","test:integration:live":"jest --config jest.config.integration.cjs"},"_npmUser":{"name":"sagirish","email":"sagirish@gmail.com"},"jest-junit":{"outputName":"junit.xml","outputDirectory":"artifacts"},"_npmVersion":"10.9.3","description":"Fluent Commerce SDK - Deno & Node.js Compatible","directories":{},"_nodeVersion":"22.20.0","dependencies":{"ssh2":"^1.17.0","graphql":"^16.9.0","csv-parse":"^5.6.0","hyparquet":"^1.3.0","@dsnp/parquetjs":"^1.8.7","fast-xml-parser":"^5.2.5","ssh2-sftp-client":"^12.0.1","@aws-sdk/client-s3":"^3.879.0","@aws-sdk/credential-providers":"^3.879.0","@aws-sdk/s3-request-presigner":"^3.886.0"},"_hasShrinkwrap":false,"devDependencies":{"ora":"^5.4.1","tsx":"^4.20.6","glob":"^11.0.3","jest":"^29.7.0","uuid":"^13.0.0","chalk":"^4.1.2","dotenv":"^17.2.2","eslint":"^8.57.0","marked":"^14.1.4","p-limit":"^3.1.0","ts-jest":"^29.1.0","ts-node":"^10.9.0","prettier":"^3.2.0","puppeteer":"^23.11.1","jest-junit":"^16.0.0","typescript":"^5.9.2","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/ssh2":"^1.15.5","@versori/run":"^0.4.18","highlight.js":"^11.11.1","markdownlint-cli":"^0.46.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.0","@types/ssh2-sftp-client":"^9.0.5","@typescript-eslint/parser":"^7.0.0","@typescript-eslint/eslint-plugin":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/fc-connect-sdk_0.1.54_1771604837716_0.9673568464114417","host":"s3://npm-registry-packages-npm-production"}},"0.1.55":{"name":"@fluentcommerce/fc-connect-sdk","version":"0.1.55","keywords":["fluent","commerce","sdk","integration","inventory","batch","graphql"],"author":{"name":"Fluent Commerce"},"license":"MIT","_id":"@fluentcommerce/fc-connect-sdk@0.1.55","maintainers":[{"name":"sagirish","email":"sagirish@gmail.com"}],"bin":{"fc-connect":"bin/fc-connect.js","fc-connect-validate-schema":"bin/validate-schema.js","fc-connect-analyze-coverage":"bin/analyze-coverage.js","fc-connect-introspect-schema":"bin/introspect-schema.js","fc-connect-generate-query-mapping":"bin/generate-query-mapping.js","fc-connect-analyze-source-structure":"bin/analyze-source-structure.js","fc-connect-generate-mutation-mapping":"bin/generate-mutation-mapping.js"},"dist":{"shasum":"328934b966b5cf4fe911686979bf46664f5acdda","tarball":"https://registry.npmjs.org/@fluentcommerce/fc-connect-sdk/-/fc-connect-sdk-0.1.55.tgz","fileCount":1167,"integrity":"sha512-i2aawvmyTnt1Nm/Oc4tMmtUPePefr5y02QNAgWe3jfsPiChcFUrqE6fwVimsrj32nJTSFS4AsQ1t54O5hpsONg==","signatures":[{"sig":"MEUCIAGMUwfiab5Be1RlNBw4PKogSr5hP8hdh2iT36putmDMAiEA/brez8Is9ZGZMp6MFN9YfHoC+USz1ZJXnLuxz96hpW4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13327388},"main":"dist/cjs/index.js","type":"module","types":"dist/cjs/index.d.ts","module":"dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"9deb038ce77545d13e366f6b32d31fd6798d9352","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"jest","build":"npm run clean && npm run build:cjs && npm run fix:cjs && npm run build:esm && npm run fix:esm && npm run build:types","clean":"rm -rf dist || echo No dist folder to clean","fix:cjs":"node scripts/fix-cjs-package.cjs","fix:esm":"node scripts/fix-esm-imports.cjs","prepare":"npm run build","ai:queue":"node scripts/generate-ai-queue.cjs","docs:all":"npm run docs:pdf","docs:pdf":"node scripts/generate-pdfs.cjs","lint:fix":"eslint src --ext .ts --fix","test:cov":"jest --coverage --coverageReporters=json-summary --coverageReporters=lcov --coverageReporters=text --reporters=default --reporters=jest-junit","validate":"npm run lint && npm run test -- --testPathIgnorePatterns=\"integration|webhook-validation|xml-parser|xml-error-handling|xml-path-resolver\" && npm run build","build:cjs":"tsc -p tsconfig.json","build:esm":"tsc -p tsconfig.esm.json","test:deno":"node scripts/analyze-deno-compat.cjs","test:watch":"jest --watch","build:types":"tsc -p tsconfig.types.json","docs:rename":"node scripts/rename-docs-with-category.cjs","security:fix":"node security-audit/safe-fix.cjs","versori:info":"npm view @versori/run --json","security:full":"npm run security:check && npm run security:snyk","security:snyk":"node security-audit/snyk-setup.cjs","test:coverage":"jest --coverage","validate:full":"npm run lint && npm test && npm run test:integration:live && npm run test:deno:live && npm run build","versori:audit":"npm audit | grep @versori || echo 'No @versori packages found in audit'","versori:check":"npm view @versori/run version","prepublishOnly":"node scripts/prepublish.cjs","security:audit":"node security-audit/security-audit.cjs","security:check":"npm run security:audit:npm && npm run security:audit","test:deno:live":"bash scripts/test-deno-local.sh","docs:rename:dry":"node scripts/rename-docs-with-category.cjs --dry-run","versori:monitor":"node scripts/versori-monitor.cjs","docs:token-count":"node scripts/count-tokens.cjs","validate:exports":"node scripts/validate-exports.mjs","versori:detailed":"node scripts/versori-monitor.cjs --detailed","versori:outdated":"npm outdated @versori/run || true","versori:security":"node scripts/versori-monitor.cjs --security-only","versori:versions":"node scripts/versori-monitor.cjs --version-only","docs:fix-encoding":"node scripts/fix-emoji-encoding.mjs","fixtures:generate":"tsx tests/fixtures/generate-fixtures.ts","security:fix:high":"node security-audit/safe-fix.cjs high","docs:inject-tokens":"node scripts/inject-tokens.cjs","security:audit:npm":"npm audit --audit-level=moderate","security:snyk:test":"snyk test","validate:templates":"node scripts/validate-templates.cjs","security:audit:json":"npm audit --json > artifacts/security-audit-$(date +%Y%m%d).json || true","versori:consistency":"node scripts/versori-monitor.cjs --consistency-only","security:snyk:report":"snyk test --json > artifacts/snyk-report-$(date +%Y%m%d).json","docs:fix-encoding:dry":"node scripts/fix-emoji-encoding.mjs --dry-run","security:fix:critical":"node security-audit/safe-fix.cjs critical","security:snyk:monitor":"snyk monitor","test:integration:live":"jest --config jest.config.integration.cjs"},"_npmUser":{"name":"sagirish","email":"sagirish@gmail.com"},"jest-junit":{"outputName":"junit.xml","outputDirectory":"artifacts"},"_npmVersion":"11.5.1","description":"Fluent Commerce SDK - Deno & Node.js Compatible","directories":{},"_nodeVersion":"24.14.0","dependencies":{"ssh2":"^1.17.0","graphql":"^16.9.0","csv-parse":"^5.6.0","hyparquet":"^1.3.0","@dsnp/parquetjs":"^1.8.7","fast-xml-parser":"^5.2.5","ssh2-sftp-client":"^12.0.1","@aws-sdk/client-s3":"^3.879.0","@aws-sdk/credential-providers":"^3.879.0","@aws-sdk/s3-request-presigner":"^3.886.0"},"_hasShrinkwrap":false,"devDependencies":{"ora":"^5.4.1","tsx":"^4.20.6","glob":"^11.0.3","jest":"^29.7.0","uuid":"^13.0.0","chalk":"^4.1.2","dotenv":"^17.2.2","eslint":"^8.57.0","marked":"^14.1.4","p-limit":"^3.1.0","ts-jest":"^29.1.0","ts-node":"^10.9.0","prettier":"^3.2.0","puppeteer":"^23.11.1","jest-junit":"^16.0.0","typescript":"^5.9.2","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/ssh2":"^1.15.5","@versori/run":"^0.5.10","highlight.js":"^11.11.1","markdownlint-cli":"^0.48.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.0","@types/ssh2-sftp-client":"^9.0.5","@fluentcommerce/ai-skills":"^0.14.0","@typescript-eslint/parser":"^7.0.0","@fluentcommerce/fluent-mcp-extn":"^0.7.3","@typescript-eslint/eslint-plugin":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/fc-connect-sdk_0.1.55_1775126333662_0.6874823834655794","host":"s3://npm-registry-packages-npm-production"}},"0.1.56":{"name":"@fluentcommerce/fc-connect-sdk","version":"0.1.56","description":"Fluent Commerce SDK - Deno & Node.js Compatible","type":"module","main":"dist/cjs/index.js","module":"dist/esm/index.js","types":"dist/cjs/index.d.ts","exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"bin":{"fc-connect":"bin/fc-connect.js","fc-connect-generate-mutation-mapping":"bin/generate-mutation-mapping.js","fc-connect-generate-query-mapping":"bin/generate-query-mapping.js","fc-connect-introspect-schema":"bin/introspect-schema.js","fc-connect-validate-schema":"bin/validate-schema.js","fc-connect-analyze-coverage":"bin/analyze-coverage.js","fc-connect-analyze-source-structure":"bin/analyze-source-structure.js"},"scripts":{"build":"npm run clean && npm run build:cjs && npm run fix:cjs && npm run build:esm && npm run fix:esm && npm run build:types","build:cjs":"tsc -p tsconfig.json","fix:cjs":"node scripts/fix-cjs-package.cjs","build:esm":"tsc -p tsconfig.esm.json","fix:esm":"node scripts/fix-esm-imports.cjs","build:types":"tsc -p tsconfig.types.json","clean":"rm -rf dist || echo No dist folder to clean","dev":"tsc --watch","lint":"eslint src --ext .ts","lint:fix":"eslint src --ext .ts --fix","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","test:integration:live":"jest --config jest.config.integration.cjs","fixtures:generate":"tsx tests/fixtures/generate-fixtures.ts","validate":"npm run lint && npm run test -- --testPathIgnorePatterns=\"integration|webhook-validation|xml-parser|xml-error-handling|xml-path-resolver\" && npm run build","validate:full":"npm run lint && npm test && npm run test:integration:live && npm run test:deno:live && npm run build","prepublishOnly":"node scripts/prepublish.cjs","prepare":"npm run build","test:deno":"node scripts/analyze-deno-compat.cjs","test:deno:live":"bash scripts/test-deno-local.sh","versori:monitor":"node scripts/versori-monitor.cjs","versori:check":"npm view @versori/run version","versori:info":"npm view @versori/run --json","versori:outdated":"npm outdated @versori/run || true","versori:audit":"npm audit | grep @versori || echo 'No @versori packages found in audit'","versori:versions":"node scripts/versori-monitor.cjs --version-only","versori:security":"node scripts/versori-monitor.cjs --security-only","versori:consistency":"node scripts/versori-monitor.cjs --consistency-only","versori:detailed":"node scripts/versori-monitor.cjs --detailed","docs:pdf":"node scripts/generate-pdfs.cjs","docs:rename":"node scripts/rename-docs-with-category.cjs","docs:rename:dry":"node scripts/rename-docs-with-category.cjs --dry-run","docs:token-count":"node scripts/count-tokens.cjs","docs:inject-tokens":"node scripts/inject-tokens.cjs","docs:all":"npm run docs:pdf","docs:fix-encoding":"node scripts/fix-emoji-encoding.mjs","docs:fix-encoding:dry":"node scripts/fix-emoji-encoding.mjs --dry-run","validate:templates":"node scripts/validate-templates.cjs","validate:exports":"node scripts/validate-exports.mjs","test:cov":"jest --coverage --coverageReporters=json-summary --coverageReporters=lcov --coverageReporters=text --reporters=default --reporters=jest-junit","ai:queue":"node scripts/generate-ai-queue.cjs","security:audit":"node security-audit/security-audit.cjs","security:audit:npm":"npm audit --audit-level=moderate","security:audit:json":"npm audit --json > artifacts/security-audit-$(date +%Y%m%d).json || true","security:check":"npm run security:audit:npm && npm run security:audit","security:snyk":"node security-audit/snyk-setup.cjs","security:snyk:test":"snyk test","security:snyk:monitor":"snyk monitor","security:snyk:report":"snyk test --json > artifacts/snyk-report-$(date +%Y%m%d).json","security:fix":"node security-audit/safe-fix.cjs","security:fix:critical":"node security-audit/safe-fix.cjs critical","security:fix:high":"node security-audit/safe-fix.cjs high","security:full":"npm run security:check && npm run security:snyk"},"jest-junit":{"outputDirectory":"artifacts","outputName":"junit.xml"},"keywords":["fluent","commerce","sdk","integration","inventory","batch","graphql"],"author":{"name":"Fluent Commerce"},"license":"MIT","engines":{"node":">=18.0.0"},"devDependencies":{"@fluentcommerce/ai-skills":"^0.14.0","@fluentcommerce/fluent-mcp-extn":"^0.7.3","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/ssh2":"^1.15.5","@types/ssh2-sftp-client":"^9.0.5","@typescript-eslint/eslint-plugin":"^7.0.0","@typescript-eslint/parser":"^7.0.0","@versori/run":"^0.5.10","chalk":"^4.1.2","dotenv":"^17.2.2","eslint":"^8.57.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.1.0","glob":"^11.0.3","highlight.js":"^11.11.1","jest":"^29.7.0","jest-junit":"^16.0.0","markdownlint-cli":"^0.48.0","marked":"^14.1.4","ora":"^5.4.1","p-limit":"^3.1.0","prettier":"^3.2.0","puppeteer":"^23.11.1","ts-jest":"^29.1.0","ts-node":"^10.9.0","tsx":"^4.20.6","typescript":"^5.9.2","uuid":"^13.0.0"},"dependencies":{"@aws-sdk/client-s3":"^3.879.0","@aws-sdk/credential-providers":"^3.879.0","@aws-sdk/s3-request-presigner":"^3.886.0","@dsnp/parquetjs":"^1.8.7","csv-parse":"^5.6.0","fast-xml-parser":"^5.2.5","graphql":"^16.9.0","hyparquet":"^1.3.0","ssh2":"^1.17.0","ssh2-sftp-client":"^12.0.1"},"_id":"@fluentcommerce/fc-connect-sdk@0.1.56","gitHead":"9deb038ce77545d13e366f6b32d31fd6798d9352","_nodeVersion":"24.14.0","_npmVersion":"11.5.1","dist":{"integrity":"sha512-Kr7MNW2wswE3yKKv4IjImJJTaBjieSTU7aO7/ZKXyK0Kg+7SANNH0WVmb8Sn7TFwhjx2gx98YrZdEtkGuyS3ow==","shasum":"35419c415526aa68246cb812c811364e6f2f67c5","tarball":"https://registry.npmjs.org/@fluentcommerce/fc-connect-sdk/-/fc-connect-sdk-0.1.56.tgz","fileCount":1167,"unpackedSize":13328010,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDA5EZWXN2AAjzcHf4FTL4+uqrxxbgl6pXW2oJNSFl8cwIhAPKj5b9HuYgYhfDbRZwGoaLx8DpbVlNMokI92/RFQ0oC"}]},"_npmUser":{"name":"sagirish","email":"sagirish@gmail.com"},"directories":{},"maintainers":[{"name":"sagirish","email":"sagirish@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/fc-connect-sdk_0.1.56_1776143485963_0.568250999691311"},"_hasShrinkwrap":false}},"time":{"created":"2025-08-31T08:12:58.400Z","modified":"2026-04-14T05:11:26.379Z","0.0.1-alpha":"2025-08-31T08:12:58.665Z","0.0.2-alpha":"2025-08-31T08:30:23.099Z","0.0.3-alpha":"2025-08-31T14:02:03.732Z","0.0.4-alpha":"2025-08-31T14:02:59.500Z","0.0.5-alpha":"2025-08-31T14:07:52.344Z","0.0.6-alpha":"2025-08-31T14:44:35.883Z","0.0.7-alpha":"2025-08-31T14:52:44.320Z","0.0.8-alpha":"2025-09-01T02:40:12.900Z","0.0.9-alpha":"2025-09-01T02:46:37.330Z","0.0.10-alpha":"2025-09-01T03:17:23.020Z","0.0.11-alpha":"2025-09-01T03:28:54.042Z","0.0.12-alpha":"2025-09-01T05:03:38.476Z","0.0.13-alpha":"2025-09-01T05:56:26.193Z","0.0.14-alpha":"2025-09-01T06:05:15.756Z","0.0.15-alpha":"2025-09-01T06:36:32.983Z","0.0.16-alpha":"2025-09-01T06:43:56.667Z","0.0.17-alpha":"2025-09-01T06:59:10.277Z","0.0.18-alpha":"2025-09-01T07:02:08.527Z","0.0.19-alpha":"2025-09-01T07:11:59.896Z","0.0.20-alpha":"2025-09-01T07:20:17.382Z","0.0.21-alpha":"2025-09-01T07:45:44.270Z","0.0.22-alpha":"2025-09-01T07:53:59.982Z","0.0.23-alpha":"2025-09-01T08:01:47.979Z","0.0.24-alpha":"2025-09-01T09:01:54.487Z","0.0.25-alpha":"2025-09-01T09:18:33.307Z","0.0.26-alpha":"2025-09-01T09:41:31.516Z","0.0.27-alpha":"2025-09-01T09:55:51.520Z","0.0.28-alpha":"2025-09-01T10:06:28.135Z","0.0.29-alpha":"2025-09-01T10:16:19.720Z","0.0.30-alpha":"2025-09-01T10:49:11.155Z","0.0.31-alpha":"2025-09-01T10:55:46.055Z","0.0.32-alpha":"2025-09-01T11:06:08.735Z","0.0.33-alpha":"2025-09-01T11:43:26.511Z","0.0.34-alpha":"2025-09-01T11:46:45.424Z","0.0.35-alpha":"2025-09-01T12:41:01.076Z","0.0.36-alpha":"2025-09-01T13:05:13.659Z","0.0.37-alpha":"2025-09-01T14:48:44.967Z","0.0.38-alpha":"2025-09-02T12:59:53.471Z","0.0.39-alpha":"2025-09-02T15:03:45.641Z","0.0.40-alpha":"2025-09-02T15:25:44.298Z","0.0.40":"2025-09-03T05:13:41.024Z","0.0.41-alpha":"2025-09-03T05:15:54.389Z","0.0.42-alpha":"2025-09-03T05:30:30.799Z","0.0.43-alpha":"2025-09-03T06:11:07.855Z","0.0.44-alpha":"2025-09-03T11:37:05.236Z","0.0.45-alpha":"2025-09-03T11:56:52.066Z","0.0.46-alpha":"2025-09-03T12:00:04.849Z","0.0.47-alpha":"2025-09-03T12:03:36.265Z","0.0.48-alpha":"2025-09-03T12:42:43.794Z","0.0.49-alpha":"2025-09-03T13:20:01.524Z","0.0.50-alpha":"2025-09-03T16:07:34.488Z","0.0.51-alpha":"2025-09-03T16:25:07.396Z","0.0.52-alpha":"2025-09-04T03:56:27.085Z","0.0.53-alpha":"2025-09-04T06:11:01.165Z","0.0.54-alpha":"2025-09-04T06:38:15.922Z","0.0.55-alpha":"2025-09-04T06:51:23.657Z","0.0.56-alpha":"2025-09-07T13:16:38.312Z","0.0.57-alpha":"2025-09-07T13:28:19.407Z","0.0.58-alpha":"2025-09-07T13:31:26.305Z","0.0.59-alpha":"2025-09-07T13:36:19.213Z","0.0.60-alpha":"2025-09-07T14:25:32.145Z","0.0.61-alpha":"2025-09-07T15:44:53.238Z","0.0.62-alpha":"2025-09-08T05:01:49.799Z","0.0.63-alpha":"2025-09-08T05:19:20.174Z","0.0.64-alpha":"2025-09-08T05:58:33.199Z","0.0.65-alpha":"2025-09-08T06:38:36.704Z","0.0.67-alpha":"2025-09-08T07:19:34.401Z","0.0.68-alpha":"2025-09-08T08:15:21.806Z","0.0.69-alpha":"2025-09-08T17:34:58.988Z","0.0.70":"2025-09-09T07:45:41.655Z","0.0.71":"2025-09-09T09:33:06.815Z","0.0.72":"2025-09-09T09:56:28.579Z","0.0.73":"2025-09-09T10:06:16.722Z","0.0.74":"2025-09-09T10:19:25.300Z","0.0.75":"2025-09-09T11:05:29.007Z","0.0.76":"2025-09-09T11:41:26.045Z","0.0.77":"2025-09-11T09:01:26.545Z","0.0.78":"2025-09-12T08:31:35.984Z","0.1.0":"2025-09-23T11:11:24.701Z","0.0.79-alpha.1":"2025-09-23T12:00:19.128Z","0.0.80":"2025-09-23T13:05:34.543Z","0.0.81":"2025-09-23T14:09:58.303Z","0.0.82":"2025-10-03T15:02:02.061Z","0.0.83":"2025-10-03T17:12:24.107Z","0.0.84":"2025-10-03T17:23:04.377Z","0.0.85":"2025-10-03T17:28:40.920Z","0.0.86":"2025-10-05T15:50:49.283Z","0.0.88":"2025-10-06T06:46:34.450Z","0.0.89":"2025-10-15T08:04:12.943Z","0.0.90":"2025-10-15T15:25:01.047Z","1.0.0":"2025-10-15T15:41:52.516Z","0.0.91":"2025-10-15T16:30:46.924Z","0.0.92":"2025-10-16T02:36:35.198Z","0.0.93":"2025-10-16T06:53:46.693Z","0.0.96":"2025-10-17T03:24:47.036Z","0.0.97":"2025-10-17T06:41:36.619Z","0.0.98":"2025-10-17T10:47:22.876Z","0.0.99":"2025-10-17T17:00:16.061Z","0.1.1":"2025-10-19T16:51:57.586Z","0.1.2":"2025-10-23T04:58:06.264Z","0.1.3":"2025-10-23T12:23:22.117Z","0.1.5":"2025-10-24T05:28:09.765Z","0.1.6":"2025-10-24T06:48:53.380Z","0.1.7":"2025-10-24T07:04:48.304Z","0.1.8":"2025-10-24T07:25:13.271Z","0.1.10":"2025-10-24T07:56:43.568Z","0.1.11":"2025-10-24T08:16:27.312Z","0.1.12":"2025-10-24T08:36:43.622Z","0.1.13":"2025-10-24T09:50:01.933Z","0.1.14":"2025-10-24T11:25:27.313Z","0.1.15":"2025-10-24T14:35:37.290Z","0.1.17":"2025-10-27T10:00:11.459Z","0.1.18":"2025-10-27T10:30:48.582Z","0.1.19":"2025-10-27T13:00:31.815Z","0.1.21":"2025-10-27T17:34:51.195Z","0.1.22":"2025-10-28T13:43:06.593Z","0.1.25":"2025-10-29T16:40:50.423Z","0.1.26":"2025-10-30T08:30:43.364Z","0.1.30":"2025-10-30T19:57:35.019Z","0.1.31":"2025-11-02T18:40:38.833Z","0.1.34":"2025-11-04T07:13:15.543Z","0.1.35":"2025-11-04T17:23:18.144Z","0.1.36":"2025-11-05T03:49:03.520Z","0.1.37":"2025-11-05T07:49:43.542Z","0.1.38":"2025-11-05T07:54:57.715Z","0.1.39":"2025-11-05T08:23:58.874Z","0.1.40":"2025-11-13T08:21:34.721Z","0.1.41":"2025-11-13T12:48:08.405Z","0.1.43":"2025-11-14T10:11:25.692Z","0.1.44":"2025-11-14T11:38:16.462Z","0.1.45":"2025-11-17T05:31:51.120Z","0.1.46":"2025-11-19T05:32:12.406Z","0.1.48":"2025-11-19T18:17:20.238Z","0.1.49":"2025-12-09T06:14:44.428Z","0.1.50":"2025-12-09T07:37:22.366Z","0.1.51":"2026-01-13T12:46:38.969Z","0.1.52":"2026-02-15T17:09:06.704Z","0.1.53":"2026-02-16T16:45:23.219Z","0.1.54":"2026-02-20T16:27:18.066Z","0.1.55":"2026-04-02T10:38:54.007Z","0.1.56":"2026-04-14T05:11:26.267Z"},"author":{"name":"Fluent Commerce"},"license":"MIT","keywords":["fluent","commerce","sdk","integration","inventory","batch","graphql"],"description":"Fluent Commerce SDK - Deno & Node.js Compatible","maintainers":[{"name":"sagirish","email":"sagirish@gmail.com"}],"readme":"# Fluent Commerce Connect SDK\n\n[![npm version](https://img.shields.io/npm/v/@fluentcommerce/fc-connect-sdk.svg)](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk)\n[![npm downloads](https://img.shields.io/npm/dm/@fluentcommerce/fc-connect-sdk.svg)](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.4+-blue)](https://www.typescriptlang.org/)\n[![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18.0.0-green)](https://nodejs.org/)\n[![Deno Compatible](https://img.shields.io/badge/Deno-Compatible-black)](https://deno.land/)\n\n> [!CAUTION]\n> **🧪 EXPERIMENTAL — LABS PROJECT**\n>\n> This package is **NOT production-ready**. It is an internal labs experiment under active development.\n>\n> - **No stability guarantees** — APIs, services, CLI options, and config may change or break between any release\n> - **No support** — this is not an officially supported Fluent Commerce product\n> - **No warranty** — provided as-is for experimentation and internal evaluation only\n> - **Do NOT use in production** without thorough review and explicit sign-off from your team\n> - **Pin to an exact version** (`@0.1.55`) if you depend on current behavior\n\nTypeScript SDK for building **Fluent Commerce** integrations across Node.js, Deno, and the Versori platform.\n\n- **Package:** [`@fluentcommerce/fc-connect-sdk`](https://www.npmjs.com/package/@fluentcommerce/fc-connect-sdk)\n- **Documentation:** Complete markdown guides included in the package\n\n---\n\n## Table of Contents\n\n- [Overview](#overview) - What is this SDK?\n- [Features](#feature-highlights) - What can it do?\n- [**Which API Should I Use?**](#-which-api-should-i-use) - **Batch vs Event vs GraphQL** 🆕\n- [Install](#install) - Get started\n- [Quick Start](#-5-minute-quickstart) - 5-minute example\n- [What's Next?](#-whats-next) - Templates, guides, next steps\n- [Universal Mapping](#️-universal-mapping) - Field transformations\n- [**Mapping Approaches**](#-mapping-approaches-which-one-do-i-use) - **Which mapper to use?** 🆕\n  - [Mapper Comparison Guide](docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md) - Real-world scenario comparison 🆕\n- [XML/JSON → GraphQL](#-xmljson-webhooks-graphql-mutations) - Auto-generate mutations 🆕\n- [Complete Workflow Examples](#-complete-workflow-examples) - Full integration patterns\n- [Architecture](#sdk-architecture) - How it works\n- [More Examples](#-more-quick-examples) - Common patterns\n- [Core Services](#core-services) - API reference\n- [CLI Tools](#cli-tooling) - Command-line utilities\n- [Standalone Usage](#-standalone-usage-outside-versori) - Node.js/Deno app integration\n- [CLI Profile Integration](#fluent-cli-profile-integration-no-hardcoded-credentials) - Reuse Fluent CLI profiles\n- [Authentication & Webhooks](#authentication-webhooks) - Security\n- [Security & Compliance](#security--compliance) - Security audits, SOC 2, vulnerability management 🆕\n- [Common Pitfalls](#common-pitfalls-and-fixes) - Troubleshooting\n- [Support](#additional-resources) - Help & resources\n\n---\n\n## Overview\n\n**Build Fluent Commerce integrations faster** with a production-ready SDK that handles the hard parts: authentication, data parsing, field mapping, error handling, and multi-runtime compatibility.\n\n**What you get:**\n- ✅ **Universal Mapping** – Transform CSV, XML, JSON, Parquet with one config\n- ✅ **Auto-Pagination** – Extract thousands of records automatically\n- ✅ **Multi-Runtime** – Same code works in Node.js, Deno, and Versori platform\n- ✅ **Production Features** – Connection pooling, retry logic, state management, webhook validation\n- ✅ **23+ Templates** – Copy-paste ready workflows for common patterns\n\n**The SDK provides composable services – you own the workflow.** Mix and match data sources, parsers, mappers, and API clients to move data between Fluent Commerce and external systems.\n\n```\nRead → Parse → Map → Your Logic → Archive\n```\n\n> **🤔 Quick Decisions:**\n> - **Not sure which mapper?** → [Mapping Approaches Guide](#-mapping-approaches-which-one-do-i-use)\n> - **Which API to use?** → [API Decision Guide](#-which-api-should-i-use) (Batch vs Event vs GraphQL)\n> - **Want a ready-made solution?** → [23+ Production Templates](docs/01-TEMPLATES/)\n\n---\n\n## 🎯 Use This SDK If You're Building...\n\nQuick pattern matching for common integration scenarios:\n\n| Scenario | What It Looks Like |\n|----------|-------------------|\n| **📦 Inventory Sync** | Daily/hourly inventory updates from WMS → Fluent (CSV/Parquet files) |\n| **🛒 Order Integration** | E-commerce orders (SFCC, Shopify) → Fluent via webhooks (XML/JSON) |\n| **📊 Data Warehouse ETL** | Extract Fluent data → Snowflake/BigQuery for analytics (GraphQL queries) |\n| **🔄 B2B File Exchange** | Process EDI/XML files from trading partners via SFTP |\n| **📱 Admin Tools** | Internal dashboards with file upload/processing capabilities |\n| **🔔 Real-time Events** | Webhook processing for inventory updates, order status changes |\n\n**Not sure if SDK fits?** See [When to Use This SDK](#when-to-use-this-sdk) for detailed decision matrix.\n\n---\n\n## Feature Highlights\n\n**Core Services:**\n\n- **Universal Mapper** – one mapping config for CSV, XML, JSON, Parquet (16 built-in resolvers, custom resolver registry)\n- **Extraction Orchestrator** – high-level GraphQL extraction with auto-pagination, path-based extraction, validation, statistics\n- **GraphQL Error Classification** – automatic retry guidance based on Fluent error codes (C/S/T prefix), retryability detection with actionable recommendations (see `docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md`)\n- **Batch Operations** – use `client.createJob()` and `client.sendBatch()` for batch processing. `FluentBatchManager` available for Versori workflows (see `docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md`)\n- **State Management** – distributed state with KV storage, file deduplication, job caching, distributed locking with stale detection\n- **Job Tracker** – lifecycle tracking, automatic expiration handling, metadata persistence\n- **Preflight Validator** – pre-execution validation saves API quota, catches config errors early\n- **Webhook Validation Service** – cryptographic signature validation (RSA SHA256/SHA1/SHA512)\n- **Webhook Authentication Service** – Secure API key generation and validation (Deno-compatible)\n- **Partial Batch Recovery** – graceful handling of partial batch failures with retry logic\n\n**Data Layer:**\n\n- **S3 Data Source** – streaming I/O with presigned URLs (works anywhere, no AWS SDK required), constant memory footprint\n- **SFTP Data Source** – connection pooling + wait queues, exponential backoff retry, Deno compatibility for AWS Transfer Family\n- **Streaming Parsers** – CSV, XML, JSON, Parquet with memory-efficient processing, validation hooks\n- **Smart Error Handling** – 4xx errors fail fast, 5xx exponential backoff, job expiration auto-recreation. Consistent `statusCode` field across success and error responses\n\n**Architecture:**\n\n- **Multi-Runtime** – single codebase for Node.js ≥18, Deno, Versori platform (auto-detection via universal client factory)\n- **Stateless & Parallel-Safe** – all services safe for `Promise.all()`, idempotent operations\n- **Layered Design** – clear separation: Client → Service → Data → Orchestration\n- **Universal Compatibility** – consistent API regardless of environment\n\n### Supported Runtimes\n\n| Runtime          | Support | Notes                                   |\n| ---------------- | ------- | --------------------------------------- |\n| Node.js ≥ 18     | ✅      | Native `fetch` & `FormData` required    |\n| Deno             | ✅      | Import using `npm:` specifier. **SFTP:** Only AES-128 ciphers supported (see troubleshooting guide) |\n| Versori Platform | ✅      | Pass Versori `ctx` directly to services |\n\n**Deno Compatibility Notes:**\n- ✅ All ESM imports have proper extensions\n- ✅ All Node.js imports use `node:` prefix\n- ✅ Buffer support via `import { Buffer } from 'node:buffer';`\n- ⚠️ SFTP: Limited to `aes128-ctr` and `aes128-cbc` ciphers (Deno crypto limitations)\n- 📚 **Complete Guide:** `docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md`\n\n### When to Use This SDK\n\n| Scenario               | When SDK Helps                                                                                                             | When to Skip It                                                                        |\n| ---------------------- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n| **UI Applications**    | ✅ Admin tools with file upload/processing<br/>✅ Internal dashboards with data export<br/>✅ Complex data transformations | ⚠️ Simple CRUD operations<br/>⚠️ Real-time UI updates<br/>⚠️ Mobile apps (bundle size) |\n| **Event Streaming**    | ✅ Webhook-based event processing<br/>✅ Scheduled batch reactions to events                                               | ⚠️ Real-time streaming<br/>⚠️ Sub-second latency requirements                          |\n| **Simple Scripts**     | ✅ Need parsing (CSV/XML/JSON)<br/>✅ Need field mapping/transformation<br/>✅ Need retry/error handling                   | ⚠️ Single GraphQL query<br/>⚠️ No transformation needed<br/>⚠️ Prototyping/exploration |\n| **Non-Fluent Systems** | ❌ SDK is Fluent Commerce specific                                                                                         | ❌ Use system-specific SDKs                                                            |\n\n**💡 Key Insight:** The SDK shines when you need **data transformation, file processing, or multi-step workflows**. For simple API calls, direct GraphQL may be lighter.\n\n---\n\n## 🔌 Which API Should I Use?\n\nChoose the right Fluent Commerce API for your use case:\n\n| **What You're Doing** | **Use This API** | **SDK Method** | **Why** |\n|----------------------|------------------|----------------|---------|\n| **Bulk inventory sync** (CSV/Parquet files, 1000+ records) | **Batch API** | `createJob()` + `sendBatch()` | Optimized for high volume, BPP change detection, handles thousands of records efficiently |\n| **Product catalog sync** (products, variants, prices) | **Event API** | `sendEvent()` | Triggers Rubix workflows, validates business rules, workflow orchestration |\n| **Location setup** (stores, warehouses) | **Event API** | `sendEvent()` | Requires workflow orchestration |\n| **Order creation** (one-time orders) | **GraphQL** | `client.graphql()` with `createOrder` mutation | Triggers Order CREATED event, full control |\n| **Order updates/events** (status changes) | **Event API** | `sendEvent()` | Triggers workflows for order state changes |\n| **Audit/search event history** (trace flows, investigate failures) | **Event API (GET)** | `getEvents()` + `getEventById()` | Read-only event/audit retrieval with filters and pagination |\n| **Customer data** (registration, profiles) | **GraphQL** | `client.graphql()` with mutations | No Rubix workflow support for customers |\n| **Data extraction** (export to S3/SFTP) | **GraphQL** | `client.graphql()` + `ExtractionOrchestrator` | Query with auto-pagination, extract thousands of records |\n| **Single operations** (create one product, update one location) | **GraphQL** | `client.graphql()` | Direct control, immediate feedback |\n\n### Quick Rules\n\n- **Batch API**: Only supports `INVENTORY` + `UPSERT` (no products, orders, etc.)\n- **Event API**: For entities that need workflow triggers (products, locations, custom entities)\n- **GraphQL**: For queries, single mutations, customers, and when you need direct control\n\n**📚 Complete Guide:** See templates for detailed examples - `docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/` (Batch API) and `docs/01-TEMPLATES/versori/workflows/ingestion/event-api/` (Event API)\n\n---\n\n## Core Services\n\n| Area           | Services & Utilities                                                                 | Typical Use Case                                  | Notes                                     |\n| -------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------- | ----------------------------------------- |\n| Data sources   | `S3DataSource`, `SftpDataSource` (connection pooling)                                | Daily inventory files, EDI integrations    | Stream-safe reads, automatic retries      |\n| Parsers        | `CSVParserService`, `XMLParserService`, `JSONParserService`, `ParquetParserService`  | Price lists, B2B orders, API responses, analytics | Works standalone or with the orchestrator |\n| Mapping        | `UniversalMapper`, `sdkResolvers`, custom resolver registry                          | Field normalization, date/time conversions        | One mapping config for every format       |\n| Execution      | `ExtractionOrchestrator`, `PreflightValidator`, `PartialBatchRecovery`, `JobTracker` | Data exports, config validation, error recovery   | Build full workflows quickly              |\n| Auth / Clients | `createClient`, `FluentClient`, `FluentVersoriClient`, `FluentConnectionTester` | Node.js scripts, Versori workflows | Runtime-aware factory, OAuth2 refresh, automatic logging, optional connection validation. See `docs/04-REFERENCE/testing/modules/04-REFERENCE-testing-03-fluent-testing.md` for connection testing |\n| Webhooks       | `FluentClient.validateWebhook`, `parseWebhookPayload`, `WebhookAuthService`          | Secure webhook processing, B2B event handling     | RSA signature validation, API keys |\n| Errors         | `classifyError`, `classifyErrors`, `ErrorClassification`                             | GraphQL error handling, retry decisions           | Auto-classifies Fluent error codes        |\n| Logging        | `createConsoleLogger`, `toStructuredLogger`, `generateCorrelationId`                 | Standalone scripts, request tracking              | Pure-function log utilities               |\n\n**📚 Learn More:** `docs/02-CORE-GUIDES/` - Complete API reference and guides for all services\n\n**Note:** For batch operations, use `client.createJob()` and `client.sendBatch()` directly (shown in examples). `FluentBatchManager` is available for Versori workflows - see `docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md` for details.\n\n---\n\n## Install\n\n```bash\n# npm (recommended)\nnpm install @fluentcommerce/fc-connect-sdk\n\n# yarn\nyarn add @fluentcommerce/fc-connect-sdk\n\n# pnpm\npnpm add @fluentcommerce/fc-connect-sdk\n```\n\nDeno:\n\n```ts\nimport { createClient } from 'npm:@fluentcommerce/fc-connect-sdk';\n```\n\n### Optional TypeScript Settings\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"lib\": [\"ES2022\"],\n    \"esModuleInterop\": true,\n    \"resolveJsonModule\": true,\n    \"strict\": true\n  }\n}\n```\n\n### Verify Installation\n\nQuick test to confirm SDK is working:\n\n```typescript\nimport { createClient } from '@fluentcommerce/fc-connect-sdk';\n\nconsole.log('✅ SDK imported successfully!');\n// Test that core services are accessible\nconsole.log('Available:', { createClient: typeof createClient });\n```\n\n**Expected output:**\n```\n✅ SDK imported successfully!\nAvailable: { createClient: 'function' }\n```\n\nIf you see this, you're ready for the [5-Minute Quickstart](#-5-minute-quickstart)!\n\n---\n\n## 🏃 5-Minute Quickstart\n\n**Goal:** Send your first batch of inventory to Fluent Commerce.\n\n### Step 1: Install\n\n```bash\nnpm install @fluentcommerce/fc-connect-sdk\n```\n\n### Step 2: Configure Authentication\n\nCreate `.fluentrc.json`:\n\n```json\n{\n  \"baseUrl\": \"https://api.fluentcommerce.com\",\n  \"clientId\": \"YOUR_CLIENT_ID\",\n  \"clientSecret\": \"YOUR_CLIENT_SECRET\",\n  \"username\": \"YOUR_USERNAME\",\n  \"password\": \"YOUR_PASSWORD\",\n  \"retailerId\": \"YOUR_RETAILER_ID\"\n}\n```\n\n### Step 3: Send Test Data\n\n```typescript\nimport { createClient } from '@fluentcommerce/fc-connect-sdk';\nimport * as fs from 'fs';\n\n// Load config\nconst config = JSON.parse(fs.readFileSync('.fluentrc.json', 'utf8'));\n\n// Create authenticated client\nconst client = await createClient({ config });\n\n// Optional: Validate connection immediately (fail fast)\n// Recommended for production to catch auth issues early\n// const client = await createClient({ config }, { validateConnection: true });\n// This validates OAuth2 tokens and API connectivity before returning\n\n// Create job\nconst job = await client.createJob({\n  name: 'quickstart-test',\n  retailerId: config.retailerId,\n});\n\n// Send test inventory\nconst batch = await client.sendBatch(job.id, {\n  entityType: 'INVENTORY',\n  action: 'UPSERT',\n  source: 'QUICKSTART', // Optional: tracks data source\n  event: 'InventoryQuantityUpdate', // Optional: targets Rubix workflow event (defaults to InventoryChanged)\n  entities: [\n    {\n      skuRef: 'TEST-SKU-001',\n      qty: 10,\n      locationRef: 'DC01',\n      retailerId: config.retailerId,\n    },\n    {\n      skuRef: 'TEST-SKU-002',\n      qty: 5,\n      locationRef: 'DC01',\n      retailerId: config.retailerId,\n    },\n  ],\n});\n\nconsole.log('✅ Successfully sent test inventory!');\nconsole.log(`📊 Job ID: ${job.id}, Batch ID: ${batch.id}`);\n```\n\n### Step 4: Verify\n\nCheck the Fluent Commerce console to see your test inventory records.\n\n**🎉 Success!** You've sent your first batch. See included documentation for production templates and patterns.\n\n### 🐛 Troubleshooting Quick Fixes\n\n**Common issues:**\n\n- **401 Unauthorized** → Check `clientId`/`clientSecret`, verify OAuth2 credentials\n- **Batch API only supports INVENTORY** → Use Event API for products/orders, GraphQL for customers\n- **Connection pool errors** → Always call `dataSource.dispose()` after use\n- **Deno/Versori Buffer errors** → Add `import { Buffer } from 'node:buffer';`\n- **Schema validation errors** → Use `npx fc-connect validate-schema` to check mapping config\n\n**📚 Full Troubleshooting:** `docs/00-START-HERE/TROUBLESHOOTING-QUICK-REFERENCE.md` - Fixes 90% of common issues\n\n---\n\n## 🎯 What's Next?\n\nNow that you've sent your first batch, explore these resources to build production integrations:\n\n### 📋 Production-Ready Templates\n\nCopy-paste 23+ working templates for common scenarios:\n\n- **SFTP CSV → Batch API** - Daily inventory sync from SFTP\n  - `docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md`\n- **S3 Parquet → Extraction** - Extract data to data warehouse\n  - `docs/01-TEMPLATES/standalone/` (see `graphql-query-export.md`, `graphql-to-parquet-partitioned-s3.md`)\n- **XML Webhook → GraphQL** - Real-time order ingestion\n  - `docs/01-TEMPLATES/versori/webhooks/xml-order-ingestion.md`\n- **Payment Gateway Integration** - Adyen payment flows (Capture, Refund, Cancel, ReAuth)\n  - `docs/01-TEMPLATES/versori/webhooks/template-payment-gateway-integration.md`\n- **Browse All Templates** - Find the right pattern for your use case\n  - `docs/01-TEMPLATES/` or `docs/TEMPLATE-LOADING-MATRIX.md`\n\n### 📚 Core Guides\n\nLearn SDK features in depth:\n\n- **Complete Mapping Guide** - Field transformations, custom resolvers\n  - `docs/02-CORE-GUIDES/mapping/`\n- **Auto-Pagination** - Handle large GraphQL result sets\n  - `docs/02-CORE-GUIDES/auto-pagination/`\n- **Data Sources** - S3 and SFTP operations\n  - `docs/02-CORE-GUIDES/data-sources/`\n- **Troubleshooting** - Fixes 90% of common issues\n  - `docs/00-START-HERE/TROUBLESHOOTING-QUICK-REFERENCE.md`\n\n### 🏗️ Deep Dive\n\nUnderstand the SDK architecture and advanced patterns:\n\n- **SDK Architecture** - [Jump to Architecture section](#sdk-architecture)\n- **Complete Workflow Examples** - [Jump to Examples](#-complete-workflow-examples)\n- **Mapper Comparison** - [Which mapper to use?](#-mapping-approaches-which-one-do-i-use)\n\n---\n\n## 🗺️ Universal Mapping\n\n**One mapping pattern for ALL data formats** - XML, JSON, CSV, Parquet.\n\n### XML/JSON → Fluent with Custom Resolvers\n\nTransform any XML or JSON structure to Fluent Commerce entities:\n\n```typescript\nimport { UniversalMapper, XMLParserService } from '@fluentcommerce/fc-connect-sdk';\n\n// XML input example\nconst xmlData = `\n<InventoryUpdate>\n  <Item>\n    <SKU>PROD-001</SKU>\n    <Location>DC-01</Location>\n    <Qty>100</Qty>\n    <LastUpdated>2025-01-27T10:30:00Z</LastUpdated>\n    <Price currency=\"USD\">29.99</Price>\n  </Item>\n</InventoryUpdate>\n`;\n\n// Parse XML to JavaScript object\nconst parser = new XMLParserService();\nconst parsed = await parser.parse(xmlData, {\n  arrayPath: 'InventoryUpdate.Item', // Extract array of items\n});\n\n// Setup mapper with custom resolvers\nconst mapper = new UniversalMapper(\n  {\n    fields: {\n      // Direct mapping\n      skuRef: { source: 'SKU', required: true },\n      locationRef: { source: 'Location', required: true },\n\n      // Built-in SDK resolver\n      qty: { source: 'Qty', resolver: 'sdk.parseInt' },\n\n      // Custom resolver for nested data\n      price: {\n        source: 'Price',\n        resolver: 'custom.extractPrice',\n      },\n\n      // Custom resolver for date transformation\n      lastModified: {\n        source: 'LastUpdated',\n        resolver: 'custom.parseISODate',\n      },\n\n      // Static value\n      type: { defaultValue: 'DELTA' },\n      status: { defaultValue: 'ACTIVE' },\n    },\n  },\n  {\n    // Register custom resolvers\n    customResolvers: {\n      'custom.extractPrice': (value, sourceData, helpers) => {\n        // Extract value from nested object: { _text: \"29.99\", \"@_currency\": \"USD\" }\n        return helpers.parseFloatSafe(value?._text || value, 0);\n      },\n\n      'custom.parseISODate': (value, sourceData, helpers) => {\n        // Transform ISO date to Fluent format\n        const date = new Date(value);\n        return date.toISOString().split('T')[0]; // \"2025-01-27\"\n      },\n    },\n  }\n);\n\n// Map each item\nfor (const item of parsed) {\n  const result = await mapper.map(item);\n  if (result.success) {\n    console.log('Mapped:', result.data);\n    // Output: { skuRef: 'PROD-001', locationRef: 'DC-01', qty: 100, price: 29.99, lastModified: '2025-01-27', ... }\n  } else {\n    console.error('Mapping failed:', result.errors);\n  }\n}\n```\n\n### JSON Mapping Example\n\n```typescript\n// JSON input\nconst jsonData = {\n  product_id: 'SKU-001',\n  warehouse: 'WH-NYC',\n  stock_level: '50',\n  updated_at: '2025-01-27T10:30:00Z',\n};\n\nconst mapper = new UniversalMapper({\n  fields: {\n    skuRef: { source: 'product_id', required: true },\n    locationRef: { source: 'warehouse', required: true },\n    qty: { source: 'stock_level', resolver: 'sdk.parseInt' },\n    type: { defaultValue: 'DELTA' },\n  },\n});\n\nconst result = await mapper.map(jsonData);\n// Output: { skuRef: 'SKU-001', locationRef: 'WH-NYC', qty: 50, type: 'DELTA' }\n```\n\n### Array Mapping with GraphQL Edges/Nodes\n\n**IMPORTANT:** The SDK supports **two patterns** for GraphQL edges/nodes arrays. Both produce identical results - choose based on preference:\n\n**Input Data (GraphQL Response):**\n```javascript\n{\n  items: {\n    edges: [\n      { node: { ref: \"FFI-001\", quantity: 10 } },\n      { node: { ref: \"FFI-002\", quantity: 5 } }\n    ]\n  }\n}\n```\n\n**Pattern 1: Wildcard syntax (recommended)**\n```json\n{\n  \"fields\": {\n    \"items\": {\n      \"source\": \"items.edges[*].node\",  // ✅ SDK extracts nodes: [{ ref: \"...\" }, ...]\n      \"isArray\": true,\n      \"fields\": {\n        \"ref\": { \"source\": \"ref\" },     // ✅ Direct access (no \"node.\" prefix)\n        \"quantity\": { \"source\": \"quantity\", \"resolver\": \"sdk.parseInt\" }\n      }\n    }\n  }\n}\n```\n**Result:** `{ items: [{ ref: \"FFI-001\", quantity: 10 }, { ref: \"FFI-002\", quantity: 5 }] }`\n\n**Pattern 2: Direct edges access**\n```json\n{\n  \"fields\": {\n    \"items\": {\n      \"source\": \"items.edges\",          // ✅ SDK extracts edges: [{ node: {...} }, ...]\n      \"isArray\": true,\n      \"fields\": {\n        \"ref\": { \"source\": \"node.ref\" }, // ✅ Need \"node.\" prefix\n        \"quantity\": { \"source\": \"node.quantity\", \"resolver\": \"sdk.parseInt\" }\n      }\n    }\n  }\n}\n```\n**Result:** `{ items: [{ ref: \"FFI-001\", quantity: 10 }, { ref: \"FFI-002\", quantity: 5 }] }` (identical to Pattern 1)\n\n**For XML with `<Item>` wrapper elements**, add nested object wrapper to either pattern:\n```json\n{\n  \"fields\": {\n    \"Items\": {\n      \"source\": \"items.edges[*].node\",  // or \"items.edges\"\n      \"isArray\": true,\n      \"fields\": {\n        \"Item\": {                        // ✅ Creates <Item> elements\n          \"fields\": {\n            \"@ref\": { \"source\": \"ref\" }, // or \"node.ref\" for Pattern 2\n            \"quantity\": { \"source\": \"quantity\", \"resolver\": \"sdk.parseInt\" }\n          }\n        }\n      }\n    }\n  }\n}\n```\n**XML Output (both patterns):**\n```xml\n<Items>\n  <Item ref=\"FFI-001\"><quantity>10</quantity></Item>\n  <Item ref=\"FFI-002\"><quantity>5</quantity></Item>\n</Items>\n```\n\n**Key Difference:** Pattern 1 extracts nodes first (cleaner paths), Pattern 2 extracts edges (more explicit). Both produce identical mapped data and XML output.\n\n**📚 Learn More:** `docs/02-CORE-GUIDES/mapping/modules/02-CORE-GUIDES-mapping-05-advanced-patterns.md` - Complete array mapping guide with step-by-step examples\n\n### Built-in SDK Resolvers\n\n**String:** `sdk.uppercase`, `sdk.lowercase`, `sdk.trim`, `sdk.toString`\n**Number:** `sdk.parseInt`, `sdk.parseFloat`, `sdk.number`\n**Date:** `sdk.formatDate`, `sdk.formatDateShort`, `sdk.parseDate`\n**Type:** `sdk.boolean`, `sdk.parseJson`, `sdk.toJson`\n**Utility:** `sdk.identity`, `sdk.coalesce`, `sdk.default`\n\n**📚 Learn More:**\n\n- **Complete Mapping Guide:** `docs/02-CORE-GUIDES/mapping/modules/` - Universal mapping documentation (7 modules)\n- **Custom Resolvers:** `docs/02-CORE-GUIDES/mapping/resolvers/` - Building custom transformation logic (7 modules)\n- **GraphQL Mutations:** `docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/` - XML/JSON to GraphQL (12 modules)\n- **Advanced Patterns:** `docs/02-CORE-GUIDES/mapping/modules/02-CORE-GUIDES-mapping-05-advanced-patterns.md` - Array mapping, GraphQL edges/nodes (all 3 options)\n\n---\n\n## 🎯 Mapping Approaches: Which One Do I Use?\n\n### Quick Decision Table\n\n| **Your Scenario** | **Use This** | **Why** |\n|-------------------|--------------|---------|\n| 📦 **Bulk inventory files** (CSV/Parquet) → Fluent | `UniversalMapper` + Batch API | Optimized for thousands of records, change detection |\n| 📬 **XML webhooks** (SFCC orders, EDI) → Fluent | `GraphQLMutationMapper` | Auto-generates GraphQL mutations from XML |\n| 🌐 **JSON webhooks** (Shopify, APIs) → Fluent | `GraphQLMutationMapper` | Schema validation + auto-query building |\n| 🔧 **Simple field transforms** (rename, type convert) | `UniversalMapper` | Lightweight, no GraphQL needed |\n| 🎨 **Custom business logic** (tax calc, SKU generation) | `UniversalMapper` + Custom Resolvers | Maximum flexibility |\n\n### Detailed Comparison\n\n| Feature | UniversalMapper | GraphQLMutationMapper | Manual GraphQL |\n|---------|----------------|----------------------|----------------|\n| **Best For** | CSV/Parquet → Batch API | XML/JSON → GraphQL mutations | Simple queries |\n| **Input Formats** | Any (CSV, XML, JSON, Parquet) | XML, JSON | Any (you build it) |\n| **Output** | Plain JavaScript objects | GraphQL mutation + variables | You build everything |\n| **Schema Validation** | ❌ No | ✅ Yes (validates against GraphQL schema) | ❌ No |\n| **Auto-generates GraphQL** | ❌ No | ✅ Yes | ❌ No |\n| **Bulk Ingestion** | ✅ Yes (Batch API) | ❌ No (one mutation at a time) | Depends |\n| **Learning Curve** | 🟢 Easy | 🟡 Medium | 🟢 Easy |\n| **Setup Complexity** | Low | Medium (needs mapping config) | Low |\n| **Custom Logic** | ✅ Custom resolvers | ✅ Custom resolvers | ✅ Write your own code |\n| **Error Handling** | ✅ Built-in | ✅ Built-in with validation | ❌ Manual |\n\n**📚 Quick Decision:** See [Mapper Quick Decision Guide](docs/00-START-HERE/mapper-quick-decision-guide.md) (2-minute read)  \n**📚 Complete Comparison:** See [Mapper Comparison Guide](docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md) for an in-depth, code-verified comparison with a real-world inventory scenario, performance benchmarks, and decision matrix.\n\n---\n\n## 📬 XML/JSON Webhooks → GraphQL Mutations\n\n**Use Case:** Transform external XML/JSON into Fluent GraphQL mutations (orders, products, etc.)\n\n### Example: SFCC XML Order → Fluent createOrder\n\n```typescript\nimport { GraphQLMutationMapper, XMLParserService, createClient } from '@fluentcommerce/fc-connect-sdk';\n\n// 1. Parse incoming XML webhook\nconst xmlParser = new XMLParserService();\nconst orderData = await xmlParser.parse(xmlString);\n\n// 2. Configure mapping (XML paths → GraphQL fields)\nconst mappingConfig = {\n  mutation: 'createOrder',\n  sourceFormat: 'xml',\n  returnFields: ['id', 'ref', 'status', 'totalPrice'], // Fields returned in response\n  arguments: {\n    input: {\n      ref: { source: 'order.@id' },\n      type: { value: 'HD' },\n      retailer: { source: 'order.retailer', resolver: 'sdk.parseInt' },\n      customer: {\n        fields: {\n          firstName: { source: 'order.customer.first-name' },\n          lastName: { source: 'order.customer.last-name' },\n          email: { source: 'order.customer.email' }\n        }\n      },\n      items: {\n        source: 'order.product-lineitems.product-lineitem',\n        fields: {\n          skuRef: { source: '@product-id' },\n          quantity: { source: 'quantity', resolver: 'sdk.parseInt' },\n          price: { source: 'price', resolver: 'sdk.parseFloat' }\n        }\n      }\n    }\n  }\n};\n\n// 3. Generate mutation automatically\nconst client = await createClient({ /* config */ });\nconst mapper = new GraphQLMutationMapper(mappingConfig, logger, { fluentClient: client });\nconst payload = await mapper.map(orderData); // Returns { query, variables }\n\n// 4. Execute (mutation is auto-built!)\nconst result = await client.graphql(payload);\nconst createdOrder = result.data.createOrder;\nconsole.log('✅ Order created:', {\n  id: createdOrder.id,        // From returnFields\n  ref: createdOrder.ref,      // From returnFields\n  status: createdOrder.status, // From returnFields\n  totalPrice: createdOrder.totalPrice // From returnFields\n});\n```\n\n**What GraphQLMutationMapper Does For You:**\n1. ✅ Parses complex XML/JSON structures\n2. ✅ Validates against GraphQL schema\n3. ✅ Builds the GraphQL mutation query automatically\n4. ✅ Handles nested objects and arrays\n5. ✅ Provides detailed error messages\n\n**vs Manual Approach:**\n```typescript\n// ❌ Without GraphQLMutationMapper (you write everything)\nconst mutation = `\n  mutation CreateOrder($input: CreateOrderInput!) {\n    createOrder(input: $input) {\n      id ref type\n      customer { firstName lastName email }\n      items { skuRef quantity price }\n    }\n  }\n`;\nconst variables = {\n  input: {\n    ref: orderData.order['@id'],\n    type: 'HD',\n    retailer: parseInt(orderData.order.retailer),\n    customer: {\n      firstName: orderData.order.customer['first-name'],\n      lastName: orderData.order.customer['last-name'],\n      email: orderData.order.customer.email\n    },\n    items: orderData.order['product-lineitems']['product-lineitem'].map(item => ({\n      skuRef: item['@product-id'],\n      quantity: parseInt(item.quantity),\n      price: parseFloat(item.price)\n    }))\n  }\n};\nawait client.graphql({ query: mutation, variables });\n```\n\n**📚 Complete Guide:** `docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/` - 12 comprehensive modules\n\n---\n\n## 📋 Complete Workflow Examples\n\nReal-world integration patterns showing the full data pipeline.\n\n### Workflow Pattern: Data → Parse → Map → Batch API\n\n```\nExternal Storage (S3/SFTP)\n         ↓\n    Download File\n         ↓\n    Parse (CSV/XML/JSON/Parquet)\n         ↓\n    Map Fields (UniversalMapper)\n         ↓\n    Send to Batch API\n         ↓\n    Archive/Cleanup\n```\n\n**📚 Learn More:** See `docs/01-TEMPLATES/` for 23+ production-ready templates\n\n---\n\n### Example 1: S3 CSV → Batch API (Daily Inventory Sync)\n\nComplete workflow reading CSV from S3, mapping fields, and sending to Fluent.\n\n```typescript\nimport {\n  createClient,\n  S3DataSource,\n  CSVParserService,\n  UniversalMapper,\n} from '@fluentcommerce/fc-connect-sdk';\n\n// ============= SETUP =============\n// Create authenticated client (auto-detects Node.js/Deno/Versori)\nconst client = await createClient({\n  config: {\n    baseUrl: 'https://api.fluentcommerce.com',\n    clientId: process.env.FLUENT_CLIENT_ID!,\n    clientSecret: process.env.FLUENT_CLIENT_SECRET!,\n    username: process.env.FLUENT_USERNAME!,\n    password: process.env.FLUENT_PASSWORD!,\n    retailerId: process.env.FLUENT_RETAILER_ID!,\n  },\n});\n\n// Configure S3 data source\nconst s3 = new S3DataSource(\n  {\n    type: 'S3_CSV',\n    connectionId: 'daily-inventory',\n    name: 'Daily Inventory',\n    s3Config: {\n      bucket: process.env.S3_BUCKET!,\n      region: process.env.S3_REGION ?? 'us-east-1',\n      accessKeyId: process.env.S3_ACCESS_KEY_ID!,\n      secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,\n    },\n  },\n  console // logger\n);\n\n// Setup CSV parser and field mapper\nconst parser = new CSVParserService();\nconst mapper = new UniversalMapper({\n  fields: {\n    skuRef: { source: 'sku_id', required: true },\n    locationRef: { source: 'location_code', required: true },\n    qty: { source: 'quantity', resolver: 'sdk.parseInt' },\n    type: { source: 'type', defaultValue: 'DELTA' },\n    status: { source: 'status', defaultValue: 'AVAILABLE' },\n  },\n});\n\n// ============= WORKFLOW =============\n// 1. Read file from S3\nconst [file] = await s3.listFiles({ prefix: 'inventory/' });\nconst csv = await s3.downloadFile(file.path, { encoding: 'utf8' });\n\n// 2. Parse CSV and map fields\nconst rows = await parser.parse(csv, { columns: true, trim: true });\nconst payload = [];\nfor (const row of rows) {\n  const mapped = await mapper.map(row);\n  if (mapped.success) {\n    // Each entity must include retailerId\n    payload.push({\n      ...mapped.data,\n      retailerId: process.env.FLUENT_RETAILER_ID!,\n    });\n  }\n}\n\n// 3. Send to Fluent Commerce Batch API\nconst job = await client.createJob({\n  name: 'inventory-sync',\n  retailerId: process.env.FLUENT_RETAILER_ID!,\n});\nconst batch = await client.sendBatch(job.id, {\n  entityType: 'INVENTORY',\n  action: 'UPSERT',\n  source: 'S3_CSV', // Optional: tracks data source\n  event: 'InventoryQuantityUpdate', // Optional: targets Rubix workflow event\n  entities: payload,\n});\n\n// 4. Archive processed file\nawait s3.moveFile(file.path, `inventory/archive/${file.name}`);\n\nconsole.log(`✅ Synced ${payload.length} inventory records`);\nconsole.log(`📊 Job ID: ${job.id}, Batch ID: ${batch.id}`);\n```\n\n**📚 Learn More:**\n\n- **S3 Operations:** `docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md`\n- **CSV Parsing:** `docs/02-CORE-GUIDES/parsers/modules/02-CORE-GUIDES-parsers-02-csv-parser.md`\n- **Universal Mapping:** `docs/02-CORE-GUIDES/mapping/modules/`\n- **Batch API:** `docs/02-CORE-GUIDES/ingestion/modules/02-CORE-GUIDES-ingestion-06-batch-api.md`\n\n---\n\n### Example 2: SFTP XML → Batch API (EDI Integration)\n\nReading XML from SFTP server, parsing with XPath, and batch processing.\n\n```typescript\nimport {\n  createClient,\n  SftpDataSource,\n  XMLParserService,\n  UniversalMapper,\n} from '@fluentcommerce/fc-connect-sdk';\n\n// Setup SFTP connection\nconst sftp = new SftpDataSource(\n  {\n    type: 'SFTP_XML',\n    connectionId: 'edi-sftp',\n    name: 'EDI SFTP',\n    sftpConfig: {\n      settings: {\n        host: process.env.SFTP_HOST!,\n        port: 22,\n        username: process.env.SFTP_USERNAME!,\n        password: process.env.SFTP_PASSWORD!,\n      },\n    },\n  },\n  console\n);\n\n// Setup XML parser with path resolution\nconst parser = new XMLParserService();\nconst mapper = new UniversalMapper({\n  fields: {\n    skuRef: { source: 'Item.SKU', required: true },\n    locationRef: { source: 'Item.Location', required: true },\n    qty: { source: 'Item.Quantity', resolver: 'sdk.parseInt' },\n    type: { defaultValue: 'DELTA' },\n    status: { defaultValue: 'AVAILABLE' },\n  },\n});\n\n// Create client\nconst client = await createClient({\n  config: {\n    /* OAuth2 config */\n  },\n});\n\n// ============= WORKFLOW =============\n// 1. List and download XML from SFTP\nconst files = await sftp.listFiles({ prefix: '/inbound/', pattern: '*.xml' });\nfor (const file of files) {\n  const xmlContent = await sftp.downloadFile(file.path, { encoding: 'utf8' });\n\n  // 2. Parse XML and extract items\n  const parsed = await parser.parse(xmlContent, {\n    arrayPath: 'InventoryUpdate.Items.Item', // Extract array of items\n  });\n\n  // 3. Map fields\n  const payload = [];\n  for (const item of parsed) {\n    const mapped = await mapper.map(item);\n    if (mapped.success) {\n      payload.push({\n        ...mapped.data,\n        retailerId: process.env.FLUENT_RETAILER_ID!,\n      });\n    }\n  }\n\n  // 4. Send to Batch API\n  const job = await client.createJob({\n    name: `sftp-${file.name}`,\n    retailerId: process.env.FLUENT_RETAILER_ID!,\n  });\n  await client.sendBatch(job.id, {\n    entityType: 'INVENTORY',\n    action: 'UPSERT',\n    source: 'SFTP_XML',\n    entities: payload,\n  });\n\n  // 5. Archive processed file\n  await sftp.moveFile(file.path, `/archive/${file.name}`);\n\n  console.log(`✅ Processed ${file.name}: ${payload.length} records`);\n}\n```\n\n**📚 Learn More:**\n\n- **SFTP Operations:** `docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md`\n- **XML Parsing:** `docs/02-CORE-GUIDES/parsers/modules/02-CORE-GUIDES-parsers-04-xml-parser.md`\n- **Complete Templates:** `docs/01-TEMPLATES/standalone/` and `docs/01-TEMPLATES/versori/`\n\n> **Note:** Batch API supports **inventory + UPSERT** only. Use GraphQL mutations for products, orders, etc.\n\n---\n\n## SDK Architecture\n\nThe SDK follows a layered, service-oriented architecture with comprehensive service orchestration:\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│                        🔌 CLIENT LAYER                              │\n├─────────────────────────────────────────────────────────────────────┤\n│  createClient Factory (Auto-detects Runtime)                        │\n│      ├─→ FluentClient (OAuth2)                                      │\n│      └─→ FluentVersoriClient (Platform Auth)                        │\n└────────────────────────────┬────────────────────────────────────────┘\n                             │\n┌────────────────────────────┴────────────────────────────────────────┐\n│                        ⚙️ SERVICE LAYER                             │\n├─────────────────────────────────────────────────────────────────────┤\n│  Core Services:                                                     │\n│    • UniversalMapper          - Field transformations               │\n│    • GraphQLMutationMapper    - XML/JSON → GraphQL                  │\n│    • ExtractionOrchestrator   - GraphQL extraction workflows        │\n│    • FluentBatchManager       - Batch operations + BPP              │\n│                                                                      │\n│  Support Services:                                                  │\n│    • StateService             - KV storage management               │\n│    • WebhookValidationService - RSA signature validation            │\n│    • WebhookAuthService       - API key auth               │\n│    • PreflightValidator       - Configuration validation            │\n│    • JobTracker               - Lifecycle management                │\n│    • PartialBatchRecovery     - Failure handling                    │\n└────────────────────────────┬────────────────────────────────────────┘\n                             │\n┌────────────────────────────┴────────────────────────────────────────┐\n│                         📁 DATA LAYER                               │\n├─────────────────────────────────────────────────────────────────────┤\n│  Data Sources:                                                      │\n│    • S3DataSource       - Presigned URLs + streaming                │\n│    • SftpDataSource     - Connection pool + wait queue              │\n│                                                                      │\n│  Parsers:                                                           │\n│    • CSVParser          - Streaming CSV processing                  │\n│    • XMLParser          - Path resolution + streaming               │\n│    • JSONParser         - Streaming JSON processing                 │\n│    • ParquetParser      - Columnar data format                      │\n└────────────────────────────┬────────────────────────────────────────┘\n                             │\n┌────────────────────────────┴────────────────────────────────────────┐\n│                    🌐 EXTERNAL SYSTEMS                              │\n├─────────────────────────────────────────────────────────────────────┤\n│  • Fluent Commerce API  - GraphQL, Batch API, Event API             │\n│  • AWS S3               - Object storage                            │\n│  • SFTP Servers         - File transfer                             │\n│  • KV Storage           - Versori KV / Redis                        │\n└─────────────────────────────────────────────────────────────────────┘\n\nData Flow: Read → Parse → Map → Your Logic → Send/Archive\n```\n\n| Layer                      | Responsibilities                                       | Key Services                                                                                                                            |\n| -------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |\n| **🔌 Client Layer**        | Runtime detection, authentication, API communication   | `createClient()`, `FluentClient`, `FluentVersoriClient`                                                                                 |\n| **⚙️ Service Layer**       | Business logic, state management, validation           | `UniversalMapper`, `GraphQLMutationMapper`, `ExtractionOrchestrator`, `StateService`, `JobTracker`, `WebhookValidationService`, `WebhookAuthService` |\n| **📁 Data Layer**          | File I/O, streaming parsers, constant memory footprint | `S3DataSource` (presigned URLs), `SftpDataSource` (pooled), CSV/XML/JSON/Parquet parsers                                                |\n| **🎯 Orchestration Layer** | High-level workflows, composition of services          | `IngestionService`, `ExtractionOrchestrator`                                                                                            |\n| **🌐 External Systems**    | Fluent Commerce API, cloud storage, distributed state  | GraphQL + Batch + Event APIs, S3, SFTP, KV storage                                                                                      |\n\n**💡 Design Principles:**\n\n- **Stateless & Parallel-Safe:** All services safe for `Promise.all()`, no hidden state\n- **Streaming-First:** Constant memory footprint for large files\n- **Universal Compatibility:** Single codebase across Node.js, Deno, Versori\n- **Smart Error Handling:** 4xx fail fast, 5xx exponential backoff, job expiration auto-recreation. Consistent `statusCode` field across success and error responses\n\n**📚 Learn More:** `docs/04-REFERENCE/architecture/` - Complete architecture documentation\n\n---\n\n## 🚀 More Quick Examples\n\n### GraphQL Mutation (Create Product)\n\n```typescript\nimport { createClient } from '@fluentcommerce/fc-connect-sdk';\n\nconst client = await createClient({\n  config: {\n    /* OAuth2 */\n  },\n});\n\n// Create a variant product using GraphQL mutation\nconst result = await client.graphql({\n  query: `\n    mutation CreateVariantProduct($input: CreateVariantProductInput!) {\n      createVariantProduct(input: $input) {\n        id\n        ref\n        type\n        gtin\n        name\n        summary\n      }\n    }\n  `,\n  variables: {\n    input: {\n      ref: 'PROD-001',\n      type: 'VARIANT',\n      gtin: '01234567890128',\n      name: 'Sample Product',\n      summary: 'A sample variant product',\n      catalogue: {\n        ref: 'DEFAULT',\n      },\n      product: {\n        ref: 'BASE-PROD-001',\n      },\n    },\n  },\n});\n\nconsole.log('✅ Product created:', result.data.createVariantProduct);\n// Output: { id: '123', ref: 'PROD-001', type: 'VARIANT', gtin: '01234567890128', name: 'Sample Product', summary: 'A sample variant product' }\n```\n\n**📚 Learn More:** `docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/` - XML/JSON to GraphQL mutations\n\n---\n\n### GraphQL Query with Auto-Pagination\n\n**Recommended: Using ExtractionOrchestrator (All Templates Use This)**\n\n```typescript\nimport { createClient, ExtractionOrchestrator } from '@fluentcommerce/fc-connect-sdk';\n\nconst client = await createClient({\n  config: {\n    /* OAuth2 */\n  },\n});\nconst orchestrator = new ExtractionOrchestrator(client, console);\n\n// Extract with auto-pagination + validation + statistics\nconst result = await orchestrator.extract({\n  query: `\n    query GetVirtualPositions($first: Int, $after: String) {\n      virtualPositions(first: $first, after: $after) {\n        edges {\n          node {\n            ref\n            quantity\n            productRef\n            locationLink { ref }\n          }\n          cursor\n        }\n        pageInfo {\n          hasNextPage\n        }\n      }\n    }\n  `,\n  resultPath: 'virtualPositions.edges.node', // Extract node objects directly\n  maxPages: 10,\n});\n\nconsole.log(\n  `✅ Extracted ${result.stats.totalRecords} positions across ${result.stats.totalPages} pages`\n);\n// Output: ✅ Extracted 847 positions across 9 pages\n// result.data = [{ ref: 'VP001', quantity: 10, productRef: 'PROD-001', locationLink: { ref: 'DC01' } }, ...]\n// result.stats = { totalPages: 9, totalRecords: 847, truncated: false }\n```\n\n**Handling Partial Responses (Errors with Data):**\n\n```typescript\n// When GraphQL returns errors but some data is available\nconst result = await orchestrator.extract({\n  query: ORDERS_QUERY,\n  resultPath: 'orders.edges.node',\n  errorHandling: 'partial', // Continue extraction even with errors\n});\n\n// Check for partial errors\nif (result.stats.partialErrors) {\n  console.warn(`Extraction completed with ${result.stats.partialErrors.length} errors`);\n  console.log(`Still extracted ${result.data.length} records`);\n  // Errors are in result.stats.partialErrors\n}\n\n// Edge case: If GraphQL returns errors with null data, result.data will be []\n// but errors are still available in result.stats.partialErrors\n```\n\n**Alternative: Using FluentClient (For Custom Response Handling)**\n\n```typescript\nconst result = await client.graphql({\n  query: `query GetVirtualPositions($first: Int, $after: String) { ... }`,\n  variables: { first: 100 },\n  pagination: { maxPages: 10 },\n});\n\n// Manual extraction from GraphQL structure\nconst nodes = result.data?.virtualPositions?.edges?.map(edge => edge.node) ?? [];\nconsole.log(`✅ Fetched ${nodes.length} virtual positions`);\n```\n\n**When to Use Each Approach:**\n\n| Approach                   | Use When                                                      | Returns                         |\n| -------------------------- | ------------------------------------------------------------- | ------------------------------- |\n| **ExtractionOrchestrator** | Extracting data to files/systems (recommended for extraction) | Flattened `data[]` + `stats`    |\n| **FluentClient.graphql()** | Mutations, custom queries, need full GraphQL response         | Full GraphQL response structure |\n\n**📚 Learn More:**\n\n- **Auto-Pagination:** `docs/02-CORE-GUIDES/auto-pagination/` - Cursor-based pagination guide (7 modules)\n- **Extraction:** `docs/02-CORE-GUIDES/extraction/` - Complete extraction guide\n\n---\n\n### Event API (Upsert Product)\n\nReal-world example sending product data via Event API (triggers Rubix workflows).\n\n```typescript\nimport { createClient } from '@fluentcommerce/fc-connect-sdk';\n\nconst client = await createClient({\n  config: {\n    /* OAuth2 */\n  },\n});\n\n// Send product upsert event\nconst result = await client.sendEvent({\n  name: 'UPSERT_PRODUCT',\n  entityType: 'PRODUCT_CATALOGUE',\n  entitySubtype: 'MASTER',\n  entityRef: 'PC:MASTER:2',\n  rootEntityType: 'PRODUCT_CATALOGUE',\n  rootEntityRef: 'PC:MASTER:2',\n  retailerId: '2',\n  attributes: {\n    ref: 'VAR_PRODUCT',\n    type: 'VARIANT',\n    status: 'ACTIVE',\n    gtin: '1234567',\n    name: 'Chaz Kangeroo Hoodie-XS-Orange',\n    summary: 'Comfortable hoodie in orange',\n    categoryRefs: ['STANDARD_CATEGORY'],\n    price: [\n      {\n        type: 'DEFAULT',\n        currency: 'USD',\n        value: 49.99,\n      },\n    ],\n    taxType: {\n      country: 'US',\n      group: 'HD',\n    },\n  },\n});\n\nconsole.log('✅ Event sent successfully');\n// Output: { id: 'evt_123', status: 'CREATED' }\n```\n\n**📚 Learn More:**\n\n- **Event API Templates:** `docs/01-TEMPLATES/versori/workflows/ingestion/event-api/` (8 templates for S3/SFTP with CSV, XML, JSON, Parquet)\n- **Batch API Guide:** `docs/02-CORE-GUIDES/ingestion/modules/02-CORE-GUIDES-ingestion-06-batch-api.md`\n\n### Event Log API (Search + Audit)\n\nQuery and retrieve events/audit logs from the Fluent Commerce REST Event API. Use these **read-only** methods for troubleshooting workflows, tracing event chains, monitoring orchestration, and auditing batch processing.\n\n**Methods:**\n- `getEvents(params)` → `GET /api/v4.1/event` - Search/filter events with flexible query parameters\n- `getEventById(eventId)` → `GET /api/v4.1/event/{eventId}` - Get a single event by ID\n\n**Important:** These methods query the Event Log (audit trail). They do NOT trigger workflows — use `sendEvent()` for that.\n\n#### Basic Usage\n\n```typescript\nimport { createClient } from '@fluentcommerce/fc-connect-sdk';\n\nconst client = await createClient({\n  config: { baseUrl, clientId, clientSecret, username, password },\n});\n\n// 1) Search for failed orchestration audit events on orders\nconst logs = await client.getEvents({\n  'context.rootEntityType': 'ORDER',\n  eventType: 'ORCHESTRATION_AUDIT',\n  eventStatus: 'FAILED',\n  count: 100,\n});\n\nconsole.log(`Found ${logs.results.length} events (hasMore=${logs.hasMore})`);\n\nfor (const event of logs.results) {\n  console.log(`  ${event.name} [${event.eventStatus}] on ${event.context?.entityType}:${event.context?.entityRef}`);\n}\n\n// 2) Get full details for a specific event by ID\nif (logs.results[0]?.id) {\n  const event = await client.getEventById(logs.results[0].id);\n  console.log(`Event: ${event.name} - Status: ${event.eventStatus}`);\n  console.log(`  Entity: ${event.context?.entityType}:${event.context?.entityRef}`);\n  console.log(`  Root: ${event.context?.rootEntityType}:${event.context?.rootEntityRef}`);\n  console.log(`  Generated: ${event.generatedOn} by ${event.generatedBy}`);\n\n  // Trace parent events (for debugging event chains)\n  if (event.context?.sourceEvents?.length) {\n    for (const parentId of event.context.sourceEvents) {\n      const parent = await client.getEventById(parentId);\n      console.log(`  Parent: ${parent.name} (${parent.eventStatus})`);\n    }\n  }\n}\n```\n\n#### Response Shape\n\n`getEvents()` returns `FluentEventLogResponse`:\n\n```typescript\n{\n  start: 1,                    // Pagination offset\n  count: 1000,                 // Results in this page\n  hasMore: false,              // More pages available?\n  results: [                   // Array of FluentEventLogItem\n    {\n      id: \"e2cc5040-...\",      // UUID\n      name: \"BATCH_COMPLETE\",  // Event/ruleset name (can be null)\n      type: \"ORCHESTRATION_AUDIT\",\n      accountId: \"MYACCOUNT\",\n      retailerId: \"5\",         // String in response (not number)\n      category: \"BATCH\",\n      context: {\n        sourceEvents: [\"babc5f37-...\"],  // Parent event IDs for tracing\n        entityType: \"BATCH\",\n        entityId: \"12\",\n        entityRef: \"12\",\n        rootEntityType: \"JOB\",\n        rootEntityId: \"13\",\n        rootEntityRef: \"13\"\n      },\n      eventStatus: \"COMPLETE\",\n      attributes: null,        // null OR array of { name, value, type }\n      source: null,\n      generatedBy: \"Rubix User\",\n      generatedOn: \"2026-02-05T06:31:56.895+00:00\"\n    }\n  ]\n}\n```\n\n`getEventById(id)` returns a single `FluentEventLogItem` (same shape as each item in `results`).\n\n#### Query Parameters\n\nAll parameters are optional. Context filters use **dot-notation keys** which require quotes in JavaScript/TypeScript:\n\n```typescript\n// ⚠️ Dot-notation keys MUST be quoted (JavaScript syntax requirement)\nawait client.getEvents({\n  'context.rootEntityType': 'ORDER',  // ✅ Quotes required (has dot)\n  'context.entityRef': 'ORD-123',     // ✅ Quotes required (has dot)\n  eventType: 'ORCHESTRATION_AUDIT',   // ✅ No quotes needed (simple key)\n  count: 100,                         // ✅ No quotes needed (simple key)\n});\n```\n\n| Parameter | Type | Description | Example |\n|-----------|------|-------------|---------|\n| `context.rootEntityType` | string | Root entity type | `'ORDER'`, `'JOB'`, `'LOCATION'` |\n| `context.rootEntityId` | string | Root entity ID | `'12345'` |\n| `context.rootEntityRef` | string | Root entity reference | `'ORD-12345'` |\n| `context.entityType` | string | Sub-entity type | `'FULFILMENT'`, `'BATCH'`, `'ARTICLE'` |\n| `context.entityId` | string | Sub-entity ID | `'67890'` |\n| `context.entityRef` | string | Sub-entity reference | `'FUL-67890'` |\n| `eventType` | string | Event type filter | `'ORCHESTRATION_AUDIT'` |\n| `eventStatus` | string | Status filter | `'FAILED'`, `'COMPLETE'` |\n| `name` | string | Event/ruleset name | `'BATCH_COMPLETE'` |\n| `category` | string | Category filter | `'ruleSet'`, `'ACTION'` |\n| `from` | string | Start date (UTC ISO 8601) | `'2026-02-01T00:00:00.000Z'` |\n| `to` | string | End date (UTC ISO 8601) | `'2026-02-15T23:59:59.999Z'` |\n| `retailerId` | string/number | Retailer filter (pass explicitly; no auto-fallback) | `'5'` |\n| `start` | number | Pagination offset (default: `0`) | `0` |\n| `count` | number | Results per page (default: `100`, max: `5000`) | `1000` |\n\n#### Valid Values Reference\n\n| Parameter | Valid Values |\n|-----------|-------------|\n| **eventType** | `ORCHESTRATION`, `ORCHESTRATION_AUDIT`, `API`, `INTEGRATION`, `SECURITY`, `GENERAL` |\n| **eventStatus** | `PENDING`, `SCHEDULED`, `NO_MATCH`, `SUCCESS`, `FAILED`, `COMPLETE` |\n| **category** | `snapshot`, `ruleSet`, `rule`, `ACTION`, `CUSTOM`, `exception`, `ORDER_WORKFLOW`, `BATCH` |\n| **rootEntityType** | `ORDER`, `LOCATION`, `FULFILMENT_OPTIONS`, `PRODUCT_CATALOGUE`, `INVENTORY_CATALOGUE`, `VIRTUAL_CATALOGUE`, `CONTROL_GROUP`, `RETURN_ORDER`, `BILLING_ACCOUNT`, `JOB` |\n| **entityType** | `ORDER`, `FULFILMENT`, `ARTICLE`, `CONSIGNMENT`, `LOCATION`, `WAVE`, `FULFILMENT_OPTIONS`, `FULFILMENT_PLAN`, `PRODUCT_CATALOGUE`, `CATEGORY`, `PRODUCT`, `INVENTORY_CATALOGUE`, `INVENTORY_POSITION`, `INVENTORY_QUANTITY`, `VIRTUAL_CATALOGUE`, `VIRTUAL_POSITION`, `CONTROL_GROUP`, `CONTROL`, `RETURN_ORDER`, `RETURN_FULFILMENT`, `BILLING_ACCOUNT`, `CREDIT_MEMO`, `BATCH` |\n\n#### Common Use Cases\n\n```typescript\n// 1. Find failed events in the last 24 hours\nconst failedEvents = await client.getEvents({\n  eventStatus: 'FAILED',\n  from: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),\n  to: new Date().toISOString(),\n  count: 1000,\n});\n\n// 2. Track batch job processing (all events for a specific job)\nconst batchEvents = await client.getEvents({\n  'context.rootEntityType': 'JOB',\n  'context.rootEntityId': '13',\n  eventType: 'ORCHESTRATION_AUDIT',\n  count: 500,\n});\n\n// 3. Paginate through large result sets\nlet start = 0;\nconst allEvents: any[] = [];\nlet hasMore = true;\n\nwhile (hasMore) {\n  const page = await client.getEvents({\n    'context.rootEntityType': 'ORDER',\n    start,\n    count: 1000,\n  });\n  allEvents.push(...page.results);\n  hasMore = page.hasMore;\n  start += page.count;\n}\nconsole.log(`Total events collected: ${allEvents.length}`);\n\n// 4. Extract performance timing from event attributes\nconst auditEvents = await client.getEvents({\n  eventType: 'ORCHESTRATION_AUDIT',\n  'context.rootEntityType': 'JOB',\n  count: 100,\n});\n\nfor (const event of auditEvents.results) {\n  if (Array.isArray(event.attributes)) {\n    const startTimer = event.attributes.find(a => a.name === 'startTimer');\n    const stopTimer = event.attributes.find(a => a.name === 'stopTimer');\n    if (startTimer && stopTimer) {\n      const duration = Number(stopTimer.value) - Number(startTimer.value);\n      console.log(`${event.name}: ${duration}ms`);\n    }\n  }\n}\n\n// 5. Find events for a specific order by reference\nconst orderEvents = await client.getEvents({\n  'context.rootEntityType': 'ORDER',\n  'context.rootEntityRef': 'HD_12345',\n  eventType: 'ORCHESTRATION_AUDIT',\n});\n```\n\n#### When to Use Which Method\n\n| Method | Use When | Returns | Example |\n|--------|----------|---------|---------|\n| `sendEvent()` | **Trigger** a workflow or business action | Event creation response | Product upsert, order cancel, location update |\n| `getEvents()` | **Search/filter** historical events | `{ results[], hasMore, start, count }` | Find failed events, audit batch processing |\n| `getEventById()` | **Get full details** for one event by ID | Single event object | Drill into context, attributes, trace sourceEvents |\n\n#### Limitations & Operational Notes\n\n| Constraint | Value | Notes |\n|------------|-------|-------|\n| **Max count per request** | `5000` | Use pagination (`start`/`count`/`hasMore`) for larger result sets |\n| **Time range (from)** | 4 months back max | API rejects queries older than ~4 months |\n| **Time range (to)** | 1 month forward max | API rejects future dates beyond ~1 month |\n| **Default time window** | Past 30 days | Applied when `from` is omitted |\n| **Date format** | UTC ISO 8601 | `YYYY-MM-DDTHH:mm:ss.SSSZ` |\n| **retailerId** | Pass explicitly | Unlike `sendEvent()`, no auto-fallback to client config — pass in params if needed |\n| **attributes field** | Nullable | Can be `null` (not empty array) — always check before iterating |\n| **name field** | Nullable | Can be `null` for some system events |\n| **GraphQL** | Not available | Event queries use REST only — no GraphQL `events` root field exists |\n\n**Key points:**\n- `getEvents()` and `getEventById()` are **read-only** — they do NOT trigger workflows\n- Empty `results: []` is valid (not an error) — your filter may simply match zero events\n- Always use bounded time ranges (`from`/`to`) for predictable performance\n- Use `eventType: 'ORCHESTRATION_AUDIT'` for workflow execution history\n- Use `context.sourceEvents` array on each event to trace parent event chains\n- The `attributes` field is `null` for most events; only rule/ruleset events populate it\n- `retailerId` in responses is a **string** (e.g., `\"5\"`) even though you can pass a number in params\n\n**📚 Detailed Guide:** `docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md`\n\n---\n\n### Error Classification\n\nAutomatically classify GraphQL errors for retry decisions and error handling.\n\n```typescript\nimport { classifyError, classifyErrors, type ErrorClassification } from '@fluentcommerce/fc-connect-sdk';\n\n// Handle errors from GraphQL response\nconst result = await client.graphql({ query, variables });\n\nif (result.errors) {\n  const classifications = classifyErrors(result.errors);\n\n  for (const classification of classifications) {\n    console.log({\n      code: classification.code,\n      severity: classification.severity,    // 'client' | 'server' | 'transient'\n      retryable: classification.retryable,  // boolean\n      action: classification.action         // Recommended action\n    });\n  }\n\n  // Check if any errors are retryable\n  const shouldRetry = classifications.some(c => c.retryable);\n  if (shouldRetry) {\n    // Implement retry logic\n  }\n}\n\n// Classify a single error\nconst singleError = { message: 'Rate limited', extensions: { code: 'T001' } };\nconst classification = classifyError(singleError);\nconsole.log(classification.retryable); // true (transient error)\n```\n\n**Error Code Prefixes:**\n- **C** (Client) - Bad request, validation errors → Not retryable\n- **S** (Server) - Internal errors → May be retryable\n- **T** (Transient) - Rate limits, timeouts → Retryable\n\n**📚 Learn More:**\n- **Comprehensive Error Handling Guide:** `docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md` - Complete reference with examples for all APIs\n- **Quick Reference:** `docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md` - Cheat sheet for error codes and retry strategies\n- **API Reference:** `docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md` - Error classification utilities\n\n---\n\n## CLI Tooling\n\nAll CLI commands are distributed with the package. Use via `npx`:\n\n```bash\nnpx fc-connect <command> [options]\n```\n\n| Command                                | Purpose                                    |\n| -------------------------------------- | ------------------------------------------ |\n| `npx fc-connect analyze-source-structure` 🆕 | Analyze data files and generate mapping templates |\n| `npx fc-connect introspect-schema`         | Download the Fluent GraphQL schema         |\n| `npx fc-connect generate-mutation-mapping` | Build ingestion mapping templates          |\n| `npx fc-connect generate-query-mapping`    | Build extraction mapping templates         |\n| `npx fc-connect validate-schema`           | Validate mapping config against the schema |\n| `npx fc-connect analyze-coverage`          | Report required / optional field coverage  |\n\n### 🚀 Quick Start: Analyze Your Data\n\n```bash\n# Analyze XML/JSON/CSV/Parquet files\nnpx fc-connect analyze-source-structure --file ./your-data.xml\n\n# Generate mapping template + documentation\nnpx fc-connect analyze-source-structure \\\n  --file ./inventory.xml \\\n  --output ./mapping.json \\\n  --markdown ./docs/analysis.md\n```\n\n**What you get:**\n- ✅ All available fields and paths\n- ✅ Array detection and structure insights\n- ✅ Smart resolver suggestions (parseFloat, trim, etc.)\n- ✅ Ready-to-use mapping templates\n- ✅ Shareable documentation\n\n**📚 Learn More:** `docs/00-START-HERE/CLI-ANALYZE-SOURCE-STRUCTURE-GUIDE.md` - Complete user guide | `docs/02-CORE-GUIDES/mapping/` - Field mapping guides | `docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md` - Complete CLI documentation\n\n---\n\n## Authentication & Webhooks\n\n**OAuth2 with Automatic Token Management:**\n\n- ✅ Refresh token support (uses `grant_type=refresh_token` when available)\n- ✅ Automatic 401 retry with exponential backoff (3 retries max)\n- ✅ Thread-safe token refresh (prevents duplicate requests)\n- ✅ 60-second expiry buffer (prevents mid-flight token expiry)\n- ✅ Handles clock skew, server-side revocation, multi-process conflicts\n\n**Webhook Validation:**\n\n- Cryptographic signature validation with RSA (`SHA256withRSA`, `SHA1withRSA`, `SHA512withRSA`)\n\n```ts\n// Authentication happens automatically - just create client\nconst client = createClient({ fetch, log, activation });\n\n// Webhook validation with signature verification\nconst isValid = await client.validateWebhook(body, headers['fluent-signature'], rawBody);\nif (!isValid) return new Response('Invalid signature', { status: 401 });\n```\n\n**Webhook Authentication Service:**\n\n- Secure API key generation (cryptographically random, 64-char hex)\n- API key validation with SHA-256 hashing\n- **Universal compatibility** - Works in Node.js, Deno, Versori, Cloudflare Workers, Vercel Edge, and more!\n- Uses Web Crypto API (native to all modern runtimes)\n\n---\n\n## retailerId Configuration\n\n**🆕 Latest:** `retailerId` is now **OPTIONAL** at client creation!\n\n### When Do You Need It?\n\n| API | Needs retailerId? |\n|-----|-------------------|\n| GraphQL queries/mutations | ❌ NO (pass in mutation input if needed) |\n| Job API (`createJob`) | ✅ YES |\n| Event API (`sendEvent`) | ✅ YES |\n| Batch API (`sendBatch`) | ❌ NO (uses jobId) |\n\n### Three Ways to Provide It\n\n```typescript\n// Option 1: In client config (standalone/Node.js)\nconst client = await createClient({\n  config: {\n    baseUrl: 'https://api.fluentcommerce.com',\n    clientId: '...',\n    clientSecret: '...',\n    retailerId: '1'  // ← Optional\n  }\n});\n\n// Option 2: Set after client creation (Versori fn() workflows)\nconst client = await createClient({ data: {}, log, openKv });\nclient.setRetailerId('1');  // ← Only if using Job/Event APIs\n\n// Option 3: Pass directly to methods (multi-tenant)\nawait client.createJob({ name: 'sync', retailerId: '1' });\nawait client.sendEvent({ name: 'Test', entityType: 'PRODUCT', retailerId: '2' });\n```\n\n**📖 Complete Guide:** [`docs/00-START-HERE/RETAILERID-CONFIGURATION.md`](docs/00-START-HERE/RETAILERID-CONFIGURATION.md)\n\n```ts\nimport { WebhookAuthService } from '@fluentcommerce/fc-connect-sdk';\n\n// Initialize service\nconst authService = new WebhookAuthService(logger);\n\n// API Key: Generate\nconst apiKey = await authService.generateApiKeyWithPrefix('prod', {\n  userId: 'client1',\n  scopes: ['webhook'],\n});\n\n// API Key: Validate\nconst validation = await authService.validateApiKey(\n  apiKey,\n  async (key) => {\n    // Lookup API key hash in your storage\n    const hash = await authService.hashApiKey(key);\n    return await lookupApiKeyMetadata(hash);\n  }\n);\n```\n\n**📚 Learn More:**\n\n- `docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md` - **API key security guide**\n- `docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md` - **Connection-based security**\n- `docs/02-CORE-GUIDES/webhook-validation/` - Complete webhook security guide (5 modules)\n- `docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentic","readmeFilename":"README.md"}