@omega.js/backend 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/LICENSE +98 -0
- package/README.md +1053 -0
- package/bin/omega +2 -0
- package/bin/omega-backend +2 -0
- package/bin/omg +2 -0
- package/cli.js +3 -0
- package/dist/cli/command-table.js +268 -0
- package/dist/cli/commands/auth.js +259 -0
- package/dist/cli/commands/base-command.js +451 -0
- package/dist/cli/commands/build.js +27 -0
- package/dist/cli/commands/clean.js +13 -0
- package/dist/cli/commands/clear.js +11 -0
- package/dist/cli/commands/cwd.js +9 -0
- package/dist/cli/commands/deploy.js +205 -0
- package/dist/cli/commands/emulator-orphans.js +440 -0
- package/dist/cli/commands/emulator.js +1829 -0
- package/dist/cli/commands/firebase-init.js +101 -0
- package/dist/cli/commands/firestore.js +261 -0
- package/dist/cli/commands/indexes.js +51 -0
- package/dist/cli/commands/install.js +151 -0
- package/dist/cli/commands/logs.js +358 -0
- package/dist/cli/commands/mcp.js +41 -0
- package/dist/cli/commands/migrate-markers.js +176 -0
- package/dist/cli/commands/migrate-rules.js +90 -0
- package/dist/cli/commands/migrate.js +59 -0
- package/dist/cli/commands/serve.js +208 -0
- package/dist/cli/commands/setup-tests/base-test.js +174 -0
- package/dist/cli/commands/setup-tests/emulator-config.js +109 -0
- package/dist/cli/commands/setup-tests/env-runtime-config-deprecated.js +47 -0
- package/dist/cli/commands/setup-tests/firebase-admin.js +49 -0
- package/dist/cli/commands/setup-tests/firebase-auth.js +26 -0
- package/dist/cli/commands/setup-tests/firebase-cli.js +26 -0
- package/dist/cli/commands/setup-tests/firebase-functions.js +49 -0
- package/dist/cli/commands/setup-tests/firestore-indexes-file.js +72 -0
- package/dist/cli/commands/setup-tests/firestore-indexes-in-json.js +20 -0
- package/dist/cli/commands/setup-tests/firestore-indexes-required.js +108 -0
- package/dist/cli/commands/setup-tests/firestore-indexes-synced.js +236 -0
- package/dist/cli/commands/setup-tests/firestore-rules-file.js +115 -0
- package/dist/cli/commands/setup-tests/firestore-rules-in-json.js +49 -0
- package/dist/cli/commands/setup-tests/functions-package.js +44 -0
- package/dist/cli/commands/setup-tests/gcloud-cli.js +26 -0
- package/dist/cli/commands/setup-tests/gitignore.js +122 -0
- package/dist/cli/commands/setup-tests/helpers/merge-line-files.js +28 -0
- package/dist/cli/commands/setup-tests/helpers/required-indexes.js +109 -0
- package/dist/cli/commands/setup-tests/helpers/seed-campaigns.js +246 -0
- package/dist/cli/commands/setup-tests/helpers.js +72 -0
- package/dist/cli/commands/setup-tests/hosting-folder.js +23 -0
- package/dist/cli/commands/setup-tests/hosting-rewrites.js +52 -0
- package/dist/cli/commands/setup-tests/index.js +111 -0
- package/dist/cli/commands/setup-tests/is-firebase-project.js +21 -0
- package/dist/cli/commands/setup-tests/java-installed.js +27 -0
- package/dist/cli/commands/setup-tests/legacy-tests-cleanup.js +43 -0
- package/dist/cli/commands/setup-tests/marketing-campaigns-seeded.js +230 -0
- package/dist/cli/commands/setup-tests/node-version.js +60 -0
- package/dist/cli/commands/setup-tests/npm-project-scripts.js +42 -0
- package/dist/cli/commands/setup-tests/nvmrc-version.js +36 -0
- package/dist/cli/commands/setup-tests/omega-backend.js +42 -0
- package/dist/cli/commands/setup-tests/omega-config.js +84 -0
- package/dist/cli/commands/setup-tests/project-directories.js +34 -0
- package/dist/cli/commands/setup-tests/project-id-consistency.js +201 -0
- package/dist/cli/commands/setup-tests/public-html-files.js +22 -0
- package/dist/cli/commands/setup-tests/realtime-rules-file.js +69 -0
- package/dist/cli/commands/setup-tests/realtime-rules-in-json.js +20 -0
- package/dist/cli/commands/setup-tests/remoteconfig-template-file.js +32 -0
- package/dist/cli/commands/setup-tests/remoteconfig-template-in-json.js +31 -0
- package/dist/cli/commands/setup-tests/service-account.js +86 -0
- package/dist/cli/commands/setup-tests/storage-lifecycle-policy.js +81 -0
- package/dist/cli/commands/setup-tests/storage-rules-file.js +32 -0
- package/dist/cli/commands/setup-tests/storage-rules-in-json.js +20 -0
- package/dist/cli/commands/stripe.js +14 -0
- package/dist/cli/commands/test-lanes/stripe-live.js +440 -0
- package/dist/cli/commands/test.js +976 -0
- package/dist/cli/commands/update.js +27 -0
- package/dist/cli/commands/version.js +10 -0
- package/dist/cli/commands/watch.js +196 -0
- package/dist/cli/flags.js +13 -0
- package/dist/cli/index.js +173 -0
- package/dist/cli/run.js +33 -0
- package/dist/cli/utils/attach-log-file.js +4 -0
- package/dist/cli/utils/compile-rules.js +1155 -0
- package/dist/cli/utils/ensure-target.js +314 -0
- package/dist/cli/utils/project-type.js +140 -0
- package/dist/cli/utils/public-files.js +49 -0
- package/dist/cli/utils/safe-install.js +4 -0
- package/dist/cli/utils/spawn-shell.js +94 -0
- package/dist/cli/utils/stage-functions.js +338 -0
- package/dist/cli/utils/stage-local-packages.js +210 -0
- package/dist/cli/utils/target-checks.js +161 -0
- package/dist/cli/utils/target.js +24 -0
- package/dist/cli/utils/ui.js +292 -0
- package/dist/defaults/AGENTS.md +125 -0
- package/dist/defaults/CHANGELOG.md +15 -0
- package/dist/defaults/CLAUDE.md +1 -0
- package/dist/defaults/_.gitignore +65 -0
- package/dist/defaults/docs/README.md +17 -0
- package/dist/defaults/test/README.md +65 -0
- package/dist/defaults/test/_init.js +14 -0
- package/dist/defaults/test/helpers/connect-trap.js +72 -0
- package/dist/defaults/test/unit/registration.test.js +143 -0
- package/dist/defaults/test/unit/rules-posture.test.js +101 -0
- package/dist/defaults/test/unit/socket-free.test.js +43 -0
- package/dist/manager/events/auth/before-create.js +89 -0
- package/dist/manager/events/auth/before-signin.js +76 -0
- package/dist/manager/events/auth/on-create.js +112 -0
- package/dist/manager/events/auth/on-delete.js +141 -0
- package/dist/manager/events/auth/utils.js +93 -0
- package/dist/manager/events/cron/daily/blog-auto-publisher.js +287 -0
- package/dist/manager/events/cron/daily/data-requests.js +57 -0
- package/dist/manager/events/cron/daily/expire-paypal-cancellations.js +191 -0
- package/dist/manager/events/cron/daily/marketing-prune.js +486 -0
- package/dist/manager/events/cron/daily/reset-usage.js +188 -0
- package/dist/manager/events/cron/daily/trial-lapse-sweep.js +355 -0
- package/dist/manager/events/cron/daily.js +3 -0
- package/dist/manager/events/cron/frequent/abandoned-carts.js +204 -0
- package/dist/manager/events/cron/frequent/email-queue.js +71 -0
- package/dist/manager/events/cron/frequent/marketing-campaigns.js +463 -0
- package/dist/manager/events/cron/frequent/retry-failed-webhooks.js +70 -0
- package/dist/manager/events/cron/frequent.js +3 -0
- package/dist/manager/events/cron/runner.js +64 -0
- package/dist/manager/events/firestore/notifications/on-write.js +123 -0
- package/dist/manager/events/firestore/payments-disputes/on-write.js +256 -0
- package/dist/manager/events/firestore/payments-disputes/providers/stripe.js +218 -0
- package/dist/manager/events/firestore/payments-disputes/providers/test.js +231 -0
- package/dist/manager/events/firestore/payments-webhooks/analytics.js +687 -0
- package/dist/manager/events/firestore/payments-webhooks/on-write.js +1224 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/index.js +395 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-completed.js +58 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-failed.js +28 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/one-time/purchase-refunded.js +30 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/send-email.js +74 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/cancellation-removed.js +14 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/cancellation-requested.js +28 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/checkout-declined.js +18 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/new-subscription.js +67 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/payment-failed.js +25 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/payment-recovered.js +26 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/payment-refunded.js +34 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/plan-changed.js +42 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/subscription-cancelled.js +33 -0
- package/dist/manager/events/firestore/payments-webhooks/transitions/subscription/subscription-winback.js +17 -0
- package/dist/manager/functions/_legacy/actions/create-post-handler.js +188 -0
- package/dist/manager/functions/_legacy/actions/generate-uuid.js +63 -0
- package/dist/manager/functions/_legacy/actions/sign-up-handler.js +205 -0
- package/dist/manager/functions/_legacy/admin/create-post.js +207 -0
- package/dist/manager/functions/_legacy/admin/firestore-write.js +72 -0
- package/dist/manager/functions/_legacy/admin/get-stats.js +218 -0
- package/dist/manager/functions/_legacy/admin/query.js +198 -0
- package/dist/manager/functions/_legacy/admin/send-notification.js +206 -0
- package/dist/manager/functions/_legacy/template.js +33 -0
- package/dist/manager/functions/_legacy/test/authenticate.js +40 -0
- package/dist/manager/functions/_legacy/test/webhook.js +37 -0
- package/dist/manager/functions/wrappers/mailchimp/addToList.js +25 -0
- package/dist/manager/helpers/analytics.js +498 -0
- package/dist/manager/helpers/api-manager.js +313 -0
- package/dist/manager/helpers/backend-router.js +37 -0
- package/dist/manager/helpers/context/authenticate.js +215 -0
- package/dist/manager/helpers/context/client-info.js +91 -0
- package/dist/manager/helpers/context/index.js +228 -0
- package/dist/manager/helpers/context/logging.js +150 -0
- package/dist/manager/helpers/context/parse.js +160 -0
- package/dist/manager/helpers/context/respond.js +247 -0
- package/dist/manager/helpers/event-middleware.js +109 -0
- package/dist/manager/helpers/metadata.js +32 -0
- package/dist/manager/helpers/middleware.js +541 -0
- package/dist/manager/helpers/redact-secret.js +25 -0
- package/dist/manager/helpers/resolved-config.js +34 -0
- package/dist/manager/helpers/roles.js +69 -0
- package/dist/manager/helpers/safe-compare.js +31 -0
- package/dist/manager/helpers/schema-engine.js +314 -0
- package/dist/manager/helpers/schema-zod.js +203 -0
- package/dist/manager/helpers/settings.js +215 -0
- package/dist/manager/helpers/usage.js +541 -0
- package/dist/manager/helpers/user.js +57 -0
- package/dist/manager/helpers/utilities.js +565 -0
- package/dist/manager/index.js +1404 -0
- package/dist/manager/libraries/abandoned-cart-config.js +12 -0
- package/dist/manager/libraries/ai/index.js +321 -0
- package/dist/manager/libraries/ai/prompt.js +85 -0
- package/dist/manager/libraries/ai/providers/anthropic-format.js +297 -0
- package/dist/manager/libraries/ai/providers/anthropic.js +169 -0
- package/dist/manager/libraries/ai/providers/claude-code.js +183 -0
- package/dist/manager/libraries/ai/providers/openai.js +1272 -0
- package/dist/manager/libraries/ai/providers/test.js +257 -0
- package/dist/manager/libraries/ai/tokens.js +54 -0
- package/dist/manager/libraries/analytics/conversions.js +478 -0
- package/dist/manager/libraries/analytics/match-data.js +573 -0
- package/dist/manager/libraries/analytics/signup.js +120 -0
- package/dist/manager/libraries/auth-user.js +46 -0
- package/dist/manager/libraries/content/feed-parser.js +198 -0
- package/dist/manager/libraries/content/ghostii.js +191 -0
- package/dist/manager/libraries/content/source-resolver.js +629 -0
- package/dist/manager/libraries/email/constants.js +532 -0
- package/dist/manager/libraries/email/data/blocked-local-parts.json +55 -0
- package/dist/manager/libraries/email/data/blocked-local-patterns.js +14 -0
- package/dist/manager/libraries/email/data/corporate-domains.json +23 -0
- package/dist/manager/libraries/email/data/custom-disposable-domains.json +58 -0
- package/dist/manager/libraries/email/data/disposable-domains.json +8184 -0
- package/dist/manager/libraries/email/data/typo-domains.js +83 -0
- package/dist/manager/libraries/email/disposable-domains.js +92 -0
- package/dist/manager/libraries/email/generators/lib/filter.js +179 -0
- package/dist/manager/libraries/email/generators/lib/image-host.js +344 -0
- package/dist/manager/libraries/email/generators/lib/image-illustrator.js +154 -0
- package/dist/manager/libraries/email/generators/lib/markdown-renderer.js +294 -0
- package/dist/manager/libraries/email/generators/lib/mjml-template.js +120 -0
- package/dist/manager/libraries/email/generators/lib/structure.js +299 -0
- package/dist/manager/libraries/email/generators/lib/svg-illustrator.js +197 -0
- package/dist/manager/libraries/email/generators/lib/templates/base.js +229 -0
- package/dist/manager/libraries/email/generators/lib/templates/card.js +33 -0
- package/dist/manager/libraries/email/generators/lib/templates/classic-schema.js +59 -0
- package/dist/manager/libraries/email/generators/lib/templates/clean.js +82 -0
- package/dist/manager/libraries/email/generators/lib/templates/editorial/helpers.js +100 -0
- package/dist/manager/libraries/email/generators/lib/templates/editorial/index.js +318 -0
- package/dist/manager/libraries/email/generators/lib/templates/feedback.js +101 -0
- package/dist/manager/libraries/email/generators/lib/templates/field-report/helpers.js +138 -0
- package/dist/manager/libraries/email/generators/lib/templates/field-report/index.js +494 -0
- package/dist/manager/libraries/email/generators/lib/templates/index.js +47 -0
- package/dist/manager/libraries/email/generators/lib/templates/newsletter-shared.js +610 -0
- package/dist/manager/libraries/email/generators/lib/templates/order.js +461 -0
- package/dist/manager/libraries/email/generators/lib/templates/plain.js +83 -0
- package/dist/manager/libraries/email/generators/lib/templates/shared-campaign.js +64 -0
- package/dist/manager/libraries/email/generators/newsletter.js +899 -0
- package/dist/manager/libraries/email/index.js +146 -0
- package/dist/manager/libraries/email/marketing/index.js +754 -0
- package/dist/manager/libraries/email/prepare.js +365 -0
- package/dist/manager/libraries/email/providers/beehiiv.js +589 -0
- package/dist/manager/libraries/email/providers/sendgrid.js +845 -0
- package/dist/manager/libraries/email/transactional/index.js +510 -0
- package/dist/manager/libraries/email/utm.js +86 -0
- package/dist/manager/libraries/email/validation-provider-neverbounce.js +70 -0
- package/dist/manager/libraries/email/validation-provider-zerobounce.js +42 -0
- package/dist/manager/libraries/email/validation.js +255 -0
- package/dist/manager/libraries/env.js +198 -0
- package/dist/manager/libraries/infer-contact.js +101 -0
- package/dist/manager/libraries/load-provider.js +65 -0
- package/dist/manager/libraries/notification.js +256 -0
- package/dist/manager/libraries/openai.js +13 -0
- package/dist/manager/libraries/payment/discount-codes.js +204 -0
- package/dist/manager/libraries/payment/fetch-failure.js +56 -0
- package/dist/manager/libraries/payment/license.js +44 -0
- package/dist/manager/libraries/payment/order-id.js +57 -0
- package/dist/manager/libraries/payment/provider-errors.js +71 -0
- package/dist/manager/libraries/payment/providers/chargebee.js +817 -0
- package/dist/manager/libraries/payment/providers/coinbase.js +330 -0
- package/dist/manager/libraries/payment/providers/paypal.js +987 -0
- package/dist/manager/libraries/payment/providers/stripe.js +755 -0
- package/dist/manager/libraries/payment/providers/test.js +250 -0
- package/dist/manager/libraries/payment/refund-linkage.js +78 -0
- package/dist/manager/libraries/payment/refund-policy.js +113 -0
- package/dist/manager/libraries/payment/winback.js +55 -0
- package/dist/manager/libraries/prompts/infer-contact.md +78 -0
- package/dist/manager/libraries/rate-limits.js +17 -0
- package/dist/manager/libraries/recaptcha.js +58 -0
- package/dist/manager/libraries/user-doc.js +234 -0
- package/dist/manager/routes/admin/backup/post.js +106 -0
- package/dist/manager/routes/admin/cron/post.js +37 -0
- package/dist/manager/routes/admin/database/get.js +35 -0
- package/dist/manager/routes/admin/database/post.js +34 -0
- package/dist/manager/routes/admin/email/post.js +74 -0
- package/dist/manager/routes/admin/firestore/get.js +35 -0
- package/dist/manager/routes/admin/firestore/post.js +56 -0
- package/dist/manager/routes/admin/firestore/query/post.js +128 -0
- package/dist/manager/routes/admin/hook/post.js +104 -0
- package/dist/manager/routes/admin/infer-contact/post.js +35 -0
- package/dist/manager/routes/admin/notification/post.js +37 -0
- package/dist/manager/routes/admin/payment/post.js +56 -0
- package/dist/manager/routes/admin/post/deduplicate-image-alts.js +52 -0
- package/dist/manager/routes/admin/post/dispatch-deploy.js +36 -0
- package/dist/manager/routes/admin/post/post.js +487 -0
- package/dist/manager/routes/admin/post/put.js +146 -0
- package/dist/manager/routes/admin/post/templates/post.html +14 -0
- package/dist/manager/routes/admin/repo/content/post.js +106 -0
- package/dist/manager/routes/admin/stats/get.js +222 -0
- package/dist/manager/routes/admin/users/disable/post.js +50 -0
- package/dist/manager/routes/admin/users/list/get.js +110 -0
- package/dist/manager/routes/admin/users/sync/post.js +119 -0
- package/dist/manager/routes/brand/get.js +26 -0
- package/dist/manager/routes/content/post/get.js +110 -0
- package/dist/manager/routes/general/email/post.js +89 -0
- package/dist/manager/routes/general/email/templates/general/download-app-link.js +42 -0
- package/dist/manager/routes/general/uuid/post.js +31 -0
- package/dist/manager/routes/handler/post/post.js +142 -0
- package/dist/manager/routes/health/get.js +43 -0
- package/dist/manager/routes/index.js +11 -0
- package/dist/manager/routes/marketing/campaign/delete.js +45 -0
- package/dist/manager/routes/marketing/campaign/get.js +69 -0
- package/dist/manager/routes/marketing/campaign/post.js +124 -0
- package/dist/manager/routes/marketing/campaign/put.js +86 -0
- package/dist/manager/routes/marketing/campaign/utils.js +59 -0
- package/dist/manager/routes/marketing/contact/delete.js +100 -0
- package/dist/manager/routes/marketing/contact/post.js +149 -0
- package/dist/manager/routes/marketing/contact/put.js +37 -0
- package/dist/manager/routes/marketing/email-preferences/post.js +275 -0
- package/dist/manager/routes/marketing/webhook/forward/post.js +170 -0
- package/dist/manager/routes/marketing/webhook/post.js +123 -0
- package/dist/manager/routes/marketing/webhook/providers/beehiiv.js +197 -0
- package/dist/manager/routes/marketing/webhook/providers/sendgrid.js +194 -0
- package/dist/manager/routes/payments/cancel/_is-trialing.js +40 -0
- package/dist/manager/routes/payments/cancel/post.js +149 -0
- package/dist/manager/routes/payments/cancel/providers/chargebee.js +41 -0
- package/dist/manager/routes/payments/cancel/providers/paypal.js +56 -0
- package/dist/manager/routes/payments/cancel/providers/stripe.js +33 -0
- package/dist/manager/routes/payments/cancel/providers/test.js +118 -0
- package/dist/manager/routes/payments/discount/get.js +25 -0
- package/dist/manager/routes/payments/dispute-alert/post.js +117 -0
- package/dist/manager/routes/payments/dispute-alert/providers/chargeblast.js +55 -0
- package/dist/manager/routes/payments/intent/post.js +341 -0
- package/dist/manager/routes/payments/intent/providers/chargebee.js +197 -0
- package/dist/manager/routes/payments/intent/providers/coinbase.js +94 -0
- package/dist/manager/routes/payments/intent/providers/paypal.js +244 -0
- package/dist/manager/routes/payments/intent/providers/stripe.js +141 -0
- package/dist/manager/routes/payments/intent/providers/test.js +341 -0
- package/dist/manager/routes/payments/plan/post.js +147 -0
- package/dist/manager/routes/payments/plan/providers/chargebee.js +62 -0
- package/dist/manager/routes/payments/plan/providers/paypal.js +62 -0
- package/dist/manager/routes/payments/plan/providers/stripe.js +59 -0
- package/dist/manager/routes/payments/plan/providers/test.js +113 -0
- package/dist/manager/routes/payments/portal/post.js +113 -0
- package/dist/manager/routes/payments/portal/providers/chargebee.js +62 -0
- package/dist/manager/routes/payments/portal/providers/paypal.js +25 -0
- package/dist/manager/routes/payments/portal/providers/stripe.js +62 -0
- package/dist/manager/routes/payments/portal/providers/test.js +18 -0
- package/dist/manager/routes/payments/refund/post.js +207 -0
- package/dist/manager/routes/payments/refund/providers/chargebee.js +147 -0
- package/dist/manager/routes/payments/refund/providers/coinbase.js +40 -0
- package/dist/manager/routes/payments/refund/providers/paypal.js +239 -0
- package/dist/manager/routes/payments/refund/providers/stripe.js +160 -0
- package/dist/manager/routes/payments/refund/providers/test.js +204 -0
- package/dist/manager/routes/payments/trial-eligibility/get.js +29 -0
- package/dist/manager/routes/payments/uncancel/post.js +106 -0
- package/dist/manager/routes/payments/uncancel/providers/chargebee.js +30 -0
- package/dist/manager/routes/payments/uncancel/providers/paypal.js +25 -0
- package/dist/manager/routes/payments/uncancel/providers/stripe.js +27 -0
- package/dist/manager/routes/payments/uncancel/providers/test.js +114 -0
- package/dist/manager/routes/payments/webhook/post.js +157 -0
- package/dist/manager/routes/payments/webhook/providers/chargebee.js +218 -0
- package/dist/manager/routes/payments/webhook/providers/coinbase.js +91 -0
- package/dist/manager/routes/payments/webhook/providers/paypal.js +214 -0
- package/dist/manager/routes/payments/webhook/providers/stripe.js +182 -0
- package/dist/manager/routes/payments/webhook/providers/test.js +18 -0
- package/dist/manager/routes/payments/winback/post.js +276 -0
- package/dist/manager/routes/payments/winback/providers/chargebee.js +24 -0
- package/dist/manager/routes/payments/winback/providers/paypal.js +22 -0
- package/dist/manager/routes/payments/winback/providers/stripe.js +41 -0
- package/dist/manager/routes/payments/winback/providers/test.js +42 -0
- package/dist/manager/routes/restart/index.js +37 -0
- package/dist/manager/routes/special/electron-client/post.js +59 -0
- package/dist/manager/routes/test/authenticate/get.js +11 -0
- package/dist/manager/routes/test/health/get.js +8 -0
- package/dist/manager/routes/test/index.js +16 -0
- package/dist/manager/routes/test/lab/post.js +17 -0
- package/dist/manager/routes/test/redirect/get.js +27 -0
- package/dist/manager/routes/test/reset-account/post.js +79 -0
- package/dist/manager/routes/test/roster/get.js +40 -0
- package/dist/manager/routes/test/schema/post.js +20 -0
- package/dist/manager/routes/test/usage/post.js +44 -0
- package/dist/manager/routes/test/webhook/post.js +21 -0
- package/dist/manager/routes/user/api-keys/post.js +51 -0
- package/dist/manager/routes/user/connections/_context.js +194 -0
- package/dist/manager/routes/user/connections/_grant.js +247 -0
- package/dist/manager/routes/user/connections/_lease.js +184 -0
- package/dist/manager/routes/user/connections/_providers.js +191 -0
- package/dist/manager/routes/user/connections/_state.js +117 -0
- package/dist/manager/routes/user/connections/delete.js +55 -0
- package/dist/manager/routes/user/connections/get.js +167 -0
- package/dist/manager/routes/user/connections/post.js +370 -0
- package/dist/manager/routes/user/connections/providers/discord.js +41 -0
- package/dist/manager/routes/user/connections/providers/google.js +55 -0
- package/dist/manager/routes/user/connections/providers/kick.js +68 -0
- package/dist/manager/routes/user/connections/providers/spotify.js +40 -0
- package/dist/manager/routes/user/connections/providers/twitch.js +52 -0
- package/dist/manager/routes/user/data-request/delete.js +84 -0
- package/dist/manager/routes/user/data-request/get.js +229 -0
- package/dist/manager/routes/user/data-request/post.js +136 -0
- package/dist/manager/routes/user/delete.js +149 -0
- package/dist/manager/routes/user/feedback/post.js +81 -0
- package/dist/manager/routes/user/get.js +14 -0
- package/dist/manager/routes/user/orders/get.js +95 -0
- package/dist/manager/routes/user/sessions/delete.js +95 -0
- package/dist/manager/routes/user/sessions/get.js +40 -0
- package/dist/manager/routes/user/settings/validate/post.js +86 -0
- package/dist/manager/routes/user/signup/post.js +662 -0
- package/dist/manager/routes/user/subscription/get.js +77 -0
- package/dist/manager/routes/user/token/post.js +30 -0
- package/dist/manager/routes/verts/delete.js +43 -0
- package/dist/manager/routes/verts/get.js +49 -0
- package/dist/manager/routes/verts/post.js +61 -0
- package/dist/manager/routes/verts/put.js +75 -0
- package/dist/manager/routes/verts/redirect/get.js +36 -0
- package/dist/manager/routes/verts/serve/get.js +67 -0
- package/dist/manager/routes/verts/utils.js +436 -0
- package/dist/manager/schemas/admin/backup/post.js +8 -0
- package/dist/manager/schemas/admin/cron/post.js +8 -0
- package/dist/manager/schemas/admin/database/get.js +5 -0
- package/dist/manager/schemas/admin/database/post.js +6 -0
- package/dist/manager/schemas/admin/email/post.js +31 -0
- package/dist/manager/schemas/admin/firestore/get.js +5 -0
- package/dist/manager/schemas/admin/firestore/post.js +8 -0
- package/dist/manager/schemas/admin/firestore/query/post.js +5 -0
- package/dist/manager/schemas/admin/hook/post.js +8 -0
- package/dist/manager/schemas/admin/infer-contact/post.js +6 -0
- package/dist/manager/schemas/admin/notification/post.js +23 -0
- package/dist/manager/schemas/admin/payment/post.js +8 -0
- package/dist/manager/schemas/admin/post/post.js +23 -0
- package/dist/manager/schemas/admin/post/put.js +13 -0
- package/dist/manager/schemas/admin/repo/content/post.js +10 -0
- package/dist/manager/schemas/admin/stats/get.js +5 -0
- package/dist/manager/schemas/admin/users/disable/post.js +9 -0
- package/dist/manager/schemas/admin/users/list/get.js +10 -0
- package/dist/manager/schemas/admin/users/sync/post.js +7 -0
- package/dist/manager/schemas/brand/get.js +3 -0
- package/dist/manager/schemas/content/post/get.js +8 -0
- package/dist/manager/schemas/general/email/post.js +10 -0
- package/dist/manager/schemas/general/uuid/post.js +9 -0
- package/dist/manager/schemas/handler/post/post.js +13 -0
- package/dist/manager/schemas/health/get.js +3 -0
- package/dist/manager/schemas/marketing/campaign/delete.js +8 -0
- package/dist/manager/schemas/marketing/campaign/get.js +13 -0
- package/dist/manager/schemas/marketing/campaign/post.js +43 -0
- package/dist/manager/schemas/marketing/campaign/put.js +37 -0
- package/dist/manager/schemas/marketing/contact/delete.js +8 -0
- package/dist/manager/schemas/marketing/contact/post.js +14 -0
- package/dist/manager/schemas/marketing/contact/put.js +8 -0
- package/dist/manager/schemas/marketing/email-preferences/post.js +15 -0
- package/dist/manager/schemas/marketing/webhook/forward/post.js +8 -0
- package/dist/manager/schemas/marketing/webhook/post.js +7 -0
- package/dist/manager/schemas/payments/cancel/post.js +15 -0
- package/dist/manager/schemas/payments/discount/get.js +8 -0
- package/dist/manager/schemas/payments/dispute-alert/post.js +6 -0
- package/dist/manager/schemas/payments/intent/post.js +28 -0
- package/dist/manager/schemas/payments/plan/post.js +11 -0
- package/dist/manager/schemas/payments/portal/post.js +12 -0
- package/dist/manager/schemas/payments/refund/post.js +14 -0
- package/dist/manager/schemas/payments/trial-eligibility/get.js +7 -0
- package/dist/manager/schemas/payments/uncancel/post.js +9 -0
- package/dist/manager/schemas/payments/webhook/post.js +6 -0
- package/dist/manager/schemas/payments/winback/post.js +12 -0
- package/dist/manager/schemas/restart/index.js +5 -0
- package/dist/manager/schemas/special/electron-client/post.js +11 -0
- package/dist/manager/schemas/test/authenticate/get.js +3 -0
- package/dist/manager/schemas/test/health/get.js +3 -0
- package/dist/manager/schemas/test/index.js +5 -0
- package/dist/manager/schemas/test/lab/post.js +3 -0
- package/dist/manager/schemas/test/redirect/get.js +7 -0
- package/dist/manager/schemas/test/reset-account/post.js +3 -0
- package/dist/manager/schemas/test/roster/get.js +3 -0
- package/dist/manager/schemas/test/schema/post.js +70 -0
- package/dist/manager/schemas/test/usage/post.js +8 -0
- package/dist/manager/schemas/test/webhook/post.js +7 -0
- package/dist/manager/schemas/user/api-keys/post.js +6 -0
- package/dist/manager/schemas/user/connections/delete.js +8 -0
- package/dist/manager/schemas/user/connections/get.js +21 -0
- package/dist/manager/schemas/user/connections/post.js +12 -0
- package/dist/manager/schemas/user/data-request/delete.js +3 -0
- package/dist/manager/schemas/user/data-request/get.js +5 -0
- package/dist/manager/schemas/user/data-request/post.js +6 -0
- package/dist/manager/schemas/user/delete.js +6 -0
- package/dist/manager/schemas/user/feedback/post.js +8 -0
- package/dist/manager/schemas/user/get.js +3 -0
- package/dist/manager/schemas/user/orders/get.js +6 -0
- package/dist/manager/schemas/user/sessions/delete.js +6 -0
- package/dist/manager/schemas/user/sessions/get.js +6 -0
- package/dist/manager/schemas/user/settings/validate/post.js +8 -0
- package/dist/manager/schemas/user/signup/post.js +27 -0
- package/dist/manager/schemas/user/subscription/get.js +5 -0
- package/dist/manager/schemas/user/token/post.js +5 -0
- package/dist/manager/schemas/verts/delete.js +8 -0
- package/dist/manager/schemas/verts/get.js +9 -0
- package/dist/manager/schemas/verts/post.js +23 -0
- package/dist/manager/schemas/verts/put.js +20 -0
- package/dist/manager/schemas/verts/redirect/get.js +10 -0
- package/dist/manager/schemas/verts/serve/get.js +14 -0
- package/dist/manager/server-manager.js +69 -0
- package/dist/mcp/client.js +98 -0
- package/dist/mcp/handler.js +521 -0
- package/dist/mcp/index.js +157 -0
- package/dist/mcp/tools.js +555 -0
- package/dist/mcp/utils.js +108 -0
- package/dist/omega-bin.js +6 -0
- package/dist/require.js +3 -0
- package/dist/test/fixtures/firebase-project/.firebaserc +5 -0
- package/dist/test/fixtures/firebase-project/config/omega.json5 +131 -0
- package/dist/test/fixtures/firebase-project/database.rules.json +6 -0
- package/dist/test/fixtures/firebase-project/firebase.json +49 -0
- package/dist/test/fixtures/firebase-project/firestore.indexes.json +4 -0
- package/dist/test/fixtures/firebase-project/package.json +14 -0
- package/dist/test/fixtures/firebase-project/src/index.js +11 -0
- package/dist/test/fixtures/firebase-project/storage.rules +8 -0
- package/dist/test/parse-audit.js +25 -0
- package/dist/test/run-tests.js +90 -0
- package/dist/test/runner.js +982 -0
- package/dist/test/seed.js +242 -0
- package/dist/test/test-accounts.js +2660 -0
- package/dist/test/utils/assertions.js +189 -0
- package/dist/test/utils/email-capture.js +252 -0
- package/dist/test/utils/extended-mode-warning.js +11 -0
- package/dist/test/utils/firestore-rules-client.js +277 -0
- package/dist/test/utils/http-client.js +228 -0
- package/dist/test/utils/test-mode-file.js +192 -0
- package/dist/utils/merge-line-files.js +6 -0
- package/dist/utils/scaffold-defaults.js +71 -0
- package/dist/utils/test-lanes.js +62 -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/analytics/adapters/ga4.js +26 -0
- package/dist/vendor/analytics/adapters/meta.js +26 -0
- package/dist/vendor/analytics/adapters/resolve.js +130 -0
- package/dist/vendor/analytics/adapters/tiktok.js +27 -0
- package/dist/vendor/analytics/catalog.js +908 -0
- package/dist/vendor/analytics/identity.js +136 -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/bare-requires.js +153 -0
- package/dist/vendor/devkit/command-path.js +46 -0
- package/dist/vendor/devkit/defaults-engine.js +372 -0
- package/dist/vendor/devkit/deploy-record.js +180 -0
- package/dist/vendor/devkit/deploy.js +286 -0
- package/dist/vendor/devkit/license.js +155 -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/merge-line-files.js +296 -0
- package/dist/vendor/devkit/npm-registry.js +52 -0
- package/dist/vendor/devkit/omega-bin.js +345 -0
- package/dist/vendor/devkit/parse-audit.js +74 -0
- package/dist/vendor/devkit/safe-install.js +18 -0
- package/dist/vendor/devkit/scaffold-guard.js +96 -0
- package/dist/vendor/devkit/stop-signals.js +28 -0
- package/dist/vendor/devkit/test/assert.js +120 -0
- package/dist/vendor/devkit/test/define-cases.js +104 -0
- package/dist/vendor/devkit/test/runner-core.js +554 -0
- package/dist/vendor/devkit/test/scope.js +162 -0
- package/dist/vendor/devkit/update.js +569 -0
- package/dist/vendor/monitoring/core.js +180 -0
- package/dist/vendor/monitoring/env.js +49 -0
- package/dist/vendor/monitoring/logger.js +39 -0
- package/dist/vendor/monitoring/node.js +72 -0
- package/docs/admin-post-route.md +57 -0
- package/docs/ai-library.md +171 -0
- package/docs/architecture.md +62 -0
- package/docs/audit.md +70 -0
- package/docs/auth-hooks.md +74 -0
- package/docs/build-system.md +65 -0
- package/docs/cdp-debugging.md +29 -0
- package/docs/cli-firestore-auth.md +85 -0
- package/docs/cli-logs.md +67 -0
- package/docs/cli-output.md +146 -0
- package/docs/code-patterns.md +77 -0
- package/docs/common-mistakes.md +12 -0
- package/docs/common-operations.md +60 -0
- package/docs/connections.md +212 -0
- package/docs/consent.md +362 -0
- package/docs/directory-structure.md +150 -0
- package/docs/email-system.md +459 -0
- package/docs/environment-detection.md +93 -0
- package/docs/file-naming.md +10 -0
- package/docs/firestore.md +134 -0
- package/docs/ghostii.md +240 -0
- package/docs/index.md +299 -0
- package/docs/key-files.md +37 -0
- package/docs/logging.md +60 -0
- package/docs/marketing-campaigns.md +407 -0
- package/docs/marketing-fields.md +25 -0
- package/docs/mcp.md +222 -0
- package/docs/migration.md +129 -0
- package/docs/payment-system.md +856 -0
- package/docs/paypal-sandbox-qa.md +105 -0
- package/docs/response-headers.md +9 -0
- package/docs/routes.md +211 -0
- package/docs/sanitization.md +71 -0
- package/docs/schemas.md +163 -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/stripe-webhook-forwarding.md +20 -0
- package/docs/test-boot-layer.md +67 -0
- package/docs/test-framework.md +583 -0
- package/docs/usage-rate-limiting.md +121 -0
- package/docs/verts.md +29 -0
- package/package.json +143 -0
- package/templates/config/omega.json5 +322 -0
- package/templates/database.rules.json +82 -0
- package/templates/firebase.json +67 -0
- package/templates/firestore.framework.rules +191 -0
- package/templates/firestore.indexes.json +4 -0
- package/templates/firestore.rules +59 -0
- package/templates/index.js +12 -0
- package/templates/public/404.html +26 -0
- package/templates/public/index.html +24 -0
- package/templates/remoteconfig.template.json +1 -0
- package/templates/storage-lifecycle-config-1-day.json +9 -0
- package/templates/storage-lifecycle-config-30-days.json +9 -0
- package/templates/storage.rules +11 -0
- package/test/_init/accounts-validation.js +58 -0
- package/test/ai/tools-live.test.js +171 -0
- package/test/analytics/conversion-delivery.test.js +1013 -0
- package/test/analytics/match-normalization.test.js +238 -0
- package/test/analytics/signup-conversion.test.js +135 -0
- package/test/boot/cli-dispatch.test.js +142 -0
- package/test/boot/defaults-scaffold.test.js +248 -0
- package/test/boot/deploy-staging.test.js +446 -0
- package/test/boot/disposable-domains.test.js +154 -0
- package/test/boot/emulator-boots.test.js +39 -0
- package/test/boot/emulator-port-preflight.test.js +126 -0
- package/test/boot/emulator-ready-timeout.test.js +46 -0
- package/test/boot/project-id-refresh.test.js +73 -0
- package/test/boot/suite-portability.test.js +278 -0
- package/test/boot/update-command.test.js +63 -0
- package/test/cli/cross-platform.test.js +168 -0
- package/test/cli/custom-project-type.test.js +426 -0
- package/test/cli/deploy-license-env.test.js +100 -0
- package/test/cli/emulator-adoption.test.js +254 -0
- package/test/cli/emulator-orphans.test.js +658 -0
- package/test/cli/emulator-ownership.test.js +177 -0
- package/test/cli/emulator-port-retry.test.js +395 -0
- package/test/cli/emulator-shutdown.test.js +788 -0
- package/test/cli/emulator-stale-reap.test.js +574 -0
- package/test/cli/ensure-target.test.js +325 -0
- package/test/cli/flags.test.js +64 -0
- package/test/cli/https-trust.test.js +38 -0
- package/test/cli/install-update-dispatch.test.js +47 -0
- package/test/cli/lane-environments.test.js +159 -0
- package/test/cli/marketing-campaigns-seeded.test.js +194 -0
- package/test/cli/migrate-bare-requires.test.js +128 -0
- package/test/cli/migrate-markers.test.js +530 -0
- package/test/cli/required-indexes.test.js +64 -0
- package/test/cli/rules-compile.test.js +622 -0
- package/test/cli/rules-migration-deferral.test.js +259 -0
- package/test/cli/rules-version.test.js +104 -0
- package/test/cli/setup-load-files.test.js +66 -0
- package/test/cli/setup-offline-mode.test.js +276 -0
- package/test/cli/setup-retired.test.js +64 -0
- package/test/cli/setup-shared-project-indexes.test.js +262 -0
- package/test/cli/setup-tests-requires.test.js +45 -0
- package/test/cli/stage-env-compose.test.js +316 -0
- package/test/cli/stripe-live-lane.test.js +303 -0
- package/test/cli/target.test.js +182 -0
- package/test/cli/templates.test.js +66 -0
- package/test/cli/test-runner-env.test.js +115 -0
- package/test/cli/test-stack-shutdown.test.js +275 -0
- package/test/cli/test-target-no-match.test.js +128 -0
- package/test/cli/verb-logs.test.js +118 -0
- package/test/cli/version-dispatch.test.js +39 -0
- package/test/content/blog-generate.test.js +164 -0
- package/test/email/campaign-config-fault.test.js +376 -0
- package/test/email/campaign-cron-pipeline.test.js +536 -0
- package/test/email/campaign-send.test.js +47 -0
- package/test/email/consent-lifecycle.test.js +258 -0
- package/test/email/content-html-policy.test.js +270 -0
- package/test/email/feedback-and-plain-send.test.js +54 -0
- package/test/email/fixtures/clean.json +30 -0
- package/test/email/fixtures/editorial.json +30 -0
- package/test/email/fixtures/field-report.json +53 -0
- package/test/email/identity.test.js +321 -0
- package/test/email/marketing/consent-gate.test.js +265 -0
- package/test/email/marketing/custom-fields-catalog.test.js +259 -0
- package/test/email/marketing/prune-per-provider.test.js +762 -0
- package/test/email/marketing/remove-log-privacy.test.js +225 -0
- package/test/email/marketing-lifecycle.test.js +139 -0
- package/test/email/newsletter-generate.test.js +853 -0
- package/test/email/newsletter-svg-tokens.test.js +51 -0
- package/test/email/newsletter-templates.test.js +492 -0
- package/test/email/order-one-time-cta.test.js +97 -0
- package/test/email/render-content.test.js +248 -0
- package/test/email/safe-url.test.js +0 -0
- package/test/email/sanitize-images.test.js +66 -0
- package/test/email/send-log-privacy.test.js +107 -0
- package/test/email/templates.test.js +288 -0
- package/test/email/testing-capture.test.js +260 -0
- package/test/email/transactional-send.test.js +36 -0
- package/test/email/transactional.test.js +562 -0
- package/test/email/unsubscribe-groups.test.js +155 -0
- package/test/email/unsubscribe-key.test.js +91 -0
- package/test/email/validation-cases.test.js +152 -0
- package/test/email/validation.test.js +746 -0
- package/test/events/auth-delete-conversion.test.js +138 -0
- package/test/events/auth-delete-race.test.js +211 -0
- package/test/events/auth-on-create-log.test.js +164 -0
- package/test/events/auth-signup-conversion.test.js +141 -0
- package/test/events/auth-signup-limit.test.js +142 -0
- package/test/events/auth-trigger-log-privacy.test.js +256 -0
- package/test/events/cron-job-doc-shape.test.js +101 -0
- package/test/events/cron-reset-usage.test.js +116 -0
- package/test/events/notification-conversion.test.js +182 -0
- package/test/events/payments/_webhook-harness.js +307 -0
- package/test/events/payments/abandoned-cart-activity.test.js +135 -0
- package/test/events/payments/analytics-payment-events.test.js +945 -0
- package/test/events/payments/dispute-email-status.test.js +55 -0
- package/test/events/payments/journey-payments-abandoned.test.js +126 -0
- package/test/events/payments/journey-payments-cancel-endpoint.test.js +102 -0
- package/test/events/payments/journey-payments-cancel-no-order.test.js +76 -0
- package/test/events/payments/journey-payments-cancel.test.js +184 -0
- package/test/events/payments/journey-payments-decline.test.js +225 -0
- package/test/events/payments/journey-payments-discount.test.js +91 -0
- package/test/events/payments/journey-payments-dispute.test.js +190 -0
- package/test/events/payments/journey-payments-failure.test.js +148 -0
- package/test/events/payments/journey-payments-legacy-product.test.js +151 -0
- package/test/events/payments/journey-payments-one-time-decline.test.js +127 -0
- package/test/events/payments/journey-payments-one-time-failure.test.js +113 -0
- package/test/events/payments/journey-payments-one-time-refund.test.js +186 -0
- package/test/events/payments/journey-payments-one-time.test.js +175 -0
- package/test/events/payments/journey-payments-plan-change.test.js +146 -0
- package/test/events/payments/journey-payments-plan-switch-trial.test.js +161 -0
- package/test/events/payments/journey-payments-plan-switch.test.js +182 -0
- package/test/events/payments/journey-payments-refund-no-order.test.js +76 -0
- package/test/events/payments/journey-payments-refund-webhook.test.js +225 -0
- package/test/events/payments/journey-payments-suspend.test.js +183 -0
- package/test/events/payments/journey-payments-trial-cancel.test.js +132 -0
- package/test/events/payments/journey-payments-trial.test.js +173 -0
- package/test/events/payments/journey-payments-uid-resolution.test.js +134 -0
- package/test/events/payments/journey-payments-uncancel.test.js +157 -0
- package/test/events/payments/journey-payments-upgrade.test.js +137 -0
- package/test/events/payments/journey-payments-winback-decline.test.js +171 -0
- package/test/events/payments/journey-payments-winback.test.js +195 -0
- package/test/events/payments/paypal-expiry-cron.test.js +166 -0
- package/test/events/payments/purchase-failed-handler.test.js +80 -0
- package/test/events/payments/purchase-refunded-handler.test.js +108 -0
- package/test/events/payments/test-processor-doc-shape.test.js +162 -0
- package/test/events/payments/transition-order-emails.test.js +185 -0
- package/test/events/payments/transition-promo-lines.test.js +192 -0
- package/test/events/payments/transitions-detect.test.js +767 -0
- package/test/events/payments/trial-lapse-sweep-staleness.test.js +173 -0
- package/test/events/payments/trial-lapse-sweep.test.js +359 -0
- package/test/events/payments/webhook-atomic-writes.test.js +69 -0
- package/test/events/payments/webhook-chargebee-unreachable.test.js +106 -0
- package/test/events/payments/webhook-discount-clear.test.js +189 -0
- package/test/events/payments/webhook-failure-intent.test.js +93 -0
- package/test/events/payments/webhook-hosted-page-uid-trust.test.js +212 -0
- package/test/events/payments/webhook-ordering.test.js +326 -0
- package/test/events/payments/webhook-provider-lookup-trust.test.js +206 -0
- package/test/events/payments/webhook-refund-amount-trust.test.js +223 -0
- package/test/events/payments/webhook-refund-envelope-shape.test.js +148 -0
- package/test/events/payments/webhook-refund-linkage-trust.test.js +404 -0
- package/test/events/payments/webhook-refund-transaction-fallback.test.js +184 -0
- package/test/events/payments/webhook-refund-without-order.test.js +170 -0
- package/test/events/payments/webhook-refusal-reporting.test.js +194 -0
- package/test/events/payments/webhook-refused-intent.test.js +142 -0
- package/test/events/payments/webhook-retry-sweep.test.js +252 -0
- package/test/events/payments/webhook-transition-claim.test.js +389 -0
- package/test/events/payments/webhook-uid-trust.test.js +203 -0
- package/test/events/payments/webhook-user-without-auth.test.js +161 -0
- package/test/fixtures/chargebee/invoice-one-time.json +27 -0
- package/test/fixtures/chargebee/subscription-active.json +44 -0
- package/test/fixtures/chargebee/subscription-cancelled.json +42 -0
- package/test/fixtures/chargebee/subscription-in-trial.json +41 -0
- package/test/fixtures/chargebee/subscription-legacy-plan.json +41 -0
- package/test/fixtures/chargebee/subscription-non-renewing.json +41 -0
- package/test/fixtures/chargebee/subscription-paused.json +42 -0
- package/test/fixtures/chargebee/webhook-payment-failed.json +51 -0
- package/test/fixtures/chargebee/webhook-subscription-created.json +47 -0
- package/test/fixtures/coinbase/charge-confirmed.json +50 -0
- package/test/fixtures/coinbase/charge-failed.json +34 -0
- package/test/fixtures/coinbase/charge-pending.json +34 -0
- package/test/fixtures/migrate/ported-route.js.txt +11 -0
- package/test/fixtures/paypal/capture-completed.json +51 -0
- package/test/fixtures/paypal/capture-refunded.json +43 -0
- package/test/fixtures/paypal/order-approved.json +62 -0
- package/test/fixtures/paypal/order-completed.json +110 -0
- package/test/fixtures/paypal/sale-refunded.json +38 -0
- package/test/fixtures/paypal/subscription-active.json +76 -0
- package/test/fixtures/paypal/subscription-cancelled.json +50 -0
- package/test/fixtures/paypal/subscription-suspended.json +65 -0
- package/test/fixtures/stripe/checkout-session-completed.json +130 -0
- package/test/fixtures/stripe/invoice-payment-failed.json +148 -0
- package/test/fixtures/stripe/invoice-subscription-payment-failed.json +28 -0
- package/test/fixtures/stripe/invoice-subscription-payment-succeeded.json +28 -0
- package/test/fixtures/stripe/subscription-active.json +161 -0
- package/test/fixtures/stripe/subscription-canceled.json +161 -0
- package/test/fixtures/stripe/subscription-trialing.json +161 -0
- package/test/helpers/_shared-config.js +15 -0
- package/test/helpers/ai-request-payload.test.js +619 -0
- package/test/helpers/ai-schema-resolve.test.js +125 -0
- package/test/helpers/ai-test-provider.test.js +227 -0
- package/test/helpers/ai-token-accounting.test.js +150 -0
- package/test/helpers/ai-tools-format.test.js +384 -0
- package/test/helpers/analytics-no-id-notice.test.js +146 -0
- package/test/helpers/analytics-user-data.test.js +194 -0
- package/test/helpers/api-manager.test.js +311 -0
- package/test/helpers/backend-router.test.js +136 -0
- package/test/helpers/content/blog-auto-publisher.test.js +482 -0
- package/test/helpers/content/feed-parser.test.js +529 -0
- package/test/helpers/content/ghostii-blocks.test.js +135 -0
- package/test/helpers/content/ghostii-feed-integration.test.js +405 -0
- package/test/helpers/content/ghostii-write-article.test.js +244 -0
- package/test/helpers/dev-only-routes.test.js +225 -0
- package/test/helpers/env-reader.test.js +362 -0
- package/test/helpers/environment.test.js +263 -0
- package/test/helpers/event-middleware.test.js +407 -0
- package/test/helpers/infer-contact.test.js +157 -0
- package/test/helpers/lane-url.test.js +90 -0
- package/test/helpers/merge-line-files.test.js +272 -0
- package/test/helpers/metadata.test.js +122 -0
- package/test/helpers/middleware-request-log.test.js +134 -0
- package/test/helpers/middleware-user-log.test.js +124 -0
- package/test/helpers/payment/chargebee/parse-webhook.test.js +490 -0
- package/test/helpers/payment/chargebee/refund-details.test.js +198 -0
- package/test/helpers/payment/chargebee/to-unified-one-time.test.js +148 -0
- package/test/helpers/payment/chargebee/to-unified-subscription.test.js +649 -0
- package/test/helpers/payment/coinbase/create-intent.test.js +247 -0
- package/test/helpers/payment/coinbase/parse-webhook.test.js +195 -0
- package/test/helpers/payment/coinbase/refund-unsupported.test.js +141 -0
- package/test/helpers/payment/coinbase/to-unified-one-time.test.js +201 -0
- package/test/helpers/payment/discount-codes.test.js +141 -0
- package/test/helpers/payment/extract-resource.test.js +113 -0
- package/test/helpers/payment/fetch-failure.test.js +215 -0
- package/test/helpers/payment/license-gate.test.js +108 -0
- package/test/helpers/payment/order-id.test.js +99 -0
- package/test/helpers/payment/paypal/create-intent.test.js +382 -0
- package/test/helpers/payment/paypal/fetch-capture.test.js +123 -0
- package/test/helpers/payment/paypal/fetch-sale.test.js +183 -0
- package/test/helpers/payment/paypal/parse-webhook.test.js +678 -0
- package/test/helpers/payment/paypal/refund-details.test.js +202 -0
- package/test/helpers/payment/paypal/resolve-plan-id.test.js +108 -0
- package/test/helpers/payment/paypal/switch-plan.test.js +92 -0
- package/test/helpers/payment/paypal/to-unified-one-time.test.js +383 -0
- package/test/helpers/payment/paypal/to-unified-subscription.test.js +884 -0
- package/test/helpers/payment/stripe/fetch-charge.test.js +147 -0
- package/test/helpers/payment/stripe/parse-webhook.test.js +448 -0
- package/test/helpers/payment/stripe/refund-details.test.js +147 -0
- package/test/helpers/payment/stripe/to-unified-one-time.test.js +307 -0
- package/test/helpers/payment/stripe/to-unified-subscription.test.js +709 -0
- package/test/helpers/persona-domain.test.js +87 -0
- package/test/helpers/recaptcha.test.js +166 -0
- package/test/helpers/resolved-config.test.js +106 -0
- package/test/helpers/response-log-redaction.test.js +262 -0
- package/test/helpers/roles.test.js +155 -0
- package/test/helpers/route-context-debug-gate.test.js +118 -0
- package/test/helpers/route-context-logging.test.js +214 -0
- package/test/helpers/route-context.test.js +129 -0
- package/test/helpers/safe-compare.test.js +114 -0
- package/test/helpers/sanitize.test.js +223 -0
- package/test/helpers/schema-engine.test.js +537 -0
- package/test/helpers/schema-zod.test.js +554 -0
- package/test/helpers/seed-accounts-load.test.js +163 -0
- package/test/helpers/seed-google-personas.test.js +114 -0
- package/test/helpers/seeded-personas.test.js +823 -0
- package/test/helpers/settings.test.js +292 -0
- package/test/helpers/setup-engines-pin.test.js +68 -0
- package/test/helpers/setup-manifest-sync.test.js +116 -0
- package/test/helpers/slugify.test.js +395 -0
- package/test/helpers/storage.test.js +195 -0
- package/test/helpers/test-banner-latch.test.js +139 -0
- package/test/helpers/usage-consume.test.js +460 -0
- package/test/helpers/usage-log-privacy.test.js +121 -0
- package/test/helpers/user-doc-heal.test.js +540 -0
- package/test/helpers/user.test.js +771 -0
- package/test/helpers/webhook-forward.test.js +419 -0
- package/test/helpers/wipe-auth-project.test.js +143 -0
- package/test/mcp/discovery.test.js +52 -0
- package/test/mcp/oauth.test.js +160 -0
- package/test/mcp/protocol.test.js +278 -0
- package/test/mcp/roles.test.js +203 -0
- package/test/mcp/utils.test.js +245 -0
- package/test/notification/identity.test.js +155 -0
- package/test/routes/admin/create-post.test.js +362 -0
- package/test/routes/admin/database.test.js +133 -0
- package/test/routes/admin/deduplicate-image-alts.test.js +191 -0
- package/test/routes/admin/email-content-html.test.js +58 -0
- package/test/routes/admin/email-request-log.test.js +86 -0
- package/test/routes/admin/email.test.js +116 -0
- package/test/routes/admin/firestore-query.test.js +206 -0
- package/test/routes/admin/firestore.test.js +129 -0
- package/test/routes/admin/infer-contact.test.js +220 -0
- package/test/routes/admin/notification.test.js +199 -0
- package/test/routes/admin/post-convert-image.test.js +159 -0
- package/test/routes/admin/post-deploy-flag.test.js +81 -0
- package/test/routes/admin/post-download-error.test.js +90 -0
- package/test/routes/admin/post-resize-image.test.js +185 -0
- package/test/routes/admin/post.test.js +369 -0
- package/test/routes/admin/repo-content.test.js +223 -0
- package/test/routes/admin/stats.test.js +114 -0
- package/test/routes/admin/users-disable.test.js +63 -0
- package/test/routes/admin/users-list.test.js +71 -0
- package/test/routes/content/post.test.js +60 -0
- package/test/routes/general/uuid.test.js +133 -0
- package/test/routes/health.test.js +110 -0
- package/test/routes/marketing/campaign.test.js +184 -0
- package/test/routes/marketing/contact.test.js +416 -0
- package/test/routes/marketing/email-preferences.test.js +293 -0
- package/test/routes/marketing/push-send.test.js +34 -0
- package/test/routes/marketing/webhook-forward.test.js +63 -0
- package/test/routes/marketing/webhook.test.js +641 -0
- package/test/routes/payments/_route-harness.js +145 -0
- package/test/routes/payments/cancel-provider-errors.test.js +227 -0
- package/test/routes/payments/cancel-skip-guards.test.js +126 -0
- package/test/routes/payments/cancel-trialing.test.js +428 -0
- package/test/routes/payments/cancel.test.js +165 -0
- package/test/routes/payments/dedup-race.test.js +186 -0
- package/test/routes/payments/discount.test.js +82 -0
- package/test/routes/payments/dispute-alert.test.js +324 -0
- package/test/routes/payments/intent-discount-amounts.test.js +550 -0
- package/test/routes/payments/intent-discount-coupons.test.js +293 -0
- package/test/routes/payments/intent-one-time-metadata.test.js +122 -0
- package/test/routes/payments/intent-purchaser-guard.test.js +139 -0
- package/test/routes/payments/intent-zero-total.test.js +260 -0
- package/test/routes/payments/intent.test.js +413 -0
- package/test/routes/payments/plan.test.js +367 -0
- package/test/routes/payments/portal-return-url.test.js +107 -0
- package/test/routes/payments/portal.test.js +94 -0
- package/test/routes/payments/refund-one-time.test.js +254 -0
- package/test/routes/payments/refund-paypal-proration.test.js +190 -0
- package/test/routes/payments/refund.test.js +181 -0
- package/test/routes/payments/trial-eligibility.test.js +73 -0
- package/test/routes/payments/uncancel.test.js +270 -0
- package/test/routes/payments/webhook-stripe-invoice.test.js +129 -0
- package/test/routes/payments/webhook-stripe-refund-one-time.test.js +130 -0
- package/test/routes/payments/webhook-test-provider.test.js +156 -0
- package/test/routes/payments/webhook.test.js +115 -0
- package/test/routes/payments/winback-stripe-coupon.test.js +126 -0
- package/test/routes/payments/winback.test.js +597 -0
- package/test/routes/test/authenticate.test.js +79 -0
- package/test/routes/test/redirect.test.js +66 -0
- package/test/routes/test/reset-account.test.js +126 -0
- package/test/routes/test/roster.test.js +101 -0
- package/test/routes/test/schema.test.js +556 -0
- package/test/routes/test/usage.test.js +374 -0
- package/test/routes/user/api-keys.test.js +158 -0
- package/test/routes/user/connections-grant.test.js +759 -0
- package/test/routes/user/connections-identity.test.js +260 -0
- package/test/routes/user/connections-log-privacy.test.js +206 -0
- package/test/routes/user/connections-refresh-lease.test.js +696 -0
- package/test/routes/user/connections-return.test.js +261 -0
- package/test/routes/user/connections-uid.test.js +516 -0
- package/test/routes/user/delete.test.js +138 -0
- package/test/routes/user/feedback.test.js +106 -0
- package/test/routes/user/orders.test.js +233 -0
- package/test/routes/user/sessions.test.js +231 -0
- package/test/routes/user/settings-validate.test.js +84 -0
- package/test/routes/user/signup-emails.test.js +113 -0
- package/test/routes/user/signup-location.test.js +84 -0
- package/test/routes/user/signup-log-privacy.test.js +112 -0
- package/test/routes/user/signup.test.js +579 -0
- package/test/routes/user/subscription.test.js +101 -0
- package/test/routes/user/token.test.js +111 -0
- package/test/routes/user/user.test.js +158 -0
- package/test/routes/verts/cache.test.js +78 -0
- package/test/routes/verts/click-destination.test.js +76 -0
- package/test/routes/verts/crud.test.js +194 -0
- package/test/routes/verts/redirect.test.js +147 -0
- package/test/routes/verts/selection.test.js +237 -0
- package/test/routes/verts/serve.test.js +185 -0
- package/test/routes/verts/unit-document.test.js +117 -0
- package/test/rules/_environment.js +66 -0
- package/test/rules/brand-merge.test.js +195 -0
- package/test/rules/field-helpers.test.js +309 -0
- package/test/rules/notifications.test.js +577 -0
- package/test/rules/payments-carts.test.js +406 -0
- package/test/rules/sessions.test.js +170 -0
- package/test/rules/user.test.js +517 -0
- package/test/rules/verts.test.js +101 -0
- package/test/security/fetch-log-secrets.test.js +124 -0
- package/test/security/primitives.test.js +105 -0
- package/test/security/repo-pinning.test.js +77 -0
- package/test/stripe-live/subscription-lifecycle.test.js +141 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
const BaseCommand = require('./base-command');
|
|
2
|
+
const chalk = require('chalk').default;
|
|
3
|
+
const powertools = require('node-powertools');
|
|
4
|
+
const attachLogFile = require('../utils/attach-log-file');
|
|
5
|
+
const stageLocalPackages = require('../utils/stage-local-packages');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const jetpack = require('fs-jetpack');
|
|
8
|
+
const { refuseWhenCustom } = require('../utils/project-type');
|
|
9
|
+
const { loadConfig, loadEnv } = require('../../vendor/config/index.js');
|
|
10
|
+
const { resolveLicenseStamp } = require('../../vendor/devkit/license.js');
|
|
11
|
+
|
|
12
|
+
const DEFAULT_REGION = 'us-central1';
|
|
13
|
+
|
|
14
|
+
class DeployCommand extends BaseCommand {
|
|
15
|
+
async execute() {
|
|
16
|
+
const self = this.main;
|
|
17
|
+
|
|
18
|
+
// Custom-server mode has no Cloud Functions to publish (#584) — refuse
|
|
19
|
+
// before staging, so nothing is written for a deploy that cannot happen.
|
|
20
|
+
if (refuseWhenCustom(self.firebaseProjectPath, 'deploy')) return;
|
|
21
|
+
|
|
22
|
+
const logPath = this.getLogsPath('deploy.log');
|
|
23
|
+
attachLogFile(logPath);
|
|
24
|
+
this.log(chalk.gray(` Logs saving to: ${logPath}\n`));
|
|
25
|
+
|
|
26
|
+
// The .env cascade, loaded HERE because nothing else in the CLI boot does:
|
|
27
|
+
// the license key below is read from this process's environment, and a
|
|
28
|
+
// licensed brand keeps OMEGA_LICENSE_KEY in the brand root's .env. Named
|
|
29
|
+
// `production` — the same environment the stage below composes dist/.env
|
|
30
|
+
// for (#586), so the verdict and the artifact read one overlay.
|
|
31
|
+
loadEnv(path.join(self.firebaseProjectPath, 'dist'), { environment: 'production' });
|
|
32
|
+
|
|
33
|
+
// The license check ([#320](https://github.com/Omega-JS-Stack/omega/issues/320)),
|
|
34
|
+
// once per deploy and BEFORE the stage: a backend deploy runs straight
|
|
35
|
+
// from the CLI, so the key comes out of the .env cascade in this process
|
|
36
|
+
// and never near the artifact. The verdict itself rides the composed
|
|
37
|
+
// dist/.env as OMEGA_LICENSE_STATUS — a keyless deploy gates the payment
|
|
38
|
+
// provider libraries at runtime. A key that cannot be answered for throws
|
|
39
|
+
// here, which stops the deploy rather than shipping the wrong verdict.
|
|
40
|
+
const licenseStatus = (await resolveLicenseStamp({
|
|
41
|
+
config: loadConfig(self.firebaseProjectPath, 'backend').config,
|
|
42
|
+
production: true,
|
|
43
|
+
})).status;
|
|
44
|
+
this.log(chalk.gray(` License: ${licenseStatus}\n`));
|
|
45
|
+
|
|
46
|
+
// dist/ is staged output (src/dist pillar): a fresh stage carries the
|
|
47
|
+
// composed config + public/ hosting boilerplate across the upload boundary.
|
|
48
|
+
// The upload is composed for PRODUCTION — base .env + `.env.production`,
|
|
49
|
+
// and no other environment's overlay ever rides along (#586).
|
|
50
|
+
this.ensureStaged({ environment: 'production', licenseStatus });
|
|
51
|
+
|
|
52
|
+
// --only pass-through (e.g. `omega deploy --only hosting` — deploys
|
|
53
|
+
// hosting on Spark plans where functions would demand Blaze)
|
|
54
|
+
const only = self.argv?.only ? ` --only ${self.argv.only}` : '';
|
|
55
|
+
|
|
56
|
+
// Local file: dependencies (local-first @omega.js packages) can't be
|
|
57
|
+
// followed by Cloud Build — stage them into the upload as packed tarballs
|
|
58
|
+
const firebaseJSON = jetpack.read(path.join(self.firebaseProjectPath, 'firebase.json'), 'json') || {};
|
|
59
|
+
const functionsBlock = Array.isArray(firebaseJSON.functions) ? firebaseJSON.functions[0] : firebaseJSON.functions;
|
|
60
|
+
const functionsPath = path.join(self.firebaseProjectPath, functionsBlock?.source || 'dist');
|
|
61
|
+
const deployingFunctions = !self.argv?.only || String(self.argv.only).split(',').some((t) => t.trim().startsWith('functions'));
|
|
62
|
+
|
|
63
|
+
// Without an Artifact Registry cleanup policy, firebase deploy EXITS 1
|
|
64
|
+
// after a successful functions deploy — and the post-steps below (public
|
|
65
|
+
// invoker) never run. Ensure it up front.
|
|
66
|
+
if (deployingFunctions) {
|
|
67
|
+
await this.ensureArtifactCleanupPolicy();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const staging = deployingFunctions
|
|
71
|
+
? await stageLocalPackages({ functionsPath, log: (message) => this.log(message) })
|
|
72
|
+
: null;
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
await powertools.execute(`firebase deploy${only}`, {
|
|
76
|
+
log: false,
|
|
77
|
+
config: {
|
|
78
|
+
cwd: self.firebaseProjectPath,
|
|
79
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
80
|
+
env: { ...process.env, FORCE_COLOR: '1' },
|
|
81
|
+
},
|
|
82
|
+
}, (child) => {
|
|
83
|
+
child.stdout.on('data', (data) => process.stdout.write(data));
|
|
84
|
+
child.stderr.on('data', (data) => process.stderr.write(data));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
require('../../vendor/devkit/deploy-record.js').recordDeploy({ dir: self.firebaseProjectPath, target: 'backend', detail: { method: 'firebase' } });
|
|
88
|
+
|
|
89
|
+
// After successful deploy, ensure HTTP functions are publicly invocable
|
|
90
|
+
await this.ensurePublicInvoker();
|
|
91
|
+
} finally {
|
|
92
|
+
if (staging) {
|
|
93
|
+
await staging.restore();
|
|
94
|
+
}
|
|
95
|
+
await attachLogFile.detach();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Ensure the Artifact Registry cleanup policy exists (old container images
|
|
101
|
+
* auto-delete). Best-effort: Spark plans, a disabled API, or a first-ever
|
|
102
|
+
* deploy (no gcf-artifacts repo yet) just skip — deploy proceeds either way.
|
|
103
|
+
*/
|
|
104
|
+
async ensureArtifactCleanupPolicy() {
|
|
105
|
+
try {
|
|
106
|
+
await powertools.execute('firebase functions:artifacts:setpolicy --force', {
|
|
107
|
+
log: false,
|
|
108
|
+
config: { cwd: this.main.firebaseProjectPath },
|
|
109
|
+
});
|
|
110
|
+
this.log(chalk.gray(' Artifact cleanup policy ensured\n'));
|
|
111
|
+
} catch (e) {
|
|
112
|
+
// Non-fatal — the deploy itself doesn't need the policy
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Ensure all HTTP-triggered functions have allUsers as cloudfunctions.invoker.
|
|
118
|
+
*
|
|
119
|
+
* Firebase CLI used to set this automatically but stopped around the Node 10
|
|
120
|
+
* runtime transition. Without it, HTTP requests get a 403 at the IAM level
|
|
121
|
+
* before @omega.js/backend's application-level auth (the omega-admin-key header) can run.
|
|
122
|
+
*
|
|
123
|
+
* Dynamically discovers all deployed functions via gcloud and fixes any
|
|
124
|
+
* HTTP-triggered function missing the allUsers invoker binding.
|
|
125
|
+
*/
|
|
126
|
+
async ensurePublicInvoker() {
|
|
127
|
+
const projectId = this.getProjectId();
|
|
128
|
+
|
|
129
|
+
if (!projectId) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Discover all deployed HTTP-triggered functions
|
|
134
|
+
let httpFunctions;
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const output = await powertools.execute(
|
|
138
|
+
`gcloud functions list --project ${projectId} --regions ${DEFAULT_REGION} --format="json(name,httpsTrigger)"`,
|
|
139
|
+
{ log: false },
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
httpFunctions = JSON.parse(output)
|
|
143
|
+
.filter((fn) => fn.httpsTrigger)
|
|
144
|
+
.map((fn) => fn.name.split('/').pop());
|
|
145
|
+
} catch {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!httpFunctions.length) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.log(chalk.gray('\n Ensuring HTTP functions are publicly invocable...\n'));
|
|
154
|
+
|
|
155
|
+
let fixed = 0;
|
|
156
|
+
let ok = 0;
|
|
157
|
+
|
|
158
|
+
for (const fnName of httpFunctions) {
|
|
159
|
+
try {
|
|
160
|
+
const policyOutput = await powertools.execute(
|
|
161
|
+
`gcloud functions get-iam-policy ${fnName} --project ${projectId} --region ${DEFAULT_REGION} --format=json`,
|
|
162
|
+
{ log: false },
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const policy = JSON.parse(policyOutput);
|
|
166
|
+
const hasAllUsers = (policy.bindings || []).some(
|
|
167
|
+
(b) => b.role === 'roles/cloudfunctions.invoker'
|
|
168
|
+
&& (b.members || []).includes('allUsers'),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
if (hasAllUsers) {
|
|
172
|
+
ok++;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
await powertools.execute(
|
|
177
|
+
`gcloud functions add-iam-policy-binding ${fnName} --project ${projectId} --region ${DEFAULT_REGION} --member="allUsers" --role="roles/cloudfunctions.invoker"`,
|
|
178
|
+
{ log: false },
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
this.log(` ${chalk.green('✓')} Set public invoker on ${chalk.cyan(fnName)}`);
|
|
182
|
+
fixed++;
|
|
183
|
+
} catch {
|
|
184
|
+
// Skip silently — function may be in a transient state
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (fixed > 0) {
|
|
189
|
+
this.log(` ${chalk.green('✓')} Public invoker: ${ok + fixed} functions accessible (${fixed} just fixed)\n`);
|
|
190
|
+
} else if (ok > 0) {
|
|
191
|
+
this.log(` ${chalk.green('✓')} Public invoker: ${ok} functions accessible\n`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
getProjectId() {
|
|
196
|
+
try {
|
|
197
|
+
const firebaserc = jetpack.read(path.join(this.main.firebaseProjectPath, '.firebaserc'), 'json');
|
|
198
|
+
return firebaserc?.projects?.default;
|
|
199
|
+
} catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
module.exports = DeployCommand;
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The machine-wide orphan reap every emulator boot runs before it claims a port
|
|
3
|
+
* ([#781](https://github.com/Omega-JS-Stack/omega/issues/781)).
|
|
4
|
+
*
|
|
5
|
+
* Emulator processes outlive the run that started them whenever the parent is
|
|
6
|
+
* killed by pid, force-killed, or torn down with its shell: firebase-tools puts
|
|
7
|
+
* each emulator in its own process group, so the survivors reparent to PID 1
|
|
8
|
+
* and hold memory and ports until somebody notices. Found on a real machine:
|
|
9
|
+
* ~100 `functionsEmulatorRuntime` workers from a node version that machine no
|
|
10
|
+
* longer runs, plus a hub on a BUMPED port with three java jars, parent gone
|
|
11
|
+
* for hours.
|
|
12
|
+
*
|
|
13
|
+
* The two reapers this file joins could reach none of it. The port-driven one
|
|
14
|
+
* only ever looked at the ports THIS run wants, and the record-driven one only
|
|
15
|
+
* at pids a record still names — a hub on 4402 belonging to a legacy run is
|
|
16
|
+
* outside both by construction.
|
|
17
|
+
*
|
|
18
|
+
* **The verdict is parentage AND a strict family match, both required, and no
|
|
19
|
+
* ownership proof at all.** An orphan of the emulator family is NOBODY's: it is
|
|
20
|
+
* reaped whatever project it names (Ian 2026-09-03, docs/shared/rulings.md),
|
|
21
|
+
* which supersedes the [#293](https://github.com/Omega-JS-Stack/omega/issues/293)
|
|
22
|
+
* line that another brand's orphans stay. The #293 lesson survives as the
|
|
23
|
+
* FAMILY half: a name matching `/emulator|firebase/i` killed another session's
|
|
24
|
+
* reload watcher, so nothing here matches on a name, on a port, or on the words
|
|
25
|
+
* `node`, `java`, `firebase` or `firebase-functions` alone — only on the exact
|
|
26
|
+
* command shapes below: the hub, the functions runtime worker, the functions
|
|
27
|
+
* discovery server, an emulator jar out of the firebase cache, and puppeteer's
|
|
28
|
+
* headless browser.
|
|
29
|
+
*
|
|
30
|
+
* Everything the sweep reads or does goes through a seam, so its verdicts are
|
|
31
|
+
* testable against real `ps` rows without a single live process.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
// Libraries
|
|
35
|
+
const powertools = require('node-powertools');
|
|
36
|
+
const { isPortFree } = require('../../vendor/config/index.js');
|
|
37
|
+
|
|
38
|
+
// ONE snapshot of every process on the machine, in the four fields the verdict
|
|
39
|
+
// needs. Read once: two `ps` calls describe two moments, and a number that
|
|
40
|
+
// changed hands between them reads as one process that never existed
|
|
41
|
+
// ([#730](https://github.com/Omega-JS-Stack/omega/issues/730)).
|
|
42
|
+
const PROCESS_TABLE_COMMAND = 'ps -A -o pid=,ppid=,uid=,command=';
|
|
43
|
+
|
|
44
|
+
// A busy machine prints a few hundred KB of table, and a command line can be
|
|
45
|
+
// long; the default 1MB buffer is a limit this must never bump into.
|
|
46
|
+
const PROCESS_TABLE_MAX_BUFFER = 16 * 1024 * 1024;
|
|
47
|
+
const PROCESS_READ_TIMEOUT_MS = 5000;
|
|
48
|
+
|
|
49
|
+
// The settle windows, as DEFAULTS only: the boot passes its own STOP_GRACE_MS,
|
|
50
|
+
// PORT_RELEASE_TIMEOUT_MS and POLL_INTERVAL_MS in, so emulator.js stays the one
|
|
51
|
+
// home of the numbers. They are restated here because the command requires THIS
|
|
52
|
+
// module, never the other way round, and a sweep run standalone must still
|
|
53
|
+
// settle before it answers.
|
|
54
|
+
const DEFAULT_GRACE_MS = 2000;
|
|
55
|
+
const DEFAULT_PORT_RELEASE_TIMEOUT_MS = 5000;
|
|
56
|
+
const DEFAULT_POLL_INTERVAL_MS = 100;
|
|
57
|
+
|
|
58
|
+
// The hub: `firebase emulators:start` (or `:exec`), reached either through the
|
|
59
|
+
// bin on PATH or through firebase-tools' own entry file. The VERB is what makes
|
|
60
|
+
// it the hub — `firebase deploy` is a live publish and never matches.
|
|
61
|
+
const HUB_BIN = /(^|\/)firebase(\.js)?\s+(emulators:start|emulators:exec)\b/;
|
|
62
|
+
const HUB_TOOLS_ENTRY = /firebase-tools\/lib\/bin\/firebase\.js\b/;
|
|
63
|
+
const HUB_VERB = /\bemulators:(start|exec)\b/;
|
|
64
|
+
|
|
65
|
+
// The functions worker, by the module path firebase-tools runs it as. No node
|
|
66
|
+
// version and no install prefix is part of it: the pile found on the machine
|
|
67
|
+
// came from a node v22 install beside a v24 one.
|
|
68
|
+
const FUNCTIONS_WORKER = /firebase-tools\/lib\/emulator\/functionsEmulatorRuntime\b/;
|
|
69
|
+
|
|
70
|
+
// The functions DISCOVERY server: firebase-tools runs the functions source's
|
|
71
|
+
// own `firebase-functions` bin to read the manifest off a random port, then
|
|
72
|
+
// asks it to quit — so a hub that dies inside that window leaves it holding the
|
|
73
|
+
// port forever ([#805](https://github.com/Omega-JS-Stack/omega/issues/805)).
|
|
74
|
+
// A node RUNNING one of its two entry paths is the whole match: the words
|
|
75
|
+
// `firebase-functions` in an argv are somebody reading the package, not it. The
|
|
76
|
+
// path is reached from a space as well as a slash — a hub started inside the
|
|
77
|
+
// functions source spawns it with a bare-relative path and nothing before it.
|
|
78
|
+
const NODE_BIN = /(^|\/)node\s/;
|
|
79
|
+
const FUNCTIONS_DISCOVERY_BIN = /(^|[\s/])node_modules\/\.bin\/firebase-functions(\s|$)/;
|
|
80
|
+
const FUNCTIONS_DISCOVERY_ENTRY = /(^|[\s/])firebase-functions\/lib\/bin\/firebase-functions\.js(\s|$)/;
|
|
81
|
+
|
|
82
|
+
// An emulator jar, by all four parts together: a java binary, a `-jar`, the
|
|
83
|
+
// firebase emulator cache the jar was downloaded into, and a `.jar`. A jar
|
|
84
|
+
// somewhere else on disk is somebody's application.
|
|
85
|
+
const JAVA_BIN = /(^|\/)java\s/;
|
|
86
|
+
const JAR_FLAG = /\s-jar\s/;
|
|
87
|
+
const JAR_PATH = /-jar\s+(\S*\/firebase\/emulators\/\S*\.jar)\b/;
|
|
88
|
+
|
|
89
|
+
// Puppeteer's browser, by the temp profile it is launched with. Only puppeteer
|
|
90
|
+
// ever creates a `puppeteer_dev_chrome_profile-` directory, so the flag alone
|
|
91
|
+
// separates a lane's headless Chrome from the one a user opened from Finder.
|
|
92
|
+
const PUPPETEER_PROFILE = /--user-data-dir=\S*puppeteer_dev_chrome_profile-/;
|
|
93
|
+
|
|
94
|
+
// Which emulator a jar is, decided on the JAR PATH rather than the argv: the
|
|
95
|
+
// firestore jar is launched with `--database-edition standard`, so reading the
|
|
96
|
+
// whole command line calls it the database emulator. First match wins.
|
|
97
|
+
const JAR_NAMES = [
|
|
98
|
+
{ pattern: /firestore/i, label: 'firestore jar' },
|
|
99
|
+
{ pattern: /pubsub/i, label: 'pubsub jar' },
|
|
100
|
+
{ pattern: /database/i, label: 'database jar' },
|
|
101
|
+
{ pattern: /storage/i, label: 'storage jar' },
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Which emulator jar a java command line is running, by its jar path.
|
|
106
|
+
* @param {string} command - Full command line from ps.
|
|
107
|
+
* @returns {string} The short label; `emulator jar` for one the cache grows later.
|
|
108
|
+
*/
|
|
109
|
+
function describeJar(command) {
|
|
110
|
+
const jar = JAR_PATH.exec(command);
|
|
111
|
+
const named = JAR_NAMES.find((entry) => entry.pattern.test(jar ? jar[1] : ''));
|
|
112
|
+
|
|
113
|
+
return named ? named.label : 'emulator jar';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Does this command line run the firebase emulator hub?
|
|
118
|
+
* @param {string} command - Full command line from ps.
|
|
119
|
+
* @returns {boolean}
|
|
120
|
+
*/
|
|
121
|
+
function isEmulatorHub(command) {
|
|
122
|
+
return HUB_BIN.test(command) || (HUB_TOOLS_ENTRY.test(command) && HUB_VERB.test(command));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Does this command line run the functions discovery server?
|
|
127
|
+
* @param {string} command - Full command line from ps.
|
|
128
|
+
* @returns {boolean}
|
|
129
|
+
*/
|
|
130
|
+
function isFunctionsDiscovery(command) {
|
|
131
|
+
return NODE_BIN.test(command)
|
|
132
|
+
&& (FUNCTIONS_DISCOVERY_BIN.test(command) || FUNCTIONS_DISCOVERY_ENTRY.test(command));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Does this command line run an emulator jar out of the firebase cache?
|
|
137
|
+
* @param {string} command - Full command line from ps.
|
|
138
|
+
* @returns {boolean}
|
|
139
|
+
*/
|
|
140
|
+
function isEmulatorJar(command) {
|
|
141
|
+
return JAVA_BIN.test(command) && JAR_FLAG.test(command) && JAR_PATH.test(command);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// The WHOLE family, as one table: the shapes and their short names have a
|
|
145
|
+
// single home, so the verdict and the log line can never come to disagree.
|
|
146
|
+
const FAMILY_SHAPES = [
|
|
147
|
+
{ matches: isEmulatorHub, label: () => 'firebase hub' },
|
|
148
|
+
{ matches: (command) => FUNCTIONS_WORKER.test(command), label: () => 'functions worker' },
|
|
149
|
+
{ matches: isFunctionsDiscovery, label: () => 'functions discovery server' },
|
|
150
|
+
{ matches: (command) => PUPPETEER_PROFILE.test(command), label: () => 'puppeteer chrome' },
|
|
151
|
+
{ matches: isEmulatorJar, label: describeJar },
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Rows from one `ps -A -o pid=,ppid=,uid=,command=` snapshot.
|
|
156
|
+
*
|
|
157
|
+
* A line that does not read as three numbers and a command is dropped rather
|
|
158
|
+
* than guessed at: a half-parsed row would be a kill order built on nothing.
|
|
159
|
+
* @param {string} text - The raw ps output.
|
|
160
|
+
* @returns {Array<{pid: number, ppid: number, uid: number, command: string}>}
|
|
161
|
+
*/
|
|
162
|
+
function parseProcessTable(text) {
|
|
163
|
+
return String(text || '')
|
|
164
|
+
.split('\n')
|
|
165
|
+
.map((line) => /^\s*(\d+)\s+(\d+)\s+(\d+)\s+(.+)$/.exec(line))
|
|
166
|
+
.filter((match) => !!match)
|
|
167
|
+
.map((match) => ({
|
|
168
|
+
pid: Number(match[1]),
|
|
169
|
+
ppid: Number(match[2]),
|
|
170
|
+
uid: Number(match[3]),
|
|
171
|
+
command: match[4],
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* The short name for a family member's command line, for the boot's one line.
|
|
177
|
+
* @param {string} command - Full command line from ps.
|
|
178
|
+
* @returns {string|null} The label, or null when the command is not family.
|
|
179
|
+
*/
|
|
180
|
+
function describeFamilyMember(command) {
|
|
181
|
+
const text = String(command || '');
|
|
182
|
+
const shape = FAMILY_SHAPES.find((entry) => entry.matches(text));
|
|
183
|
+
|
|
184
|
+
return shape ? shape.label(text) : null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Is this row an ORPHANED emulator-family process of THIS user?
|
|
189
|
+
*
|
|
190
|
+
* Three things, all required, and no ownership proof among them:
|
|
191
|
+
*
|
|
192
|
+
* 1. ORPHANED — `ppid === 1`. A live `omega dev`, a hand-run
|
|
193
|
+
* `firebase emulators:start`, a second brand's stack and another agent
|
|
194
|
+
* session all keep a live parent, so none of them is ever a candidate.
|
|
195
|
+
* 2. OURS TO SIGNAL — the row's uid is this user's. Missing uid evidence
|
|
196
|
+
* proves nothing and reads as "not a candidate".
|
|
197
|
+
* 3. FAMILY — one of the exact command shapes above. This is the half that
|
|
198
|
+
* keeps the reload watcher alive: nodemon runs at PID 1 with a live
|
|
199
|
+
* session behind it and names firebase paths in its argv.
|
|
200
|
+
* @param {{pid: number|string, ppid: number|string, uid: number|string, command: string}} row - One ps row.
|
|
201
|
+
* @param {number} uid - This user's uid (`process.getuid()`).
|
|
202
|
+
* @returns {boolean}
|
|
203
|
+
*/
|
|
204
|
+
function isOrphanedEmulatorFamily(row, uid) {
|
|
205
|
+
const pid = Number(row?.pid);
|
|
206
|
+
const owner = Number(uid);
|
|
207
|
+
|
|
208
|
+
// PID 1 is init, and a non-numeric row is a parse failure — never candidates.
|
|
209
|
+
if (!Number.isInteger(pid) || pid <= 1) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (Number(row?.ppid) !== 1) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!Number.isInteger(owner) || Number(row?.uid) !== owner) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return describeFamilyMember(row?.command) !== null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Every port a command line publishes (`--port 9152`, `--port=8085`,
|
|
226
|
+
* `--websocket_port 9150`).
|
|
227
|
+
*
|
|
228
|
+
* A reap is BY PID, so nothing else says which ports the process held — and a
|
|
229
|
+
* SIGKILLed JVM keeps its listener for a moment after the process is gone,
|
|
230
|
+
* which is exactly the "probed free, then failed to bind" race the boot's retry
|
|
231
|
+
* exists to catch ([#778](https://github.com/Omega-JS-Stack/omega/issues/778)).
|
|
232
|
+
* @param {string} command - Full command line from ps.
|
|
233
|
+
* @returns {number[]}
|
|
234
|
+
*/
|
|
235
|
+
function publishedPorts(command) {
|
|
236
|
+
return [...String(command || '').matchAll(/--[\w-]*port[=\s](\d+)/g)].map((match) => Number(match[1]));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* One `ps -A` snapshot of the whole machine.
|
|
241
|
+
*
|
|
242
|
+
* A failed read answers with NOTHING, never with a partial table: no rows means
|
|
243
|
+
* no candidates, and a boot that cannot see the machine must not send signals.
|
|
244
|
+
* @returns {string} The raw ps output, or '' when it could not be read.
|
|
245
|
+
*/
|
|
246
|
+
function readProcessTable() {
|
|
247
|
+
const { execSync } = require('child_process');
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
return execSync(PROCESS_TABLE_COMMAND, {
|
|
251
|
+
encoding: 'utf8',
|
|
252
|
+
maxBuffer: PROCESS_TABLE_MAX_BUFFER,
|
|
253
|
+
timeout: PROCESS_READ_TIMEOUT_MS,
|
|
254
|
+
});
|
|
255
|
+
} catch (error) {
|
|
256
|
+
return '';
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* One pid's row right now, for the re-read that precedes a SIGKILL.
|
|
262
|
+
* @param {number|string} pid - The pid to read.
|
|
263
|
+
* @returns {{pid: number, ppid: number, uid: number, command: string}|null}
|
|
264
|
+
*/
|
|
265
|
+
function readProcessRow(pid) {
|
|
266
|
+
const { execSync } = require('child_process');
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
const text = execSync(`ps -o pid=,ppid=,uid=,command= -p ${Number(pid)} 2>/dev/null`, { encoding: 'utf8' });
|
|
270
|
+
|
|
271
|
+
return parseProcessTable(text)[0] || null;
|
|
272
|
+
} catch (error) {
|
|
273
|
+
// Unreadable is not "gone": the escalation re-proves identity from this
|
|
274
|
+
// row, and no row is no proof, so the pid is spared either way.
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Poll a pid set until every one is gone or the window closes.
|
|
281
|
+
*
|
|
282
|
+
* ONE snapshot per pass, indexed by pid, rather than a `ps` per pid: the pile
|
|
283
|
+
* this sweep exists for was ~100 processes deep, and a per-pid read would fork
|
|
284
|
+
* a hundred times every 100ms for the whole grace window.
|
|
285
|
+
* @param {number[]} pids - The pids to watch.
|
|
286
|
+
* @param {number} timeoutMs - How long to wait in total.
|
|
287
|
+
* @param {Function} readTable - The `ps -A` snapshot seam.
|
|
288
|
+
* @param {number} pollIntervalMs - How often to look.
|
|
289
|
+
* @returns {Promise<number[]>} The pids still alive when the window closed.
|
|
290
|
+
*/
|
|
291
|
+
async function waitForExit(pids, timeoutMs, readTable, pollIntervalMs) {
|
|
292
|
+
const deadline = Date.now() + timeoutMs;
|
|
293
|
+
let alive = pids;
|
|
294
|
+
|
|
295
|
+
while (alive.length > 0 && Date.now() < deadline) {
|
|
296
|
+
await powertools.wait(pollIntervalMs);
|
|
297
|
+
|
|
298
|
+
const running = new Set(parseProcessTable(readTable()).map((row) => row.pid));
|
|
299
|
+
|
|
300
|
+
alive = alive.filter((pid) => running.has(Number(pid)));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return alive;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Poll a port set until nothing is listening or the window closes.
|
|
308
|
+
* @param {number[]} ports - The ports the reaped processes published.
|
|
309
|
+
* @param {Function} isFree - The port probe seam.
|
|
310
|
+
* @param {number} timeoutMs - How long to wait in total.
|
|
311
|
+
* @param {number} pollIntervalMs - How often to look.
|
|
312
|
+
* @returns {Promise<number[]>} The ports still held when the window closed.
|
|
313
|
+
*/
|
|
314
|
+
async function waitForPorts(ports, isFree, timeoutMs, pollIntervalMs) {
|
|
315
|
+
const deadline = Date.now() + timeoutMs;
|
|
316
|
+
let held = [...new Set(ports)];
|
|
317
|
+
|
|
318
|
+
while (held.length > 0 && Date.now() < deadline) {
|
|
319
|
+
const free = await Promise.all(held.map((port) => isFree(port)));
|
|
320
|
+
held = held.filter((port, index) => !free[index]);
|
|
321
|
+
|
|
322
|
+
if (held.length > 0) {
|
|
323
|
+
await powertools.wait(pollIntervalMs);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return held;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* The boot's one line, when anything went down.
|
|
332
|
+
* @param {Array<{pid: number, label: string}>} reaped - What went down.
|
|
333
|
+
* @param {number[]} killed - Which of them needed SIGKILL.
|
|
334
|
+
* @returns {string}
|
|
335
|
+
*/
|
|
336
|
+
function formatReapLine(reaped, killed) {
|
|
337
|
+
const plural = reaped.length > 1 ? 'es' : '';
|
|
338
|
+
const escalated = killed.length > 0 ? ` (${killed.length} needed SIGKILL)` : '';
|
|
339
|
+
const named = reaped.map((entry) => `${entry.pid} ${entry.label}`).join(', ');
|
|
340
|
+
|
|
341
|
+
return `Reaped ${reaped.length} orphaned emulator process${plural} left by earlier runs${escalated}: ${named}.`;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Reap every ORPHANED emulator-family process on the machine.
|
|
346
|
+
*
|
|
347
|
+
* SIGTERM to every match, the grace window, then SIGKILL to whatever is still
|
|
348
|
+
* standing — and the survivor's row is READ AGAIN first, because the window is
|
|
349
|
+
* long enough for a number to be freed and handed out again, and there is no
|
|
350
|
+
* apologising to a SIGKILL. Then the ports those rows published are waited on,
|
|
351
|
+
* so the allocator that probes them moments later is not racing a JVM that is
|
|
352
|
+
* still unwinding.
|
|
353
|
+
* @param {object} [options]
|
|
354
|
+
* @param {number} [options.uid] - This user's uid.
|
|
355
|
+
* @param {Function} [options.readTable] - The `ps -A` snapshot seam.
|
|
356
|
+
* @param {Function} [options.readProcess] - The per-pid `ps` seam.
|
|
357
|
+
* @param {Function} [options.kill] - The signal seam.
|
|
358
|
+
* @param {Function} [options.isFree] - The port probe seam.
|
|
359
|
+
* @param {Function} [options.log] - Where the one line goes (silent by default).
|
|
360
|
+
* @param {number} [options.graceMs] - How long a SIGTERM gets before SIGKILL.
|
|
361
|
+
* @param {number} [options.portReleaseTimeoutMs] - How long a freed port gets to come back.
|
|
362
|
+
* @param {number} [options.pollIntervalMs] - How often either wait looks.
|
|
363
|
+
* @returns {Promise<{reaped: Array<{pid: number, label: string}>, killed: number[]}>}
|
|
364
|
+
*/
|
|
365
|
+
async function reapMachineOrphans({
|
|
366
|
+
// A host with no `process.getuid` (Windows) hands the verdict no uid, and
|
|
367
|
+
// "no uid proves nothing" turns the whole sweep into a silent no-op there —
|
|
368
|
+
// which is the right answer on the one platform these emulators do not
|
|
369
|
+
// reparent to PID 1 on.
|
|
370
|
+
uid = typeof process.getuid === 'function' ? process.getuid() : undefined,
|
|
371
|
+
readTable = readProcessTable,
|
|
372
|
+
readProcess = readProcessRow,
|
|
373
|
+
kill = process.kill,
|
|
374
|
+
isFree = isPortFree,
|
|
375
|
+
log = () => {},
|
|
376
|
+
graceMs = DEFAULT_GRACE_MS,
|
|
377
|
+
portReleaseTimeoutMs = DEFAULT_PORT_RELEASE_TIMEOUT_MS,
|
|
378
|
+
pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,
|
|
379
|
+
} = {}) {
|
|
380
|
+
const targets = parseProcessTable(readTable())
|
|
381
|
+
.filter((row) => isOrphanedEmulatorFamily(row, uid))
|
|
382
|
+
// The sweep is the only signaller here with no ownership proof at all, so
|
|
383
|
+
// the two numbers it must never send a signal to are named outright.
|
|
384
|
+
.filter((row) => row.pid !== process.pid && row.pid !== process.ppid);
|
|
385
|
+
|
|
386
|
+
if (targets.length === 0) {
|
|
387
|
+
return { reaped: [], killed: [] };
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
for (const target of targets) {
|
|
391
|
+
try { kill(target.pid, 'SIGTERM'); } catch (e) { /* exited between the read and the signal */ }
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const survivors = await waitForExit(targets.map((target) => target.pid), graceMs, readTable, pollIntervalMs);
|
|
395
|
+
const killed = [];
|
|
396
|
+
|
|
397
|
+
for (const pid of survivors) {
|
|
398
|
+
const live = readProcess(pid);
|
|
399
|
+
|
|
400
|
+
if (!isOrphanedEmulatorFamily(live, uid)) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
try {
|
|
405
|
+
kill(pid, 'SIGKILL');
|
|
406
|
+
killed.push(pid);
|
|
407
|
+
} catch (e) { /* gone in the meantime */ }
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
await waitForExit(killed, graceMs, readTable, pollIntervalMs);
|
|
411
|
+
|
|
412
|
+
// Only what actually went down: a target that outlived the grace window and
|
|
413
|
+
// came back as somebody else's number was spared, and reporting it reaped
|
|
414
|
+
// would name a pid this sweep never took.
|
|
415
|
+
const spared = survivors.filter((pid) => !killed.includes(pid));
|
|
416
|
+
const reaped = targets
|
|
417
|
+
.filter((target) => !spared.includes(target.pid))
|
|
418
|
+
.map((target) => ({ pid: target.pid, label: describeFamilyMember(target.command) }));
|
|
419
|
+
|
|
420
|
+
if (reaped.length > 0) {
|
|
421
|
+
log(formatReapLine(reaped, killed));
|
|
422
|
+
|
|
423
|
+
const ports = targets
|
|
424
|
+
.filter((target) => !spared.includes(target.pid))
|
|
425
|
+
.flatMap((target) => publishedPorts(target.command));
|
|
426
|
+
|
|
427
|
+
await waitForPorts(ports, isFree, portReleaseTimeoutMs, pollIntervalMs);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return { reaped: reaped, killed: killed };
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
module.exports = {
|
|
434
|
+
parseProcessTable: parseProcessTable,
|
|
435
|
+
isOrphanedEmulatorFamily: isOrphanedEmulatorFamily,
|
|
436
|
+
describeFamilyMember: describeFamilyMember,
|
|
437
|
+
reapMachineOrphans: reapMachineOrphans,
|
|
438
|
+
readProcessTable: readProcessTable,
|
|
439
|
+
readProcessRow: readProcessRow,
|
|
440
|
+
};
|