@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,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain service — points the registrar at Cloudflare. Runs after cloudflare
|
|
3
|
+
* (the zone must exist so its assigned nameservers are known). API-capable
|
|
4
|
+
* registrars (namecheap) are reconciled automatically; manual registrars get
|
|
5
|
+
* printed instructions, and only while the zone is still pending — an active
|
|
6
|
+
* zone proves the nameservers are already set.
|
|
7
|
+
*
|
|
8
|
+
* The email half of `domain` config (email.providers, email.forwarding) is
|
|
9
|
+
* consumed by the cloudflare service (dns-records MX/SPF + email-routing);
|
|
10
|
+
* this service owns only the registrar side.
|
|
11
|
+
*
|
|
12
|
+
* Auth: NAMECHEAP_USERNAME + NAMECHEAP_API_KEY in the brand .env (namecheap
|
|
13
|
+
* only), plus CLOUDFLARE_TOKEN to read the zone's assigned nameservers.
|
|
14
|
+
* Missing credentials → the service skips with guidance.
|
|
15
|
+
*/
|
|
16
|
+
const chalk = require('chalk').default;
|
|
17
|
+
const { serviceInputSpec } = require('../../config.js');
|
|
18
|
+
const { createServiceRunner } = require('../../lib/service-runner.js');
|
|
19
|
+
const { requestServiceInput } = require('../../lib/service-input.js');
|
|
20
|
+
const { CloudflareAPI } = require('../edge/lib/cloudflare-api.js');
|
|
21
|
+
const { getApexDomain } = require('../../lib/domain-utils.js');
|
|
22
|
+
const { NamecheapAPI } = require('./lib/namecheap-api.js');
|
|
23
|
+
const { API_PROVIDERS, resolveRegistrar } = require('./lib/registrars.js');
|
|
24
|
+
|
|
25
|
+
module.exports.run = createServiceRunner({
|
|
26
|
+
serviceDir: __dirname,
|
|
27
|
+
setup: async (context) => {
|
|
28
|
+
const domainConfig = context.brandConfig.domain || {};
|
|
29
|
+
|
|
30
|
+
if (domainConfig.enabled === false) {
|
|
31
|
+
return { skip: true, reason: 'domain.enabled = false' };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const provider = resolveRegistrar(context.brandConfig);
|
|
35
|
+
if (!provider) {
|
|
36
|
+
return { skip: true, reason: 'no domain.providers.<registrar> configured' };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const url = (context.brandConfig.brand?.url || '').replace(/^https?:\/\//, '');
|
|
40
|
+
if (!url) {
|
|
41
|
+
return { skip: true, reason: 'no brand.url configured' };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// The zone lookup needs Cloudflare even for manual registrars — the
|
|
45
|
+
// required nameserver values come from the zone
|
|
46
|
+
// The input descriptors live in the REQUIRES registry (one home): the
|
|
47
|
+
// Cloudflare token is unconditional, the namecheap credentials are
|
|
48
|
+
// registrar-specific (their entry-level `when` drops them for the rest)
|
|
49
|
+
if (!context.cloudflareApi) {
|
|
50
|
+
const gate = await requestServiceInput(context, serviceInputSpec('domain', { names: ['CLOUDFLARE_TOKEN'] }));
|
|
51
|
+
if (gate) return gate;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (provider === 'namecheap' && !context.namecheapApi) {
|
|
55
|
+
const gate = await requestServiceInput(context, serviceInputSpec('domain', { names: ['NAMECHEAP_USERNAME', 'NAMECHEAP_API_KEY'] }));
|
|
56
|
+
if (gate) return gate;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(` Provider: ${chalk.cyan(provider)}${API_PROVIDERS.has(provider) ? '' : chalk.dim(' (manual)')}`);
|
|
60
|
+
|
|
61
|
+
// Tests inject fake clients via context.cloudflareApi / context.namecheapApi
|
|
62
|
+
return {
|
|
63
|
+
cloudflareApi: context.cloudflareApi || new CloudflareAPI(),
|
|
64
|
+
namecheapApi: provider === 'namecheap' ? (context.namecheapApi || new NamecheapAPI()) : null,
|
|
65
|
+
domain: getApexDomain(url), // nameservers live on the apex's registrar entry
|
|
66
|
+
provider,
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Namecheap API client — XML query API (there is no JSON variant), ported from
|
|
3
|
+
* omega-manager. Requires the caller's IP to be whitelisted in the Namecheap
|
|
4
|
+
* dashboard; the client detects its public IP via api.ipify.org.
|
|
5
|
+
*
|
|
6
|
+
* Docs: https://www.namecheap.com/support/api/methods/
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const API_BASE = 'https://api.namecheap.com/xml.response';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The Namecheap API access page — enabling the API, resetting the key and the
|
|
13
|
+
* IP whitelist all live on this ONE page, which is why every rejection in that
|
|
14
|
+
* family opens the root and never a deep link (#698, Ian 2026-08-30).
|
|
15
|
+
*/
|
|
16
|
+
const API_ACCESS_URL = 'https://ap.www.namecheap.com/settings/tools/apiaccess/';
|
|
17
|
+
|
|
18
|
+
// Namecheap refuses a caller whose IP is not whitelisted with the API-access
|
|
19
|
+
// error family — the same numbers a disabled API or a stale key answer with,
|
|
20
|
+
// and all three are fixed on the page above.
|
|
21
|
+
const API_ACCESS_ERROR_CODES = new Set(['1011102', '1011150']);
|
|
22
|
+
const API_ACCESS_ERROR_TEXT = /whitelist|api access has not been enabled|invalid request ip/i;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Whether a thrown API error is the IP-whitelist rejection — the walkthrough's
|
|
26
|
+
* trigger. Reads the error Number the client parses off the <Error> element,
|
|
27
|
+
* with the message as the second signal.
|
|
28
|
+
*
|
|
29
|
+
* @param {Error} error - An error thrown by makeRequest
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
function isWhitelistError(error) {
|
|
33
|
+
return API_ACCESS_ERROR_CODES.has(error?.namecheapCode)
|
|
34
|
+
|| API_ACCESS_ERROR_TEXT.test(error?.message || '');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class NamecheapAPI {
|
|
38
|
+
constructor(options = {}) {
|
|
39
|
+
this.username = options.username || process.env.NAMECHEAP_USERNAME;
|
|
40
|
+
this.apiKey = options.apiKey || process.env.NAMECHEAP_API_KEY;
|
|
41
|
+
|
|
42
|
+
if (!this.username || !this.apiKey) {
|
|
43
|
+
throw new Error('Namecheap API not configured. Set NAMECHEAP_USERNAME and NAMECHEAP_API_KEY in the brand .env');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async getClientIp() {
|
|
48
|
+
if (this._clientIp) {
|
|
49
|
+
return this._clientIp;
|
|
50
|
+
}
|
|
51
|
+
const response = await fetch('https://api.ipify.org?format=json');
|
|
52
|
+
const data = await response.json();
|
|
53
|
+
this._clientIp = data.ip;
|
|
54
|
+
return this._clientIp;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async makeRequest(command, params = {}) {
|
|
58
|
+
const clientIp = await this.getClientIp();
|
|
59
|
+
|
|
60
|
+
const queryParams = new URLSearchParams({
|
|
61
|
+
ApiUser: this.username,
|
|
62
|
+
ApiKey: this.apiKey,
|
|
63
|
+
UserName: this.username,
|
|
64
|
+
ClientIp: clientIp,
|
|
65
|
+
Command: command,
|
|
66
|
+
...params,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const url = `${API_BASE}?${queryParams.toString()}`;
|
|
70
|
+
const response = await fetch(url);
|
|
71
|
+
const xml = await response.text();
|
|
72
|
+
|
|
73
|
+
const status = xml.match(/Status="(\w+)"/)?.[1];
|
|
74
|
+
if (status !== 'OK') {
|
|
75
|
+
// Namecheap nests the elements (<Errors><Error Number="…">msg</Error>),
|
|
76
|
+
// so the attribute group must be optional-but-space-led — otherwise the
|
|
77
|
+
// wrapper matches first and the message carries the inner tag with it.
|
|
78
|
+
const failure = xml.match(/<Error(\s[^>]*)?>(.*?)<\/Error>/);
|
|
79
|
+
const error = new Error(`Namecheap API error: ${failure?.[2] || 'Unknown error'}`);
|
|
80
|
+
// The whitelist walkthrough (#698) needs both: WHICH rejection this is,
|
|
81
|
+
// and the IP to add — the XML never echoes it, so the client that sent
|
|
82
|
+
// it is the only source.
|
|
83
|
+
error.namecheapCode = failure?.[1]?.match(/Number="(\d+)"/)?.[1] || null;
|
|
84
|
+
error.clientIp = clientIp;
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return xml;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* List all domains in the account
|
|
93
|
+
* @returns {Array<{domain: string, sld: string, tld: string, expires: string}>}
|
|
94
|
+
*/
|
|
95
|
+
async listDomains() {
|
|
96
|
+
const xml = await this.makeRequest('namecheap.domains.getList', {
|
|
97
|
+
PageSize: 100,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const domains = [];
|
|
101
|
+
const domainRegex = /<Domain\s+([^>]+)\/>/g;
|
|
102
|
+
let match;
|
|
103
|
+
|
|
104
|
+
while ((match = domainRegex.exec(xml)) !== null) {
|
|
105
|
+
const attrs = match[1];
|
|
106
|
+
const name = attrs.match(/Name="([^"]+)"/)?.[1];
|
|
107
|
+
|
|
108
|
+
if (name) {
|
|
109
|
+
const parts = name.split('.');
|
|
110
|
+
const tld = parts.pop();
|
|
111
|
+
const sld = parts.join('.');
|
|
112
|
+
|
|
113
|
+
domains.push({
|
|
114
|
+
domain: name.toLowerCase(),
|
|
115
|
+
sld,
|
|
116
|
+
tld,
|
|
117
|
+
expires: attrs.match(/Expires="([^"]+)"/)?.[1] || null,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return domains;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get current DNS settings for a domain
|
|
127
|
+
* @param {string} sld - Second level domain (e.g. 'mybrand')
|
|
128
|
+
* @param {string} tld - Top level domain (e.g. 'com', 'co.uk')
|
|
129
|
+
* @returns {Object} - { usingCustom: boolean, nameservers: string[] }
|
|
130
|
+
*/
|
|
131
|
+
async getDns(sld, tld) {
|
|
132
|
+
const xml = await this.makeRequest('namecheap.domains.dns.getList', {
|
|
133
|
+
SLD: sld,
|
|
134
|
+
TLD: tld,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const isCustom = xml.includes('IsUsingOurDNS="false"');
|
|
138
|
+
const nameservers = [];
|
|
139
|
+
const nsRegex = /<Nameserver>(.*?)<\/Nameserver>/g;
|
|
140
|
+
let match;
|
|
141
|
+
|
|
142
|
+
while ((match = nsRegex.exec(xml)) !== null) {
|
|
143
|
+
nameservers.push(match[1].toLowerCase());
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
usingCustom: isCustom,
|
|
148
|
+
nameservers,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Set custom nameservers for a domain
|
|
154
|
+
* @param {string} sld - Second level domain
|
|
155
|
+
* @param {string} tld - Top level domain
|
|
156
|
+
* @param {string[]} nameservers - Array of nameserver hostnames
|
|
157
|
+
*/
|
|
158
|
+
async setCustomNameservers(sld, tld, nameservers) {
|
|
159
|
+
await this.makeRequest('namecheap.domains.dns.setCustom', {
|
|
160
|
+
SLD: sld,
|
|
161
|
+
TLD: tld,
|
|
162
|
+
Nameservers: nameservers.join(','),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = { NamecheapAPI, API_ACCESS_URL, isWhitelistError };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain-role knowledge shared across services — which providers the domain
|
|
3
|
+
* service can drive via API (their nameservers need no human), the dashboard
|
|
4
|
+
* nameserver pages for the manual ones (the cloudflare zone flow opens them
|
|
5
|
+
* while polling for activation), and the two provider resolvers.
|
|
6
|
+
*
|
|
7
|
+
* `domain` carries TWO roles, each with its own providers block (#425): the
|
|
8
|
+
* registrar at `domain.providers.<registrar>` and the mailbox provider at
|
|
9
|
+
* `domain.email.providers.<provider>`. Presence picks one — @omega.js/config's
|
|
10
|
+
* chosenProvider owns that rule — and no entry at all means nothing chosen,
|
|
11
|
+
* exactly what the old null provider meant: the domain service skips and
|
|
12
|
+
* cloudflare's email operations stay off.
|
|
13
|
+
*/
|
|
14
|
+
const { chosenProvider } = require('../../../vendor/config/index.js');
|
|
15
|
+
|
|
16
|
+
// Providers whose nameservers the domain service sets via API
|
|
17
|
+
const API_PROVIDERS = new Set(['namecheap']);
|
|
18
|
+
|
|
19
|
+
// Nameserver-management pages per registrar (manual providers get these
|
|
20
|
+
// opened in the browser during the zone-activation flow)
|
|
21
|
+
const REGISTRAR_NAMESERVER_URLS = {
|
|
22
|
+
squarespace: (domain) => `https://account.squarespace.com/domains/managed/${domain}/dns/domain-nameservers`,
|
|
23
|
+
namecheap: (domain) => `https://ap.www.namecheap.com/domains/domaincontrolpanel/${domain}/domain`,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The brand's domain registrar (`domain.providers.<registrar>`).
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} brandConfig - Resolved brand config
|
|
30
|
+
* @returns {string|null} - 'namecheap' | 'squarespace' | … | null
|
|
31
|
+
*/
|
|
32
|
+
function resolveRegistrar(brandConfig) {
|
|
33
|
+
return chosenProvider(brandConfig?.domain?.providers);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The brand's mailbox provider (`domain.email.providers.<provider>`).
|
|
38
|
+
*
|
|
39
|
+
* @param {Object} brandConfig - Resolved brand config
|
|
40
|
+
* @returns {string|null} - 'cloudflare' | 'squarespace' | 'privateemail' | … | null
|
|
41
|
+
*/
|
|
42
|
+
function resolveEmailProvider(brandConfig) {
|
|
43
|
+
return chosenProvider(brandConfig?.domain?.email?.providers);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = { API_PROVIDERS, REGISTRAR_NAMESERVER_URLS, resolveRegistrar, resolveEmailProvider };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Namecheap IP-whitelist walkthrough (#698).
|
|
3
|
+
*
|
|
4
|
+
* Namecheap refuses every API call from an IP that is not on its whitelist, so
|
|
5
|
+
* a new machine — or the same machine on a new network — fails the domain
|
|
6
|
+
* service on every run. Rather than warn forever, an interactive walk drives
|
|
7
|
+
* the fix in place: the house open-and-poll idiom gates on Enter, opens the
|
|
8
|
+
* apiaccess ROOT page (enable, key reset and whitelist all live there), names
|
|
9
|
+
* the IP to add, and RE-CHECKS the refused call — ENTER checks now, `s` steps
|
|
10
|
+
* aside.
|
|
11
|
+
*
|
|
12
|
+
* Non-interactive and dry runs never sit here: they print the page and the IP
|
|
13
|
+
* and hand the warn back to the caller, exactly as before.
|
|
14
|
+
*/
|
|
15
|
+
const chalk = require('chalk').default;
|
|
16
|
+
const { openBrowserAndPoll } = require('../../../vendor/devkit/flows.js');
|
|
17
|
+
const { canPrompt } = require('../../../lib/run-gates.js');
|
|
18
|
+
const { API_ACCESS_URL, isWhitelistError } = require('./namecheap-api.js');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Walk the user through whitelisting the caller IP, retrying the refused call
|
|
22
|
+
* until it passes or the user steps aside.
|
|
23
|
+
*
|
|
24
|
+
* @param {Error} error - The rejection (carries `clientIp` from the client).
|
|
25
|
+
* @param {Function} retry - Async () => the refused call, run again.
|
|
26
|
+
* @param {object} [options] - Run options (a dry run or no TTY never prompts).
|
|
27
|
+
* @returns {Promise<{ success: boolean, result?: any, error?: string }>} -
|
|
28
|
+
* `result` is the retried call's value once Namecheap accepts it; `error` is
|
|
29
|
+
* the recheck's OWN failure when it got past the whitelist and failed anyway.
|
|
30
|
+
*/
|
|
31
|
+
async function walkWhitelist(error, retry, options = {}) {
|
|
32
|
+
const { clientIp } = error;
|
|
33
|
+
|
|
34
|
+
console.log(` ${chalk.yellow('⚠')} Namecheap refused this machine's IP ${chalk.cyan(clientIp)} — it is not on the API whitelist`);
|
|
35
|
+
|
|
36
|
+
if (!canPrompt(options)) {
|
|
37
|
+
console.log(` ${chalk.dim(`→ Add it under "Whitelisted IPs" at ${API_ACCESS_URL}, then rerun`)}`);
|
|
38
|
+
return { success: false };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const result = await openBrowserAndPoll({
|
|
42
|
+
url: API_ACCESS_URL,
|
|
43
|
+
label: 'the Namecheap API access page',
|
|
44
|
+
promptMessage: `Add ${clientIp} under "Whitelisted IPs" (the same page enables API access and resets the key).`,
|
|
45
|
+
waitMessage: 'Rechecking the Namecheap API',
|
|
46
|
+
check: async () => {
|
|
47
|
+
try {
|
|
48
|
+
return { done: true, result: await retry() };
|
|
49
|
+
} catch (retryError) {
|
|
50
|
+
// Still refused — keep waiting. Any other failure is the walk's answer.
|
|
51
|
+
return isWhitelistError(retryError) ? { done: false } : { done: true, error: retryError.message };
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
intervalMs: 10000,
|
|
55
|
+
indent: ' ',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (result.success) {
|
|
59
|
+
console.log(` ${chalk.green('✓')} Namecheap accepted the call — the IP is whitelisted`);
|
|
60
|
+
return { success: true, result: result.result };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The recheck got PAST the whitelist and failed for its own reason — say so,
|
|
64
|
+
// and hand it back: it is the truer answer, not the stale rejection (#698).
|
|
65
|
+
// The whitelist closer would be false here, so it only prints when the walk
|
|
66
|
+
// really ended on the rejection.
|
|
67
|
+
if (result.error) {
|
|
68
|
+
console.log(` ${chalk.yellow('⚠')} The recheck failed${chalk.dim(`: ${result.error}`)}`);
|
|
69
|
+
return { success: false, error: result.error };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log(` ${chalk.dim('⊘ Still refused — rerun once the IP is whitelisted')}`);
|
|
73
|
+
return { success: false };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = { walkWhitelist };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure cache rules match `edge.providers.cloudflare.cacheRules`.
|
|
3
|
+
*
|
|
4
|
+
* 1. Reads the http_request_cache_settings entrypoint ruleset (or notes it needs creating).
|
|
5
|
+
* 2. Diffs each configured rule by description — creates missing, updates stale, removes unconfigured.
|
|
6
|
+
* 3. POSTs a new ruleset if missing; PUTs the merged ruleset if updating.
|
|
7
|
+
*/
|
|
8
|
+
const chalk = require('chalk').default;
|
|
9
|
+
const { cacheRead } = require('../lib/read-cache.js');
|
|
10
|
+
const { fetchRuleset, applyRuleset, getZoneId, zoneGate } = require('../lib/ruleset-helper.js');
|
|
11
|
+
|
|
12
|
+
module.exports = async function ensureCacheRules(context) {
|
|
13
|
+
const { cloudflareApi: api, brandRoot, brandConfig, options = {} } = context;
|
|
14
|
+
const zoneId = getZoneId(context);
|
|
15
|
+
const gated = zoneGate(context, 'cacheRules');
|
|
16
|
+
if (gated) return gated;
|
|
17
|
+
|
|
18
|
+
// === READ ===
|
|
19
|
+
const { ruleset, needsCreate } = await fetchRuleset(api, zoneId, 'http_request_cache_settings');
|
|
20
|
+
const readCount = ruleset?.rules?.length || 0;
|
|
21
|
+
console.log(` ${chalk.green('✓')} Read ${chalk.dim(`(${readCount} items)`)}`);
|
|
22
|
+
cacheRead(brandRoot, 'cache-rules', { count: readCount, ruleset, needsCreate });
|
|
23
|
+
|
|
24
|
+
// === DIFF ===
|
|
25
|
+
const cacheRulesConfig = brandConfig?.edge?.providers?.cloudflare?.cacheRules;
|
|
26
|
+
if (!cacheRulesConfig || !Array.isArray(cacheRulesConfig) || cacheRulesConfig.length === 0) {
|
|
27
|
+
console.log(` ${chalk.dim('⊘ No changes needed')}`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const modifiedRules = ruleset?.rules ? [...ruleset.rules] : [];
|
|
32
|
+
let hasChanges = false;
|
|
33
|
+
|
|
34
|
+
for (const configRule of cacheRulesConfig) {
|
|
35
|
+
const ruleName = configRule.name;
|
|
36
|
+
const ruleIndex = modifiedRules.findIndex((rule) => rule.description === ruleName);
|
|
37
|
+
const currentRule = ruleIndex >= 0 ? modifiedRules[ruleIndex] : null;
|
|
38
|
+
|
|
39
|
+
const expectedRule = {
|
|
40
|
+
...(currentRule || {}),
|
|
41
|
+
action: 'set_cache_settings',
|
|
42
|
+
action_parameters: {
|
|
43
|
+
cache: true,
|
|
44
|
+
// Nullish, never falsy: 0 is a legal TTL a brand can mean (#754)
|
|
45
|
+
edge_ttl: { mode: 'override_origin', default: configRule.edgeTtl ?? 31536000 },
|
|
46
|
+
browser_ttl: { mode: 'override_origin', default: configRule.browserTtl ?? 14400 },
|
|
47
|
+
},
|
|
48
|
+
expression: configRule.expression || currentRule?.expression,
|
|
49
|
+
description: ruleName,
|
|
50
|
+
enabled: configRule.enabled !== undefined ? configRule.enabled : (currentRule?.enabled ?? true),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
if (!currentRule) {
|
|
54
|
+
console.log(` ${chalk.dim('·')} create ${chalk.cyan(`"${ruleName}"`)}`);
|
|
55
|
+
modifiedRules.push(expectedRule);
|
|
56
|
+
hasChanges = true;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const currentEdgeTtl = currentRule.action_parameters?.edge_ttl?.default;
|
|
61
|
+
const currentBrowserTtl = currentRule.action_parameters?.browser_ttl?.default;
|
|
62
|
+
const needsUpdate =
|
|
63
|
+
currentEdgeTtl !== expectedRule.action_parameters.edge_ttl.default
|
|
64
|
+
|| currentBrowserTtl !== expectedRule.action_parameters.browser_ttl.default
|
|
65
|
+
|| currentRule.enabled !== expectedRule.enabled
|
|
66
|
+
|| currentRule.expression !== expectedRule.expression;
|
|
67
|
+
|
|
68
|
+
if (needsUpdate) {
|
|
69
|
+
console.log(` ${chalk.dim('·')} update ${chalk.cyan(`"${ruleName}"`)}`);
|
|
70
|
+
modifiedRules[ruleIndex] = expectedRule;
|
|
71
|
+
hasChanges = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Remove stale rules (in Cloudflare but not in config)
|
|
76
|
+
const configNames = new Set(cacheRulesConfig.map((r) => r.name));
|
|
77
|
+
const staleIndices = [];
|
|
78
|
+
for (let i = modifiedRules.length - 1; i >= 0; i--) {
|
|
79
|
+
if (modifiedRules[i].description && !configNames.has(modifiedRules[i].description)) {
|
|
80
|
+
console.log(` ${chalk.dim('·')} remove ${chalk.cyan(`"${modifiedRules[i].description}"`)}`);
|
|
81
|
+
staleIndices.push(i);
|
|
82
|
+
hasChanges = true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (const i of staleIndices) modifiedRules.splice(i, 1);
|
|
86
|
+
|
|
87
|
+
if (!hasChanges && !needsCreate) {
|
|
88
|
+
console.log(` ${chalk.dim('⊘ No changes needed')}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// === WRITE ===
|
|
93
|
+
const output = await applyRuleset(api, zoneId, {
|
|
94
|
+
ruleset,
|
|
95
|
+
needsCreate,
|
|
96
|
+
rules: modifiedRules,
|
|
97
|
+
phase: 'http_request_cache_settings',
|
|
98
|
+
name: 'Cache Rules',
|
|
99
|
+
description: 'Cache rules managed by Omega Manager',
|
|
100
|
+
label: 'Cache rules',
|
|
101
|
+
dryRun: options.dryRun,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return { output: { cacheRules: output } };
|
|
105
|
+
};
|