@omega.js/manager 0.1.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/.claude-plugin/marketplace.json +14 -0
- package/LICENSE +98 -0
- package/README.md +165 -0
- package/bin/omega +2 -0
- package/bin/omg +2 -0
- package/claude-plugin/.claude-plugin/plugin.json +11 -0
- package/claude-plugin/.mcp.json +9 -0
- package/claude-plugin/README.md +139 -0
- package/claude-plugin/hooks/gate/mark.sh +58 -0
- package/claude-plugin/hooks/gate/run.sh +97 -0
- package/claude-plugin/hooks/guard/run.sh +249 -0
- package/claude-plugin/hooks/hooks.json +63 -0
- package/claude-plugin/hooks/inject/run.sh +127 -0
- package/claude-plugin/hooks/lib/omega-gate.sh +20 -0
- package/claude-plugin/hooks/lib/omega-scope.sh +41 -0
- package/claude-plugin/hooks/lib/omega-skills.sh +209 -0
- package/claude-plugin/hooks/quality/run.sh +132 -0
- package/claude-plugin/hooks/shape/run.sh +45 -0
- package/claude-plugin/mcp-router-launch.js +29 -0
- package/claude-plugin/skills/README.md +48 -0
- package/claude-plugin/skills/accessibility/SKILL.md +31 -0
- package/claude-plugin/skills/analytics/SKILL.md +30 -0
- package/claude-plugin/skills/backend/SKILL.md +25 -0
- package/claude-plugin/skills/brandcheck/SKILL.md +29 -0
- package/claude-plugin/skills/browser/SKILL.md +64 -0
- package/claude-plugin/skills/client/SKILL.md +24 -0
- package/claude-plugin/skills/desktop/SKILL.md +25 -0
- package/claude-plugin/skills/extension/SKILL.md +25 -0
- package/claude-plugin/skills/main/SKILL.md +54 -0
- package/claude-plugin/skills/manager/SKILL.md +25 -0
- package/claude-plugin/skills/seo/SKILL.md +36 -0
- package/claude-plugin/skills/theme/SKILL.md +33 -0
- package/claude-plugin/skills/web/SKILL.md +29 -0
- package/dist/cli-run.js +34 -0
- package/dist/cli.js +29 -0
- package/dist/commands/build.js +17 -0
- package/dist/commands/clean.js +16 -0
- package/dist/commands/company.js +46 -0
- package/dist/commands/deploy.js +143 -0
- package/dist/commands/dev.js +437 -0
- package/dist/commands/devlog.js +25 -0
- package/dist/commands/help.js +48 -0
- package/dist/commands/manage.js +53 -0
- package/dist/commands/migrate.js +76 -0
- package/dist/commands/onboard.js +31 -0
- package/dist/commands/pipeline.js +319 -0
- package/dist/commands/test.js +380 -0
- package/dist/commands/update.js +128 -0
- package/dist/commands/version.js +8 -0
- package/dist/company-init.js +167 -0
- package/dist/company.js +283 -0
- package/dist/config.js +1359 -0
- package/dist/devlog/index.js +226 -0
- package/dist/devlog/lib/collect-commits.js +136 -0
- package/dist/devlog/lib/generate-post.js +201 -0
- package/dist/devlog/lib/ghostii.js +122 -0
- package/dist/devlog/lib/project-map.js +98 -0
- package/dist/devlog/lib/publish-website.js +88 -0
- package/dist/index.js +45 -0
- package/dist/lib/agents-md.js +201 -0
- package/dist/lib/analytics-secret.js +22 -0
- package/dist/lib/argv.js +21 -0
- package/dist/lib/auth-admin.js +120 -0
- package/dist/lib/automation-client.js +210 -0
- package/dist/lib/backend-marketing.js +49 -0
- package/dist/lib/brand.js +240 -0
- package/dist/lib/bundle-id.js +53 -0
- package/dist/lib/claude-settings.js +125 -0
- package/dist/lib/company-scaffold.js +213 -0
- package/dist/lib/company.js +227 -0
- package/dist/lib/config-flow.js +350 -0
- package/dist/lib/config-write.js +41 -0
- package/dist/lib/custom-target.js +75 -0
- package/dist/lib/domain-utils.js +19 -0
- package/dist/lib/duration.js +39 -0
- package/dist/lib/env-order.js +236 -0
- package/dist/lib/env-secret.js +78 -0
- package/dist/lib/firestore-rest.js +326 -0
- package/dist/lib/framework-bin.js +156 -0
- package/dist/lib/gitignore.js +63 -0
- package/dist/lib/google-auth.js +495 -0
- package/dist/lib/google-token.js +66 -0
- package/dist/lib/jwt.js +31 -0
- package/dist/lib/legacy-oauth.js +59 -0
- package/dist/lib/node-version.js +127 -0
- package/dist/lib/owner-plan.js +78 -0
- package/dist/lib/package-scripts.js +152 -0
- package/dist/lib/preflight.js +470 -0
- package/dist/lib/product-create.js +144 -0
- package/dist/lib/run-command.js +74 -0
- package/dist/lib/run-gates.js +70 -0
- package/dist/lib/run-output.js +42 -0
- package/dist/lib/run-summary.js +384 -0
- package/dist/lib/scaffold.js +427 -0
- package/dist/lib/service-input.js +207 -0
- package/dist/lib/service-runner.js +466 -0
- package/dist/lib/stale.js +24 -0
- package/dist/lib/target-selection.js +155 -0
- package/dist/lib/verb-fanout.js +128 -0
- package/dist/lib/verify-live.js +188 -0
- package/dist/manage.js +311 -0
- package/dist/omega-bin.js +7 -0
- package/dist/onboard.js +532 -0
- package/dist/services/account/ensure/users.js +259 -0
- package/dist/services/account/index.js +97 -0
- package/dist/services/account/lib/backend-client.js +107 -0
- package/dist/services/account/lib/password.js +36 -0
- package/dist/services/account/lib/resolve-password.js +100 -0
- package/dist/services/advertising/ensure/sites.js +101 -0
- package/dist/services/advertising/index.js +101 -0
- package/dist/services/advertising/lib/adsense-api.js +41 -0
- package/dist/services/ai/ensure/keys.js +21 -0
- package/dist/services/ai/index.js +36 -0
- package/dist/services/analytics/ensure/google-firebase-link.js +230 -0
- package/dist/services/analytics/ensure/google-streams.js +256 -0
- package/dist/services/analytics/ensure/meta-pixel.js +22 -0
- package/dist/services/analytics/ensure/tiktok-pixel.js +22 -0
- package/dist/services/analytics/index.js +134 -0
- package/dist/services/analytics/lib/analytics-api.js +156 -0
- package/dist/services/analytics/lib/meta-api.js +83 -0
- package/dist/services/analytics/lib/pixel-account.js +78 -0
- package/dist/services/analytics/lib/pixel-provision.js +152 -0
- package/dist/services/analytics/lib/pixel-specs.js +57 -0
- package/dist/services/analytics/lib/pixel-token.js +88 -0
- package/dist/services/analytics/lib/property-flow.js +77 -0
- package/dist/services/analytics/lib/tiktok-api.js +157 -0
- package/dist/services/analytics/lib/tiktok-auth.js +153 -0
- package/dist/services/assets/ensure/logo-gen.js +68 -0
- package/dist/services/assets/index.js +109 -0
- package/dist/services/assets/lib/assets-config.js +168 -0
- package/dist/services/assets/lib/brandmark-api.js +160 -0
- package/dist/services/assets/lib/derived.js +113 -0
- package/dist/services/assets/lib/font-loader.js +67 -0
- package/dist/services/assets/lib/reconcile.js +122 -0
- package/dist/services/assets/lib/reset.js +118 -0
- package/dist/services/assets/lib/svg-logo-generator.js +154 -0
- package/dist/services/assets/lib/svg-to-black.js +32 -0
- package/dist/services/assets/write/favicons.js +82 -0
- package/dist/services/assets/write/icons.js +64 -0
- package/dist/services/assets/write/process.js +96 -0
- package/dist/services/assets/write/reconcile.js +30 -0
- package/dist/services/assets/write/social-icons.js +108 -0
- package/dist/services/assets/write/templates.js +345 -0
- package/dist/services/bookmark/ensure/sync.js +255 -0
- package/dist/services/bookmark/index.js +17 -0
- package/dist/services/campaigns/ensure/contact-person.js +40 -0
- package/dist/services/campaigns/ensure/custom-fields.js +84 -0
- package/dist/services/campaigns/ensure/domain-auth.js +92 -0
- package/dist/services/campaigns/ensure/event-webhook.js +89 -0
- package/dist/services/campaigns/ensure/link-branding.js +187 -0
- package/dist/services/campaigns/ensure/list.js +50 -0
- package/dist/services/campaigns/ensure/segments.js +109 -0
- package/dist/services/campaigns/ensure/sender-identity.js +153 -0
- package/dist/services/campaigns/ensure/unsubscribe-groups.js +116 -0
- package/dist/services/campaigns/index.js +79 -0
- package/dist/services/campaigns/lib/dns-sync.js +81 -0
- package/dist/services/campaigns/lib/segment-query.js +138 -0
- package/dist/services/campaigns/lib/sendgrid-api.js +287 -0
- package/dist/services/captcha/ensure/site-key.js +83 -0
- package/dist/services/captcha/index.js +78 -0
- package/dist/services/captcha/lib/console-url.js +45 -0
- package/dist/services/captcha/lib/recaptcha-api.js +36 -0
- package/dist/services/certificates/ensure/api-key.js +22 -0
- package/dist/services/certificates/ensure/bundle-ids.js +115 -0
- package/dist/services/certificates/ensure/certificates.js +187 -0
- package/dist/services/certificates/ensure/profiles.js +143 -0
- package/dist/services/certificates/index.js +225 -0
- package/dist/services/certificates/lib/apple-api.js +183 -0
- package/dist/services/certificates/lib/certificate-manager.js +252 -0
- package/dist/services/certificates/lib/identifier-manager.js +107 -0
- package/dist/services/certificates/lib/keychain.js +135 -0
- package/dist/services/certificates/lib/manual-walkthrough.js +165 -0
- package/dist/services/certificates/lib/profile-manager.js +115 -0
- package/dist/services/chat/data/baseline-knowledge.md +96 -0
- package/dist/services/chat/ensure/chat.js +106 -0
- package/dist/services/chat/ensure/user.js +45 -0
- package/dist/services/chat/index.js +139 -0
- package/dist/services/chat/lib/baseline-knowledge.js +137 -0
- package/dist/services/cloud/ensure/authentication.js +267 -0
- package/dist/services/cloud/ensure/billing.js +120 -0
- package/dist/services/cloud/ensure/cloud-messaging.js +105 -0
- package/dist/services/cloud/ensure/database.js +60 -0
- package/dist/services/cloud/ensure/firestore.js +79 -0
- package/dist/services/cloud/ensure/functions.js +49 -0
- package/dist/services/cloud/ensure/hosting.js +398 -0
- package/dist/services/cloud/ensure/oauth-consent.js +248 -0
- package/dist/services/cloud/ensure/project-settings.js +72 -0
- package/dist/services/cloud/ensure/sdk-config.js +95 -0
- package/dist/services/cloud/ensure/service-account.js +152 -0
- package/dist/services/cloud/ensure/services.js +103 -0
- package/dist/services/cloud/ensure/storage.js +47 -0
- package/dist/services/cloud/index.js +130 -0
- package/dist/services/cloud/lib/access-heal.js +130 -0
- package/dist/services/cloud/lib/firebase-api.js +662 -0
- package/dist/services/cloud/lib/project-flow.js +102 -0
- package/dist/services/directory/ensure/entry.js +48 -0
- package/dist/services/directory/index.js +64 -0
- package/dist/services/directory/lib/blocks.js +104 -0
- package/dist/services/disperse/index.js +45 -0
- package/dist/services/disperse/write/certs.js +117 -0
- package/dist/services/domain/ensure/nameservers.js +179 -0
- package/dist/services/domain/index.js +69 -0
- package/dist/services/domain/lib/namecheap-api.js +167 -0
- package/dist/services/domain/lib/registrars.js +46 -0
- package/dist/services/domain/lib/whitelist-walkthrough.js +76 -0
- package/dist/services/edge/ensure/cache-rules.js +105 -0
- package/dist/services/edge/ensure/dns-records.js +304 -0
- package/dist/services/edge/ensure/email-routing.js +292 -0
- package/dist/services/edge/ensure/rules-configuration.js +98 -0
- package/dist/services/edge/ensure/rules-managed-transforms.js +101 -0
- package/dist/services/edge/ensure/rules-redirect.js +107 -0
- package/dist/services/edge/ensure/rules-response-headers.js +90 -0
- package/dist/services/edge/ensure/rules-security.js +142 -0
- package/dist/services/edge/ensure/speed-scheduled-tests.js +98 -0
- package/dist/services/edge/ensure/workers.js +219 -0
- package/dist/services/edge/ensure/zone-settings.js +108 -0
- package/dist/services/edge/ensure/zone.js +183 -0
- package/dist/services/edge/index.js +73 -0
- package/dist/services/edge/lib/cloudflare-api.js +84 -0
- package/dist/services/edge/lib/dns-records-helpers.js +518 -0
- package/dist/services/edge/lib/read-cache.js +16 -0
- package/dist/services/edge/lib/ruleset-helper.js +108 -0
- package/dist/services/edge/workers/omega-api-proxy.js +43 -0
- package/dist/services/email/data/baseline-filter.md +4 -0
- package/dist/services/email/data/baseline-knowledge.md +86 -0
- package/dist/services/email/ensure/agent.js +107 -0
- package/dist/services/email/ensure/user.js +45 -0
- package/dist/services/email/index.js +138 -0
- package/dist/services/email/lib/baseline.js +82 -0
- package/dist/services/email/lib/knowledge-file.js +53 -0
- package/dist/services/forms/ensure/form.js +46 -0
- package/dist/services/forms/ensure/user.js +45 -0
- package/dist/services/forms/index.js +138 -0
- package/dist/services/migrations/ensure/notifications.js +189 -0
- package/dist/services/migrations/ensure/orders.js +34 -0
- package/dist/services/migrations/ensure/payment-provider.js +132 -0
- package/dist/services/migrations/ensure/payments-intents.js +34 -0
- package/dist/services/migrations/ensure/state-retirement.js +266 -0
- package/dist/services/migrations/ensure/targets-rename.js +124 -0
- package/dist/services/migrations/ensure/users.js +1176 -0
- package/dist/services/migrations/index.js +101 -0
- package/dist/services/migrations/lib/attribution-touch.js +64 -0
- package/dist/services/migrations/lib/ensure-metadata.js +144 -0
- package/dist/services/migrations/lib/migration-runner.js +473 -0
- package/dist/services/migrations/lib/sanitize-strings.js +112 -0
- package/dist/services/migrations/lib/schema-validator.js +154 -0
- package/dist/services/monitoring/ensure/dsn.js +54 -0
- package/dist/services/monitoring/ensure/projects.js +135 -0
- package/dist/services/monitoring/index.js +54 -0
- package/dist/services/monitoring/lib/sentry-api.js +94 -0
- package/dist/services/newsletter/ensure/custom-fields.js +90 -0
- package/dist/services/newsletter/ensure/publication.js +94 -0
- package/dist/services/newsletter/ensure/segments.js +140 -0
- package/dist/services/newsletter/ensure/webhook.js +108 -0
- package/dist/services/newsletter/index.js +64 -0
- package/dist/services/newsletter/lib/beehiiv-api.js +124 -0
- package/dist/services/newsletter/lib/segment-automation.js +577 -0
- package/dist/services/payment/ensure/chargebee-account.js +30 -0
- package/dist/services/payment/ensure/chargebee-products.js +359 -0
- package/dist/services/payment/ensure/chargebee-webhook.js +113 -0
- package/dist/services/payment/ensure/paypal-account.js +36 -0
- package/dist/services/payment/ensure/paypal-products.js +374 -0
- package/dist/services/payment/ensure/paypal-webhook.js +128 -0
- package/dist/services/payment/ensure/stripe-account.js +93 -0
- package/dist/services/payment/ensure/stripe-disputes.js +56 -0
- package/dist/services/payment/ensure/stripe-products.js +245 -0
- package/dist/services/payment/ensure/stripe-radar.js +74 -0
- package/dist/services/payment/ensure/stripe-webhook.js +130 -0
- package/dist/services/payment/index.js +163 -0
- package/dist/services/payment/lib/chargebee-api.js +338 -0
- package/dist/services/payment/lib/payment-utils.js +116 -0
- package/dist/services/payment/lib/paypal-api.js +354 -0
- package/dist/services/payment/lib/provider-setup.js +134 -0
- package/dist/services/payment/lib/stripe-api.js +152 -0
- package/dist/services/repo/ensure/org.js +70 -0
- package/dist/services/repo/ensure/pages.js +72 -0
- package/dist/services/repo/ensure/repo.js +90 -0
- package/dist/services/repo/index.js +52 -0
- package/dist/services/repo/lib/github-api.js +196 -0
- package/dist/services/search/ensure/ga-link.js +57 -0
- package/dist/services/search/ensure/property.js +137 -0
- package/dist/services/search/ensure/sitemaps.js +70 -0
- package/dist/services/search/index.js +61 -0
- package/dist/services/search/lib/search-console-api.js +92 -0
- package/dist/services/seo/ensure/github-repos.js +271 -0
- package/dist/services/seo/index.js +55 -0
- package/dist/services/seo/lib/gh-api.js +161 -0
- package/dist/services/seo/templates/developer-tool/.github/workflows/maintenance.yml +25 -0
- package/dist/services/seo/templates/developer-tool/.nvmrc +1 -0
- package/dist/services/seo/templates/developer-tool/_README.md.js +121 -0
- package/dist/services/seo/templates/developer-tool/_package.json.js +33 -0
- package/dist/services/seo/templates/developer-tool/src/index.js +120 -0
- package/dist/services/seo/templates/index.js +57 -0
- package/dist/services/server/ensure/brands.js +63 -0
- package/dist/services/server/index.js +42 -0
- package/dist/services/testing/ensure/target-checks.js +97 -0
- package/dist/services/testing/index.js +11 -0
- package/dist/services/testing/lib/checks.js +467 -0
- package/dist/services/update/index.js +20 -0
- package/dist/services/update/lib/cache.js +59 -0
- package/dist/services/update/lib/fingerprint.js +157 -0
- package/dist/services/update/write/targets.js +206 -0
- package/dist/services/workspace/ensure/agents.js +42 -0
- package/dist/services/workspace/ensure/claude-settings.js +34 -0
- package/dist/services/workspace/ensure/config.js +54 -0
- package/dist/services/workspace/ensure/defaults.js +60 -0
- package/dist/services/workspace/ensure/env-keys.js +55 -0
- package/dist/services/workspace/ensure/env-order.js +66 -0
- package/dist/services/workspace/ensure/env-rules.js +97 -0
- package/dist/services/workspace/ensure/gitignore.js +18 -0
- package/dist/services/workspace/ensure/scripts.js +126 -0
- package/dist/services/workspace/ensure/structure.js +97 -0
- package/dist/services/workspace/ensure/translation-sdk.js +148 -0
- package/dist/services/workspace/ensure/workflows.js +54 -0
- package/dist/services/workspace/index.js +8 -0
- package/dist/vendor/account/engine.js +182 -0
- package/dist/vendor/account/features.js +220 -0
- package/dist/vendor/account/index.js +53 -0
- package/dist/vendor/account/schema.js +272 -0
- package/dist/vendor/account/subscription.js +38 -0
- package/dist/vendor/config/company.js +31 -0
- package/dist/vendor/config/defaults.js +173 -0
- package/dist/vendor/config/demo.js +18 -0
- package/dist/vendor/config/desktop-artifacts.js +110 -0
- package/dist/vendor/config/edit.js +769 -0
- package/dist/vendor/config/env-delivery.js +145 -0
- package/dist/vendor/config/env-rules.js +93 -0
- package/dist/vendor/config/env-schema.js +1078 -0
- package/dist/vendor/config/env.js +445 -0
- package/dist/vendor/config/hooks.js +97 -0
- package/dist/vendor/config/index.js +237 -0
- package/dist/vendor/config/instances.js +208 -0
- package/dist/vendor/config/load.js +490 -0
- package/dist/vendor/config/merge.js +68 -0
- package/dist/vendor/config/order.js +139 -0
- package/dist/vendor/config/ports.js +374 -0
- package/dist/vendor/config/providers.js +32 -0
- package/dist/vendor/config/repo.js +142 -0
- package/dist/vendor/config/retired-keys.js +430 -0
- package/dist/vendor/config/schema.js +1610 -0
- package/dist/vendor/config/secrets.js +50 -0
- package/dist/vendor/config/seed.js +34 -0
- package/dist/vendor/config/site-global.js +205 -0
- package/dist/vendor/config/validate.js +554 -0
- package/dist/vendor/config/winback.js +61 -0
- package/dist/vendor/devkit/attach-log-file.js +262 -0
- package/dist/vendor/devkit/certs.js +199 -0
- package/dist/vendor/devkit/ci-workflows.js +520 -0
- package/dist/vendor/devkit/cli-router.js +156 -0
- package/dist/vendor/devkit/command-path.js +46 -0
- package/dist/vendor/devkit/deploy-record.js +180 -0
- package/dist/vendor/devkit/flows.js +317 -0
- package/dist/vendor/devkit/local-https.js +360 -0
- package/dist/vendor/devkit/local.js +1905 -0
- package/dist/vendor/devkit/logger.js +128 -0
- package/dist/vendor/devkit/omega-bin.js +345 -0
- package/dist/vendor/devkit/prompt.js +187 -0
- package/dist/vendor/devkit/safe-install.js +18 -0
- package/dist/vendor/devkit/stop-signals.js +28 -0
- package/dist/vendor/devkit/test/scope.js +162 -0
- package/dist/vendor/devkit/translate/cache.js +84 -0
- package/dist/vendor/devkit/translate/engine.js +243 -0
- package/dist/vendor/devkit/translate/index.js +49 -0
- package/dist/vendor/devkit/translate/languages.js +134 -0
- package/dist/vendor/devkit/translate/providers.js +188 -0
- package/dist/vendor/devkit/update.js +569 -0
- package/docs/AGENTS.md +200 -0
- package/docs/account.md +45 -0
- package/docs/advertising.md +46 -0
- package/docs/ai.md +34 -0
- package/docs/analytics.md +69 -0
- package/docs/assets.md +57 -0
- package/docs/bookmark.md +26 -0
- package/docs/brand.md +151 -0
- package/docs/campaigns.md +96 -0
- package/docs/captcha.md +46 -0
- package/docs/certificates.md +68 -0
- package/docs/chat.md +47 -0
- package/docs/cloud.md +110 -0
- package/docs/company.md +64 -0
- package/docs/directory.md +140 -0
- package/docs/disperse.md +46 -0
- package/docs/domain.md +56 -0
- package/docs/edge.md +234 -0
- package/docs/email.md +42 -0
- package/docs/forms.md +48 -0
- package/docs/index.md +109 -0
- package/docs/migration.md +203 -0
- package/docs/migrations.md +56 -0
- package/docs/monitoring.md +41 -0
- package/docs/newsletter.md +48 -0
- package/docs/payment.md +83 -0
- package/docs/repo.md +48 -0
- package/docs/search.md +44 -0
- package/docs/seo.md +34 -0
- package/docs/server.md +37 -0
- package/docs/shared/agent-docs.md +89 -0
- package/docs/shared/analytics.md +612 -0
- package/docs/shared/brands.md +51 -0
- package/docs/shared/breaking-changes.md +497 -0
- package/docs/shared/config.md +1387 -0
- package/docs/shared/deploys.md +215 -0
- package/docs/shared/icons.md +201 -0
- package/docs/shared/local-dev.md +147 -0
- package/docs/shared/logging.md +202 -0
- package/docs/shared/monitoring.md +153 -0
- package/docs/shared/publishing.md +183 -0
- package/docs/shared/rulings.md +34 -0
- package/docs/shared/testing.md +147 -0
- package/docs/shared/theming.md +604 -0
- package/docs/shared/translation.md +291 -0
- package/docs/shared/updates.md +61 -0
- package/docs/testing.md +34 -0
- package/docs/update.md +36 -0
- package/docs/workspace.md +64 -0
- package/package.json +88 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure Chargebee items and item prices exist for all paid products.
|
|
3
|
+
*
|
|
4
|
+
* Uses the Items model (Item Family → Item → Item Price) with fully
|
|
5
|
+
* deterministic IDs — family = {brandId}, item = {brandId}-{productId},
|
|
6
|
+
* price = {brandId}-{productId}-{interval} — so resolution needs no stored
|
|
7
|
+
* state at all: a 404 on the deterministic ID means "create it". Items are
|
|
8
|
+
* diffed on name/external_name/description/redirect_url/metadata; prices on
|
|
9
|
+
* amount (updated in place — Chargebee allows it) plus trial/external_name.
|
|
10
|
+
* Legacy plans (product.chargebee.legacyPlanIds, the pre-Items model) are
|
|
11
|
+
* reported read-only. One-time 'once' prices aren't managed yet (visible
|
|
12
|
+
* note; omega-manager skipped them silently).
|
|
13
|
+
*/
|
|
14
|
+
const chalk = require('chalk').default;
|
|
15
|
+
const { paidProducts, productDisplayName } = require('../lib/payment-utils.js');
|
|
16
|
+
|
|
17
|
+
// Map config interval names to Chargebee period units
|
|
18
|
+
// (Chargebee does not support daily billing cycles)
|
|
19
|
+
const INTERVAL_MAP = {
|
|
20
|
+
annually: { period_unit: 'year', period: 1 },
|
|
21
|
+
monthly: { period_unit: 'month', period: 1 },
|
|
22
|
+
weekly: { period_unit: 'week', period: 1 },
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Map product types to Chargebee item types
|
|
26
|
+
const TYPE_MAP = {
|
|
27
|
+
subscription: 'plan',
|
|
28
|
+
'one-time': 'charge',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether an API error means "resource doesn't exist"
|
|
33
|
+
*/
|
|
34
|
+
function isNotFound(error) {
|
|
35
|
+
return error.message.includes('404')
|
|
36
|
+
|| error.message.includes('not_found')
|
|
37
|
+
|| error.message.includes('resource_not_found');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Build desired item details from brand/product config
|
|
42
|
+
*/
|
|
43
|
+
function buildItemDetails(brandConfig, brandId, product) {
|
|
44
|
+
return {
|
|
45
|
+
name: productDisplayName(brandConfig, product),
|
|
46
|
+
externalName: product.name,
|
|
47
|
+
description: product.description || brandConfig.brand.description || '',
|
|
48
|
+
redirectUrl: brandConfig.brand.url,
|
|
49
|
+
metadata: { brandId, productId: product.id },
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Diff a Chargebee item against desired and return the update payload
|
|
55
|
+
*/
|
|
56
|
+
function getItemUpdates(chargebeeItem, desired) {
|
|
57
|
+
const updates = {};
|
|
58
|
+
|
|
59
|
+
if (chargebeeItem.name !== desired.name) {
|
|
60
|
+
updates.name = desired.name;
|
|
61
|
+
}
|
|
62
|
+
if ((chargebeeItem.external_name || '') !== desired.externalName) {
|
|
63
|
+
updates.external_name = desired.externalName;
|
|
64
|
+
}
|
|
65
|
+
if ((chargebeeItem.description || '') !== desired.description) {
|
|
66
|
+
updates.description = desired.description;
|
|
67
|
+
}
|
|
68
|
+
if ((chargebeeItem.redirect_url || '') !== desired.redirectUrl) {
|
|
69
|
+
updates.redirect_url = desired.redirectUrl;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const existingMeta = parseMetadata(chargebeeItem.metadata);
|
|
73
|
+
if (existingMeta.brandId !== desired.metadata.brandId || existingMeta.productId !== desired.metadata.productId) {
|
|
74
|
+
updates.metadata = JSON.stringify(desired.metadata);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return Object.keys(updates).length > 0 ? updates : null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Parse Chargebee metadata (may be a JSON string or object)
|
|
82
|
+
*/
|
|
83
|
+
function parseMetadata(metadata) {
|
|
84
|
+
if (!metadata) {
|
|
85
|
+
return {};
|
|
86
|
+
}
|
|
87
|
+
if (typeof metadata === 'string') {
|
|
88
|
+
try {
|
|
89
|
+
return JSON.parse(metadata);
|
|
90
|
+
} catch {
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return metadata;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Ensure the Item Family for this brand exists (family ID = brandId)
|
|
99
|
+
*/
|
|
100
|
+
async function ensureItemFamily(api, familyId, brandConfig, dryRun) {
|
|
101
|
+
let family;
|
|
102
|
+
try {
|
|
103
|
+
family = await api.getItemFamily(familyId);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (!isNotFound(error)) {
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (dryRun) {
|
|
110
|
+
console.log(` ${chalk.cyan('+')} Would create Item Family: ${chalk.dim(familyId)} "${brandConfig.brand.name}" ${chalk.yellow('[DRY RUN]')}`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
family = await api.createItemFamily({
|
|
115
|
+
id: familyId,
|
|
116
|
+
name: brandConfig.brand.name,
|
|
117
|
+
description: brandConfig.brand.description || '',
|
|
118
|
+
});
|
|
119
|
+
console.log(` ${chalk.green('✓')} Created Item Family: ${chalk.cyan(family.id)}`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log(` ${chalk.green('✓')} Item Family: ${chalk.dim(family.id)}`);
|
|
124
|
+
|
|
125
|
+
if (family.name !== brandConfig.brand.name) {
|
|
126
|
+
if (dryRun) {
|
|
127
|
+
console.log(` ${chalk.cyan('~')} Would update family name: "${family.name}" → "${brandConfig.brand.name}" ${chalk.yellow('[DRY RUN]')}`);
|
|
128
|
+
} else {
|
|
129
|
+
await api.updateItemFamily(familyId, { name: brandConfig.brand.name });
|
|
130
|
+
console.log(` ${chalk.green('✓')} Updated family name: ${brandConfig.brand.name}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Ensure item prices on a Chargebee item match config amounts.
|
|
137
|
+
* Deterministic price IDs: {brandId}-{productId}-{interval}
|
|
138
|
+
*/
|
|
139
|
+
async function ensureItemPrices(api, itemId, product, brandConfig, brandId, dryRun) {
|
|
140
|
+
const existingPrices = await api.listItemPricesForItem(itemId);
|
|
141
|
+
const trialDays = product.trial?.days || 0;
|
|
142
|
+
|
|
143
|
+
for (const interval of Object.keys(product.prices)) {
|
|
144
|
+
const expectedAmount = product.prices[interval];
|
|
145
|
+
|
|
146
|
+
if (!expectedAmount) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const mapping = INTERVAL_MAP[interval];
|
|
151
|
+
|
|
152
|
+
// One-time 'once' prices aren't managed yet (charge-type items exist
|
|
153
|
+
// without prices; checkout uses ad-hoc charges)
|
|
154
|
+
if (!mapping && interval === 'once') {
|
|
155
|
+
console.log(` ${chalk.dim('⊘ once: one-time charge prices not managed yet')}`);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!mapping) {
|
|
160
|
+
throw new Error(`Chargebee does not support "${interval}" billing cycle. Use weekly, monthly, or annually instead.`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const expectedCents = Math.round(expectedAmount * 100);
|
|
164
|
+
const priceId = `${brandId}-${product.id}-${interval}`;
|
|
165
|
+
const priceName = `${productDisplayName(brandConfig, product)} (${interval.charAt(0).toUpperCase() + interval.slice(1)})`;
|
|
166
|
+
|
|
167
|
+
const existing = existingPrices.find((p) => p.id === priceId);
|
|
168
|
+
|
|
169
|
+
if (existing) {
|
|
170
|
+
if (existing.price === expectedCents) {
|
|
171
|
+
const statusIcon = existing.status === 'active' ? chalk.green('✓') : chalk.yellow('⚠');
|
|
172
|
+
console.log(` ${statusIcon} ${interval}: $${expectedAmount} ${chalk.dim(priceId)}`);
|
|
173
|
+
|
|
174
|
+
// Minor fields (trial, external_name) may still need updating
|
|
175
|
+
const priceUpdates = {};
|
|
176
|
+
|
|
177
|
+
if (trialDays > 0 && existing.trial_period !== trialDays) {
|
|
178
|
+
priceUpdates.trial_period = trialDays;
|
|
179
|
+
priceUpdates.trial_period_unit = 'day';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if ((existing.external_name || '') !== priceName) {
|
|
183
|
+
priceUpdates.external_name = priceName;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (Object.keys(priceUpdates).length > 0) {
|
|
187
|
+
const fields = Object.keys(priceUpdates).join(', ');
|
|
188
|
+
if (dryRun) {
|
|
189
|
+
console.log(` ${chalk.cyan('~')} Would update: ${fields} ${chalk.yellow('[DRY RUN]')}`);
|
|
190
|
+
} else {
|
|
191
|
+
await api.updateItemPrice(priceId, priceUpdates);
|
|
192
|
+
console.log(` ${chalk.green('✓')} Updated: ${fields}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Price amount changed — update in place
|
|
200
|
+
if (dryRun) {
|
|
201
|
+
console.log(` ${chalk.cyan('~')} ${interval}: would update $${existing.price / 100} → $${expectedAmount} ${chalk.dim(priceId)} ${chalk.yellow('[DRY RUN]')}`);
|
|
202
|
+
} else {
|
|
203
|
+
await api.updateItemPrice(priceId, { price: expectedCents });
|
|
204
|
+
console.log(` ${chalk.green('✓')} ${interval}: updated $${existing.price / 100} → $${expectedAmount} ${chalk.dim(priceId)}`);
|
|
205
|
+
}
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Item price doesn't exist — create it
|
|
210
|
+
if (dryRun) {
|
|
211
|
+
const trialLabel = trialDays > 0 ? ` (${trialDays}d trial)` : '';
|
|
212
|
+
console.log(` ${chalk.cyan('+')} ${interval}: would create $${expectedAmount}${trialLabel} "${priceName}" ${chalk.yellow('[DRY RUN]')}`);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const createParams = {
|
|
217
|
+
id: priceId,
|
|
218
|
+
itemId,
|
|
219
|
+
name: priceName,
|
|
220
|
+
externalName: priceName,
|
|
221
|
+
pricingModel: 'flat_fee',
|
|
222
|
+
price: expectedCents,
|
|
223
|
+
currencyCode: 'USD',
|
|
224
|
+
periodUnit: mapping.period_unit,
|
|
225
|
+
period: mapping.period,
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
if (trialDays > 0) {
|
|
229
|
+
createParams.trialPeriod = trialDays;
|
|
230
|
+
createParams.trialPeriodUnit = 'day';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const newPrice = await api.createItemPrice(createParams);
|
|
234
|
+
console.log(` ${chalk.green('✓')} ${interval}: created $${expectedAmount} ${chalk.cyan(newPrice.id)}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Report legacy Chargebee plans (the pre-Items model) read-only — the
|
|
240
|
+
* backend needs to know they still resolve; nothing modifies them.
|
|
241
|
+
*/
|
|
242
|
+
async function logLegacyPlans(api, products) {
|
|
243
|
+
const legacyIds = new Map(); // planId → productId
|
|
244
|
+
for (const product of products) {
|
|
245
|
+
for (const id of product.chargebee?.legacyPlanIds || []) {
|
|
246
|
+
legacyIds.set(id, product.id);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (legacyIds.size === 0) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
console.log(` ${chalk.dim('Legacy Chargebee plans:')}`);
|
|
255
|
+
|
|
256
|
+
for (const [legacyPlanId, productId] of legacyIds) {
|
|
257
|
+
try {
|
|
258
|
+
const plan = await api.getPlan(legacyPlanId);
|
|
259
|
+
const statusColor = plan.status === 'active' ? chalk.green : chalk.yellow;
|
|
260
|
+
const price = plan.price ? `$${plan.price / 100}` : 'N/A';
|
|
261
|
+
const period = plan.period_unit ? `/${plan.period}${plan.period_unit}` : '';
|
|
262
|
+
|
|
263
|
+
console.log(` ${chalk.green('✓')} ${chalk.dim(legacyPlanId)} → ${productId}: ${statusColor(plan.status)} ${price}${period} "${plan.name || ''}"`);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
if (isNotFound(error)) {
|
|
266
|
+
console.log(` ${chalk.yellow('⚠')} ${chalk.dim(legacyPlanId)} → ${productId}: ${chalk.red('not found')}`);
|
|
267
|
+
} else {
|
|
268
|
+
console.log(` ${chalk.yellow('⚠')} ${chalk.dim(legacyPlanId)} → ${productId}: ${chalk.dim(error.message)}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
module.exports = async function ensureChargebeeProducts(context) {
|
|
275
|
+
const { brandConfig, brandId, chargebeeApi: api, options } = context;
|
|
276
|
+
const dryRun = options?.dryRun || false;
|
|
277
|
+
|
|
278
|
+
if (!api) {
|
|
279
|
+
console.log(` ${chalk.dim('⊘ Chargebee not configured')}`);
|
|
280
|
+
return {};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (dryRun) {
|
|
284
|
+
console.log(` ${chalk.yellow('[DRY RUN]')} No changes will be made`);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const products = paidProducts(brandConfig);
|
|
288
|
+
|
|
289
|
+
// --- Step 1: Ensure the brand's Item Family exists ---
|
|
290
|
+
const familyId = brandId;
|
|
291
|
+
await ensureItemFamily(api, familyId, brandConfig, dryRun);
|
|
292
|
+
|
|
293
|
+
// --- Step 2: Ensure Items + Item Prices ---
|
|
294
|
+
for (const product of products) {
|
|
295
|
+
console.log(` ${chalk.bold(product.name)} (${product.id}):`);
|
|
296
|
+
|
|
297
|
+
const desired = buildItemDetails(brandConfig, brandId, product);
|
|
298
|
+
const itemId = `${brandId}-${product.id}`;
|
|
299
|
+
const itemType = TYPE_MAP[product.type] || 'plan';
|
|
300
|
+
|
|
301
|
+
let chargebeeItem;
|
|
302
|
+
try {
|
|
303
|
+
chargebeeItem = await api.getItem(itemId);
|
|
304
|
+
} catch (error) {
|
|
305
|
+
if (!isNotFound(error)) {
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Item doesn't exist — create it
|
|
310
|
+
if (dryRun) {
|
|
311
|
+
console.log(` ${chalk.cyan('+')} Would create item: ${chalk.dim(desired.name)} (${itemType}) ${chalk.yellow('[DRY RUN]')}`);
|
|
312
|
+
for (const [interval, amount] of Object.entries(product.prices)) {
|
|
313
|
+
if (!amount) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const trialDays = product.trial?.days || 0;
|
|
317
|
+
const trialLabel = trialDays > 0 ? ` (${trialDays}d trial)` : '';
|
|
318
|
+
console.log(` ${chalk.cyan('+')} ${interval}: $${amount}${trialLabel} ${chalk.dim(`${itemId}-${interval}`)} ${chalk.yellow('[DRY RUN]')}`);
|
|
319
|
+
}
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
chargebeeItem = await api.createItem({
|
|
324
|
+
id: itemId,
|
|
325
|
+
name: desired.name,
|
|
326
|
+
externalName: desired.externalName,
|
|
327
|
+
type: itemType,
|
|
328
|
+
itemFamilyId: familyId,
|
|
329
|
+
description: desired.description,
|
|
330
|
+
redirectUrl: desired.redirectUrl,
|
|
331
|
+
metadata: desired.metadata,
|
|
332
|
+
});
|
|
333
|
+
console.log(` ${chalk.green('✓')} Created item: ${chalk.cyan(chargebeeItem.id)}`);
|
|
334
|
+
|
|
335
|
+
await ensureItemPrices(api, itemId, product, brandConfig, brandId, dryRun);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
console.log(` ${chalk.green('✓')} Item exists: ${chalk.dim(chargebeeItem.id)}`);
|
|
340
|
+
|
|
341
|
+
const updates = getItemUpdates(chargebeeItem, desired);
|
|
342
|
+
if (updates) {
|
|
343
|
+
const fields = Object.keys(updates).join(', ');
|
|
344
|
+
if (dryRun) {
|
|
345
|
+
console.log(` ${chalk.cyan('~')} Would update: ${chalk.dim(fields)} ${chalk.yellow('[DRY RUN]')}`);
|
|
346
|
+
} else {
|
|
347
|
+
await api.updateItem(itemId, updates);
|
|
348
|
+
console.log(` ${chalk.green('✓')} Updated: ${chalk.dim(fields)}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
await ensureItemPrices(api, itemId, product, brandConfig, brandId, dryRun);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// --- Step 3: Report legacy plans ---
|
|
356
|
+
await logLegacyPlans(api, products);
|
|
357
|
+
|
|
358
|
+
return { output: { chargebeeSync: { productsProcessed: products.length } } };
|
|
359
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure a Chargebee webhook endpoint exists for this brand's backend.
|
|
3
|
+
*
|
|
4
|
+
* Matches by exact URL (which carries &brand={brandId} — Chargebee sites
|
|
5
|
+
* can serve multiple brands), deletes every OTHER endpoint on the brand's API
|
|
6
|
+
* host (stale twins — one endpoint per host, and endpoints on other hosts are
|
|
7
|
+
* never touched), re-enables disabled endpoints, creates when missing.
|
|
8
|
+
* Chargebee's API doesn't return enabled_events, so event drift can't be
|
|
9
|
+
* diffed — events are set on create only (delete + recreate to change them).
|
|
10
|
+
* Skipped for shared Firebase projects. Requires OMEGA_WEBHOOK_KEY.
|
|
11
|
+
*/
|
|
12
|
+
const chalk = require('chalk').default;
|
|
13
|
+
const { buildWebhookUrl, redactWebhookUrl, staleWebhookEndpoints } = require('../lib/payment-utils.js');
|
|
14
|
+
|
|
15
|
+
// Events the backend handles for Chargebee subscription/payment processing
|
|
16
|
+
const ENABLED_EVENTS = [
|
|
17
|
+
// Subscriptions
|
|
18
|
+
'subscription_created',
|
|
19
|
+
'subscription_started',
|
|
20
|
+
'subscription_activated',
|
|
21
|
+
'subscription_changed',
|
|
22
|
+
'subscription_cancelled',
|
|
23
|
+
'subscription_paused',
|
|
24
|
+
'subscription_resumed',
|
|
25
|
+
'subscription_renewed',
|
|
26
|
+
'subscription_reactivated',
|
|
27
|
+
'subscription_trial_end_reminder',
|
|
28
|
+
|
|
29
|
+
// Payments
|
|
30
|
+
'payment_succeeded',
|
|
31
|
+
'payment_failed',
|
|
32
|
+
'payment_refunded',
|
|
33
|
+
|
|
34
|
+
// Invoices
|
|
35
|
+
'invoice_generated',
|
|
36
|
+
'invoice_updated',
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
module.exports = async function ensureChargebeeWebhook(context) {
|
|
40
|
+
const { brandConfig, brandId, chargebeeApi: api, options } = context;
|
|
41
|
+
const dryRun = options?.dryRun || false;
|
|
42
|
+
|
|
43
|
+
if (!api) {
|
|
44
|
+
console.log(` ${chalk.dim('⊘ Chargebee not configured')}`);
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Shared Firebase project — no backend deploys from this brand, so api.{domain} doesn't exist
|
|
49
|
+
if (brandConfig.cloud?.shared === true) {
|
|
50
|
+
console.log(` ${chalk.dim('⊘ Shared Firebase project — no brand API for webhooks')}`);
|
|
51
|
+
return {};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!process.env.OMEGA_WEBHOOK_KEY) {
|
|
55
|
+
// Unreachable by design (#635): the key is OMEGA's own (`generated:` in
|
|
56
|
+
// the env schema) and the payment service's setup mints it through the
|
|
57
|
+
// shared contract before any operation runs. Absent here = broken wiring.
|
|
58
|
+
throw new Error('OMEGA_WEBHOOK_KEY absent after the payment setup ran — its REQUIRES entry or its requestServiceInput call is missing');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const desiredUrl = buildWebhookUrl(brandConfig, 'chargebee', brandId);
|
|
62
|
+
|
|
63
|
+
const webhooks = await api.listWebhooks();
|
|
64
|
+
|
|
65
|
+
// Exactly ONE endpoint on the brand's API host: the desired URL. Legacy twins
|
|
66
|
+
// there receive every event and answer 400 forever (#570).
|
|
67
|
+
for (const stale of staleWebhookEndpoints(webhooks, desiredUrl)) {
|
|
68
|
+
if (dryRun) {
|
|
69
|
+
console.log(` ${chalk.cyan('-')} Would delete stale webhook ${chalk.dim(redactWebhookUrl(stale.url))} ${chalk.yellow('[DRY RUN]')}`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
await api.deleteWebhook(stale.id);
|
|
74
|
+
console.log(` ${chalk.yellow('⚠')} Deleted stale webhook ${chalk.dim(`(${stale.id})`)} ${redactWebhookUrl(stale.url)}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const existing = webhooks.find((wh) => wh.url === desiredUrl);
|
|
78
|
+
|
|
79
|
+
if (existing) {
|
|
80
|
+
if (existing.disabled === true) {
|
|
81
|
+
if (dryRun) {
|
|
82
|
+
console.log(` ${chalk.cyan('~')} Would re-enable disabled webhook ${chalk.yellow('[DRY RUN]')}`);
|
|
83
|
+
return { output: { chargebeeWebhook: { id: existing.id, planned: 'enable' } } };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(` ${chalk.yellow('⚠')} Webhook is disabled — re-enabling...`);
|
|
87
|
+
await api.updateWebhook(existing.id, { status: 'active' });
|
|
88
|
+
console.log(` ${chalk.green('✓')} Webhook re-enabled ${chalk.dim(`(${existing.id})`)}`);
|
|
89
|
+
} else {
|
|
90
|
+
console.log(` ${chalk.green('✓')} Webhook active ${chalk.dim(`(${existing.id})`)}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log(` ${chalk.dim(redactWebhookUrl(desiredUrl))}`);
|
|
94
|
+
|
|
95
|
+
// Chargebee doesn't return enabled_events, so event drift can't be
|
|
96
|
+
// checked here — events are set on create only.
|
|
97
|
+
return { output: { chargebeeWebhook: { id: existing.id } } };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (dryRun) {
|
|
101
|
+
console.log(` ${chalk.cyan('+')} Would create webhook ${chalk.yellow('[DRY RUN]')}`);
|
|
102
|
+
console.log(` ${chalk.dim(redactWebhookUrl(desiredUrl))}`);
|
|
103
|
+
console.log(` ${chalk.dim(`Events: ${ENABLED_EVENTS.length} event types`)}`);
|
|
104
|
+
return { output: { chargebeeWebhook: { planned: 'create' } } };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const webhookName = `${brandConfig.brand.name} Backend`;
|
|
108
|
+
const webhook = await api.createWebhook({ url: desiredUrl, name: webhookName, eventTypes: ENABLED_EVENTS });
|
|
109
|
+
console.log(` ${chalk.green('✓')} Webhook created: ${chalk.dim(webhook.id)}`);
|
|
110
|
+
console.log(` ${chalk.dim(redactWebhookUrl(desiredUrl))}`);
|
|
111
|
+
|
|
112
|
+
return { output: { chargebeeWebhook: { id: webhook.id, created: true } } };
|
|
113
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Report PayPal app/account info.
|
|
3
|
+
*
|
|
4
|
+
* PayPal doesn't expose a "get my account settings" API via client
|
|
5
|
+
* credentials, but the OAuth2 token response includes the app ID and the
|
|
6
|
+
* auth probe resolves the environment (live vs sandbox). Proving the
|
|
7
|
+
* credentials here also means later paypal operations fail loudly instead
|
|
8
|
+
* of mysteriously. Pure read — dry-run is identical by construction.
|
|
9
|
+
*/
|
|
10
|
+
const chalk = require('chalk').default;
|
|
11
|
+
|
|
12
|
+
module.exports = async function ensurePayPalAccount(context) {
|
|
13
|
+
const { paypalApi: api } = context;
|
|
14
|
+
|
|
15
|
+
if (!api) {
|
|
16
|
+
console.log(` ${chalk.dim('⊘ PayPal not configured')}`);
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
// Ensure we've authenticated (triggers live/sandbox detection)
|
|
22
|
+
await api.getAccessToken();
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.log(` ${chalk.yellow('⚠')} Could not authenticate with PayPal${chalk.dim(`: ${error.message}`)}`);
|
|
25
|
+
return { status: 'warned', reason: 'could not authenticate with PayPal', output: { paypalAccount: { authenticated: false, error: error.message } } };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const info = api.getAccountInfo();
|
|
29
|
+
const envColor = info.environment === 'live' ? chalk.green : chalk.yellow;
|
|
30
|
+
|
|
31
|
+
console.log(` environment: ${envColor(info.environment)}`);
|
|
32
|
+
console.log(` app ID: ${chalk.cyan(info.appId || '(unknown)')}`);
|
|
33
|
+
console.log(` client ID: ${chalk.dim(info.clientId.slice(0, 12) + '...')}`);
|
|
34
|
+
|
|
35
|
+
return { output: { paypalAccount: { authenticated: true, environment: info.environment, appId: info.appId } } };
|
|
36
|
+
};
|