@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,788 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: a stack stop takes the whole family with it
|
|
3
|
+
* ([#304](https://github.com/Omega-JS-Stack/omega/issues/304)).
|
|
4
|
+
*
|
|
5
|
+
* firebase-tools starts each java emulator in its OWN process group, so the
|
|
6
|
+
* group signal shutdown() sends reaches `sh`/firebase and nothing else. When
|
|
7
|
+
* the graceful stop does not finish inside the grace window the escalation
|
|
8
|
+
* SIGKILLs the parent, the jars reparent to PID 1, and they hold the classic
|
|
9
|
+
* ports until somebody hand-kills them — four parentless firestore jars after
|
|
10
|
+
* one afternoon of normal restarts. The pid record written while the tree was
|
|
11
|
+
* still attached is the only surviving link, so the stop path signals it BY PID.
|
|
12
|
+
*
|
|
13
|
+
* Run: npx omega test backend:cli/emulator-shutdown
|
|
14
|
+
*
|
|
15
|
+
* The processes below are REAL and detached (their own process group, exactly
|
|
16
|
+
* like the jars) — nothing here is a stand-in for a process. Only their command
|
|
17
|
+
* lines are fixtures, copied from `ps -o command=` against a booted sandbox
|
|
18
|
+
* emulator, because a real firestore jar takes seconds to boot and proves
|
|
19
|
+
* nothing extra about the signal.
|
|
20
|
+
*
|
|
21
|
+
* The last two cases run the COMMAND, not one of its methods: the stop path can
|
|
22
|
+
* be correct and still never be reached, which is how the reaper call and the
|
|
23
|
+
* exit path's join could both be deleted with every other case here green. They
|
|
24
|
+
* boot against a `firebase` on PATH that only decides the two things the boot
|
|
25
|
+
* path reads — whether the ready marker arrives, and when the child exits — so
|
|
26
|
+
* the spawn, the process group, the pid record and the ports stay real.
|
|
27
|
+
*/
|
|
28
|
+
const os = require('os');
|
|
29
|
+
const net = require('net');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
const { spawn } = require('child_process');
|
|
32
|
+
const jetpack = require('fs-jetpack');
|
|
33
|
+
const powertools = require('node-powertools');
|
|
34
|
+
|
|
35
|
+
const EmulatorCommand = require('../../dist/cli/commands/emulator.js');
|
|
36
|
+
const WatchCommand = require('../../dist/cli/commands/watch.js');
|
|
37
|
+
const defineCases = require('../../dist/vendor/devkit/test/define-cases.js');
|
|
38
|
+
|
|
39
|
+
const { isStoppableEmulatorProcess, listListeningPids, PORT_LOOKUP_TIMEOUT_MS } = EmulatorCommand;
|
|
40
|
+
|
|
41
|
+
const OURS = 'demo-sandbox-brand';
|
|
42
|
+
|
|
43
|
+
// What the recorded pids actually are, from a booted sandbox emulator.
|
|
44
|
+
const FIRESTORE_JAR = 'java -jar cloud-firestore-emulator-v1.21.0.jar --host 127.0.0.1 --port 8080 --project_id demo-sandbox-brand';
|
|
45
|
+
const PUBSUB_JAR = 'java -jar cloud-pubsub-emulator-0.8.34-all.jar --host=127.0.0.1 --port=8085';
|
|
46
|
+
const NEIGHBOUR_JAR = FIRESTORE_JAR.replace(OURS, 'demo-other-brand');
|
|
47
|
+
// The reload watcher, from the same ps: a nodemon the CLI process spawns, not
|
|
48
|
+
// firebase-tools — so the record's walk down from the emulator child never
|
|
49
|
+
// reaches it ([#629](https://github.com/Omega-JS-Stack/omega/issues/629)).
|
|
50
|
+
const NODEMON_WATCHER = 'nodemon --on-change-only --delay 1 --watch /omega/packages/backend/src --ext js,json --exec node-e-writes-.temp/emulator.log.reset';
|
|
51
|
+
|
|
52
|
+
// Stand-ins for `firebase emulators:start`, on PATH as `firebase`. A real
|
|
53
|
+
// firebase boot needs a real project and half a minute; what the boot path owes
|
|
54
|
+
// its caller is decided by two things only — whether the ready marker ever
|
|
55
|
+
// arrives, and when the child exits.
|
|
56
|
+
const FIREBASE_READY_THEN_EXITS = '#!/bin/sh\necho "All emulators ready!"\nsleep 0.5\n';
|
|
57
|
+
const FIREBASE_DIES_BEFORE_READY = '#!/bin/sh\necho "Error: could not start emulators" >&2\nexit 1\n';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A real, detached, long-lived process whose command line reads like `marker`.
|
|
61
|
+
* Detached is the point: it sits in its own process group, so the group signal
|
|
62
|
+
* the stop path sends its firebase child can never reach it.
|
|
63
|
+
*/
|
|
64
|
+
function spawnDetached(marker) {
|
|
65
|
+
const child = spawn(process.execPath, ['-e', 'setTimeout(() => {}, 30000)', ...marker.split(' ')], {
|
|
66
|
+
detached: true,
|
|
67
|
+
stdio: 'ignore',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
child.unref();
|
|
71
|
+
|
|
72
|
+
return child.pid;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A port nothing is listening on. The suites run against a LIVE emulator, so
|
|
77
|
+
* the classic numbers are held by the stack running this very test — the stop
|
|
78
|
+
* path's port check would read that as a leak.
|
|
79
|
+
*/
|
|
80
|
+
async function freePort() {
|
|
81
|
+
const server = net.createServer();
|
|
82
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
83
|
+
const port = server.address().port;
|
|
84
|
+
await new Promise((resolve) => server.close(resolve));
|
|
85
|
+
|
|
86
|
+
return port;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Did this child process exit inside the window? A signalled child is a ZOMBIE
|
|
91
|
+
* until its parent reaps it, and a zombie still answers `kill(pid, 0)` — the
|
|
92
|
+
* exit event is the honest read.
|
|
93
|
+
*/
|
|
94
|
+
function exitedWithin(child, timeoutMs) {
|
|
95
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
96
|
+
return Promise.resolve(true);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return new Promise((resolve) => {
|
|
100
|
+
const timer = setTimeout(() => resolve(false), timeoutMs);
|
|
101
|
+
child.once('exit', () => {
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
resolve(true);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function isAlive(pid) {
|
|
109
|
+
try {
|
|
110
|
+
process.kill(pid, 0);
|
|
111
|
+
return true;
|
|
112
|
+
} catch (e) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function stopAll(pids) {
|
|
118
|
+
for (const pid of pids) {
|
|
119
|
+
try { process.kill(pid, 'SIGKILL'); } catch (e) { /* already gone */ }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* An emulator command pointed at a throwaway project dir, with a pid record
|
|
125
|
+
* already written — the state a stop path finds after boot recorded the stack.
|
|
126
|
+
*/
|
|
127
|
+
function commandWithRecord(pids) {
|
|
128
|
+
const projectDir = path.join(os.tmpdir(), `omega-shutdown-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
129
|
+
const command = new EmulatorCommand({ firebaseProjectPath: projectDir, argv: {}, options: {} });
|
|
130
|
+
const lines = [];
|
|
131
|
+
|
|
132
|
+
command.log = (message) => lines.push(String(message));
|
|
133
|
+
command.logWarning = (message) => lines.push(String(message));
|
|
134
|
+
|
|
135
|
+
jetpack.write(command.getTempPath('emulator-pids.json'), {
|
|
136
|
+
pids: pids,
|
|
137
|
+
projectId: OURS,
|
|
138
|
+
rootPid: pids[0],
|
|
139
|
+
startedAt: new Date().toISOString(),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
return { command, lines, cleanup: () => jetpack.remove(projectDir) };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* An emulator command that can actually BOOT: a throwaway project whose
|
|
147
|
+
* firebase.json names ports nothing else uses, and a `firebase` on PATH that
|
|
148
|
+
* behaves like `script` says.
|
|
149
|
+
*
|
|
150
|
+
* Three seams are neutralized because they reach outside the throwaway project
|
|
151
|
+
* rather than into it: attachVerbLog re-tees THIS process' stdout (the runner's
|
|
152
|
+
* own output), and ensureStaged/startStageWatch build and watch a src/ tree
|
|
153
|
+
* that does not exist here. Everything the stop path touches — the spawn, the
|
|
154
|
+
* process group, the pid record, the ports — is real.
|
|
155
|
+
*/
|
|
156
|
+
async function bootableCommand(script) {
|
|
157
|
+
const projectDir = path.join(os.tmpdir(), `omega-boot-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
158
|
+
// execute() runs IN-PROCESS and the boot path publishes its resolved map
|
|
159
|
+
// into process.env (portsToEnv + emulator hosts). This runner is SHARED with
|
|
160
|
+
// every later suite — a leaked OMEGA_HOSTING_PORT pointed the payment
|
|
161
|
+
// journeys' in-process webhook at the throwaway project's dead port. Snapshot
|
|
162
|
+
// the whole env and restore it in cleanup.
|
|
163
|
+
const savedEnv = { ...process.env };
|
|
164
|
+
const savedPath = process.env.PATH;
|
|
165
|
+
|
|
166
|
+
// Ports the kernel just handed out: free, so the allocator resolves them
|
|
167
|
+
// verbatim, and nowhere near the classic map the live emulator running this
|
|
168
|
+
// very suite is sitting on.
|
|
169
|
+
const names = ['auth', 'functions', 'firestore', 'database', 'hosting', 'storage', 'pubsub', 'ui'];
|
|
170
|
+
const emulators = {};
|
|
171
|
+
const taken = new Set();
|
|
172
|
+
for (const name of names) {
|
|
173
|
+
let port = await freePort();
|
|
174
|
+
while (taken.has(port)) port = await freePort();
|
|
175
|
+
taken.add(port);
|
|
176
|
+
emulators[name] = { port: port };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
jetpack.write(path.join(projectDir, 'firebase.json'), JSON.stringify({ emulators }, null, 2));
|
|
180
|
+
jetpack.dir(path.join(projectDir, 'dist'));
|
|
181
|
+
jetpack.file(path.join(projectDir, 'bin', 'firebase'), { content: script, mode: '755' });
|
|
182
|
+
process.env.PATH = `${path.join(projectDir, 'bin')}${path.delimiter}${savedPath}`;
|
|
183
|
+
|
|
184
|
+
const command = new EmulatorCommand({
|
|
185
|
+
firebaseProjectPath: projectDir,
|
|
186
|
+
argv: { https: false, seed: false },
|
|
187
|
+
options: {},
|
|
188
|
+
});
|
|
189
|
+
const lines = [];
|
|
190
|
+
|
|
191
|
+
command.log = (message) => lines.push(String(message));
|
|
192
|
+
command.logWarning = (message) => lines.push(String(message));
|
|
193
|
+
command.logError = (message) => lines.push(String(message));
|
|
194
|
+
command.attachVerbLog = () => '';
|
|
195
|
+
command.ensureStaged = () => {};
|
|
196
|
+
command.startStageWatch = () => ({ close: () => {} });
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
command,
|
|
200
|
+
lines,
|
|
201
|
+
ports: emulators,
|
|
202
|
+
cleanup: () => {
|
|
203
|
+
for (const key of Object.keys(process.env)) {
|
|
204
|
+
if (!(key in savedEnv)) delete process.env[key];
|
|
205
|
+
}
|
|
206
|
+
Object.assign(process.env, savedEnv);
|
|
207
|
+
jetpack.remove(projectDir);
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Run `fn` with an `lsof` on PATH that never answers — the smbfs stall of
|
|
214
|
+
* [#332](https://github.com/Omega-JS-Stack/omega/issues/332), made
|
|
215
|
+
* deterministic. Nothing about the sweep is stubbed: it shells out for real,
|
|
216
|
+
* to a real process, and the only fixture is that the process never replies.
|
|
217
|
+
*
|
|
218
|
+
* `exec` in the shim is the point: the hung process must BE the one the lookup
|
|
219
|
+
* spawned, so the bound's kill lands on the thing holding its stdout — a shell
|
|
220
|
+
* left waiting on a `sleep` grandchild would hang past any timeout.
|
|
221
|
+
*/
|
|
222
|
+
async function withHungLsof(fn) {
|
|
223
|
+
const binDir = path.join(os.tmpdir(), `omega-lsof-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
224
|
+
const savedPath = process.env.PATH;
|
|
225
|
+
|
|
226
|
+
jetpack.file(path.join(binDir, 'lsof'), { content: '#!/bin/sh\nexec sleep 600\n', mode: '755' });
|
|
227
|
+
process.env.PATH = `${binDir}${path.delimiter}${savedPath}`;
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
return await fn();
|
|
231
|
+
} finally {
|
|
232
|
+
process.env.PATH = savedPath;
|
|
233
|
+
jetpack.remove(binDir);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Run `fn` with the background watcher swapped for a REAL detached process.
|
|
239
|
+
*
|
|
240
|
+
* The watcher itself is a nodemon over the framework's own src/ — pointing one
|
|
241
|
+
* at this repo mid-test would start a second live reload lane, and on a
|
|
242
|
+
* registry install it does not start at all. What the run owes it is a signal,
|
|
243
|
+
* and a real process proves the signal for real.
|
|
244
|
+
*/
|
|
245
|
+
async function withRealWatcherStandIn(fn) {
|
|
246
|
+
const original = WatchCommand.prototype.startBackground;
|
|
247
|
+
const watchers = [];
|
|
248
|
+
|
|
249
|
+
WatchCommand.prototype.startBackground = function () {
|
|
250
|
+
const child = spawn(process.execPath, ['-e', 'setTimeout(() => {}, 30000)'], {
|
|
251
|
+
detached: true,
|
|
252
|
+
stdio: 'ignore',
|
|
253
|
+
});
|
|
254
|
+
child.unref();
|
|
255
|
+
watchers.push(child);
|
|
256
|
+
|
|
257
|
+
return child;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
return await fn(watchers);
|
|
262
|
+
} finally {
|
|
263
|
+
WatchCommand.prototype.startBackground = original;
|
|
264
|
+
stopAll(watchers.map((child) => child.pid));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* The stub `firebase`, on PATH: a process group shaped like firebase-tools' own
|
|
270
|
+
* — a shell with a child of its own — that reports ready and then idles until
|
|
271
|
+
* something signals it. `$$` is the group leader the run spawned; `$!` is a
|
|
272
|
+
* member only the GROUP signal reaches. Neither ever binds a port, and no real
|
|
273
|
+
* emulator is involved.
|
|
274
|
+
* @param {string} groupPath - Where the stub records its two pids.
|
|
275
|
+
* @returns {string} The script body.
|
|
276
|
+
*/
|
|
277
|
+
function firebaseGroupThenIdles(groupPath) {
|
|
278
|
+
return [
|
|
279
|
+
'#!/bin/sh',
|
|
280
|
+
"node -e 'setTimeout(() => {}, 30000)' &",
|
|
281
|
+
`printf '%s %s\\n' "$$" "$!" > "${groupPath}"`,
|
|
282
|
+
'echo "All emulators ready!"',
|
|
283
|
+
'wait',
|
|
284
|
+
'',
|
|
285
|
+
].join('\n');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* The run under test, as a REAL child process. A signal is only a signal when
|
|
290
|
+
* it arrives at a process: in-process cases can call the stop path but can
|
|
291
|
+
* never prove that SIGHUP reaches it at all.
|
|
292
|
+
*
|
|
293
|
+
* Three seams are neutralized for the same reasons bootableCommand() names, and
|
|
294
|
+
* one more: the recorded-pid reap is proven by the cases above, and here it
|
|
295
|
+
* would send the run looking at ports outside the throwaway project — so the
|
|
296
|
+
* group signal stands on its own.
|
|
297
|
+
*/
|
|
298
|
+
const SIGNAL_DRIVER = `
|
|
299
|
+
const fs = require('fs');
|
|
300
|
+
const { spawn } = require('child_process');
|
|
301
|
+
const [, , projectDir, commandPath, watchPath, statePath] = process.argv;
|
|
302
|
+
|
|
303
|
+
const EmulatorCommand = require(commandPath);
|
|
304
|
+
const WatchCommand = require(watchPath);
|
|
305
|
+
|
|
306
|
+
WatchCommand.prototype.startBackground = function () {
|
|
307
|
+
const child = spawn(process.execPath, ['-e', 'setTimeout(() => {}, 30000)'], { detached: true, stdio: 'ignore' });
|
|
308
|
+
child.unref();
|
|
309
|
+
fs.writeFileSync(statePath, String(child.pid));
|
|
310
|
+
|
|
311
|
+
return child;
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const command = new EmulatorCommand({
|
|
315
|
+
firebaseProjectPath: projectDir,
|
|
316
|
+
argv: { https: false, seed: false },
|
|
317
|
+
options: {},
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
command.attachVerbLog = () => '';
|
|
321
|
+
command.ensureStaged = () => {};
|
|
322
|
+
command.startStageWatch = () => ({ close: () => {} });
|
|
323
|
+
command.terminateRecordedEmulatorProcesses = async () => {};
|
|
324
|
+
|
|
325
|
+
command.execute();
|
|
326
|
+
`;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Poll until `check` passes or the window closes.
|
|
330
|
+
* @param {Function} check - Returns truthy when the wait is over.
|
|
331
|
+
* @param {number} timeoutMs - How long to keep looking.
|
|
332
|
+
* @returns {Promise<boolean>} Whether it passed inside the window.
|
|
333
|
+
*/
|
|
334
|
+
async function waitUntil(check, timeoutMs) {
|
|
335
|
+
const deadline = Date.now() + timeoutMs;
|
|
336
|
+
|
|
337
|
+
while (Date.now() < deadline) {
|
|
338
|
+
if (check()) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
await powertools.wait(50);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return check();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Boot the emulator command in its own process and wait for it to report ready.
|
|
350
|
+
* Returns the handle plus every pid the run is now responsible for.
|
|
351
|
+
*/
|
|
352
|
+
async function bootedRun() {
|
|
353
|
+
const dir = path.join(os.tmpdir(), `omega-signal-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
354
|
+
const groupPath = path.join(dir, 'group.txt');
|
|
355
|
+
const statePath = path.join(dir, 'watcher.txt');
|
|
356
|
+
|
|
357
|
+
// Kernel-assigned ports, exactly as bootableCommand does: free, so nothing
|
|
358
|
+
// bumps, and nowhere near the classic map.
|
|
359
|
+
const emulators = {};
|
|
360
|
+
const taken = new Set();
|
|
361
|
+
for (const name of ['auth', 'functions', 'firestore', 'database', 'hosting', 'storage', 'pubsub', 'ui']) {
|
|
362
|
+
let port = await freePort();
|
|
363
|
+
while (taken.has(port)) port = await freePort();
|
|
364
|
+
taken.add(port);
|
|
365
|
+
emulators[name] = { port: port };
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
jetpack.write(path.join(dir, 'firebase.json'), JSON.stringify({ emulators }, null, 2));
|
|
369
|
+
jetpack.dir(path.join(dir, 'dist'));
|
|
370
|
+
jetpack.write(path.join(dir, 'driver.js'), SIGNAL_DRIVER);
|
|
371
|
+
jetpack.file(path.join(dir, 'bin', 'firebase'), { content: firebaseGroupThenIdles(groupPath), mode: '755' });
|
|
372
|
+
|
|
373
|
+
// Detached: the run gets its OWN process group, so the signal below lands on
|
|
374
|
+
// that ONE process and nothing else — the strictly harder case, and the one
|
|
375
|
+
// `omega dev`'s stop and a closed terminal both produce.
|
|
376
|
+
const child = spawn(process.execPath, [
|
|
377
|
+
path.join(dir, 'driver.js'),
|
|
378
|
+
dir,
|
|
379
|
+
require.resolve('../../dist/cli/commands/emulator.js'),
|
|
380
|
+
require.resolve('../../dist/cli/commands/watch.js'),
|
|
381
|
+
statePath,
|
|
382
|
+
], {
|
|
383
|
+
env: { ...process.env, PATH: `${path.join(dir, 'bin')}${path.delimiter}${process.env.PATH}` },
|
|
384
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
385
|
+
detached: true,
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
let output = '';
|
|
389
|
+
child.stdout.on('data', (data) => { output += data.toString(); });
|
|
390
|
+
child.stderr.on('data', (data) => { output += data.toString(); });
|
|
391
|
+
|
|
392
|
+
const ready = await waitUntil(() => /Emulator ready/.test(output) && jetpack.exists(groupPath) && jetpack.exists(statePath), 60000);
|
|
393
|
+
const [leader, member] = String(jetpack.read(groupPath) || '').trim().split(/\s+/).map(Number);
|
|
394
|
+
const watcher = Number(jetpack.read(statePath));
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
child: child,
|
|
398
|
+
ready: ready,
|
|
399
|
+
output: () => output,
|
|
400
|
+
stubPids: [leader, member].filter(Number.isInteger),
|
|
401
|
+
watcher: watcher,
|
|
402
|
+
cleanup: () => {
|
|
403
|
+
try { process.kill(-child.pid, 'SIGKILL'); } catch (e) { /* already gone */ }
|
|
404
|
+
stopAll([leader, member, watcher, child.pid].filter(Number.isInteger));
|
|
405
|
+
jetpack.remove(dir);
|
|
406
|
+
},
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Boot the run, signal it with `signal`, and prove nothing it started is left.
|
|
412
|
+
* Every process signalled here is one this case spawned.
|
|
413
|
+
* @param {object} assert - The case assertions.
|
|
414
|
+
* @param {string} signal - The stop signal under test.
|
|
415
|
+
*/
|
|
416
|
+
async function stopsEverything(assert, signal) {
|
|
417
|
+
const run = await bootedRun();
|
|
418
|
+
|
|
419
|
+
try {
|
|
420
|
+
assert.equal(run.ready, true, `the run must come up before it can be stopped: ${run.output()}`);
|
|
421
|
+
assert.equal(run.stubPids.length, 2, 'the stub emulator reported its group leader and a member');
|
|
422
|
+
assert.equal(Number.isInteger(run.watcher), true, 'the run started a background watcher');
|
|
423
|
+
|
|
424
|
+
process.kill(run.child.pid, signal);
|
|
425
|
+
|
|
426
|
+
assert.equal(await exitedWithin(run.child, 30000), true, `the run must take its stop path on ${signal}: ${run.output()}`);
|
|
427
|
+
assert.equal(
|
|
428
|
+
await waitUntil(() => run.stubPids.every((pid) => !isAlive(pid)), 15000),
|
|
429
|
+
true,
|
|
430
|
+
`the emulator process group must be gone after ${signal} (still alive: ${run.stubPids.filter((pid) => isAlive(pid)).join(', ')})`,
|
|
431
|
+
);
|
|
432
|
+
assert.equal(await waitUntil(() => !isAlive(run.watcher), 15000), true, `no watcher may outlive the run on ${signal}`);
|
|
433
|
+
} finally {
|
|
434
|
+
run.cleanup();
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// The stop path also sweeps the ports it was handed, and on a defaults run the
|
|
439
|
+
// SHARED hub/storage numbers with them. A unit test's map is synthetic, so the
|
|
440
|
+
// shared pair is never this record's business — every direct call below says so.
|
|
441
|
+
const NO_SHARED_SWEEP = { sweepShared: false };
|
|
442
|
+
|
|
443
|
+
module.exports = defineCases({
|
|
444
|
+
description: 'emulator stop path: the recorded stack goes down with it',
|
|
445
|
+
type: 'group',
|
|
446
|
+
timeout: 30000,
|
|
447
|
+
|
|
448
|
+
tests: [
|
|
449
|
+
{
|
|
450
|
+
name: 'the-stop-path-terminates-the-jars-the-group-signal-missed',
|
|
451
|
+
async run({ assert }) {
|
|
452
|
+
const firestore = spawnDetached(FIRESTORE_JAR);
|
|
453
|
+
const pubsub = spawnDetached(PUBSUB_JAR);
|
|
454
|
+
const { command, cleanup } = commandWithRecord([firestore, pubsub]);
|
|
455
|
+
|
|
456
|
+
try {
|
|
457
|
+
await command.terminateRecordedEmulatorProcesses({ firestore: await freePort() }, NO_SHARED_SWEEP);
|
|
458
|
+
|
|
459
|
+
assert.equal(isAlive(firestore), false, 'the recorded firestore jar should be stopped');
|
|
460
|
+
assert.equal(isAlive(pubsub), false, 'the recorded pubsub jar should be stopped');
|
|
461
|
+
} finally {
|
|
462
|
+
stopAll([firestore, pubsub]);
|
|
463
|
+
cleanup();
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
|
|
468
|
+
{
|
|
469
|
+
name: 'a-recycled-pid-is-never-a-kill-order',
|
|
470
|
+
async run({ assert }) {
|
|
471
|
+
// The record names pids, and the OS hands those numbers out again. A
|
|
472
|
+
// recorded number now running something that is not emulator machinery
|
|
473
|
+
// is a stranger, and the stop path has no port to narrow by.
|
|
474
|
+
const stranger = spawnDetached('some-other-tool --serve');
|
|
475
|
+
const { command, cleanup } = commandWithRecord([stranger]);
|
|
476
|
+
|
|
477
|
+
try {
|
|
478
|
+
await command.terminateRecordedEmulatorProcesses({ firestore: await freePort() }, NO_SHARED_SWEEP);
|
|
479
|
+
|
|
480
|
+
assert.equal(isAlive(stranger), true, 'a recycled pid running something else must be left alone');
|
|
481
|
+
} finally {
|
|
482
|
+
stopAll([stranger]);
|
|
483
|
+
cleanup();
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
|
|
488
|
+
{
|
|
489
|
+
name: 'a-recycled-pid-running-another-brands-jar-is-left-alone',
|
|
490
|
+
async run({ assert }) {
|
|
491
|
+
// The harder recycling: the number came back as emulator machinery, so
|
|
492
|
+
// "is this a jar" passes and the record's pid membership used to end
|
|
493
|
+
// the question there. The jar names ITS project on its own command
|
|
494
|
+
// line, and it is not ours.
|
|
495
|
+
const neighbour = spawnDetached(NEIGHBOUR_JAR);
|
|
496
|
+
const { command, cleanup } = commandWithRecord([neighbour]);
|
|
497
|
+
|
|
498
|
+
try {
|
|
499
|
+
await command.terminateRecordedEmulatorProcesses({ firestore: await freePort() }, NO_SHARED_SWEEP);
|
|
500
|
+
|
|
501
|
+
assert.equal(isAlive(neighbour), true, "another brand's live jar must survive our recorded pid");
|
|
502
|
+
} finally {
|
|
503
|
+
stopAll([neighbour]);
|
|
504
|
+
cleanup();
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
|
|
509
|
+
{
|
|
510
|
+
name: 'a-port-still-held-by-somebody-else-is-reported-not-killed',
|
|
511
|
+
async run({ assert }) {
|
|
512
|
+
// The port check is evidence for the human, never a kill order:
|
|
513
|
+
// signaling whatever answers on a port is what took down another
|
|
514
|
+
// project's live stack ([#274](https://github.com/Omega-JS-Stack/omega/issues/274)).
|
|
515
|
+
const server = net.createServer();
|
|
516
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
517
|
+
const port = server.address().port;
|
|
518
|
+
|
|
519
|
+
const { command, lines, cleanup } = commandWithRecord([]);
|
|
520
|
+
|
|
521
|
+
try {
|
|
522
|
+
await command.terminateRecordedEmulatorProcesses({ hosting: port }, NO_SHARED_SWEEP);
|
|
523
|
+
|
|
524
|
+
assert.equal(server.listening, true, 'the foreign listener keeps its port');
|
|
525
|
+
assert.match(lines.join('\n'), new RegExp(`still in use after shutdown: ${port}`));
|
|
526
|
+
} finally {
|
|
527
|
+
server.close();
|
|
528
|
+
cleanup();
|
|
529
|
+
}
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
|
|
533
|
+
{
|
|
534
|
+
name: 'a-port-lookup-that-hangs-is-bounded-and-names-nobody',
|
|
535
|
+
timeout: 60000,
|
|
536
|
+
async run({ assert }) {
|
|
537
|
+
// lsof is the one step with no Node primitive, and on a machine with a
|
|
538
|
+
// network mount it can stall for MINUTES before it answers
|
|
539
|
+
// ([#332](https://github.com/Omega-JS-Stack/omega/issues/332)). The
|
|
540
|
+
// call was unbounded, and being synchronous it blocks the event loop —
|
|
541
|
+
// so nothing downstream, not even a test's own timeout, could cut it
|
|
542
|
+
// short ([#459](https://github.com/Omega-JS-Stack/omega/issues/459)).
|
|
543
|
+
const port = await freePort();
|
|
544
|
+
const startedAt = Date.now();
|
|
545
|
+
const pids = await withHungLsof(() => listListeningPids(port));
|
|
546
|
+
const elapsed = Date.now() - startedAt;
|
|
547
|
+
|
|
548
|
+
assert.deepEqual(pids, [], 'a lookup that never answered names nobody — no ownership, so no kill order');
|
|
549
|
+
assert.equal(elapsed >= 1000, true, `the hung stub really was reached (a missing lsof returns at once), took ${elapsed}ms`);
|
|
550
|
+
assert.equal(elapsed < PORT_LOOKUP_TIMEOUT_MS * 2, true, `the lookup must return inside its bound, took ${elapsed}ms`);
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
|
|
554
|
+
{
|
|
555
|
+
name: 'a-stop-path-whose-lookup-hangs-still-finishes-and-kills-nothing',
|
|
556
|
+
timeout: 60000,
|
|
557
|
+
async run({ assert }) {
|
|
558
|
+
// The gate failure this bound exists for: a held port sends the sweep
|
|
559
|
+
// to lsof, lsof stalls on the smbfs mount, and the stop path sat there
|
|
560
|
+
// until the lane's whole 113s budget was gone. The verdict was never
|
|
561
|
+
// wrong — there was simply no bound on reaching it. A sweep that could
|
|
562
|
+
// not prove ownership takes the branch it already had: report, not kill.
|
|
563
|
+
const server = net.createServer();
|
|
564
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
565
|
+
const port = server.address().port;
|
|
566
|
+
|
|
567
|
+
const { command, lines, cleanup } = commandWithRecord([]);
|
|
568
|
+
const startedAt = Date.now();
|
|
569
|
+
|
|
570
|
+
try {
|
|
571
|
+
await withHungLsof(() => command.terminateRecordedEmulatorProcesses({ hosting: port }, NO_SHARED_SWEEP));
|
|
572
|
+
const elapsed = Date.now() - startedAt;
|
|
573
|
+
|
|
574
|
+
assert.equal(server.listening, true, 'a holder the sweep could not identify keeps its port');
|
|
575
|
+
assert.match(lines.join('\n'), new RegExp(`still in use after shutdown: ${port}`));
|
|
576
|
+
assert.equal(elapsed < 30000, true, `the stop path must stay bounded end to end, took ${elapsed}ms`);
|
|
577
|
+
} finally {
|
|
578
|
+
server.close();
|
|
579
|
+
cleanup();
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
|
|
584
|
+
{
|
|
585
|
+
name: 'the-orphan-sweep-runs-before-the-port-verdict',
|
|
586
|
+
async run({ assert }) {
|
|
587
|
+
// A jar the record never named (spawned after the last snapshot, then
|
|
588
|
+
// reparented to PID 1) is the SWEEP's case, not the record's. Polling
|
|
589
|
+
// the ports first spent the whole release window waiting on a port the
|
|
590
|
+
// next step was about to free, then called it somebody else's.
|
|
591
|
+
const server = net.createServer();
|
|
592
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
593
|
+
const port = server.address().port;
|
|
594
|
+
|
|
595
|
+
const { command, lines, cleanup } = commandWithRecord([]);
|
|
596
|
+
let swept = false;
|
|
597
|
+
|
|
598
|
+
// The sweep's own kill decision is proven above and in the #274/#293
|
|
599
|
+
// suites; what is under test here is WHEN it runs, so it stands in as
|
|
600
|
+
// the thing it would do to a squatter it owns.
|
|
601
|
+
command.terminateOrphanedEmulatorProcesses = () => {
|
|
602
|
+
swept = true;
|
|
603
|
+
server.close();
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
const startedAt = Date.now();
|
|
607
|
+
|
|
608
|
+
try {
|
|
609
|
+
await command.terminateRecordedEmulatorProcesses({ hosting: port }, NO_SHARED_SWEEP);
|
|
610
|
+
|
|
611
|
+
assert.equal(swept, true, 'the stop path runs the owned-orphan sweep itself');
|
|
612
|
+
assert.equal(lines.join('\n').includes('still in use'), false, `a port the sweep freed is not somebody else's: ${lines.join(' | ')}`);
|
|
613
|
+
assert.equal(Date.now() - startedAt < 2000, true, 'no full release-window stall for a port the sweep already freed');
|
|
614
|
+
} finally {
|
|
615
|
+
server.close();
|
|
616
|
+
cleanup();
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
},
|
|
620
|
+
|
|
621
|
+
{
|
|
622
|
+
name: 'the-run-that-shut-down-cleanly-reports-nothing',
|
|
623
|
+
async run({ assert }) {
|
|
624
|
+
// Everything already gone (the group signal did reach them) and every
|
|
625
|
+
// port free: the stop path is silent, no phantom warnings.
|
|
626
|
+
const gone = spawnDetached(FIRESTORE_JAR);
|
|
627
|
+
stopAll([gone]);
|
|
628
|
+
await powertools.wait(200);
|
|
629
|
+
|
|
630
|
+
const { command, lines, cleanup } = commandWithRecord([gone]);
|
|
631
|
+
|
|
632
|
+
try {
|
|
633
|
+
await command.terminateRecordedEmulatorProcesses({ firestore: await freePort() }, NO_SHARED_SWEEP);
|
|
634
|
+
|
|
635
|
+
assert.equal(lines.length, 0, `a clean stop should say nothing, said: ${lines.join(' | ')}`);
|
|
636
|
+
} finally {
|
|
637
|
+
cleanup();
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
},
|
|
641
|
+
|
|
642
|
+
// ─── the ownership bar the stop path clears ───
|
|
643
|
+
|
|
644
|
+
{
|
|
645
|
+
name: 'a-recorded-pid-still-running-emulator-machinery-is-stoppable',
|
|
646
|
+
async run({ assert }) {
|
|
647
|
+
assert.equal(isStoppableEmulatorProcess({ pid: 37088, command: FIRESTORE_JAR }, { pids: [37088], projectId: OURS }), true);
|
|
648
|
+
assert.equal(isStoppableEmulatorProcess({ pid: 37088, command: 'node /Users/ian/some-other-tool/server.js' }, { pids: [37088], projectId: OURS }), false);
|
|
649
|
+
assert.equal(isStoppableEmulatorProcess({ pid: 51001, command: NEIGHBOUR_JAR }, { pids: [], projectId: OURS }), false);
|
|
650
|
+
},
|
|
651
|
+
},
|
|
652
|
+
|
|
653
|
+
{
|
|
654
|
+
name: 'a-command-line-that-names-another-project-outranks-the-record',
|
|
655
|
+
async run({ assert }) {
|
|
656
|
+
// Pid membership short-circuited the project check, so a recorded
|
|
657
|
+
// number recycled onto the neighbouring brand's jar read as ours.
|
|
658
|
+
assert.equal(isStoppableEmulatorProcess({ pid: 37088, command: NEIGHBOUR_JAR }, { pids: [37088], projectId: OURS }), false);
|
|
659
|
+
|
|
660
|
+
// A jar that names NO project (pubsub never does) is still decided by
|
|
661
|
+
// the record — that is the whole reason the record exists.
|
|
662
|
+
assert.equal(isStoppableEmulatorProcess({ pid: 37088, command: PUBSUB_JAR }, { pids: [37088], projectId: OURS }), true);
|
|
663
|
+
|
|
664
|
+
// And with no project id of our own there is nothing to disagree with.
|
|
665
|
+
assert.equal(isStoppableEmulatorProcess({ pid: 37088, command: NEIGHBOUR_JAR }, { pids: [37088], projectId: null }), true);
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
|
|
669
|
+
// ─── the wiring: the run's exit path joins the stop path ───
|
|
670
|
+
|
|
671
|
+
{
|
|
672
|
+
name: 'the-exit-path-joins-the-shutdown-and-its-reaper',
|
|
673
|
+
timeout: 60000,
|
|
674
|
+
async run({ assert }) {
|
|
675
|
+
// Deleting the reaper call from shutdown(), or the `await shutdown()`
|
|
676
|
+
// the exit path joins it with, left every other test in this file
|
|
677
|
+
// green: they call the reaper directly. This one boots the real command
|
|
678
|
+
// and watches the RUN carry it.
|
|
679
|
+
await withRealWatcherStandIn(async (watchers) => {
|
|
680
|
+
const { command, ports, cleanup } = await bootableCommand(FIREBASE_READY_THEN_EXITS);
|
|
681
|
+
const reaped = [];
|
|
682
|
+
|
|
683
|
+
// Resolves a beat late on purpose: a shutdown that fires and forgets
|
|
684
|
+
// returns before this records anything.
|
|
685
|
+
command.terminateRecordedEmulatorProcesses = async (emulatorPorts, options) => {
|
|
686
|
+
await powertools.wait(200);
|
|
687
|
+
reaped.push({ emulatorPorts, options });
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
try {
|
|
691
|
+
await command.execute();
|
|
692
|
+
|
|
693
|
+
assert.equal(reaped.length, 1, 'the run must join the shutdown it started, reaper included');
|
|
694
|
+
assert.equal(reaped[0].emulatorPorts.hosting, ports.hosting.port, 'the reaper gets this run\'s RESOLVED port map');
|
|
695
|
+
assert.equal(reaped[0].options.sweepShared, true, 'nothing bumped, so the shared hub/storage ports are this run\'s to sweep');
|
|
696
|
+
assert.equal(await exitedWithin(watchers[0], 3000), true, 'the background watcher goes down with the run');
|
|
697
|
+
} finally {
|
|
698
|
+
cleanup();
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
|
|
704
|
+
{
|
|
705
|
+
name: 'a-boot-that-never-came-up-still-tears-down-what-it-started',
|
|
706
|
+
timeout: 60000,
|
|
707
|
+
async run({ assert }) {
|
|
708
|
+
// The boot-failure catch exited straight out: the watcher it had just
|
|
709
|
+
// started stayed alive (a nodemon nothing else signals) and whatever
|
|
710
|
+
// the spawn got as far as was never stopped.
|
|
711
|
+
await withRealWatcherStandIn(async (watchers) => {
|
|
712
|
+
const { command, cleanup } = await bootableCommand(FIREBASE_DIES_BEFORE_READY);
|
|
713
|
+
const reaped = [];
|
|
714
|
+
command.terminateRecordedEmulatorProcesses = async () => { reaped.push(true); };
|
|
715
|
+
|
|
716
|
+
// The one stub the framework's rules name outright: a real exit here
|
|
717
|
+
// takes the test runner with it mid-assertion.
|
|
718
|
+
const realExit = process.exit;
|
|
719
|
+
const exits = [];
|
|
720
|
+
process.exit = (code) => { exits.push(code); };
|
|
721
|
+
|
|
722
|
+
try {
|
|
723
|
+
await command.execute();
|
|
724
|
+
|
|
725
|
+
assert.deepEqual(exits, [1], 'a failed boot still exits non-zero');
|
|
726
|
+
assert.equal(reaped.length, 1, 'a failed boot runs the same stop path a normal one does');
|
|
727
|
+
assert.equal(await exitedWithin(watchers[0], 3000), true, 'the watcher does not outlive the failed boot');
|
|
728
|
+
} finally {
|
|
729
|
+
process.exit = realExit;
|
|
730
|
+
cleanup();
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
},
|
|
734
|
+
},
|
|
735
|
+
|
|
736
|
+
// ─── the stop path is reached on EVERY way this run is asked to stop ───
|
|
737
|
+
|
|
738
|
+
{
|
|
739
|
+
name: 'the-record-names-the-background-watcher-the-descent-cannot-reach',
|
|
740
|
+
async run({ assert }) {
|
|
741
|
+
// The record walks DOWN from the emulator child, which covers
|
|
742
|
+
// firebase-tools' own tree — the jars and every functions runtime
|
|
743
|
+
// worker it forks. The reload watcher hangs off the CLI process
|
|
744
|
+
// instead, so the walk never sees it: unnamed, a run that dies without
|
|
745
|
+
// teardown leaves a nodemon no later stop path can even name.
|
|
746
|
+
const root = spawnDetached(FIRESTORE_JAR);
|
|
747
|
+
const watcher = spawnDetached(NODEMON_WATCHER);
|
|
748
|
+
const { command, cleanup } = commandWithRecord([]);
|
|
749
|
+
|
|
750
|
+
try {
|
|
751
|
+
command.backgroundWatcherPid = watcher;
|
|
752
|
+
const pids = command.writeEmulatorPidRecord(root, OURS);
|
|
753
|
+
|
|
754
|
+
assert.equal(pids.includes(root), true, 'the emulator child is the record\'s root');
|
|
755
|
+
assert.equal(pids.includes(watcher), true, 'the background watcher is recorded with it');
|
|
756
|
+
assert.equal(command.readEmulatorOwnership().pids.includes(watcher), true, 'and it survives the round trip through the file');
|
|
757
|
+
assert.equal(isStoppableEmulatorProcess({ pid: watcher, command: NODEMON_WATCHER }, command.readEmulatorOwnership()), true, 'so the stop path may signal it');
|
|
758
|
+
} finally {
|
|
759
|
+
stopAll([root, watcher]);
|
|
760
|
+
cleanup();
|
|
761
|
+
}
|
|
762
|
+
},
|
|
763
|
+
},
|
|
764
|
+
|
|
765
|
+
{
|
|
766
|
+
name: 'a-programmatic-stop-takes-the-whole-stack-down',
|
|
767
|
+
timeout: 120000,
|
|
768
|
+
async run({ assert }) {
|
|
769
|
+
// `omega dev` stops its backend child with SIGTERM. The stop path was
|
|
770
|
+
// wired to SIGINT alone, so the default action killed THIS process and
|
|
771
|
+
// left the detached group — and the watcher — running.
|
|
772
|
+
await stopsEverything(assert, 'SIGTERM');
|
|
773
|
+
},
|
|
774
|
+
},
|
|
775
|
+
|
|
776
|
+
{
|
|
777
|
+
name: 'a-closed-terminal-takes-the-whole-stack-down',
|
|
778
|
+
timeout: 120000,
|
|
779
|
+
async run({ assert }) {
|
|
780
|
+
// A closed terminal sends SIGHUP, and it orphaned the same tree: four
|
|
781
|
+
// generations of parentless java emulators on one machine, one of them
|
|
782
|
+
// still holding 8080 four days later
|
|
783
|
+
// ([#629](https://github.com/Omega-JS-Stack/omega/issues/629)).
|
|
784
|
+
await stopsEverything(assert, 'SIGHUP');
|
|
785
|
+
},
|
|
786
|
+
},
|
|
787
|
+
],
|
|
788
|
+
});
|