@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,976 @@
|
|
|
1
|
+
const BaseCommand = require('./base-command');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const util = require('util');
|
|
6
|
+
const { spawnShell } = require('../utils/spawn-shell');
|
|
7
|
+
const chalk = require('chalk').default;
|
|
8
|
+
const jetpack = require('fs-jetpack');
|
|
9
|
+
const powertools = require('node-powertools');
|
|
10
|
+
const { loadEmulatorPorts } = require('./setup-tests/emulator-config');
|
|
11
|
+
const { javaInstallHint } = require('./setup-tests/helpers');
|
|
12
|
+
const { readPortsFile, portsToEnv } = require('../../vendor/config/index.js');
|
|
13
|
+
const { writeTestMode, captureSyncedEnv, SYNCED_ENV_KEYS } = require('../../test/utils/test-mode-file');
|
|
14
|
+
const EmulatorCommand = require('./emulator');
|
|
15
|
+
const { refuseWhenCustom } = require('../utils/project-type');
|
|
16
|
+
const { runTargetChecks } = require('../utils/target-checks');
|
|
17
|
+
const { STOP_SIGNALS } = require('../../vendor/devkit/stop-signals.js');
|
|
18
|
+
|
|
19
|
+
// The Firebase emulator hub — fixed, not part of the N7-allocated map.
|
|
20
|
+
const HUB_PORT = 4400;
|
|
21
|
+
|
|
22
|
+
// Where a running hub publishes WHO it is: firebase-tools writes
|
|
23
|
+
// `${os.tmpdir()}/hub-<projectId>.json` ({version, origins, pid}) for the life
|
|
24
|
+
// of the stack. The file name IS the identity — the hub's own
|
|
25
|
+
// `GET /emulators` answers a map of emulator → listen info and has never
|
|
26
|
+
// carried a project id, so the read that asked it for one always came back
|
|
27
|
+
// empty ([#258](https://github.com/Omega-JS-Stack/omega/issues/258)).
|
|
28
|
+
const HUB_LOCATOR_PREFIX = 'hub-';
|
|
29
|
+
const HUB_LOCATOR_SUFFIX = '.json';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Does a process with this pid exist right now?
|
|
33
|
+
*
|
|
34
|
+
* Signal 0 checks for existence without delivering anything. EPERM means it
|
|
35
|
+
* exists and belongs to another user — still alive, which is the question.
|
|
36
|
+
* @param {number} pid
|
|
37
|
+
* @returns {boolean}
|
|
38
|
+
*/
|
|
39
|
+
function isProcessAlive(pid) {
|
|
40
|
+
if (!Number.isInteger(pid) || pid <= 1) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
process.kill(pid, 0);
|
|
46
|
+
return true;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return error.code === 'EPERM';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The project id of the emulator whose HUB is listening on `hubPort`, read
|
|
54
|
+
* from the locator files firebase-tools publishes.
|
|
55
|
+
*
|
|
56
|
+
* A locator only counts when it claims THIS port and its pid is still alive —
|
|
57
|
+
* firebase-tools does not always remove the file, so a crashed run's leftover
|
|
58
|
+
* would otherwise name a hub that is long gone. Two live claims on one port
|
|
59
|
+
* mean one of them is a stale file whose pid got recycled, and nothing says
|
|
60
|
+
* which: ambiguous reads as unproven, the same safe fall-through as no file at
|
|
61
|
+
* all ([#258](https://github.com/Omega-JS-Stack/omega/issues/258)).
|
|
62
|
+
* @param {number} hubPort - The hub port to identify.
|
|
63
|
+
* @param {string} [tmpDir] - Where locators live (defaults to os.tmpdir()).
|
|
64
|
+
* @returns {string|null} The project id, or null when unproven.
|
|
65
|
+
*/
|
|
66
|
+
function readHubLocatorProjectId(hubPort, tmpDir) {
|
|
67
|
+
const dir = tmpDir || os.tmpdir();
|
|
68
|
+
const claimants = new Set();
|
|
69
|
+
|
|
70
|
+
for (const name of jetpack.list(dir) || []) {
|
|
71
|
+
if (!name.startsWith(HUB_LOCATOR_PREFIX) || !name.endsWith(HUB_LOCATOR_SUFFIX)) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const projectId = name.slice(HUB_LOCATOR_PREFIX.length, -HUB_LOCATOR_SUFFIX.length);
|
|
76
|
+
if (!projectId) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let locator;
|
|
81
|
+
try {
|
|
82
|
+
locator = jetpack.read(path.join(dir, name), 'json');
|
|
83
|
+
} catch (error) {
|
|
84
|
+
continue; // Not a locator, or half-written
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const onThisPort = (locator?.origins || []).some((origin) => {
|
|
88
|
+
try {
|
|
89
|
+
return Number(new URL(origin).port) === Number(hubPort);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (onThisPort && isProcessAlive(Number(locator.pid))) {
|
|
96
|
+
claimants.add(projectId);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return claimants.size === 1 ? [...claimants][0] : null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Adopt the emulator already listening on our functions port, or allocate
|
|
105
|
+
* fresh ports and boot our own?
|
|
106
|
+
*
|
|
107
|
+
* A bare port probe answered "something is listening", which the run read as
|
|
108
|
+
* "our emulator is up" — so another brand's stack on the classic ports got
|
|
109
|
+
* adopted and the run died on a health fetch against the wrong project
|
|
110
|
+
* ([#258](https://github.com/Omega-JS-Stack/omega/issues/258)). Adoption now
|
|
111
|
+
* needs PROOF of identity: unproven falls through to the N7 bump path, which
|
|
112
|
+
* relocates around the incumbent exactly as a second brand's boot does.
|
|
113
|
+
* @param {object} evidence
|
|
114
|
+
* @param {boolean} evidence.portInUse - Something is listening on the functions port.
|
|
115
|
+
* @param {boolean} [evidence.ownsPortsFile] - This project's own live ports file publishes that port.
|
|
116
|
+
* @param {string|null} evidence.runningProjectId - Project id the listener reports (null when unreadable).
|
|
117
|
+
* @param {string|null} evidence.expectedProjectId - Project id this run belongs to.
|
|
118
|
+
* @returns {{adopt: boolean, reason: string, runningProjectId: string|null}}
|
|
119
|
+
*/
|
|
120
|
+
function decideEmulatorAdoption({ portInUse, ownsPortsFile, runningProjectId, expectedProjectId }) {
|
|
121
|
+
const decision = { adopt: false, reason: 'no-emulator', runningProjectId: runningProjectId || null };
|
|
122
|
+
|
|
123
|
+
if (!portInUse) {
|
|
124
|
+
return decision;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// This project's .temp/ports.json, written by OUR emulator and read only
|
|
128
|
+
// while its writer is alive. The hub is NOT allocated by N7, so a bumped run
|
|
129
|
+
// shares it with whoever booted first — this is the proof that still holds.
|
|
130
|
+
if (ownsPortsFile) {
|
|
131
|
+
return { ...decision, adopt: true, reason: 'ports-file' };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!runningProjectId || !expectedProjectId) {
|
|
135
|
+
return { ...decision, reason: 'unidentified' };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (runningProjectId !== expectedProjectId) {
|
|
139
|
+
return { ...decision, reason: 'project-mismatch' };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return { ...decision, adopt: true, reason: 'project-match' };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
class TestCommand extends BaseCommand {
|
|
146
|
+
async execute() {
|
|
147
|
+
const self = this.main;
|
|
148
|
+
const argv = self.argv;
|
|
149
|
+
|
|
150
|
+
// The emulator test lane needs Cloud Functions; custom mode has none (#584)
|
|
151
|
+
if (refuseWhenCustom(self.firebaseProjectPath, 'test')) return;
|
|
152
|
+
|
|
153
|
+
// Tee THIS process to <targetRoot>/logs/test.log (#197) — the setup lines, the
|
|
154
|
+
// port summary and the emulator boot that the runner-child's dist/test.log
|
|
155
|
+
// never sees.
|
|
156
|
+
this.attachVerbLog('test');
|
|
157
|
+
|
|
158
|
+
// `--extended` CLI shorthand for the shared, unprefixed TEST_EXTENDED_MODE
|
|
159
|
+
// env var (cross-framework parity with BXM/UJM/EM). Either the flag OR the
|
|
160
|
+
// env var opts into REAL external services (default skipped). Set this
|
|
161
|
+
// BEFORE the captureSyncedEnv/writeTestMode pre-flight below so the flag
|
|
162
|
+
// flows into the emulator's test-mode.json too — making
|
|
163
|
+
// `npx omega test --extended` equivalent to `TEST_EXTENDED_MODE=true npx omega test`.
|
|
164
|
+
if (argv.extended) {
|
|
165
|
+
process.env.TEST_EXTENDED_MODE = 'true';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Framework self-test: when `npx omega test` is run from the @omega.js/backend repo
|
|
169
|
+
// (no firebase.json in cwd), boot the bundled fixture project under
|
|
170
|
+
// src/test/fixtures/firebase-project. Mirrors BXM/UJM *_TEST_BOOT_PROJECT.
|
|
171
|
+
const isSelfTest = this.setupSelfTest();
|
|
172
|
+
|
|
173
|
+
// The AUDIT half of the retired `omega setup` (#675): the target checks
|
|
174
|
+
// run before anything boots, healing what they can and halting on what
|
|
175
|
+
// they cannot. Skipped on the framework self-test — the bundled fixture is
|
|
176
|
+
// not a consumer target to heal, and the checks would rewrite it.
|
|
177
|
+
if (!isSelfTest) {
|
|
178
|
+
this.ui.section('Target checks');
|
|
179
|
+
await runTargetChecks(self);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// functions/ is staged output (src/dist pillar): stage fresh so the run
|
|
183
|
+
// reads current src + composed config. The auto-start emulator path stages
|
|
184
|
+
// again inside startEmulators — idempotent and cheap; THIS call covers the
|
|
185
|
+
// existing-emulator path, where nothing else would refresh the tree.
|
|
186
|
+
// A test lane composes its .env for TESTING (#586): the run's own
|
|
187
|
+
// OMEGA_TEST_MODE is set on the emulator child, not on this process, so the
|
|
188
|
+
// environment is named here rather than sniffed.
|
|
189
|
+
this.ensureStaged({ environment: 'testing' });
|
|
190
|
+
|
|
191
|
+
// Get test paths from CLI args (e.g., "bem test admin/" or "bem test general/generate-uuid")
|
|
192
|
+
const testPaths = (argv._ || []).slice(1); // Remove 'test' from args
|
|
193
|
+
|
|
194
|
+
// On self-test with no explicit target, run only the boot smoke suite —
|
|
195
|
+
// the fast inner loop. The FULL suite also passes against the fixture
|
|
196
|
+
// (`npm test -- backend:`): it carries corpus-parity payment config and
|
|
197
|
+
// boot-syncs the canonical rules for exactly that.
|
|
198
|
+
if (isSelfTest && testPaths.length === 0) {
|
|
199
|
+
testPaths.push('backend:boot');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Determine the project directory
|
|
203
|
+
const projectDir = self.firebaseProjectPath;
|
|
204
|
+
const functionsDir = path.join(projectDir, 'dist');
|
|
205
|
+
|
|
206
|
+
// Pre-flight: write the allowlisted env subset to a shared state file
|
|
207
|
+
// (`<projectDir>/.temp/test-mode.json`). The running emulator watches this
|
|
208
|
+
// file and mutates its own `process.env` to match, eliminating the need
|
|
209
|
+
// to coordinate env vars across both terminals. The test command is the
|
|
210
|
+
// authoritative writer — whatever you pass here becomes the live mode
|
|
211
|
+
// within ~50ms.
|
|
212
|
+
//
|
|
213
|
+
// Allowlist lives in src/test/utils/test-mode-file.js (SYNCED_ENV_KEYS).
|
|
214
|
+
// Today: just TEST_EXTENDED_MODE. Add more keys there to make them
|
|
215
|
+
// live-syncable.
|
|
216
|
+
{
|
|
217
|
+
const envSubset = captureSyncedEnv(process.env);
|
|
218
|
+
writeTestMode(projectDir, envSubset);
|
|
219
|
+
const extended = !!process.env.TEST_EXTENDED_MODE;
|
|
220
|
+
this.log(chalk.gray(` Test mode: ${extended ? 'extended (real external APIs)' : 'normal (external APIs skipped)'}`));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// N7: a RUNNING emulator's published port map wins — it may have bumped
|
|
224
|
+
// off the firebase.json values (second-brand boot). No live map →
|
|
225
|
+
// firebase.json/classic (and the auto-start path re-resolves after boot).
|
|
226
|
+
let emulatorPorts = loadEmulatorPorts(projectDir);
|
|
227
|
+
const publishedPorts = readPortsFile(projectDir);
|
|
228
|
+
if (publishedPorts) {
|
|
229
|
+
emulatorPorts = { ...emulatorPorts, ...publishedPorts };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Load project configuration
|
|
233
|
+
const projectConfig = this.loadProjectConfig(functionsDir, argv);
|
|
234
|
+
if (!projectConfig) {
|
|
235
|
+
// Config-validation abort must fail the process — a bare return exits 0
|
|
236
|
+
// and reads as a green run to any script chaining on the exit code.
|
|
237
|
+
process.exitCode = 1;
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Opt-in lanes. OFF by default and gated on conditions the default suite
|
|
242
|
+
// must never depend on (credentials, the network, a CLI). A gate that
|
|
243
|
+
// refuses prints ONE line and the run exits clean — a skipped lane is a
|
|
244
|
+
// normal outcome, not a failure
|
|
245
|
+
// ([#212](https://github.com/Omega-JS-Stack/omega/issues/212)).
|
|
246
|
+
if (argv.lane) {
|
|
247
|
+
const gate = this.openLane(argv.lane);
|
|
248
|
+
|
|
249
|
+
if (!gate) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
this.lane = gate;
|
|
254
|
+
testPaths.push(`backend:${gate.laneModule.LANE}`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Build unified test config object
|
|
258
|
+
// Use hosting URL for all API requests (rewrites to omega_api function)
|
|
259
|
+
const testConfig = {
|
|
260
|
+
...projectConfig,
|
|
261
|
+
apiUrl: `http://127.0.0.1:${emulatorPorts.hosting}`,
|
|
262
|
+
projectDir,
|
|
263
|
+
testPaths,
|
|
264
|
+
emulatorPorts,
|
|
265
|
+
isFrameworkSelfTest: isSelfTest, // gates the boot/ smoke layer (excluded for consumers)
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// Adopt the running emulator only when it PROVES it is ours — a listener on
|
|
269
|
+
// the functions port is not evidence of ownership
|
|
270
|
+
// ([#258](https://github.com/Omega-JS-Stack/omega/issues/258)).
|
|
271
|
+
const portInUse = await this.isEmulatorRunning(emulatorPorts);
|
|
272
|
+
const adoption = decideEmulatorAdoption({
|
|
273
|
+
portInUse: portInUse,
|
|
274
|
+
ownsPortsFile: !!publishedPorts && publishedPorts.functions === emulatorPorts.functions,
|
|
275
|
+
runningProjectId: portInUse ? this.readRunningProjectId(emulatorPorts) : null,
|
|
276
|
+
expectedProjectId: projectConfig.cloud?.config?.projectId || null,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
if (adoption.adopt) {
|
|
280
|
+
this.log(chalk.cyan('Running tests against EXISTING emulator'));
|
|
281
|
+
|
|
282
|
+
// The forwarder needs the RESOLVED port, so it starts here rather than at
|
|
283
|
+
// the gate — and stops in the finally, so a failed run never leaves a
|
|
284
|
+
// `stripe listen` behind holding the terminal.
|
|
285
|
+
const laneSession = await this.startLane(testConfig, emulatorPorts);
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
await this.runTestsDirectly(this.buildTestCommand({ ...testConfig, laneEnv: laneSession.env }), functionsDir, emulatorPorts);
|
|
289
|
+
} finally {
|
|
290
|
+
laneSession.stop();
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
if (adoption.reason === 'project-mismatch') {
|
|
294
|
+
this.log(chalk.yellow(` Port ${emulatorPorts.functions} belongs to project "${adoption.runningProjectId}", not "${projectConfig.cloud?.config?.projectId}" — booting this project's own emulator on free ports.`));
|
|
295
|
+
} else if (adoption.reason === 'unidentified') {
|
|
296
|
+
this.log(chalk.yellow(` Port ${emulatorPorts.functions} is in use by a listener that does not identify itself — booting this project's own emulator on free ports.`));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
this.log(chalk.cyan('Starting emulator and running tests...'));
|
|
300
|
+
// The command is built INSIDE runEmulatorTests, after boot — allocation
|
|
301
|
+
// may bump ports, and a pre-built command would bake the stale ones.
|
|
302
|
+
await this.runEmulatorTests(testConfig, functionsDir);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Open an opt-in lane, or say why it stays shut
|
|
308
|
+
*
|
|
309
|
+
* The ONE decision point for every lane: the gate answers from facts already
|
|
310
|
+
* on this machine (a credential, a CLI, the environment), so a refusal costs
|
|
311
|
+
* nothing and reads as a skip. Nothing is started here — the forwarding needs
|
|
312
|
+
* a port the emulator has not chosen yet.
|
|
313
|
+
*
|
|
314
|
+
* @param {string} name - The `--lane=` value
|
|
315
|
+
* @returns {object|null} The opened lane, or null when it stays shut
|
|
316
|
+
*/
|
|
317
|
+
openLane(name) {
|
|
318
|
+
let laneModule;
|
|
319
|
+
|
|
320
|
+
try {
|
|
321
|
+
laneModule = require(path.join(__dirname, 'test-lanes', `${name}.js`));
|
|
322
|
+
} catch (error) {
|
|
323
|
+
this.logError(`Unknown test lane: ${name}`);
|
|
324
|
+
process.exitCode = 1;
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const decision = laneModule.resolveGate({ env: laneModule.env, hasStripeCli: !!laneModule.findStripeCli() });
|
|
329
|
+
|
|
330
|
+
if (!decision.ok) {
|
|
331
|
+
this.log(laneModule.skipLine(decision.reason));
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
this.log(chalk.cyan(` Lane --lane=${name}: ENABLED (real external services)`));
|
|
336
|
+
|
|
337
|
+
return { laneModule, decision };
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Bring an opened lane up against the RESOLVED emulator ports
|
|
342
|
+
*
|
|
343
|
+
* Creates the Stripe fixtures the brand's catalogue needs (idempotently — a
|
|
344
|
+
* rerun reuses them) and starts the forwarder, handing back the env the runner
|
|
345
|
+
* child needs and the stop the caller owes it. No lane opened = an inert
|
|
346
|
+
* session, so both run paths call this unconditionally.
|
|
347
|
+
*
|
|
348
|
+
* @param {object} testConfig - The resolved test config
|
|
349
|
+
* @param {object} emulatorPorts - The port map the emulator actually took
|
|
350
|
+
* @returns {Promise<{ env: object, stop: function }>}
|
|
351
|
+
*/
|
|
352
|
+
async startLane(testConfig, emulatorPorts) {
|
|
353
|
+
const inert = { env: {}, stop: () => {} };
|
|
354
|
+
|
|
355
|
+
if (!this.lane) {
|
|
356
|
+
return inert;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const { laneModule, decision } = this.lane;
|
|
360
|
+
const stripePath = laneModule.findStripeCli();
|
|
361
|
+
|
|
362
|
+
const { fixtures, unsupported } = laneModule.planFixtures(
|
|
363
|
+
testConfig.payment?.products,
|
|
364
|
+
testConfig.payment?.currency,
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
for (const item of unsupported) {
|
|
368
|
+
this.logWarning(` Lane ${laneModule.LANE}: ${item.productId} has no Stripe fixture — ${item.reason}`);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const stripe = require('stripe')(decision.key);
|
|
372
|
+
|
|
373
|
+
await laneModule.ensureFixtures({
|
|
374
|
+
stripe: stripe,
|
|
375
|
+
fixtures: fixtures,
|
|
376
|
+
log: (line) => this.log(chalk.gray(` [${laneModule.LANE}] ${line}`)),
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
const { stop } = await laneModule.startForwarding({
|
|
380
|
+
apiKey: decision.key,
|
|
381
|
+
forwardUrl: laneModule.forwardUrl({ hostingPort: emulatorPorts.hosting, webhookKey: testConfig.webhookKey }),
|
|
382
|
+
log: (line) => this.log(chalk.gray(` [Stripe] ${line}`)),
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
this.log(chalk.gray(` [${laneModule.LANE}] forwarding real test-mode webhooks to localhost:${emulatorPorts.hosting}\n`));
|
|
386
|
+
|
|
387
|
+
return {
|
|
388
|
+
env: {
|
|
389
|
+
[laneModule.LANE_ENV]: laneModule.LANE,
|
|
390
|
+
STRIPE_CLI_PATH: stripePath,
|
|
391
|
+
},
|
|
392
|
+
stop: stop,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Load project configuration from config/omega.json5 and .env
|
|
398
|
+
*/
|
|
399
|
+
loadProjectConfig(functionsDir, argv) {
|
|
400
|
+
const { hasOmegaConfig, loadConfig, loadEnv, resolvedBrandHost } = require('../../vendor/config/index.js');
|
|
401
|
+
|
|
402
|
+
// Load the .env cascade first so env vars are available
|
|
403
|
+
loadEnv(functionsDir);
|
|
404
|
+
|
|
405
|
+
// Load config/omega.json5 (resolved — the loader walks up to the brand
|
|
406
|
+
// layer from the functions dir in a brand monorepo)
|
|
407
|
+
if (!hasOmegaConfig(functionsDir)) {
|
|
408
|
+
this.logError('Error: Missing config/omega.json5');
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
let config;
|
|
413
|
+
try {
|
|
414
|
+
config = loadConfig(functionsDir, 'backend').config;
|
|
415
|
+
} catch (error) {
|
|
416
|
+
this.logError(`Error: Could not load config/omega.json5: ${error.message}`);
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Derive computed values (not in config file)
|
|
421
|
+
const adminKey = argv.key || process.env.OMEGA_ADMIN_KEY;
|
|
422
|
+
const webhookKey = argv.webhookKey || process.env.OMEGA_WEBHOOK_KEY;
|
|
423
|
+
// The persona domain is the brand's HOST — one derivation, shared with the
|
|
424
|
+
// seeder and the dev palette
|
|
425
|
+
// ([#708](https://github.com/Omega-JS-Stack/omega/issues/708)).
|
|
426
|
+
const domain = resolvedBrandHost(config);
|
|
427
|
+
|
|
428
|
+
// Validate required configuration
|
|
429
|
+
if (!config.cloud?.config?.projectId) {
|
|
430
|
+
this.logError('Error: Missing cloud.config.projectId in config/omega.json5');
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (!adminKey) {
|
|
435
|
+
this.logError('Error: Missing admin key');
|
|
436
|
+
this.log(chalk.gray(' Set OMEGA_ADMIN_KEY in your .env file or pass --key flag'));
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (!webhookKey) {
|
|
441
|
+
this.logError('Error: Missing webhook key');
|
|
442
|
+
this.log(chalk.gray(' Set OMEGA_WEBHOOK_KEY in your .env file or pass --webhook-key flag'));
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (!config.brand?.id) {
|
|
447
|
+
this.logError('Error: Missing brand.id in config/omega.json5');
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (!domain) {
|
|
452
|
+
this.logError('Error: Missing brand.url in config/omega.json5 (personas are seeded on the brand host)');
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Pass entire config + computed values not in config file
|
|
457
|
+
return {
|
|
458
|
+
...config,
|
|
459
|
+
adminKey,
|
|
460
|
+
webhookKey,
|
|
461
|
+
domain,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Build the test command with environment variables
|
|
467
|
+
*/
|
|
468
|
+
/**
|
|
469
|
+
* Framework self-test detection + fixture wiring.
|
|
470
|
+
*
|
|
471
|
+
* When `npx omega test` runs from a directory that is NOT a Firebase project
|
|
472
|
+
* (no firebase.json) AND is the @omega.js/backend repo (or OMEGA_TEST_BOOT_PROJECT
|
|
473
|
+
* is set), point the run at the bundled fixture project and link the local
|
|
474
|
+
* framework + firebase deps into it so the emulator's function workers resolve
|
|
475
|
+
* them. This is @omega.js/backend's equivalent of BXM's OMEGA_TEST_BOOT_PROJECT / UJM's
|
|
476
|
+
* UJ_TEST_BOOT_PROJECT. Returns true if self-test wiring was applied.
|
|
477
|
+
*/
|
|
478
|
+
setupSelfTest() {
|
|
479
|
+
const self = this.main;
|
|
480
|
+
|
|
481
|
+
// Normal consumer run — cwd is already a Firebase project. Nothing to do.
|
|
482
|
+
if (jetpack.exists(path.join(self.firebaseProjectPath, 'firebase.json'))) {
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Self-test if OMEGA_TEST_BOOT_PROJECT is set, or cwd is the @omega.js/backend repo.
|
|
487
|
+
let isSelfTest = !!process.env.OMEGA_TEST_BOOT_PROJECT;
|
|
488
|
+
if (!isSelfTest) {
|
|
489
|
+
try {
|
|
490
|
+
isSelfTest = require(path.join(process.cwd(), 'package.json')).name === '@omega.js/backend';
|
|
491
|
+
} catch (_) { /* no package.json — not a self-test */ }
|
|
492
|
+
}
|
|
493
|
+
if (!isSelfTest) {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const fixture = process.env.OMEGA_TEST_BOOT_PROJECT
|
|
498
|
+
? path.resolve(process.env.OMEGA_TEST_BOOT_PROJECT)
|
|
499
|
+
: path.resolve(__dirname, '..', '..', 'test', 'fixtures', 'firebase-project');
|
|
500
|
+
|
|
501
|
+
process.env.OMEGA_TEST_BOOT_PROJECT = fixture;
|
|
502
|
+
self.firebaseProjectPath = fixture;
|
|
503
|
+
|
|
504
|
+
// The test HTTP client authenticates with the fixture's admin keys (the
|
|
505
|
+
// server reads the same keys from config/omega.json5). Inject them from
|
|
506
|
+
// the fixture config so loadProjectConfig finds them — no committed .env
|
|
507
|
+
// needed (single source = the fixture config). The namespace rides the
|
|
508
|
+
// same mechanism: the uuid route's v5 default reads OMEGA_NAMESPACE in
|
|
509
|
+
// the emulated functions, which inherit this process env.
|
|
510
|
+
try {
|
|
511
|
+
const cfg = require('../../vendor/config/index.js').loadConfig(fixture, 'backend').config;
|
|
512
|
+
process.env.OMEGA_ADMIN_KEY = process.env.OMEGA_ADMIN_KEY || cfg.omega?.key;
|
|
513
|
+
process.env.OMEGA_WEBHOOK_KEY = process.env.OMEGA_WEBHOOK_KEY || cfg.omega?.webhookKey;
|
|
514
|
+
process.env.OMEGA_NAMESPACE = process.env.OMEGA_NAMESPACE || cfg.omega?.namespace;
|
|
515
|
+
} catch (_) { /* fixture config unreadable — let the normal key check report it */ }
|
|
516
|
+
|
|
517
|
+
// Anonymous HMAC unsubscribe tests sign links with this shared secret; the
|
|
518
|
+
// emulated functions inherit it from this process env (same mechanism as the
|
|
519
|
+
// webhook key above). Test-only value — production sets its own env var.
|
|
520
|
+
process.env.UNSUBSCRIBE_HMAC_KEY = process.env.UNSUBSCRIBE_HMAC_KEY || '_test-unsubscribe-hmac-key';
|
|
521
|
+
|
|
522
|
+
this.ensureFixtureServiceAccount(fixture);
|
|
523
|
+
this.ensureFixtureEnv(fixture);
|
|
524
|
+
this.ensureFixtureRules(fixture);
|
|
525
|
+
this.linkFixtureDeps(fixture);
|
|
526
|
+
this.log(chalk.cyan(` Self-test: booting bundled fixture project (${fixture})`));
|
|
527
|
+
return true;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Write a throwaway service-account.json into the fixture so firebase-admin's
|
|
532
|
+
* `cert()` can parse it. @omega.js/backend's manager uses the cert path when
|
|
533
|
+
* GOOGLE_APPLICATION_CREDENTIALS is unset (as in the functions emulator). The
|
|
534
|
+
* key is a freshly-generated RSA key — emulator-only, never authenticates
|
|
535
|
+
* against Google (the project is a `demo-` project), so it is generated at
|
|
536
|
+
* runtime and gitignored, never committed. Written to the TARGET ROOT (the
|
|
537
|
+
* authored home under the src/dist pillar) — the stage step carries it into
|
|
538
|
+
* functions/.
|
|
539
|
+
*/
|
|
540
|
+
ensureFixtureServiceAccount(fixture) {
|
|
541
|
+
const crypto = require('crypto');
|
|
542
|
+
const saPath = path.join(fixture, 'service-account.json');
|
|
543
|
+
const projectId = 'demo-omega-backend';
|
|
544
|
+
const { privateKey } = crypto.generateKeyPairSync('rsa', {
|
|
545
|
+
modulusLength: 2048,
|
|
546
|
+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
|
|
547
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
548
|
+
});
|
|
549
|
+
const serviceAccount = {
|
|
550
|
+
type: 'service_account',
|
|
551
|
+
project_id: projectId,
|
|
552
|
+
private_key_id: '0'.repeat(40),
|
|
553
|
+
private_key: privateKey,
|
|
554
|
+
client_email: `fixture@${projectId}.iam.gserviceaccount.com`,
|
|
555
|
+
client_id: '0'.repeat(21),
|
|
556
|
+
auth_uri: 'https://accounts.google.com/o/oauth2/auth',
|
|
557
|
+
token_uri: 'https://oauth2.googleapis.com/token',
|
|
558
|
+
auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
|
|
559
|
+
client_x509_cert_url: `https://www.googleapis.com/robot/v1/metadata/x509/fixture%40${projectId}.iam.gserviceaccount.com`,
|
|
560
|
+
};
|
|
561
|
+
try {
|
|
562
|
+
fs.writeFileSync(saPath, `${JSON.stringify(serviceAccount, null, 2)}\n`);
|
|
563
|
+
} catch (e) {
|
|
564
|
+
this.logWarning(`Could not write fixture service-account.json: ${e.message}`);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Seed the fixture's `.env` with every key the env schema marks REQUIRED
|
|
570
|
+
* ([#581](https://github.com/Omega-JS-Stack/omega/issues/581)). The fixture
|
|
571
|
+
* carries a consumer `config/omega.json5`, so it IS a brand's backend to the
|
|
572
|
+
* boot guard — and firebase-tools analyzes function definitions in its own
|
|
573
|
+
* child process, which never saw the values injected into this one above, so
|
|
574
|
+
* `Manager.init()` threw before a single function loaded.
|
|
575
|
+
*
|
|
576
|
+
* Values come from the SAME resolution the injection above does (the fixture
|
|
577
|
+
* config's `omega.*` keys, the shared unsubscribe secret), so the server and
|
|
578
|
+
* the test client authenticate with one value; a key the schema marks
|
|
579
|
+
* required LATER gets an obvious dummy, so the fixture can never fall behind
|
|
580
|
+
* the schema again. Existing lines are never touched — a fixture edit
|
|
581
|
+
* survives the run that reads it. Written to the TARGET ROOT (the authored
|
|
582
|
+
* home under the src/dist pillar); the stage step carries it into functions/.
|
|
583
|
+
* Emulator-only values, gitignored like the service account, never committed.
|
|
584
|
+
*/
|
|
585
|
+
ensureFixtureEnv(fixture) {
|
|
586
|
+
const { requiredEnvKeys } = require('../../vendor/config/index.js');
|
|
587
|
+
const envPath = path.join(fixture, '.env');
|
|
588
|
+
const existing = jetpack.exists(envPath) ? jetpack.read(envPath) : '';
|
|
589
|
+
const present = util.parseEnv(existing);
|
|
590
|
+
|
|
591
|
+
const lines = requiredEnvKeys('backend')
|
|
592
|
+
.filter((name) => !present[name])
|
|
593
|
+
.map((name) => `${name}="${process.env[name] || `fixture-${name.toLowerCase().replace(/_/g, '-')}`}"`);
|
|
594
|
+
|
|
595
|
+
if (lines.length === 0) {
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const header = existing ? '' : '# @omega.js/backend self-test fixture — emulator-only values, seeded per run.\n';
|
|
600
|
+
|
|
601
|
+
try {
|
|
602
|
+
jetpack.write(envPath, `${header}${existing}${existing && !existing.endsWith('\n') ? '\n' : ''}${lines.join('\n')}\n`);
|
|
603
|
+
} catch (e) {
|
|
604
|
+
this.logWarning(`Could not write fixture .env: ${e.message}`);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Seed the fixture's BRAND rules source — the same seed the scaffold ships
|
|
610
|
+
* to a consumer. The framework half is no longer
|
|
611
|
+
* copied anywhere: the stage below compiles it in
|
|
612
|
+
* ([#255](https://github.com/Omega-JS-Stack/omega/issues/255)), so the rules
|
|
613
|
+
* suite exercises the real compiled artifact, exactly what a consumer
|
|
614
|
+
* deploys. Runtime-derived and gitignored like the service account, and
|
|
615
|
+
* never clobbered — a fixture edit survives the run that reads it.
|
|
616
|
+
*/
|
|
617
|
+
ensureFixtureRules(fixture) {
|
|
618
|
+
const { ensureBrandRulesSource } = require('../utils/compile-rules');
|
|
619
|
+
ensureBrandRulesSource({ projectDir: fixture });
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Symlink the local framework + firebase deps into the fixture's TARGET-ROOT
|
|
624
|
+
* node_modules so the emulator's function workers can resolve them — Node
|
|
625
|
+
* resolution walks up from the staged functions/ tree (which carries no
|
|
626
|
+
* node_modules of its own under the src/dist pillar). Mirrors what
|
|
627
|
+
* `npx omega install dev` does in a real consumer, but for the fixture and
|
|
628
|
+
* without an npm install (firebase-admin/firebase-functions come from
|
|
629
|
+
* @omega.js/backend's own node_modules; @omega.js/backend points at the repo root).
|
|
630
|
+
*/
|
|
631
|
+
linkFixtureDeps(fixture) {
|
|
632
|
+
const fnNodeModules = path.join(fixture, 'node_modules');
|
|
633
|
+
jetpack.dir(fnNodeModules);
|
|
634
|
+
|
|
635
|
+
const frameworkRoot = path.resolve(__dirname, '..', '..', '..'); // src/cli/commands -> repo root
|
|
636
|
+
const links = {
|
|
637
|
+
'@omega.js/backend': frameworkRoot,
|
|
638
|
+
'firebase-admin': path.join(frameworkRoot, 'node_modules', 'firebase-admin'),
|
|
639
|
+
'firebase-functions': path.join(frameworkRoot, 'node_modules', 'firebase-functions'),
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
for (const [name, target] of Object.entries(links)) {
|
|
643
|
+
const linkPath = path.join(fnNodeModules, name);
|
|
644
|
+
try { fs.rmSync(linkPath, { recursive: true, force: true }); } catch (_) { /* nothing to remove */ }
|
|
645
|
+
try {
|
|
646
|
+
// The link's PARENT, not just node_modules — a scoped name like
|
|
647
|
+
// @omega.js/backend needs its node_modules/@omega.js dir to exist first
|
|
648
|
+
fs.mkdirSync(path.dirname(linkPath), { recursive: true });
|
|
649
|
+
fs.symlinkSync(target, linkPath, process.platform === 'win32' ? 'junction' : 'dir');
|
|
650
|
+
} catch (e) {
|
|
651
|
+
this.logWarning(`Could not link ${name} into fixture: ${e.message}`);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
buildTestCommand(testConfig) {
|
|
657
|
+
const testScriptPath = path.join(__dirname, '..', '..', 'test', 'run-tests.js');
|
|
658
|
+
|
|
659
|
+
// The RESOLVED port map, minus the TLS front. The runner loads route
|
|
660
|
+
// handlers IN-PROCESS, so its Manager's URL getters answer from
|
|
661
|
+
// OMEGA_*_PORT the same way a function worker's do — unset, they fell back
|
|
662
|
+
// to the classic 5002, which under `omega emulator`'s HTTPS default is the
|
|
663
|
+
// mkcert proxy, not hosting: the test provider's auto-webhook followed the
|
|
664
|
+
// proxy's 307 to https and died on a cert this process has no CA for
|
|
665
|
+
// ([#291](https://github.com/Omega-JS-Stack/omega/issues/291)). `https` is
|
|
666
|
+
// deliberately dropped — the runner is a plain-http client of the stack
|
|
667
|
+
// (its own apiUrl already is), so it gets hosting's internal port.
|
|
668
|
+
const { https: _tlsFront, ...plainHttpPorts } = testConfig.emulatorPorts;
|
|
669
|
+
|
|
670
|
+
// Pass entire config as base64-encoded JSON to avoid shell escaping issues
|
|
671
|
+
const testEnv = {
|
|
672
|
+
...portsToEnv(plainHttpPorts),
|
|
673
|
+
OMEGA_TEST_CONFIG: Buffer.from(JSON.stringify(testConfig)).toString('base64'),
|
|
674
|
+
FIRESTORE_EMULATOR_HOST: `127.0.0.1:${testConfig.emulatorPorts.firestore}`,
|
|
675
|
+
FIREBASE_AUTH_EMULATOR_HOST: `127.0.0.1:${testConfig.emulatorPorts.auth}`,
|
|
676
|
+
// The project the emulator booted with — resolved from the same config
|
|
677
|
+
// the emulator command boots on (loadProjectConfig hard-fails without it).
|
|
678
|
+
// The runner's admin app and the wipe's auth bulk-clear both read it, and
|
|
679
|
+
// the wipe's URL names a project the emulator answers 200 for whether it
|
|
680
|
+
// knows it or not: without this the wipe cleared a project nothing in the
|
|
681
|
+
// run ever touched and reported success
|
|
682
|
+
// ([#292](https://github.com/Omega-JS-Stack/omega/issues/292)).
|
|
683
|
+
GCLOUD_PROJECT: testConfig.cloud.config.projectId,
|
|
684
|
+
// GCLOUD_PROJECT alone makes the child's init-time environment read as
|
|
685
|
+
// production (nothing else marks it yet: runner.js stamps its own
|
|
686
|
+
// OMEGA_TEST_MODE only later, inside run()), which wakes the
|
|
687
|
+
// firebase-functions logger compat shim and turns every test line into
|
|
688
|
+
// JSON. Say what this process IS before Manager.init() looks.
|
|
689
|
+
OMEGA_TEST_MODE: 'true',
|
|
690
|
+
// An opt-in lane's own environment: the lane name the runner's discovery
|
|
691
|
+
// gates on, plus whatever the lane brought up (the forwarder's signing
|
|
692
|
+
// secret). Empty on every default run.
|
|
693
|
+
...(testConfig.laneEnv || {}),
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
const envString = Object.entries(testEnv)
|
|
697
|
+
.map(([key, value]) => `${key}='${value}'`)
|
|
698
|
+
.join(' ');
|
|
699
|
+
|
|
700
|
+
return `${envString} node "${testScriptPath}"`;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Check if emulator is already running
|
|
705
|
+
* @param {object} emulatorPorts - The port map this run expects.
|
|
706
|
+
* @returns {Promise<boolean>}
|
|
707
|
+
*/
|
|
708
|
+
isEmulatorRunning(emulatorPorts) {
|
|
709
|
+
// Check if functions emulator port is in use
|
|
710
|
+
// If it is, assume emulator is running
|
|
711
|
+
return this.isPortInUse(emulatorPorts.functions);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* The project id the emulator listening on our ports belongs to, read from
|
|
716
|
+
* the hub locator firebase-tools publishes for a running stack. Anything
|
|
717
|
+
* unproven (no locator, a dead pid, two live claims) comes back null, which
|
|
718
|
+
* the decision above treats as "unidentified", never as "ours".
|
|
719
|
+
* @param {object} emulatorPorts - The resolved port map.
|
|
720
|
+
* @returns {string|null} The running emulator's project id.
|
|
721
|
+
*/
|
|
722
|
+
readRunningProjectId(emulatorPorts) {
|
|
723
|
+
return readHubLocatorProjectId(emulatorPorts?.hub || HUB_PORT);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Signal the running emulator process to roll emulator.log.
|
|
728
|
+
*
|
|
729
|
+
* Mechanism: write a sentinel file at emulator.log.reset. The emulator command
|
|
730
|
+
* (src/cli/commands/emulator.js) polls for it and, on detection, closes its
|
|
731
|
+
* current write stream and reopens with flags: 'w' (truncating cleanly from its
|
|
732
|
+
* own perspective — avoids the sparse-file problem caused by external truncation).
|
|
733
|
+
*
|
|
734
|
+
* Waits up to 2s for the sentinel to be consumed. If it's still there after 2s
|
|
735
|
+
* the emulator isn't watching (probably running an older @omega.js/backend or started outside
|
|
736
|
+
* `npx omega emulator`); we delete the sentinel and proceed — tests still run, the
|
|
737
|
+
* log just won't be reset for this run.
|
|
738
|
+
*/
|
|
739
|
+
async requestEmulatorLogReset(projectDir) {
|
|
740
|
+
const sentinelPath = this.getTempPath('emulator.log.reset');
|
|
741
|
+
|
|
742
|
+
try {
|
|
743
|
+
fs.writeFileSync(sentinelPath, '');
|
|
744
|
+
} catch (e) {
|
|
745
|
+
return; // Can't write — skip, not fatal
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// Poll for the emulator to consume the sentinel (it deletes the file when done)
|
|
749
|
+
const maxWaitMs = 2000;
|
|
750
|
+
const pollIntervalMs = 100;
|
|
751
|
+
const start = Date.now();
|
|
752
|
+
|
|
753
|
+
while (Date.now() - start < maxWaitMs) {
|
|
754
|
+
if (!fs.existsSync(sentinelPath)) {
|
|
755
|
+
return; // Emulator picked it up and rolled the log
|
|
756
|
+
}
|
|
757
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// Timed out — emulator didn't see the sentinel. Clean up so we don't leave it behind.
|
|
761
|
+
try { fs.unlinkSync(sentinelPath); } catch (e) { /* ok */ }
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Run tests directly (emulator already running)
|
|
766
|
+
*/
|
|
767
|
+
async runTestsDirectly(testCommand, functionsDir, emulatorPorts) {
|
|
768
|
+
const projectDir = this.main.firebaseProjectPath;
|
|
769
|
+
|
|
770
|
+
// Ask the running emulator process to roll emulator.log so this test run gets a
|
|
771
|
+
// clean slate. We touch a sentinel file the emulator polls for (every ~500ms) and
|
|
772
|
+
// wait briefly for it to be consumed. If the emulator isn't watching (older @omega.js/backend
|
|
773
|
+
// version, or not started via `npx omega emulator`), we time out silently — the log
|
|
774
|
+
// just won't be fresh, tests still run normally.
|
|
775
|
+
await this.requestEmulatorLogReset(projectDir);
|
|
776
|
+
|
|
777
|
+
this.log(chalk.gray(` Hosting: http://127.0.0.1:${emulatorPorts.hosting}`));
|
|
778
|
+
this.log(chalk.gray(` Firestore: 127.0.0.1:${emulatorPorts.firestore}`));
|
|
779
|
+
this.log(chalk.gray(` Auth: 127.0.0.1:${emulatorPorts.auth}`));
|
|
780
|
+
this.log(chalk.gray(` UI: http://127.0.0.1:${emulatorPorts.ui}`));
|
|
781
|
+
|
|
782
|
+
// Set up log file in the project's functions/ directory (alongside firebase-tools logs)
|
|
783
|
+
const logPath = this.getLogsPath('test.log');
|
|
784
|
+
const logStream = fs.createWriteStream(logPath, { flags: 'w' });
|
|
785
|
+
const stripAnsi = (str) => str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
786
|
+
|
|
787
|
+
this.log(chalk.gray(` Logs saving to: ${logPath}\n`));
|
|
788
|
+
|
|
789
|
+
// The runner's OWN exit code, kept: a no-match answers with a code of its
|
|
790
|
+
// own inside a brand-root fan-out (#814), and collapsing every non-zero to
|
|
791
|
+
// 1 here would hide it. powertools registers its close listener before it
|
|
792
|
+
// hands the child over, so this one has run by the time the catch does.
|
|
793
|
+
let childExit = 0;
|
|
794
|
+
|
|
795
|
+
try {
|
|
796
|
+
await powertools.execute(testCommand, {
|
|
797
|
+
log: false,
|
|
798
|
+
cwd: functionsDir,
|
|
799
|
+
config: {
|
|
800
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
801
|
+
env: { ...process.env, FORCE_COLOR: '1' },
|
|
802
|
+
},
|
|
803
|
+
}, (child) => {
|
|
804
|
+
// Tee stdout to both console and log file (strip ANSI codes for clean log)
|
|
805
|
+
child.stdout.on('data', (data) => {
|
|
806
|
+
process.stdout.write(data);
|
|
807
|
+
logStream.write(stripAnsi(data.toString()));
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
// Tee stderr to both console and log file (strip ANSI codes for clean log)
|
|
811
|
+
child.stderr.on('data', (data) => {
|
|
812
|
+
process.stderr.write(data);
|
|
813
|
+
logStream.write(stripAnsi(data.toString()));
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
// Clean up log stream when child exits
|
|
817
|
+
child.on('close', (code) => {
|
|
818
|
+
childExit = code ?? 1;
|
|
819
|
+
logStream.end();
|
|
820
|
+
});
|
|
821
|
+
});
|
|
822
|
+
} catch (error) {
|
|
823
|
+
process.exit(childExit || 1);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* Run tests with Firebase emulator (starts emulator, runs tests, shuts down).
|
|
829
|
+
*
|
|
830
|
+
* Two real child processes are used so emulator output and test-runner output
|
|
831
|
+
* land in separate log files:
|
|
832
|
+
* - `emulator.log` — `firebase emulators:start` stdout/stderr (managed by EmulatorCommand)
|
|
833
|
+
* - `test.log` — the test-runner subprocess stdout/stderr (managed here)
|
|
834
|
+
*/
|
|
835
|
+
async runEmulatorTests(testConfig, functionsDir) {
|
|
836
|
+
try {
|
|
837
|
+
await powertools.execute('java -version', { log: false });
|
|
838
|
+
} catch (e) {
|
|
839
|
+
this.logError(`Java is required to run tests (Firebase emulators depend on it).`);
|
|
840
|
+
this.logError(`Install with: ${javaInstallHint()}`);
|
|
841
|
+
process.exit(1);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
this.log(chalk.gray(' Starting Firebase emulator...\n'));
|
|
845
|
+
|
|
846
|
+
const emulatorCmd = new EmulatorCommand(this.main);
|
|
847
|
+
let started;
|
|
848
|
+
|
|
849
|
+
try {
|
|
850
|
+
started = await emulatorCmd.startEmulators({ environment: 'testing' });
|
|
851
|
+
} catch (error) {
|
|
852
|
+
this.logError(`Emulator error: ${error.message || error}`);
|
|
853
|
+
process.exit(1);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
const { shutdown, exitPromise, emulatorPorts } = started;
|
|
857
|
+
|
|
858
|
+
// The forwarder needs the RESOLVED port too, so it starts after the boot
|
|
859
|
+
const laneSession = await this.startLane(testConfig, emulatorPorts);
|
|
860
|
+
|
|
861
|
+
// Build the test command from the RESOLVED ports — allocation may have
|
|
862
|
+
// bumped them off the firebase.json values testConfig was seeded with.
|
|
863
|
+
const testCommand = this.buildTestCommand({
|
|
864
|
+
...testConfig,
|
|
865
|
+
apiUrl: `http://127.0.0.1:${emulatorPorts.hosting}`,
|
|
866
|
+
emulatorPorts,
|
|
867
|
+
laneEnv: laneSession.env,
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
// ONE handler, three signals: this run OWNS the stack it just booted, so
|
|
871
|
+
// every way it is asked to stop takes the same teardown. Wired to SIGINT
|
|
872
|
+
// alone, a supervisor's SIGTERM or a closed terminal's SIGHUP took Node's
|
|
873
|
+
// default action and orphaned the whole firebase tree onto PID 1 — the
|
|
874
|
+
// [#629](https://github.com/Omega-JS-Stack/omega/issues/629) defect on this
|
|
875
|
+
// sibling path ([#722](https://github.com/Omega-JS-Stack/omega/issues/722)).
|
|
876
|
+
//
|
|
877
|
+
// The signal is DIRECTED at this pid, so it reaches the CLI and nothing
|
|
878
|
+
// else: the test runner spawned below is this run's child, not its
|
|
879
|
+
// co-signee, and a teardown that only stops the emulator leaves the suites
|
|
880
|
+
// running orphaned to PID 1. It is therefore signalled by hand, and the
|
|
881
|
+
// handler is reentrancy-guarded — a second signal arriving mid-teardown
|
|
882
|
+
// (SIGINT then SIGTERM is exactly how a supervisor escalates) would
|
|
883
|
+
// otherwise start the whole thing again underneath the first.
|
|
884
|
+
let testChild = null;
|
|
885
|
+
let stopping = false;
|
|
886
|
+
|
|
887
|
+
const onStopSignal = async () => {
|
|
888
|
+
if (stopping) {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
stopping = true;
|
|
893
|
+
|
|
894
|
+
this.log(chalk.gray('\n Shutting down emulator...'));
|
|
895
|
+
|
|
896
|
+
if (testChild && testChild.exitCode === null && testChild.signalCode === null) {
|
|
897
|
+
try { testChild.kill('SIGTERM'); } catch (e) { /* already gone */ }
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
await shutdown();
|
|
901
|
+
process.exit(130);
|
|
902
|
+
};
|
|
903
|
+
STOP_SIGNALS.forEach((signal) => process.on(signal, onStopSignal));
|
|
904
|
+
|
|
905
|
+
// Print the same connection summary the existing-emulator path shows
|
|
906
|
+
this.log('');
|
|
907
|
+
this.log(chalk.gray(` Hosting: http://127.0.0.1:${emulatorPorts.hosting}`));
|
|
908
|
+
this.log(chalk.gray(` Firestore: 127.0.0.1:${emulatorPorts.firestore}`));
|
|
909
|
+
this.log(chalk.gray(` Auth: 127.0.0.1:${emulatorPorts.auth}`));
|
|
910
|
+
this.log(chalk.gray(` UI: http://127.0.0.1:${emulatorPorts.ui}`));
|
|
911
|
+
|
|
912
|
+
// Spawn the test runner as its own child so its stdout/stderr can be teed to test.log
|
|
913
|
+
const logPath = this.getLogsPath('test.log');
|
|
914
|
+
const logStream = fs.createWriteStream(logPath, { flags: 'w' });
|
|
915
|
+
const stripAnsi = (str) => str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
916
|
+
|
|
917
|
+
this.log(chalk.gray(` Logs saving to: ${logPath}\n`));
|
|
918
|
+
|
|
919
|
+
let testExitCode = 0;
|
|
920
|
+
|
|
921
|
+
try {
|
|
922
|
+
testChild = spawnShell(testCommand, {
|
|
923
|
+
cwd: functionsDir,
|
|
924
|
+
env: { ...process.env, FORCE_COLOR: '1' },
|
|
925
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
testChild.stdout.on('data', (data) => {
|
|
929
|
+
process.stdout.write(data);
|
|
930
|
+
if (!logStream.destroyed) logStream.write(stripAnsi(data.toString()));
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
testChild.stderr.on('data', (data) => {
|
|
934
|
+
process.stderr.write(data);
|
|
935
|
+
if (!logStream.destroyed) logStream.write(stripAnsi(data.toString()));
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
testExitCode = await new Promise((resolve) => {
|
|
939
|
+
testChild.on('close', (code) => {
|
|
940
|
+
if (!logStream.destroyed) logStream.end();
|
|
941
|
+
resolve(code ?? 1);
|
|
942
|
+
});
|
|
943
|
+
});
|
|
944
|
+
} catch (error) {
|
|
945
|
+
this.logError(`Test runner error: ${error.message || error}`);
|
|
946
|
+
testExitCode = 1;
|
|
947
|
+
} finally {
|
|
948
|
+
laneSession.stop();
|
|
949
|
+
|
|
950
|
+
// A stop signal owns the teardown AND the exit from the moment it
|
|
951
|
+
// arrives: this path is only reached at all because the handler killed
|
|
952
|
+
// the child this run was waiting on. Tearing down again here would
|
|
953
|
+
// signal the stack out from under it — and dropping the handlers would
|
|
954
|
+
// hand the next signal back to Node's default action mid-teardown. So
|
|
955
|
+
// the process is left to the handler's own exit.
|
|
956
|
+
if (stopping) {
|
|
957
|
+
await new Promise(() => {});
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
STOP_SIGNALS.forEach((signal) => process.removeListener(signal, onStopSignal));
|
|
961
|
+
await shutdown();
|
|
962
|
+
await exitPromise;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
process.exit(testExitCode);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// Static, alongside Middleware's precedent — the adopt-or-bump decision is
|
|
970
|
+
// pure, so tests exercise it directly instead of through a booted emulator, and
|
|
971
|
+
// the identity read takes a tmp dir so real locator files can stand in for a
|
|
972
|
+
// running hub.
|
|
973
|
+
TestCommand.decideEmulatorAdoption = decideEmulatorAdoption;
|
|
974
|
+
TestCommand.readHubLocatorProjectId = readHubLocatorProjectId;
|
|
975
|
+
|
|
976
|
+
module.exports = TestCommand;
|