@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,658 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: every emulator boot reaps the machine's ORPHANED emulator-family
|
|
3
|
+
* processes before it claims a port
|
|
4
|
+
* ([#781](https://github.com/Omega-JS-Stack/omega/issues/781)).
|
|
5
|
+
*
|
|
6
|
+
* Found on a real machine: ~100 `functionsEmulatorRuntime` workers from a
|
|
7
|
+
* legacy node v22 firebase-tools, plus a hub on a bumped port with three java
|
|
8
|
+
* jars, all reparented to PID 1 with their parents gone for hours. Nothing in
|
|
9
|
+
* this framework could see any of it: the port-driven reaper only looked at
|
|
10
|
+
* the ports THIS run wanted and only signalled what it could prove was this
|
|
11
|
+
* project's, and the record-driven reap only reaches pids a record still names.
|
|
12
|
+
*
|
|
13
|
+
* Run: npx omega test backend:cli/emulator-orphans
|
|
14
|
+
*
|
|
15
|
+
* The verdict is pure (a ps row in, a boolean out) and the sweep reads the
|
|
16
|
+
* world through seams, so every case below states a process table and reads
|
|
17
|
+
* back exactly what would have been signalled — nothing real is touched. The
|
|
18
|
+
* rows are copied from `ps -A -o pid=,ppid=,uid=,command=` on the machine that
|
|
19
|
+
* reported this, except the rows marked BUILT below: shapes firebase-tools
|
|
20
|
+
* launches that were not running when the snapshot was taken.
|
|
21
|
+
*
|
|
22
|
+
* The one exception is the real-process drill at the bottom, which spawns its
|
|
23
|
+
* own idle node, orphans it, and runs the REAL sweep against the REAL `ps`.
|
|
24
|
+
* Its `kill` seam forwards the signal only for the pids this file spawned and
|
|
25
|
+
* merely RECORDS anything else the sweep matched: the sweep is machine-wide by
|
|
26
|
+
* design, and a test run is not the place to exercise that half.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// Libraries
|
|
30
|
+
const os = require('os');
|
|
31
|
+
const path = require('path');
|
|
32
|
+
const childProcess = require('child_process');
|
|
33
|
+
const jetpack = require('fs-jetpack');
|
|
34
|
+
|
|
35
|
+
const EmulatorCommand = require('../../dist/cli/commands/emulator.js');
|
|
36
|
+
const orphans = require('../../dist/cli/commands/emulator-orphans.js');
|
|
37
|
+
const defineCases = require('../../dist/vendor/devkit/test/define-cases.js');
|
|
38
|
+
|
|
39
|
+
const { parseProcessTable, isOrphanedEmulatorFamily, describeFamilyMember, reapMachineOrphans } = orphans;
|
|
40
|
+
|
|
41
|
+
// This user, and somebody else (root owns half the rows in any snapshot).
|
|
42
|
+
const UID = 501;
|
|
43
|
+
const OTHER_UID = 0;
|
|
44
|
+
|
|
45
|
+
// Where an orphan lands, and two live parents: this session's own boot, and a
|
|
46
|
+
// terminal a developer typed `firebase emulators:start` into.
|
|
47
|
+
const ORPHANED = 1;
|
|
48
|
+
|
|
49
|
+
// Every temp root the drill writes carries this, and it is the ONLY thing the
|
|
50
|
+
// drill will send a real signal to.
|
|
51
|
+
const DRILL_MARKER = 'omega-orphan-drill-';
|
|
52
|
+
const OUR_BOOT = 34965;
|
|
53
|
+
const A_TERMINAL = 51900;
|
|
54
|
+
|
|
55
|
+
// ─── REAL rows (2026-09-03, ppid varies per case) ───
|
|
56
|
+
|
|
57
|
+
// The hub, both shapes: the bin on PATH, and (BUILT) firebase-tools' own entry
|
|
58
|
+
// file, the form an `emulators:exec` lane runs.
|
|
59
|
+
const HUB = 'node /Users/ian/.nvm/versions/node/v24.15.0/bin/firebase emulators:start --only functions,firestore,auth,database,hosting,pubsub';
|
|
60
|
+
const HUB_TOOLS_ENTRY = 'node /Users/ian/.nvm/versions/node/v22.22.1/lib/node_modules/firebase-tools/lib/bin/firebase.js emulators:exec --project demo-other-brand npm test';
|
|
61
|
+
|
|
62
|
+
// The functions worker — the shape that piled up ~100 deep, from the LEGACY
|
|
63
|
+
// node v22 install, which is why no path or version can be part of the match.
|
|
64
|
+
const WORKER = '/Users/ian/.nvm/versions/node/v22.22.1/bin/node /Users/ian/.nvm/versions/node/v22.22.1/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime';
|
|
65
|
+
|
|
66
|
+
// The functions DISCOVERY server: firebase-tools spawns the functions source's
|
|
67
|
+
// own `firebase-functions` bin with a random 8000-8999 PORT, reads the manifest
|
|
68
|
+
// off it, then asks it to quit. A hub killed inside that window leaves it with
|
|
69
|
+
// no parent and no timer. Real row, found on switchboard 2026-09-06: started
|
|
70
|
+
// two days earlier, ppid 1, still holding port 8615
|
|
71
|
+
// ([#805](https://github.com/Omega-JS-Stack/omega/issues/805)).
|
|
72
|
+
const DISCOVERY = 'node targets/backend/node_modules/.bin/firebase-functions targets/backend/dist';
|
|
73
|
+
// BUILT: the file that bin is a symlink to, the form a run through the entry
|
|
74
|
+
// file itself prints.
|
|
75
|
+
const DISCOVERY_ENTRY = '/Users/ian/.nvm/versions/node/v24.15.0/bin/node /Users/ian/Developer/Repositories/StreamForge-App/switchboard/targets/backend/node_modules/firebase-functions/lib/bin/firebase-functions.js /Users/ian/Developer/Repositories/StreamForge-App/switchboard/targets/backend/dist';
|
|
76
|
+
// BUILT: the same spawn from a backend target that IS the cwd, so firebase-tools
|
|
77
|
+
// hands it a bare-relative source dir and nothing precedes `node_modules`.
|
|
78
|
+
const DISCOVERY_RELATIVE = 'node node_modules/.bin/firebase-functions dist';
|
|
79
|
+
|
|
80
|
+
// The jars, from the hub that survived on port 4402. The firestore one carries
|
|
81
|
+
// `--database-edition standard`, so a naive name match calls it the database.
|
|
82
|
+
const FIRESTORE_JAR = 'java -Dgoogle.cloud_firestore.debug_log_level=FINE -Duser.language=en -jar /Users/ian/.cache/firebase/emulators/cloud-firestore-emulator-v1.21.0.jar --host 127.0.0.1 --port 9152 --websocket_port 9150 --database-edition standard --project_id demo-other-brand --single_project_mode true';
|
|
83
|
+
const DATABASE_JAR = 'java -Duser.language=en -jar /Users/ian/.cache/firebase/emulators/firebase-database-emulator-v4.11.2.jar --host 127.0.0.1 --port 9153 --functions_emulator_port 9155';
|
|
84
|
+
const PUBSUB_JAR = 'java -jar /Users/ian/.cache/firebase/emulators/pubsub-emulator-0.8.34/pubsub-emulator/lib/cloud-pubsub-emulator-0.8.34-all.jar --host=127.0.0.1 --port=9154';
|
|
85
|
+
// BUILT: the storage rules runtime, and a jar the emulator cache grows later.
|
|
86
|
+
const STORAGE_JAR = 'java -jar /Users/ian/.cache/firebase/emulators/cloud-storage-rules-runtime-v1.1.3.jar';
|
|
87
|
+
const UNKNOWN_JAR = 'java -jar /Users/ian/.cache/firebase/emulators/some-future-emulator-v1.0.0.jar --port 9160';
|
|
88
|
+
|
|
89
|
+
// Puppeteer's browser: the temp profile name is the whole signal — only
|
|
90
|
+
// puppeteer ever creates a `puppeteer_dev_chrome_profile-` directory.
|
|
91
|
+
const PUPPETEER_CHROME = '/Users/ian/.cache/puppeteer/chrome/mac_arm-140.0.7339.80/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing --allow-pre-commit-input --disable-background-networking --headless=new --user-data-dir=/var/folders/gx/7g25kfls0c96yfb6nt3bsg1m0000gn/T/puppeteer_dev_chrome_profile-a1B2c3 --remote-debugging-port=0';
|
|
92
|
+
|
|
93
|
+
// ─── REAL rows that must survive, even at PID 1 ───
|
|
94
|
+
|
|
95
|
+
const USER_CHROME = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
|
96
|
+
// BUILT. devkit's port-hold and boot-child are LIBRARY modules a lane requires
|
|
97
|
+
// in-process — they are never a spawned argv, so a command line naming one is
|
|
98
|
+
// always somebody else reading the file (an editor, a grep, a node -e).
|
|
99
|
+
const EDITOR_ON_PORT_HOLD = '/Applications/Visual Studio Code.app/Contents/MacOS/Electron /Users/ian/Developer/Repositories/Omega/omega/packages/devkit/src/test/port-hold.js';
|
|
100
|
+
// BUILT. An editor sitting on the discovery server's own bin file, and one on a
|
|
101
|
+
// source file of the same package: a command line that NAMES `firebase-functions`
|
|
102
|
+
// is not a node running it.
|
|
103
|
+
const EDITOR_ON_DISCOVERY_BIN = '/Applications/Visual Studio Code.app/Contents/MacOS/Electron /Users/ian/Developer/Repositories/StreamForge-App/switchboard/targets/backend/node_modules/firebase-functions/lib/bin/firebase-functions.js';
|
|
104
|
+
const EDITOR_ON_FUNCTIONS_SOURCE = '/Applications/Visual Studio Code.app/Contents/MacOS/Electron /Users/ian/Developer/Repositories/StreamForge-App/switchboard/targets/backend/node_modules/firebase-functions/lib/common/providers/https.js';
|
|
105
|
+
const OMEGA_CLI = 'node /Users/ian/Developer/Repositories/Omega/omega/node_modules/.bin/omega emulator';
|
|
106
|
+
const MGR_CLI = 'node /Users/ian/Developer/Repositories/Omega/omega/node_modules/.bin/mgr dev';
|
|
107
|
+
const FIREBASE_DEPLOY = 'node /Users/ian/.nvm/versions/node/v24.15.0/bin/firebase deploy --only functions --project omegajs';
|
|
108
|
+
// The reload watcher: it runs with PPID 1 while its session is very much alive,
|
|
109
|
+
// and its argv names firebase paths — the row the loose name regex killed
|
|
110
|
+
// ([#293](https://github.com/Omega-JS-Stack/omega/issues/293)).
|
|
111
|
+
const RELOAD_WATCHER = 'node /Users/ian/.nvm/versions/node/v22.22.1/bin/nodemon --on-change-only --delay 1 --watch /Users/ian/Developer/Repositories/Omega/omega/packages/backend/src --ext js,json --exec node -e "fs.writeFileSync(\'/Users/ian/Developer/Repositories/Omega/omega/brands/sandbox-brand/targets/backend/.temp/emulator.log.reset\',\'\')"';
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* A fixture process table plus the seams the sweep reads the world through.
|
|
115
|
+
*
|
|
116
|
+
* `readTable` renders the rows exactly as `ps -A -o pid=,ppid=,uid=,command=`
|
|
117
|
+
* does, `readProcess` is the per-pid re-read the escalation proves itself with,
|
|
118
|
+
* `kill` is the signal, and `isFree` is the port probe — so a case states what
|
|
119
|
+
* is running and reads back what would have been signalled. Nothing leaves this
|
|
120
|
+
* process.
|
|
121
|
+
* @param {object} table - pid → { ppid, uid, command } as ps would report it.
|
|
122
|
+
* @param {object} [options]
|
|
123
|
+
* @param {Function} [options.afterTerm] - What SIGTERM does (default: it exits).
|
|
124
|
+
* @param {number[]} [options.busyPorts] - Ports the probe reports as still held.
|
|
125
|
+
*/
|
|
126
|
+
function processTable(table, { afterTerm, busyPorts = [] } = {}) {
|
|
127
|
+
const live = new Map(Object.entries(table).map(([pid, row]) => [Number(pid), { uid: UID, ...row }]));
|
|
128
|
+
const signals = [];
|
|
129
|
+
const probed = [];
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
signals: signals,
|
|
133
|
+
probed: probed,
|
|
134
|
+
live: live,
|
|
135
|
+
signalled: (pid) => signals.filter((entry) => entry.pid === Number(pid)).map((entry) => entry.signal),
|
|
136
|
+
seams: {
|
|
137
|
+
uid: UID,
|
|
138
|
+
graceMs: 50,
|
|
139
|
+
readTable: () => [...live.entries()].map(([pid, row]) => ` ${pid} ${row.ppid} ${row.uid} ${row.command}`).join('\n'),
|
|
140
|
+
readProcess: (pid) => {
|
|
141
|
+
const row = live.get(Number(pid));
|
|
142
|
+
|
|
143
|
+
return row ? { pid: Number(pid), ppid: row.ppid, uid: row.uid, command: row.command } : null;
|
|
144
|
+
},
|
|
145
|
+
kill: (pid, signal) => {
|
|
146
|
+
signals.push({ pid: Number(pid), signal: signal });
|
|
147
|
+
|
|
148
|
+
if (signal === 'SIGTERM') {
|
|
149
|
+
(afterTerm || ((target, rows) => rows.delete(target)))(Number(pid), live);
|
|
150
|
+
} else {
|
|
151
|
+
live.delete(Number(pid));
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
isFree: async (port) => {
|
|
155
|
+
probed.push(port);
|
|
156
|
+
|
|
157
|
+
return !busyPorts.includes(port);
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** A row as ps prints it, for the pure-verdict cases. */
|
|
164
|
+
function row(pid, ppid, command, uid = UID) {
|
|
165
|
+
return { pid: pid, ppid: ppid, uid: uid, command: command };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* The idle stand-in for a functions worker: a real node process whose argv path
|
|
170
|
+
* is the family shape, so the REAL matcher sees a REAL row for it.
|
|
171
|
+
* @param {string} dir - The temp root to write it under.
|
|
172
|
+
* @returns {string} The script path.
|
|
173
|
+
*/
|
|
174
|
+
function writeWorkerScript(dir) {
|
|
175
|
+
const script = path.join(dir, 'firebase-tools', 'lib', 'emulator', 'functionsEmulatorRuntime.js');
|
|
176
|
+
|
|
177
|
+
jetpack.write(script, 'setInterval(() => {}, 1000);\n');
|
|
178
|
+
|
|
179
|
+
return script;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Poll `probe` until it answers truthy or the window closes.
|
|
184
|
+
* @param {Function} probe - Returns the answer, or a falsy value to keep waiting.
|
|
185
|
+
* @param {number} timeoutMs - How long to keep asking.
|
|
186
|
+
* @returns {Promise<*>} The answer, or null when the window closed.
|
|
187
|
+
*/
|
|
188
|
+
async function until(probe, timeoutMs) {
|
|
189
|
+
const deadline = Date.now() + timeoutMs;
|
|
190
|
+
|
|
191
|
+
while (Date.now() < deadline) {
|
|
192
|
+
const answer = probe();
|
|
193
|
+
|
|
194
|
+
if (answer) {
|
|
195
|
+
return answer;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Every live pid whose command line contains `needle`, from the real `ps`. */
|
|
205
|
+
function livePidsRunning(needle) {
|
|
206
|
+
return parseProcessTable(orphans.readProcessTable())
|
|
207
|
+
.filter((entry) => entry.command.includes(needle))
|
|
208
|
+
.map((entry) => entry.pid);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = defineCases({
|
|
212
|
+
description: 'machine-wide reap of orphaned emulator-family processes (#781)',
|
|
213
|
+
type: 'group',
|
|
214
|
+
timeout: 60000,
|
|
215
|
+
|
|
216
|
+
tests: [
|
|
217
|
+
// ─── the snapshot ───
|
|
218
|
+
|
|
219
|
+
{
|
|
220
|
+
name: 'a-real-ps-snapshot-parses-into-rows',
|
|
221
|
+
async run({ assert }) {
|
|
222
|
+
const text = [
|
|
223
|
+
` 1 0 0 /sbin/launchd`,
|
|
224
|
+
`73529 1 501 ${FIRESTORE_JAR}`,
|
|
225
|
+
`74155 ${OUR_BOOT} 501 ${PUBSUB_JAR}`,
|
|
226
|
+
``,
|
|
227
|
+
`garbage line with no numbers`,
|
|
228
|
+
].join('\n');
|
|
229
|
+
|
|
230
|
+
const rows = parseProcessTable(text);
|
|
231
|
+
|
|
232
|
+
assert.equal(rows.length, 3, 'blank and unparseable lines are dropped, never guessed at');
|
|
233
|
+
assert.deepEqual(rows[0], { pid: 1, ppid: 0, uid: 0, command: '/sbin/launchd' });
|
|
234
|
+
assert.equal(rows[1].pid, 73529);
|
|
235
|
+
assert.equal(rows[1].ppid, 1);
|
|
236
|
+
assert.equal(rows[1].uid, 501);
|
|
237
|
+
assert.equal(rows[1].command, FIRESTORE_JAR, 'the command keeps every flag and space it was printed with');
|
|
238
|
+
assert.equal(rows[2].ppid, OUR_BOOT);
|
|
239
|
+
assert.deepEqual(parseProcessTable(''), []);
|
|
240
|
+
assert.deepEqual(parseProcessTable(null), []);
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
// ─── the two proofs: orphaned AND family ───
|
|
245
|
+
|
|
246
|
+
{
|
|
247
|
+
name: 'this-sessions-live-stack-is-untouched',
|
|
248
|
+
async run({ assert }) {
|
|
249
|
+
// Every member of a LIVE stack hangs off the boot that spawned it, so
|
|
250
|
+
// the sweep never considers it — the boot cannot eat its own tail.
|
|
251
|
+
assert.equal(isOrphanedEmulatorFamily(row(37088, OUR_BOOT, FIRESTORE_JAR), UID), false);
|
|
252
|
+
assert.equal(isOrphanedEmulatorFamily(row(37360, OUR_BOOT, PUBSUB_JAR), UID), false);
|
|
253
|
+
assert.equal(isOrphanedEmulatorFamily(row(37361, OUR_BOOT, WORKER), UID), false);
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
{
|
|
258
|
+
name: 'a-hand-run-hub-in-a-terminal-is-untouched',
|
|
259
|
+
async run({ assert }) {
|
|
260
|
+
// A developer typed `firebase emulators:start` in a shell that is still
|
|
261
|
+
// open: the shell is its parent, so it is nobody's leftover.
|
|
262
|
+
assert.equal(isOrphanedEmulatorFamily(row(51901, A_TERMINAL, HUB), UID), false);
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
{
|
|
267
|
+
name: 'another-uid-is-never-a-candidate',
|
|
268
|
+
async run({ assert }) {
|
|
269
|
+
// Same row, same PID 1, a different owner. Signalling it would fail
|
|
270
|
+
// anyway — but the verdict is the gate, not the OS's refusal.
|
|
271
|
+
assert.equal(isOrphanedEmulatorFamily(row(73529, ORPHANED, FIRESTORE_JAR, OTHER_UID), UID), false);
|
|
272
|
+
assert.equal(isOrphanedEmulatorFamily(row(73529, ORPHANED, FIRESTORE_JAR), undefined), false, 'no uid of our own proves nothing');
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
{
|
|
277
|
+
name: 'a-legacy-workers-orphan-is-reaped-whatever-node-installed-it',
|
|
278
|
+
async run({ assert }) {
|
|
279
|
+
// The ~100-deep pile: a firebase-tools from a node version this machine
|
|
280
|
+
// no longer even runs. No path and no version is part of the match.
|
|
281
|
+
assert.equal(isOrphanedEmulatorFamily(row(38483, ORPHANED, WORKER), UID), true);
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
{
|
|
286
|
+
name: 'the-discovery-servers-orphan-is-reaped-in-both-its-shapes',
|
|
287
|
+
async run({ assert }) {
|
|
288
|
+
// The row that outlived two boots on switchboard: the hub that spawned
|
|
289
|
+
// it went down inside its 10s quit window, so nothing was left to ask
|
|
290
|
+
// it to leave and nothing but this sweep can reach it (#805).
|
|
291
|
+
assert.equal(isOrphanedEmulatorFamily(row(38500, ORPHANED, DISCOVERY), UID), true);
|
|
292
|
+
assert.equal(isOrphanedEmulatorFamily(row(38501, ORPHANED, DISCOVERY_ENTRY), UID), true);
|
|
293
|
+
assert.equal(isOrphanedEmulatorFamily(row(38504, ORPHANED, DISCOVERY_RELATIVE), UID), true, 'a bare-relative source dir puts nothing at all before `node_modules`');
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
{
|
|
298
|
+
name: 'a-discovery-server-under-a-living-hub-is-untouched',
|
|
299
|
+
async run({ assert }) {
|
|
300
|
+
// Same parentage rule as the worker: while the hub that spawned it is
|
|
301
|
+
// alive, the hub owns its teardown and the sweep never considers it.
|
|
302
|
+
assert.equal(isOrphanedEmulatorFamily(row(38502, OUR_BOOT, DISCOVERY), UID), false);
|
|
303
|
+
assert.equal(isOrphanedEmulatorFamily(row(38503, A_TERMINAL, DISCOVERY_ENTRY), UID), false);
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
{
|
|
308
|
+
name: 'a-command-that-merely-names-firebase-functions-survives-the-sweep',
|
|
309
|
+
async run({ assert }) {
|
|
310
|
+
// The #293 lesson on the newest shape: the match is a node RUNNING the
|
|
311
|
+
// bin, so an editor holding that very file open is not family, and
|
|
312
|
+
// neither is anything else naming the package.
|
|
313
|
+
assert.equal(isOrphanedEmulatorFamily(row(60009, ORPHANED, EDITOR_ON_DISCOVERY_BIN), UID), false);
|
|
314
|
+
assert.equal(isOrphanedEmulatorFamily(row(60010, ORPHANED, EDITOR_ON_FUNCTIONS_SOURCE), UID), false);
|
|
315
|
+
assert.equal(describeFamilyMember(EDITOR_ON_DISCOVERY_BIN), null);
|
|
316
|
+
assert.equal(describeFamilyMember(EDITOR_ON_FUNCTIONS_SOURCE), null);
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
|
|
320
|
+
{
|
|
321
|
+
name: 'a-bumped-port-hub-and-every-jar-under-it-are-reaped',
|
|
322
|
+
async run({ assert }) {
|
|
323
|
+
// The hub sat on 4402, so no port this run wants could ever reach it,
|
|
324
|
+
// and it named another brand's project — which stops mattering the
|
|
325
|
+
// moment its parent is gone (#781 supersedes #293 on that point).
|
|
326
|
+
assert.equal(isOrphanedEmulatorFamily(row(38400, ORPHANED, HUB), UID), true);
|
|
327
|
+
assert.equal(isOrphanedEmulatorFamily(row(38401, ORPHANED, HUB_TOOLS_ENTRY), UID), true);
|
|
328
|
+
assert.equal(isOrphanedEmulatorFamily(row(73529, ORPHANED, FIRESTORE_JAR), UID), true);
|
|
329
|
+
assert.equal(isOrphanedEmulatorFamily(row(73530, ORPHANED, DATABASE_JAR), UID), true);
|
|
330
|
+
assert.equal(isOrphanedEmulatorFamily(row(74155, ORPHANED, PUBSUB_JAR), UID), true);
|
|
331
|
+
assert.equal(isOrphanedEmulatorFamily(row(74156, ORPHANED, STORAGE_JAR), UID), true);
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
{
|
|
336
|
+
name: 'puppeteers-headless-browser-is-family',
|
|
337
|
+
async run({ assert }) {
|
|
338
|
+
// A lane's chrome outlives the lane exactly as the jars do, and its
|
|
339
|
+
// throwaway profile directory is the only thing that says so.
|
|
340
|
+
assert.equal(isOrphanedEmulatorFamily(row(41003, ORPHANED, PUPPETEER_CHROME), UID), true);
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
{
|
|
345
|
+
name: 'the-reload-watcher-survives-the-sweep',
|
|
346
|
+
async run({ assert }) {
|
|
347
|
+
// nodemon runs at PID 1 with a LIVE session behind it, and its argv
|
|
348
|
+
// names firebase paths. The strict family match is the whole reason it
|
|
349
|
+
// lives: it is not a hub, a worker, a jar, a helper or a browser.
|
|
350
|
+
assert.equal(isOrphanedEmulatorFamily(row(60001, ORPHANED, RELOAD_WATCHER), UID), false);
|
|
351
|
+
assert.equal(describeFamilyMember(RELOAD_WATCHER), null);
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
{
|
|
356
|
+
name: 'the-cli-a-deploy-and-a-users-browser-survive-the-sweep',
|
|
357
|
+
async run({ assert }) {
|
|
358
|
+
// `omega emulator` is the process running this very sweep; `firebase
|
|
359
|
+
// deploy` is a live publish; a Chrome launched from Finder has PID 1
|
|
360
|
+
// for a parent and no puppeteer profile.
|
|
361
|
+
assert.equal(isOrphanedEmulatorFamily(row(60002, ORPHANED, OMEGA_CLI), UID), false);
|
|
362
|
+
assert.equal(isOrphanedEmulatorFamily(row(60003, ORPHANED, MGR_CLI), UID), false);
|
|
363
|
+
assert.equal(isOrphanedEmulatorFamily(row(60004, ORPHANED, FIREBASE_DEPLOY), UID), false);
|
|
364
|
+
assert.equal(isOrphanedEmulatorFamily(row(60005, ORPHANED, USER_CHROME), UID), false);
|
|
365
|
+
assert.equal(isOrphanedEmulatorFamily(row(60006, ORPHANED, 'node /Users/ian/some-other-tool/server.js'), UID), false);
|
|
366
|
+
assert.equal(isOrphanedEmulatorFamily(row(60007, ORPHANED, 'java -jar /Users/ian/Developer/tools/some-app.jar'), UID), false, 'a jar outside the firebase emulator cache is somebody else\'s');
|
|
367
|
+
assert.equal(isOrphanedEmulatorFamily(row(60008, ORPHANED, EDITOR_ON_PORT_HOLD), UID), false, "a devkit lane helper is a library module, so a process NAMING one is never running one");
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
|
|
371
|
+
{
|
|
372
|
+
name: 'init-itself-is-never-a-candidate',
|
|
373
|
+
async run({ assert }) {
|
|
374
|
+
assert.equal(isOrphanedEmulatorFamily(row(1, 0, '/sbin/launchd'), UID), false);
|
|
375
|
+
assert.equal(isOrphanedEmulatorFamily(row(NaN, ORPHANED, WORKER), UID), false);
|
|
376
|
+
assert.equal(isOrphanedEmulatorFamily(undefined, UID), false);
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
// ─── the short label the log prints ───
|
|
381
|
+
|
|
382
|
+
{
|
|
383
|
+
name: 'every-family-member-has-a-short-name',
|
|
384
|
+
async run({ assert }) {
|
|
385
|
+
assert.equal(describeFamilyMember(HUB), 'firebase hub');
|
|
386
|
+
assert.equal(describeFamilyMember(HUB_TOOLS_ENTRY), 'firebase hub');
|
|
387
|
+
assert.equal(describeFamilyMember(WORKER), 'functions worker');
|
|
388
|
+
assert.equal(describeFamilyMember(DISCOVERY), 'functions discovery server');
|
|
389
|
+
assert.equal(describeFamilyMember(DISCOVERY_ENTRY), 'functions discovery server');
|
|
390
|
+
assert.equal(describeFamilyMember(FIRESTORE_JAR), 'firestore jar', 'the firestore jar names a database edition — the JAR decides, not the argv');
|
|
391
|
+
assert.equal(describeFamilyMember(DATABASE_JAR), 'database jar');
|
|
392
|
+
assert.equal(describeFamilyMember(PUBSUB_JAR), 'pubsub jar');
|
|
393
|
+
assert.equal(describeFamilyMember(STORAGE_JAR), 'storage jar');
|
|
394
|
+
assert.equal(describeFamilyMember(UNKNOWN_JAR), 'emulator jar', 'a jar the cache grows tomorrow is still an emulator jar');
|
|
395
|
+
assert.equal(describeFamilyMember(PUPPETEER_CHROME), 'puppeteer chrome');
|
|
396
|
+
assert.equal(describeFamilyMember(USER_CHROME), null);
|
|
397
|
+
assert.equal(describeFamilyMember(EDITOR_ON_PORT_HOLD), null);
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
// ─── the sweep ───
|
|
402
|
+
|
|
403
|
+
{
|
|
404
|
+
name: 'the-sweep-signals-every-orphan-and-nothing-else',
|
|
405
|
+
async run({ assert }) {
|
|
406
|
+
const table = processTable({
|
|
407
|
+
73529: { ppid: ORPHANED, command: FIRESTORE_JAR },
|
|
408
|
+
74155: { ppid: ORPHANED, command: PUBSUB_JAR },
|
|
409
|
+
38483: { ppid: ORPHANED, command: WORKER },
|
|
410
|
+
37088: { ppid: OUR_BOOT, command: FIRESTORE_JAR },
|
|
411
|
+
60001: { ppid: ORPHANED, command: RELOAD_WATCHER },
|
|
412
|
+
60002: { ppid: ORPHANED, command: FIRESTORE_JAR, uid: OTHER_UID },
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
const result = await reapMachineOrphans(table.seams);
|
|
416
|
+
|
|
417
|
+
assert.deepEqual(result.reaped.map((entry) => entry.pid).sort(), [38483, 73529, 74155]);
|
|
418
|
+
assert.deepEqual(result.killed, [], 'everything left on the first signal');
|
|
419
|
+
assert.deepEqual(table.signals.map((entry) => entry.signal), ['SIGTERM', 'SIGTERM', 'SIGTERM']);
|
|
420
|
+
assert.deepEqual(table.signalled(37088), [], "a live stack's jar is never signalled");
|
|
421
|
+
assert.deepEqual(table.signalled(60001), [], 'the watcher is never signalled');
|
|
422
|
+
assert.deepEqual(table.signalled(60002), [], "another user's jar is never signalled");
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
|
|
426
|
+
{
|
|
427
|
+
name: 'only-the-survivors-of-sigterm-are-sigkilled',
|
|
428
|
+
async run({ assert }) {
|
|
429
|
+
// Escalation order is the safety story: SIGTERM to everything, and
|
|
430
|
+
// SIGKILL only to what is still standing after the grace window.
|
|
431
|
+
const table = processTable({
|
|
432
|
+
73529: { ppid: ORPHANED, command: FIRESTORE_JAR },
|
|
433
|
+
74155: { ppid: ORPHANED, command: PUBSUB_JAR },
|
|
434
|
+
}, {
|
|
435
|
+
// The firestore jar ignores SIGTERM, as a JVM mid-write does.
|
|
436
|
+
afterTerm: (pid, rows) => { if (pid !== 73529) rows.delete(pid); },
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
const result = await reapMachineOrphans(table.seams);
|
|
440
|
+
|
|
441
|
+
assert.deepEqual(table.signalled(74155), ['SIGTERM'], 'a process that left needs nothing more');
|
|
442
|
+
assert.deepEqual(table.signalled(73529), ['SIGTERM', 'SIGKILL'], 'the survivor is escalated, in that order');
|
|
443
|
+
assert.deepEqual(result.killed, [73529]);
|
|
444
|
+
assert.deepEqual(result.reaped.map((entry) => entry.pid).sort(), [73529, 74155]);
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
{
|
|
449
|
+
name: 'a-recycled-pid-is-spared-on-the-re-read',
|
|
450
|
+
async run({ assert }) {
|
|
451
|
+
// The grace window is long enough for a number to be freed and handed
|
|
452
|
+
// out again, and there is no apologising to a SIGKILL: the row is read
|
|
453
|
+
// again and must STILL be an orphaned family member.
|
|
454
|
+
const table = processTable({
|
|
455
|
+
73529: { ppid: ORPHANED, command: FIRESTORE_JAR },
|
|
456
|
+
}, {
|
|
457
|
+
afterTerm: (pid, rows) => rows.set(pid, { ppid: A_TERMINAL, uid: UID, command: 'node /Users/ian/some-other-tool/server.js' }),
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
const result = await reapMachineOrphans(table.seams);
|
|
461
|
+
|
|
462
|
+
assert.deepEqual(table.signalled(73529), ['SIGTERM'], 'the number came back as a stranger — no SIGKILL');
|
|
463
|
+
assert.deepEqual(result.killed, []);
|
|
464
|
+
assert.deepEqual(result.reaped, [], 'nothing of ours went down, so nothing is reported reaped');
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
|
|
468
|
+
{
|
|
469
|
+
name: 'the-ports-the-orphans-held-are-waited-on-before-the-boot-continues',
|
|
470
|
+
async run({ assert }) {
|
|
471
|
+
// A SIGKILLed JVM holds its listener after kill() returns, and the
|
|
472
|
+
// allocator probes these very ports moments later.
|
|
473
|
+
const table = processTable({
|
|
474
|
+
73529: { ppid: ORPHANED, command: FIRESTORE_JAR },
|
|
475
|
+
74155: { ppid: ORPHANED, command: PUBSUB_JAR },
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
await reapMachineOrphans(table.seams);
|
|
479
|
+
|
|
480
|
+
assert.deepEqual([...new Set(table.probed)].sort((a, b) => a - b), [9150, 9152, 9154], 'every port the reaped rows published, websocket included');
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
{
|
|
485
|
+
name: 'the-sweep-never-signals-itself-or-its-parent',
|
|
486
|
+
async run({ assert }) {
|
|
487
|
+
// No ownership proof stands behind this sweep, so the two numbers it
|
|
488
|
+
// must never signal are named outright: a family-shaped row wearing
|
|
489
|
+
// this very pid would otherwise make the boot kill itself mid-reap.
|
|
490
|
+
const table = processTable({
|
|
491
|
+
[process.pid]: { ppid: ORPHANED, command: FIRESTORE_JAR },
|
|
492
|
+
[process.ppid]: { ppid: ORPHANED, command: WORKER },
|
|
493
|
+
73529: { ppid: ORPHANED, command: PUBSUB_JAR },
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
// Not vacuous: both rows clear the verdict, so the guard is the only
|
|
497
|
+
// thing standing between this boot and its own SIGTERM.
|
|
498
|
+
assert.equal(isOrphanedEmulatorFamily(row(process.pid, ORPHANED, FIRESTORE_JAR), UID), true);
|
|
499
|
+
|
|
500
|
+
const result = await reapMachineOrphans(table.seams);
|
|
501
|
+
|
|
502
|
+
assert.deepEqual(table.signalled(process.pid), [], 'the running boot is never a candidate');
|
|
503
|
+
assert.deepEqual(table.signalled(process.ppid), [], 'nor is whatever launched it');
|
|
504
|
+
assert.deepEqual(result.reaped.map((entry) => entry.pid), [73529], 'the real orphan beside them still goes');
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
|
|
508
|
+
{
|
|
509
|
+
name: 'nothing-orphaned-means-no-signal-and-no-probe',
|
|
510
|
+
async run({ assert }) {
|
|
511
|
+
const table = processTable({
|
|
512
|
+
37088: { ppid: OUR_BOOT, command: FIRESTORE_JAR },
|
|
513
|
+
60001: { ppid: ORPHANED, command: RELOAD_WATCHER },
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
const result = await reapMachineOrphans(table.seams);
|
|
517
|
+
|
|
518
|
+
assert.deepEqual(result, { reaped: [], killed: [] });
|
|
519
|
+
assert.deepEqual(table.signals, []);
|
|
520
|
+
assert.deepEqual(table.probed, [], 'a boot with nothing to reap pays for nothing');
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
// ─── what the boot prints ───
|
|
525
|
+
|
|
526
|
+
{
|
|
527
|
+
name: 'the-boot-names-every-pid-it-reaped-and-what-it-was',
|
|
528
|
+
async run({ assert }) {
|
|
529
|
+
const command = new EmulatorCommand({ firebaseProjectPath: os.tmpdir(), argv: {}, options: {} });
|
|
530
|
+
const lines = [];
|
|
531
|
+
|
|
532
|
+
command.log = (message) => lines.push(String(message));
|
|
533
|
+
|
|
534
|
+
const table = processTable({
|
|
535
|
+
73529: { ppid: ORPHANED, command: FIRESTORE_JAR },
|
|
536
|
+
74155: { ppid: ORPHANED, command: PUBSUB_JAR },
|
|
537
|
+
38483: { ppid: ORPHANED, command: WORKER },
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
await command.reapMachineOrphans(table.seams);
|
|
541
|
+
|
|
542
|
+
assert.equal(lines.length, 1, 'one line per boot, not one per pid');
|
|
543
|
+
// Named in table order, which `ps -A` prints by pid.
|
|
544
|
+
assert.match(lines[0], /Reaped 3 orphaned emulator processes left by earlier runs: 38483 functions worker, 73529 firestore jar, 74155 pubsub jar\./);
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
|
|
548
|
+
{
|
|
549
|
+
name: 'the-boot-is-silent-when-there-is-nothing-to-reap',
|
|
550
|
+
async run({ assert }) {
|
|
551
|
+
const command = new EmulatorCommand({ firebaseProjectPath: os.tmpdir(), argv: {}, options: {} });
|
|
552
|
+
const lines = [];
|
|
553
|
+
|
|
554
|
+
command.log = (message) => lines.push(String(message));
|
|
555
|
+
|
|
556
|
+
const table = processTable({ 37088: { ppid: OUR_BOOT, command: FIRESTORE_JAR } });
|
|
557
|
+
|
|
558
|
+
await command.reapMachineOrphans(table.seams);
|
|
559
|
+
|
|
560
|
+
assert.deepEqual(lines, [], 'a clean machine says nothing at all');
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
|
|
564
|
+
{
|
|
565
|
+
name: 'a-single-reap-and-a-sigkill-read-in-plain-english',
|
|
566
|
+
async run({ assert }) {
|
|
567
|
+
const command = new EmulatorCommand({ firebaseProjectPath: os.tmpdir(), argv: {}, options: {} });
|
|
568
|
+
const lines = [];
|
|
569
|
+
|
|
570
|
+
command.log = (message) => lines.push(String(message));
|
|
571
|
+
|
|
572
|
+
const table = processTable({ 73529: { ppid: ORPHANED, command: FIRESTORE_JAR } }, { afterTerm: () => {} });
|
|
573
|
+
|
|
574
|
+
await command.reapMachineOrphans(table.seams);
|
|
575
|
+
|
|
576
|
+
// The escalation note sits where every sibling reap line puts it, so
|
|
577
|
+
// the pid list is never read as "this one needed SIGKILL".
|
|
578
|
+
assert.match(lines[0], /Reaped 1 orphaned emulator process left by earlier runs \(1 needed SIGKILL\): 73529 firestore jar\./);
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
|
|
582
|
+
// ─── the real thing ───
|
|
583
|
+
|
|
584
|
+
{
|
|
585
|
+
name: 'a-real-orphan-is-reaped-and-a-parented-one-survives',
|
|
586
|
+
async run({ assert }) {
|
|
587
|
+
// The whole chain against the real OS: a real `ps -A`, a real row for a
|
|
588
|
+
// real process, and a real SIGTERM. The script is a plain idling node
|
|
589
|
+
// whose path IS the functions-worker shape.
|
|
590
|
+
const dir = jetpack.tmpDir({ prefix: 'omega-orphan-drill-' }).cwd();
|
|
591
|
+
const script = writeWorkerScript(dir);
|
|
592
|
+
const spared = [];
|
|
593
|
+
let live = null;
|
|
594
|
+
|
|
595
|
+
try {
|
|
596
|
+
// The orphan: `sh` exits the moment it has forked, so the node it
|
|
597
|
+
// started reparents to PID 1 with nobody left to tear it down. Its
|
|
598
|
+
// stdio is redirected because execSync waits for the child's pipes to
|
|
599
|
+
// close, and an idling node never closes an inherited one.
|
|
600
|
+
childProcess.execSync(`sh -c 'node ${script} > /dev/null 2>&1 &'`, { stdio: 'ignore' });
|
|
601
|
+
|
|
602
|
+
const orphanPid = await until(() => {
|
|
603
|
+
const found = parseProcessTable(orphans.readProcessTable())
|
|
604
|
+
.filter((entry) => entry.command.includes(script) && entry.ppid === 1)
|
|
605
|
+
.map((entry) => entry.pid);
|
|
606
|
+
|
|
607
|
+
return found.length > 0 ? found[0] : null;
|
|
608
|
+
}, 10000);
|
|
609
|
+
|
|
610
|
+
assert.ok(orphanPid, 'the drill needs a real orphan to reap');
|
|
611
|
+
|
|
612
|
+
// The one it must NOT touch: same command line, live parent (this
|
|
613
|
+
// very process), so the parentage half of the proof spares it.
|
|
614
|
+
live = childProcess.spawn(process.execPath, [script], { stdio: 'ignore' });
|
|
615
|
+
|
|
616
|
+
await until(() => livePidsRunning(script).includes(live.pid), 10000);
|
|
617
|
+
|
|
618
|
+
const result = await reapMachineOrphans({
|
|
619
|
+
graceMs: 2000,
|
|
620
|
+
// Machine-wide is the DESIGN, but a test run signals only what
|
|
621
|
+
// THIS FILE spawned — every one of those runs out of a temp root
|
|
622
|
+
// carrying the drill marker. Anything else the sweep matched on
|
|
623
|
+
// this machine is recorded and left standing.
|
|
624
|
+
kill: (pid, signal) => {
|
|
625
|
+
const live = orphans.readProcessRow(pid);
|
|
626
|
+
|
|
627
|
+
if (!live || !live.command.includes(DRILL_MARKER)) {
|
|
628
|
+
spared.push({ pid: Number(pid), signal: signal });
|
|
629
|
+
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
process.kill(pid, signal);
|
|
634
|
+
},
|
|
635
|
+
// Our idle node binds nothing, and probing real ports is not this
|
|
636
|
+
// drill's business.
|
|
637
|
+
isFree: async () => true,
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
assert.ok(result.reaped.some((entry) => entry.pid === orphanPid), 'the real orphan is reported reaped');
|
|
641
|
+
assert.equal(result.reaped.find((entry) => entry.pid === orphanPid).label, 'functions worker');
|
|
642
|
+
|
|
643
|
+
const gone = await until(() => !livePidsRunning(script).includes(orphanPid), 5000);
|
|
644
|
+
|
|
645
|
+
assert.ok(gone, 'the real orphan is actually gone');
|
|
646
|
+
assert.ok(livePidsRunning(script).includes(live.pid), 'the same shape with a live parent survives the sweep');
|
|
647
|
+
assert.deepEqual(spared.filter((entry) => entry.pid === live.pid), [], 'the parented one was never even signalled');
|
|
648
|
+
} finally {
|
|
649
|
+
if (live) {
|
|
650
|
+
live.kill();
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
jetpack.remove(dir);
|
|
654
|
+
}
|
|
655
|
+
},
|
|
656
|
+
},
|
|
657
|
+
],
|
|
658
|
+
});
|