@biggora/claude-plugins 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -4
- package/package.json +1 -1
- package/registry/registry.json +334 -244
- package/specs/coding.md +30 -0
- package/specs/pod.md +2 -0
- package/src/commands/skills/add.js +63 -7
- package/src/commands/skills/list.js +23 -52
- package/src/commands/skills/remove.js +26 -27
- package/src/commands/skills/resolve.js +155 -0
- package/src/commands/skills/update.js +58 -74
- package/src/skills/captcha/README.md +221 -0
- package/src/skills/captcha/SKILL.md +355 -0
- package/src/skills/captcha/references/captcha-types.md +254 -0
- package/src/skills/captcha/references/services.md +172 -0
- package/src/skills/captcha/references/stealth.md +238 -0
- package/src/skills/captcha/scripts/solve_captcha.py +323 -0
- package/src/skills/captcha/scripts/solve_image_grid.py +350 -0
- package/src/skills/google-merchant-api/SKILL.md +581 -0
- package/src/skills/google-merchant-api/references/accounts.md +247 -0
- package/src/skills/google-merchant-api/references/content-api-legacy.md +216 -0
- package/src/skills/google-merchant-api/references/datasources.md +233 -0
- package/src/skills/google-merchant-api/references/inventories.md +201 -0
- package/src/skills/google-merchant-api/references/migration.md +267 -0
- package/src/skills/google-merchant-api/references/products.md +316 -0
- package/src/skills/google-merchant-api/references/promotions.md +201 -0
- package/src/skills/google-merchant-api/references/reports.md +240 -0
- package/src/skills/lv-aggregators-api/SKILL.md +113 -0
- package/src/skills/lv-aggregators-api/references/integration-guide.md +368 -0
- package/src/skills/lv-aggregators-api/references/kurpirkt.md +103 -0
- package/src/skills/lv-aggregators-api/references/salidzini.md +122 -0
- package/src/skills/nest-best-practices/SKILL.md +251 -0
- package/src/skills/nest-best-practices/references/best-practices-request-lifecycle.md +158 -0
- package/src/skills/nest-best-practices/references/cli-monorepo.md +106 -0
- package/src/skills/nest-best-practices/references/cli-overview.md +157 -0
- package/src/skills/nest-best-practices/references/core-controllers.md +165 -0
- package/src/skills/nest-best-practices/references/core-dependency-injection.md +179 -0
- package/src/skills/nest-best-practices/references/core-middleware.md +139 -0
- package/src/skills/nest-best-practices/references/core-modules.md +138 -0
- package/src/skills/nest-best-practices/references/core-providers.md +188 -0
- package/src/skills/nest-best-practices/references/faq-raw-body-hybrid.md +122 -0
- package/src/skills/nest-best-practices/references/fundamentals-circular-dependency.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-custom-decorators.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-dynamic-modules.md +125 -0
- package/src/skills/nest-best-practices/references/fundamentals-exception-filters.md +202 -0
- package/src/skills/nest-best-practices/references/fundamentals-execution-context.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-guards.md +136 -0
- package/src/skills/nest-best-practices/references/fundamentals-interceptors.md +187 -0
- package/src/skills/nest-best-practices/references/fundamentals-lazy-loading.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-lifecycle-events.md +87 -0
- package/src/skills/nest-best-practices/references/fundamentals-module-reference.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-pipes.md +197 -0
- package/src/skills/nest-best-practices/references/fundamentals-provider-scopes.md +92 -0
- package/src/skills/nest-best-practices/references/fundamentals-testing.md +142 -0
- package/src/skills/nest-best-practices/references/graphql-overview.md +233 -0
- package/src/skills/nest-best-practices/references/graphql-resolvers-mutations.md +199 -0
- package/src/skills/nest-best-practices/references/graphql-scalars-unions-enums.md +180 -0
- package/src/skills/nest-best-practices/references/graphql-subscriptions.md +228 -0
- package/src/skills/nest-best-practices/references/microservices-grpc.md +175 -0
- package/src/skills/nest-best-practices/references/microservices-overview.md +221 -0
- package/src/skills/nest-best-practices/references/microservices-transports.md +119 -0
- package/src/skills/nest-best-practices/references/openapi-swagger.md +207 -0
- package/src/skills/nest-best-practices/references/recipes-authentication.md +97 -0
- package/src/skills/nest-best-practices/references/recipes-cqrs.md +176 -0
- package/src/skills/nest-best-practices/references/recipes-crud-generator.md +87 -0
- package/src/skills/nest-best-practices/references/recipes-documentation.md +93 -0
- package/src/skills/nest-best-practices/references/recipes-mongoose.md +153 -0
- package/src/skills/nest-best-practices/references/recipes-prisma.md +98 -0
- package/src/skills/nest-best-practices/references/recipes-terminus.md +148 -0
- package/src/skills/nest-best-practices/references/recipes-typeorm.md +122 -0
- package/src/skills/nest-best-practices/references/security-authorization.md +196 -0
- package/src/skills/nest-best-practices/references/security-cors-helmet-rate-limiting.md +204 -0
- package/src/skills/nest-best-practices/references/security-encryption-hashing.md +93 -0
- package/src/skills/nest-best-practices/references/techniques-caching.md +142 -0
- package/src/skills/nest-best-practices/references/techniques-compression-streaming-sse.md +194 -0
- package/src/skills/nest-best-practices/references/techniques-configuration.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-database.md +153 -0
- package/src/skills/nest-best-practices/references/techniques-events.md +163 -0
- package/src/skills/nest-best-practices/references/techniques-fastify.md +137 -0
- package/src/skills/nest-best-practices/references/techniques-file-upload.md +140 -0
- package/src/skills/nest-best-practices/references/techniques-http-module.md +176 -0
- package/src/skills/nest-best-practices/references/techniques-logging.md +146 -0
- package/src/skills/nest-best-practices/references/techniques-mvc-serve-static.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-queues.md +162 -0
- package/src/skills/nest-best-practices/references/techniques-serialization.md +158 -0
- package/src/skills/nest-best-practices/references/techniques-sessions-cookies.md +167 -0
- package/src/skills/nest-best-practices/references/techniques-task-scheduling.md +166 -0
- package/src/skills/nest-best-practices/references/techniques-validation.md +126 -0
- package/src/skills/nest-best-practices/references/techniques-versioning.md +153 -0
- package/src/skills/nest-best-practices/references/websockets-advanced.md +96 -0
- package/src/skills/nest-best-practices/references/websockets-gateways.md +215 -0
- package/src/skills/tailwindcss-best-practices/SKILL.md +180 -0
- package/src/skills/tailwindcss-best-practices/references/best-practices-utility-patterns.md +87 -0
- package/src/skills/tailwindcss-best-practices/references/core-installation.md +109 -0
- package/src/skills/tailwindcss-best-practices/references/core-preflight.md +200 -0
- package/src/skills/tailwindcss-best-practices/references/core-responsive.md +163 -0
- package/src/skills/tailwindcss-best-practices/references/core-source-detection.md +114 -0
- package/src/skills/tailwindcss-best-practices/references/core-theme.md +108 -0
- package/src/skills/tailwindcss-best-practices/references/core-utility-classes.md +59 -0
- package/src/skills/tailwindcss-best-practices/references/core-variants.md +204 -0
- package/src/skills/tailwindcss-best-practices/references/effects-form-controls.md +76 -0
- package/src/skills/tailwindcss-best-practices/references/effects-mask.md +91 -0
- package/src/skills/tailwindcss-best-practices/references/effects-scroll-snap.md +59 -0
- package/src/skills/tailwindcss-best-practices/references/effects-text-shadow.md +78 -0
- package/src/skills/tailwindcss-best-practices/references/effects-transition-animation.md +80 -0
- package/src/skills/tailwindcss-best-practices/references/effects-visibility-interactivity.md +82 -0
- package/src/skills/tailwindcss-best-practices/references/features-content-detection.md +175 -0
- package/src/skills/tailwindcss-best-practices/references/features-custom-styles.md +203 -0
- package/src/skills/tailwindcss-best-practices/references/features-dark-mode.md +137 -0
- package/src/skills/tailwindcss-best-practices/references/features-functions-directives.md +241 -0
- package/src/skills/tailwindcss-best-practices/references/features-upgrade.md +160 -0
- package/src/skills/tailwindcss-best-practices/references/layout-aspect-ratio.md +39 -0
- package/src/skills/tailwindcss-best-practices/references/layout-columns.md +80 -0
- package/src/skills/tailwindcss-best-practices/references/layout-display.md +110 -0
- package/src/skills/tailwindcss-best-practices/references/layout-flexbox.md +112 -0
- package/src/skills/tailwindcss-best-practices/references/layout-grid.md +87 -0
- package/src/skills/tailwindcss-best-practices/references/layout-height.md +97 -0
- package/src/skills/tailwindcss-best-practices/references/layout-inset.md +103 -0
- package/src/skills/tailwindcss-best-practices/references/layout-logical-properties.md +92 -0
- package/src/skills/tailwindcss-best-practices/references/layout-margin.md +126 -0
- package/src/skills/tailwindcss-best-practices/references/layout-min-max-sizing.md +63 -0
- package/src/skills/tailwindcss-best-practices/references/layout-object-fit-position.md +64 -0
- package/src/skills/tailwindcss-best-practices/references/layout-overflow.md +57 -0
- package/src/skills/tailwindcss-best-practices/references/layout-padding.md +77 -0
- package/src/skills/tailwindcss-best-practices/references/layout-position.md +85 -0
- package/src/skills/tailwindcss-best-practices/references/layout-tables.md +67 -0
- package/src/skills/tailwindcss-best-practices/references/layout-width.md +102 -0
- package/src/skills/tailwindcss-best-practices/references/transform-base.md +68 -0
- package/src/skills/tailwindcss-best-practices/references/transform-rotate.md +70 -0
- package/src/skills/tailwindcss-best-practices/references/transform-scale.md +83 -0
- package/src/skills/tailwindcss-best-practices/references/transform-skew.md +62 -0
- package/src/skills/tailwindcss-best-practices/references/transform-translate.md +77 -0
- package/src/skills/tailwindcss-best-practices/references/typography-font-text.md +142 -0
- package/src/skills/tailwindcss-best-practices/references/typography-list-style.md +65 -0
- package/src/skills/tailwindcss-best-practices/references/typography-text-align.md +60 -0
- package/src/skills/tailwindcss-best-practices/references/visual-background.md +76 -0
- package/src/skills/tailwindcss-best-practices/references/visual-border.md +108 -0
- package/src/skills/tailwindcss-best-practices/references/visual-effects.md +111 -0
- package/src/skills/tailwindcss-best-practices/references/visual-svg.md +82 -0
- package/src/skills/test-mobile-app/SKILL.md +11 -6
- package/src/skills/test-mobile-app/scripts/analyze_apk.py +15 -4
- package/src/skills/test-mobile-app/scripts/check_environment.py +5 -5
- package/src/skills/test-mobile-app/scripts/run_tests.py +1 -1
- package/src/skills/test-web-ui/SKILL.md +264 -84
- package/src/skills/test-web-ui/scripts/discover.py +25 -12
- package/src/skills/test-web-ui/scripts/run_tests.py +3 -2
- package/src/skills/typescript-expert/SKILL.md +145 -0
- package/src/skills/typescript-expert/commands/typescript-fix.md +65 -0
- package/src/skills/typescript-expert/references/advanced-conditional-types.md +190 -0
- package/src/skills/typescript-expert/references/advanced-decorators.md +243 -0
- package/src/skills/typescript-expert/references/advanced-mapped-types.md +223 -0
- package/src/skills/typescript-expert/references/advanced-template-literals.md +209 -0
- package/src/skills/typescript-expert/references/advanced-type-guards.md +308 -0
- package/src/skills/typescript-expert/references/best-practices-patterns.md +313 -0
- package/src/skills/typescript-expert/references/best-practices-performance.md +185 -0
- package/src/skills/typescript-expert/references/best-practices-tsconfig.md +242 -0
- package/src/skills/typescript-expert/references/core-generics.md +246 -0
- package/src/skills/typescript-expert/references/core-interfaces-types.md +231 -0
- package/src/skills/typescript-expert/references/core-type-system.md +261 -0
- package/src/skills/typescript-expert/references/core-utility-types.md +235 -0
- package/src/skills/typescript-expert/references/features-ts5x.md +370 -0
- package/src/skills/vite-best-practices/SKILL.md +115 -0
- package/src/skills/vite-best-practices/references/build-and-ssr.md +255 -0
- package/src/skills/vite-best-practices/references/core-config.md +231 -0
- package/src/skills/vite-best-practices/references/core-features.md +222 -0
- package/src/skills/vite-best-practices/references/core-plugin-api.md +294 -0
- package/src/skills/vite-best-practices/references/environment-api.md +108 -0
- package/src/skills/vite-best-practices/references/rolldown-migration.md +242 -0
- package/codex-cli-workspace/iteration-1/benchmark.json +0 -122
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/eval_metadata.json +0 -13
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/grading.json +0 -52
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/outputs/response.md +0 -163
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/grading.json +0 -58
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/outputs/response.md +0 -151
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/eval_metadata.json +0 -13
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/grading.json +0 -52
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/outputs/response.md +0 -86
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/grading.json +0 -58
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/outputs/response.md +0 -164
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/eval_metadata.json +0 -13
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/grading.json +0 -52
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/outputs/response.md +0 -130
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/grading.json +0 -64
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/outputs/response.md +0 -209
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/review.html +0 -1325
- package/gemini-cli-workspace/iteration-1/benchmark.json +0 -86
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/outputs/response.md +0 -401
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/outputs/response.md +0 -405
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/outputs/response.md +0 -212
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/outputs/response.md +0 -427
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/eval_metadata.json +0 -32
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/outputs/response.md +0 -171
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/outputs/response.md +0 -199
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/review.html +0 -1325
- package/gemini-cli-workspace/iteration-2/benchmark.json +0 -173
- package/gemini-cli-workspace/iteration-2/benchmark.md +0 -28
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/outputs/response.md +0 -195
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/outputs/response.md +0 -377
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/outputs/response.md +0 -127
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/outputs/response.md +0 -164
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/eval_metadata.json +0 -32
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/outputs/response.md +0 -91
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/outputs/response.md +0 -112
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-viewer.html +0 -1325
- package/screen-recording-workspace/evals.json +0 -41
- package/screen-recording-workspace/iteration-1/benchmark.json +0 -102
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/eval_metadata.json +0 -31
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/outputs/demo.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/outputs/demo.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/eval_metadata.json +0 -31
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/outputs/region_capture.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/outputs/region_capture.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/eval_metadata.json +0 -31
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/outputs/fallback_recording.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/outputs/fallback_recording.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/outputs/record_screen.py +0 -67
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/review.html +0 -1325
- package/src/skills/codex-cli/evals/evals.json +0 -47
- package/src/skills/gemini-cli/evals/evals.json +0 -46
- package/src/skills/tm-search/evals/evals.json +0 -23
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Inventories Sub-API Reference
|
|
2
|
+
|
|
3
|
+
Base: `https://merchantapi.googleapis.com/inventories/v1`
|
|
4
|
+
|
|
5
|
+
Manage product availability and pricing at the store level (local) or region level (regional).
|
|
6
|
+
|
|
7
|
+
## Local Inventories
|
|
8
|
+
|
|
9
|
+
Store-level inventory for brick-and-mortar locations.
|
|
10
|
+
|
|
11
|
+
| Method | Endpoint | Description |
|
|
12
|
+
|--------|----------|-------------|
|
|
13
|
+
| `POST` | `/accounts/{account}/products/{product}/localInventories` | Insert/update local inventory |
|
|
14
|
+
| `GET` | `/accounts/{account}/products/{product}/localInventories` | List local inventories |
|
|
15
|
+
| `DELETE` | `/accounts/{account}/products/{product}/localInventories/{storeCode}` | Delete local inventory |
|
|
16
|
+
|
|
17
|
+
### LocalInventory Object
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"name": "accounts/123456/products/en~US~SKU001/localInventories/STORE-NYC-01",
|
|
22
|
+
"account": "accounts/123456",
|
|
23
|
+
"storeCode": "STORE-NYC-01",
|
|
24
|
+
"availability": "in_stock",
|
|
25
|
+
"price": {
|
|
26
|
+
"amountMicros": "69990000",
|
|
27
|
+
"currencyCode": "USD"
|
|
28
|
+
},
|
|
29
|
+
"salePrice": {
|
|
30
|
+
"amountMicros": "59990000",
|
|
31
|
+
"currencyCode": "USD"
|
|
32
|
+
},
|
|
33
|
+
"salePriceEffectiveDate": {
|
|
34
|
+
"startTime": "2024-12-01T00:00:00Z",
|
|
35
|
+
"endTime": "2024-12-31T23:59:59Z"
|
|
36
|
+
},
|
|
37
|
+
"quantity": "25",
|
|
38
|
+
"pickupMethod": "buy",
|
|
39
|
+
"pickupSla": "same day",
|
|
40
|
+
"instoreProductLocation": "Aisle 5, Shelf B",
|
|
41
|
+
"customAttributes": [
|
|
42
|
+
{ "name": "display_unit", "value": "true" }
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Fields
|
|
48
|
+
|
|
49
|
+
| Field | Type | Required | Description |
|
|
50
|
+
|-------|------|----------|-------------|
|
|
51
|
+
| `storeCode` | string | Required | Your store identifier (must match Google Business Profile) |
|
|
52
|
+
| `availability` | enum | Optional | `in_stock`, `out_of_stock`, `preorder`, `backorder` |
|
|
53
|
+
| `price` | Price | Optional | Store-specific price override |
|
|
54
|
+
| `salePrice` | Price | Optional | Store-specific sale price |
|
|
55
|
+
| `salePriceEffectiveDate` | Interval | Optional | Sale period |
|
|
56
|
+
| `quantity` | int64 | Optional | Stock quantity |
|
|
57
|
+
| `pickupMethod` | enum | Optional | `buy`, `reserve`, `ship_to_store`, `not_supported` |
|
|
58
|
+
| `pickupSla` | enum | Optional | `same_day`, `next_day`, `2_day` ... `7_day`, `multi_week` |
|
|
59
|
+
| `instoreProductLocation` | string | Optional | Physical location in store |
|
|
60
|
+
| `customAttributes[]` | array | Optional | Additional attributes |
|
|
61
|
+
|
|
62
|
+
### Insert Example
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const MERCHANT_ID = '123456';
|
|
66
|
+
const PRODUCT_ID = 'en~US~SKU001';
|
|
67
|
+
|
|
68
|
+
const localInventory = {
|
|
69
|
+
storeCode: 'STORE-NYC-01',
|
|
70
|
+
availability: 'in_stock',
|
|
71
|
+
price: { amountMicros: '69990000', currencyCode: 'USD' },
|
|
72
|
+
quantity: '25',
|
|
73
|
+
pickupMethod: 'buy',
|
|
74
|
+
pickupSla: 'same_day',
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const response = await fetch(
|
|
78
|
+
`https://merchantapi.googleapis.com/inventories/v1/accounts/${MERCHANT_ID}/products/${PRODUCT_ID}/localInventories`,
|
|
79
|
+
{
|
|
80
|
+
method: 'POST',
|
|
81
|
+
headers: {
|
|
82
|
+
'Authorization': `Bearer ${token}`,
|
|
83
|
+
'Content-Type': 'application/json',
|
|
84
|
+
},
|
|
85
|
+
body: JSON.stringify(localInventory),
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Regional Inventories
|
|
91
|
+
|
|
92
|
+
Region-level overrides for pricing and availability based on geographic regions you define.
|
|
93
|
+
|
|
94
|
+
| Method | Endpoint | Description |
|
|
95
|
+
|--------|----------|-------------|
|
|
96
|
+
| `POST` | `/accounts/{account}/products/{product}/regionalInventories` | Insert/update regional inventory |
|
|
97
|
+
| `GET` | `/accounts/{account}/products/{product}/regionalInventories` | List regional inventories |
|
|
98
|
+
| `DELETE` | `/accounts/{account}/products/{product}/regionalInventories/{region}` | Delete regional inventory |
|
|
99
|
+
|
|
100
|
+
### RegionalInventory Object
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"name": "accounts/123456/products/en~US~SKU001/regionalInventories/northeast",
|
|
105
|
+
"account": "accounts/123456",
|
|
106
|
+
"region": "northeast",
|
|
107
|
+
"availability": "in_stock",
|
|
108
|
+
"price": {
|
|
109
|
+
"amountMicros": "74990000",
|
|
110
|
+
"currencyCode": "USD"
|
|
111
|
+
},
|
|
112
|
+
"salePrice": {
|
|
113
|
+
"amountMicros": "64990000",
|
|
114
|
+
"currencyCode": "USD"
|
|
115
|
+
},
|
|
116
|
+
"salePriceEffectiveDate": {
|
|
117
|
+
"startTime": "2024-12-01T00:00:00Z",
|
|
118
|
+
"endTime": "2024-12-31T23:59:59Z"
|
|
119
|
+
},
|
|
120
|
+
"customAttributes": []
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Fields
|
|
125
|
+
|
|
126
|
+
| Field | Type | Required | Description |
|
|
127
|
+
|-------|------|----------|-------------|
|
|
128
|
+
| `region` | string | Required | Region ID (must be defined via Accounts > Regions) |
|
|
129
|
+
| `availability` | enum | Optional | Same as local inventory |
|
|
130
|
+
| `price` | Price | Optional | Region-specific price override |
|
|
131
|
+
| `salePrice` | Price | Optional | Region-specific sale price |
|
|
132
|
+
| `salePriceEffectiveDate` | Interval | Optional | Sale period |
|
|
133
|
+
| `customAttributes[]` | array | Optional | Additional attributes |
|
|
134
|
+
|
|
135
|
+
### Workflow: Set Up Regional Pricing
|
|
136
|
+
|
|
137
|
+
1. **Define regions** via the Accounts sub-API:
|
|
138
|
+
```javascript
|
|
139
|
+
// Create a region
|
|
140
|
+
await fetch(
|
|
141
|
+
`https://merchantapi.googleapis.com/accounts/v1/accounts/${MERCHANT_ID}/regions`,
|
|
142
|
+
{
|
|
143
|
+
method: 'POST',
|
|
144
|
+
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
145
|
+
body: JSON.stringify({
|
|
146
|
+
displayName: 'US Northeast',
|
|
147
|
+
postalCodeArea: {
|
|
148
|
+
regionCode: 'US',
|
|
149
|
+
postalCodes: [
|
|
150
|
+
{ begin: '10000', end: '14999' },
|
|
151
|
+
{ begin: '06000', end: '06999' },
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
}),
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
2. **Set regional inventory** for products:
|
|
160
|
+
```javascript
|
|
161
|
+
await fetch(
|
|
162
|
+
`https://merchantapi.googleapis.com/inventories/v1/accounts/${MERCHANT_ID}/products/en~US~SKU001/regionalInventories`,
|
|
163
|
+
{
|
|
164
|
+
method: 'POST',
|
|
165
|
+
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
166
|
+
body: JSON.stringify({
|
|
167
|
+
region: 'northeast',
|
|
168
|
+
price: { amountMicros: '74990000', currencyCode: 'USD' },
|
|
169
|
+
availability: 'in_stock',
|
|
170
|
+
}),
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Bulk Inventory Updates
|
|
176
|
+
|
|
177
|
+
For updating many products' inventory, use async parallel requests:
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
// Update inventory for multiple products in parallel
|
|
181
|
+
const inventoryUpdates = [
|
|
182
|
+
{ productId: 'en~US~SKU001', storeCode: 'STORE-01', quantity: '50', availability: 'in_stock' },
|
|
183
|
+
{ productId: 'en~US~SKU002', storeCode: 'STORE-01', quantity: '0', availability: 'out_of_stock' },
|
|
184
|
+
{ productId: 'en~US~SKU003', storeCode: 'STORE-01', quantity: '12', availability: 'in_stock' },
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
const results = await Promise.allSettled(
|
|
188
|
+
inventoryUpdates.map(({ productId, ...inventory }) =>
|
|
189
|
+
fetch(
|
|
190
|
+
`https://merchantapi.googleapis.com/inventories/v1/accounts/${MERCHANT_ID}/products/${productId}/localInventories`,
|
|
191
|
+
{
|
|
192
|
+
method: 'POST',
|
|
193
|
+
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
194
|
+
body: JSON.stringify(inventory),
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Respect rate limits — implement exponential backoff for `429` responses.
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# Migration: Content API for Shopping to Merchant API
|
|
2
|
+
|
|
3
|
+
The Content API for Shopping (v2.1) sunsets **August 18, 2026**. The Merchant API (v1) is the replacement.
|
|
4
|
+
|
|
5
|
+
## Key Architectural Changes
|
|
6
|
+
|
|
7
|
+
### 1. Products Split into Input + Output
|
|
8
|
+
|
|
9
|
+
**Content API:** Single `products` resource for read and write.
|
|
10
|
+
|
|
11
|
+
**Merchant API:** Split into:
|
|
12
|
+
- `productInputs` - What you submit (write)
|
|
13
|
+
- `products` - What Google processed (read-only, includes status)
|
|
14
|
+
|
|
15
|
+
This means `productstatuses` is gone — status is now part of the `products` resource.
|
|
16
|
+
|
|
17
|
+
### 2. Modular Sub-APIs
|
|
18
|
+
|
|
19
|
+
**Content API:** Monolithic API with all resources under one service.
|
|
20
|
+
|
|
21
|
+
**Merchant API:** 14 independent sub-APIs, each with own versioning:
|
|
22
|
+
- `products/v1`, `accounts/v1`, `inventories/v1`, `reports/v1`, etc.
|
|
23
|
+
|
|
24
|
+
### 3. Resource Naming
|
|
25
|
+
|
|
26
|
+
**Content API ID format:**
|
|
27
|
+
```
|
|
28
|
+
channel:contentLanguage:targetCountry:offerId
|
|
29
|
+
Example: online:en:US:sku123
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Merchant API name format:**
|
|
33
|
+
```
|
|
34
|
+
accounts/{accountId}/products/{contentLanguage}~{feedLabel}~{offerId}
|
|
35
|
+
Example: accounts/123456/products/en~US~sku123
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 4. Price Format
|
|
39
|
+
|
|
40
|
+
**Content API:**
|
|
41
|
+
```json
|
|
42
|
+
{ "value": "79.99", "currency": "USD" }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Merchant API:**
|
|
46
|
+
```json
|
|
47
|
+
{ "amountMicros": "79990000", "currencyCode": "USD" }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Conversion: `amountMicros = value * 1000000`
|
|
51
|
+
|
|
52
|
+
### 5. Field Nesting
|
|
53
|
+
|
|
54
|
+
**Content API:** Flat top-level attributes.
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"offerId": "SKU-001",
|
|
58
|
+
"title": "My Product",
|
|
59
|
+
"price": { "value": "79.99", "currency": "USD" }
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Merchant API:** Attributes nested under `productAttributes`.
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"offerId": "SKU-001",
|
|
67
|
+
"productAttributes": {
|
|
68
|
+
"title": "My Product",
|
|
69
|
+
"price": { "amountMicros": "79990000", "currencyCode": "USD" }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 6. targetCountry → feedLabel
|
|
75
|
+
|
|
76
|
+
`targetCountry` is renamed to `feedLabel`. Values are the same (e.g., `US`, `GB`).
|
|
77
|
+
|
|
78
|
+
### 7. Batching
|
|
79
|
+
|
|
80
|
+
**Content API:** `customBatch` methods.
|
|
81
|
+
|
|
82
|
+
**Merchant API:** No custom batch. Use async parallel requests or HTTP batching instead.
|
|
83
|
+
|
|
84
|
+
### 8. Data Source Required
|
|
85
|
+
|
|
86
|
+
All `productInputs` write operations require a `dataSource` query parameter:
|
|
87
|
+
```
|
|
88
|
+
POST /products/v1/accounts/{id}/productInputs:insert?dataSource=accounts/{id}/dataSources/{dsId}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 9. Base64url Encoding
|
|
92
|
+
|
|
93
|
+
Product names containing special characters (`% . + / : ~ , ( * ! ) & ? = @ # $`) must use unpadded base64url encoding (RFC 4648 Section 5).
|
|
94
|
+
|
|
95
|
+
## Method Mapping
|
|
96
|
+
|
|
97
|
+
| Content API Method | Merchant API Method |
|
|
98
|
+
|-------------------|---------------------|
|
|
99
|
+
| `products.insert` | `productInputs:insert` |
|
|
100
|
+
| `products.update` | `productInputs:patch` |
|
|
101
|
+
| `products.delete` | `productInputs:delete` |
|
|
102
|
+
| `products.get` | `products.get` |
|
|
103
|
+
| `products.list` | `products.list` |
|
|
104
|
+
| `products.custombatch` | Async parallel requests |
|
|
105
|
+
| `productstatuses.get` | `products.get` (status included) |
|
|
106
|
+
| `productstatuses.list` | `products.list` (status included) |
|
|
107
|
+
| `productstatuses.custombatch` | Async parallel requests |
|
|
108
|
+
| `accounts.get` | `accounts.get` |
|
|
109
|
+
| `accounts.list` | `accounts.list` |
|
|
110
|
+
| `accounts.update` | `accounts.patch` |
|
|
111
|
+
| `accounts.insert` | `accounts:createAndConfigure` |
|
|
112
|
+
| `accounts.delete` | `accounts.delete` |
|
|
113
|
+
| `accountstatuses.get` | `accounts/{id}/issues.list` |
|
|
114
|
+
| `datafeeds.*` | `dataSources.*` |
|
|
115
|
+
| `datafeedstatuses.*` | `dataSources/{id}/fileUploads/{id}` |
|
|
116
|
+
| `liasettings.*` | `omnichannelSettings.*` |
|
|
117
|
+
| `shippingsettings.*` | `shippingSettings.*` |
|
|
118
|
+
| `regions.*` | `regions.*` |
|
|
119
|
+
| `returnpolicy.*` | `onlineReturnPolicies.*` |
|
|
120
|
+
|
|
121
|
+
## Migration Strategy
|
|
122
|
+
|
|
123
|
+
### Recommended Order
|
|
124
|
+
|
|
125
|
+
1. **Accounts** - Foundation for everything else
|
|
126
|
+
2. **Products** - Core product management
|
|
127
|
+
3. **Data Sources** - Feed management (compatible across APIs)
|
|
128
|
+
4. **Reports** - Performance data
|
|
129
|
+
5. **Everything else** - Promotions, inventory, notifications, etc.
|
|
130
|
+
|
|
131
|
+
### Incremental Approach
|
|
132
|
+
|
|
133
|
+
You can migrate one sub-API at a time. Content API and Merchant API can coexist:
|
|
134
|
+
- Data sources created with Content API work with Merchant API
|
|
135
|
+
- Products inserted via Content API are visible through Merchant API
|
|
136
|
+
- Migrate sub-APIs independently, test each before moving to the next
|
|
137
|
+
|
|
138
|
+
### Code Migration Example
|
|
139
|
+
|
|
140
|
+
**Before (Content API):**
|
|
141
|
+
```javascript
|
|
142
|
+
// Insert product
|
|
143
|
+
const response = await fetch(
|
|
144
|
+
`https://shoppingcontent.googleapis.com/content/v2.1/${MERCHANT_ID}/products`,
|
|
145
|
+
{
|
|
146
|
+
method: 'POST',
|
|
147
|
+
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
148
|
+
body: JSON.stringify({
|
|
149
|
+
offerId: 'SKU-001',
|
|
150
|
+
title: 'Premium Headphones',
|
|
151
|
+
description: 'Great headphones',
|
|
152
|
+
link: 'https://example.com/product',
|
|
153
|
+
imageLink: 'https://example.com/image.jpg',
|
|
154
|
+
contentLanguage: 'en',
|
|
155
|
+
targetCountry: 'US',
|
|
156
|
+
channel: 'online',
|
|
157
|
+
availability: 'in stock',
|
|
158
|
+
condition: 'new',
|
|
159
|
+
price: { value: '79.99', currency: 'USD' },
|
|
160
|
+
brand: 'AudioBrand',
|
|
161
|
+
gtin: '0123456789012',
|
|
162
|
+
}),
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Get product status
|
|
167
|
+
const status = await fetch(
|
|
168
|
+
`https://shoppingcontent.googleapis.com/content/v2.1/${MERCHANT_ID}/productstatuses/online:en:US:SKU-001`,
|
|
169
|
+
{ headers: { 'Authorization': `Bearer ${token}` } }
|
|
170
|
+
);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**After (Merchant API):**
|
|
174
|
+
```javascript
|
|
175
|
+
// Insert product input
|
|
176
|
+
const response = await fetch(
|
|
177
|
+
`https://merchantapi.googleapis.com/products/v1/accounts/${MERCHANT_ID}/productInputs:insert?dataSource=accounts/${MERCHANT_ID}/dataSources/${DS_ID}`,
|
|
178
|
+
{
|
|
179
|
+
method: 'POST',
|
|
180
|
+
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
181
|
+
body: JSON.stringify({
|
|
182
|
+
offerId: 'SKU-001',
|
|
183
|
+
contentLanguage: 'en',
|
|
184
|
+
feedLabel: 'US',
|
|
185
|
+
productAttributes: {
|
|
186
|
+
title: 'Premium Headphones',
|
|
187
|
+
description: 'Great headphones',
|
|
188
|
+
link: 'https://example.com/product',
|
|
189
|
+
imageLink: 'https://example.com/image.jpg',
|
|
190
|
+
availability: 'in_stock',
|
|
191
|
+
condition: 'new',
|
|
192
|
+
price: { amountMicros: '79990000', currencyCode: 'USD' },
|
|
193
|
+
brand: 'AudioBrand',
|
|
194
|
+
gtin: '0123456789012',
|
|
195
|
+
channel: 'ONLINE',
|
|
196
|
+
},
|
|
197
|
+
}),
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
// Get product (includes status)
|
|
202
|
+
const product = await fetch(
|
|
203
|
+
`https://merchantapi.googleapis.com/products/v1/accounts/${MERCHANT_ID}/products/en~US~SKU-001`,
|
|
204
|
+
{ headers: { 'Authorization': `Bearer ${token}` } }
|
|
205
|
+
);
|
|
206
|
+
// product.productStatus contains destinationStatuses and itemLevelIssues
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Price Conversion Helper
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
// Content API price → Merchant API price
|
|
213
|
+
function toMerchantPrice(contentPrice) {
|
|
214
|
+
return {
|
|
215
|
+
amountMicros: String(Math.round(parseFloat(contentPrice.value) * 1_000_000)),
|
|
216
|
+
currencyCode: contentPrice.currency,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Merchant API price → Content API price
|
|
221
|
+
function toContentPrice(merchantPrice) {
|
|
222
|
+
return {
|
|
223
|
+
value: String(parseInt(merchantPrice.amountMicros) / 1_000_000),
|
|
224
|
+
currency: merchantPrice.currencyCode,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
# Content API price → Merchant API price
|
|
231
|
+
def to_merchant_price(content_price):
|
|
232
|
+
return {
|
|
233
|
+
'amountMicros': str(round(float(content_price['value']) * 1_000_000)),
|
|
234
|
+
'currencyCode': content_price['currency'],
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
# Merchant API price → Content API price
|
|
238
|
+
def to_content_price(merchant_price):
|
|
239
|
+
return {
|
|
240
|
+
'value': str(int(merchant_price['amountMicros']) / 1_000_000),
|
|
241
|
+
'currency': merchant_price['currencyCode'],
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Product ID Conversion
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
// Content API ID → Merchant API name
|
|
249
|
+
function toMerchantProductName(contentId, accountId) {
|
|
250
|
+
// contentId format: "online:en:US:sku123"
|
|
251
|
+
const [channel, lang, country, ...offerId] = contentId.split(':');
|
|
252
|
+
const offer = offerId.join(':');
|
|
253
|
+
const prefix = channel === 'local' ? 'local~' : '';
|
|
254
|
+
return `accounts/${accountId}/products/${prefix}${lang}~${country}~${offer}`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Merchant API name → Content API ID
|
|
258
|
+
function toContentProductId(merchantName) {
|
|
259
|
+
// merchantName: "accounts/123/products/en~US~sku123"
|
|
260
|
+
const productPart = merchantName.split('/products/')[1];
|
|
261
|
+
const isLocal = productPart.startsWith('local~');
|
|
262
|
+
const parts = (isLocal ? productPart.slice(6) : productPart).split('~');
|
|
263
|
+
const [lang, feedLabel, ...offerId] = parts;
|
|
264
|
+
const channel = isLocal ? 'local' : 'online';
|
|
265
|
+
return `${channel}:${lang}:${feedLabel}:${offerId.join('~')}`;
|
|
266
|
+
}
|
|
267
|
+
```
|