@endora-commerce/cli 0.100.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 +21 -0
- package/README.md +37 -0
- package/dist/bin/endora.d.ts +28 -0
- package/dist/bin/endora.d.ts.map +1 -0
- package/dist/bin/endora.js +926 -0
- package/dist/bin/endora.js.map +1 -0
- package/dist/check/estate.d.ts +189 -0
- package/dist/check/estate.d.ts.map +1 -0
- package/dist/check/estate.js +1037 -0
- package/dist/check/estate.js.map +1 -0
- package/dist/check/hosts.d.ts +25 -0
- package/dist/check/hosts.d.ts.map +1 -0
- package/dist/check/hosts.js +1347 -0
- package/dist/check/hosts.js.map +1 -0
- package/dist/check/index.d.ts +60 -0
- package/dist/check/index.d.ts.map +1 -0
- package/dist/check/index.js +111 -0
- package/dist/check/index.js.map +1 -0
- package/dist/check/layout.d.ts +136 -0
- package/dist/check/layout.d.ts.map +1 -0
- package/dist/check/layout.js +262 -0
- package/dist/check/layout.js.map +1 -0
- package/dist/check/ledger.d.ts +98 -0
- package/dist/check/ledger.d.ts.map +1 -0
- package/dist/check/ledger.js +173 -0
- package/dist/check/ledger.js.map +1 -0
- package/dist/check/peer-owners.d.ts +116 -0
- package/dist/check/peer-owners.d.ts.map +1 -0
- package/dist/check/peer-owners.js +225 -0
- package/dist/check/peer-owners.js.map +1 -0
- package/dist/check/report.d.ts +33 -0
- package/dist/check/report.d.ts.map +1 -0
- package/dist/check/report.js +107 -0
- package/dist/check/report.js.map +1 -0
- package/dist/check/run.d.ts +147 -0
- package/dist/check/run.d.ts.map +1 -0
- package/dist/check/run.js +111 -0
- package/dist/check/run.js.map +1 -0
- package/dist/checks.d.ts +17 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +17 -0
- package/dist/checks.js.map +1 -0
- package/dist/dev/index.d.ts +83 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +298 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/generate/divergence.d.ts +38 -0
- package/dist/generate/divergence.d.ts.map +1 -0
- package/dist/generate/divergence.js +237 -0
- package/dist/generate/divergence.js.map +1 -0
- package/dist/generate/index.d.ts +90 -0
- package/dist/generate/index.d.ts.map +1 -0
- package/dist/generate/index.js +369 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/inputs/declaration.d.ts +18 -0
- package/dist/inputs/declaration.d.ts.map +1 -0
- package/dist/inputs/declaration.js +64 -0
- package/dist/inputs/declaration.js.map +1 -0
- package/dist/inputs/env-file.d.ts +73 -0
- package/dist/inputs/env-file.d.ts.map +1 -0
- package/dist/inputs/env-file.js +134 -0
- package/dist/inputs/env-file.js.map +1 -0
- package/dist/inputs/prompt.d.ts +21 -0
- package/dist/inputs/prompt.d.ts.map +1 -0
- package/dist/inputs/prompt.js +59 -0
- package/dist/inputs/prompt.js.map +1 -0
- package/dist/inputs/resolve.d.ts +163 -0
- package/dist/inputs/resolve.d.ts.map +1 -0
- package/dist/inputs/resolve.js +290 -0
- package/dist/inputs/resolve.js.map +1 -0
- package/dist/install/host.d.ts +27 -0
- package/dist/install/host.d.ts.map +1 -0
- package/dist/install/host.js +90 -0
- package/dist/install/host.js.map +1 -0
- package/dist/install/index.d.ts +173 -0
- package/dist/install/index.d.ts.map +1 -0
- package/dist/install/index.js +793 -0
- package/dist/install/index.js.map +1 -0
- package/dist/install/wizard.d.ts +144 -0
- package/dist/install/wizard.d.ts.map +1 -0
- package/dist/install/wizard.js +362 -0
- package/dist/install/wizard.js.map +1 -0
- package/dist/lib/admin-artefacts.d.ts +70 -0
- package/dist/lib/admin-artefacts.d.ts.map +1 -0
- package/dist/lib/admin-artefacts.js +354 -0
- package/dist/lib/admin-artefacts.js.map +1 -0
- package/dist/lib/admin-surfaces.d.ts +298 -0
- package/dist/lib/admin-surfaces.d.ts.map +1 -0
- package/dist/lib/admin-surfaces.js +669 -0
- package/dist/lib/admin-surfaces.js.map +1 -0
- package/dist/lib/delegated-composer.d.ts +85 -0
- package/dist/lib/delegated-composer.d.ts.map +1 -0
- package/dist/lib/delegated-composer.js +241 -0
- package/dist/lib/delegated-composer.js.map +1 -0
- package/dist/lib/divergence-artefacts.d.ts +305 -0
- package/dist/lib/divergence-artefacts.d.ts.map +1 -0
- package/dist/lib/divergence-artefacts.js +828 -0
- package/dist/lib/divergence-artefacts.js.map +1 -0
- package/dist/lib/divergence.d.ts +337 -0
- package/dist/lib/divergence.d.ts.map +1 -0
- package/dist/lib/divergence.js +1005 -0
- package/dist/lib/divergence.js.map +1 -0
- package/dist/lib/docs-artefacts.d.ts +395 -0
- package/dist/lib/docs-artefacts.d.ts.map +1 -0
- package/dist/lib/docs-artefacts.js +781 -0
- package/dist/lib/docs-artefacts.js.map +1 -0
- package/dist/lib/emitted-exports.d.ts +21 -0
- package/dist/lib/emitted-exports.d.ts.map +1 -0
- package/dist/lib/emitted-exports.js +96 -0
- package/dist/lib/emitted-exports.js.map +1 -0
- package/dist/lib/emitted-freshness.d.ts +112 -0
- package/dist/lib/emitted-freshness.d.ts.map +1 -0
- package/dist/lib/emitted-freshness.js +288 -0
- package/dist/lib/emitted-freshness.js.map +1 -0
- package/dist/lib/entity-index-artefact.d.ts +95 -0
- package/dist/lib/entity-index-artefact.d.ts.map +1 -0
- package/dist/lib/entity-index-artefact.js +210 -0
- package/dist/lib/entity-index-artefact.js.map +1 -0
- package/dist/lib/instance-build-inputs.d.ts +108 -0
- package/dist/lib/instance-build-inputs.d.ts.map +1 -0
- package/dist/lib/instance-build-inputs.js +165 -0
- package/dist/lib/instance-build-inputs.js.map +1 -0
- package/dist/lib/module-docs.d.ts +473 -0
- package/dist/lib/module-docs.d.ts.map +1 -0
- package/dist/lib/module-docs.js +711 -0
- package/dist/lib/module-docs.js.map +1 -0
- package/dist/lib/module-package-subpaths.d.ts +56 -0
- package/dist/lib/module-package-subpaths.d.ts.map +1 -0
- package/dist/lib/module-package-subpaths.js +223 -0
- package/dist/lib/module-package-subpaths.js.map +1 -0
- package/dist/lib/module-packages.d.ts +200 -0
- package/dist/lib/module-packages.d.ts.map +1 -0
- package/dist/lib/module-packages.js +580 -0
- package/dist/lib/module-packages.js.map +1 -0
- package/dist/lib/module-population.d.ts +129 -0
- package/dist/lib/module-population.d.ts.map +1 -0
- package/dist/lib/module-population.js +172 -0
- package/dist/lib/module-population.js.map +1 -0
- package/dist/lib/module-roots.d.ts +337 -0
- package/dist/lib/module-roots.d.ts.map +1 -0
- package/dist/lib/module-roots.js +586 -0
- package/dist/lib/module-roots.js.map +1 -0
- package/dist/lib/nested-checkouts.d.ts +33 -0
- package/dist/lib/nested-checkouts.d.ts.map +1 -0
- package/dist/lib/nested-checkouts.js +160 -0
- package/dist/lib/nested-checkouts.js.map +1 -0
- package/dist/lib/platform-root.d.ts +43 -0
- package/dist/lib/platform-root.d.ts.map +1 -0
- package/dist/lib/platform-root.js +134 -0
- package/dist/lib/platform-root.js.map +1 -0
- package/dist/lib/platform-surface.d.ts +235 -0
- package/dist/lib/platform-surface.d.ts.map +1 -0
- package/dist/lib/platform-surface.js +393 -0
- package/dist/lib/platform-surface.js.map +1 -0
- package/dist/lib/port-registrations.d.ts +223 -0
- package/dist/lib/port-registrations.d.ts.map +1 -0
- package/dist/lib/port-registrations.js +532 -0
- package/dist/lib/port-registrations.js.map +1 -0
- package/dist/lib/read-size.d.ts +154 -0
- package/dist/lib/read-size.d.ts.map +1 -0
- package/dist/lib/read-size.js +182 -0
- package/dist/lib/read-size.js.map +1 -0
- package/dist/lib/registration-owners.d.ts +79 -0
- package/dist/lib/registration-owners.d.ts.map +1 -0
- package/dist/lib/registration-owners.js +77 -0
- package/dist/lib/registration-owners.js.map +1 -0
- package/dist/lib/release-index.d.ts +53 -0
- package/dist/lib/release-index.d.ts.map +1 -0
- package/dist/lib/release-index.js +162 -0
- package/dist/lib/release-index.js.map +1 -0
- package/dist/lib/repeating-timers.d.ts +79 -0
- package/dist/lib/repeating-timers.d.ts.map +1 -0
- package/dist/lib/repeating-timers.js +189 -0
- package/dist/lib/repeating-timers.js.map +1 -0
- package/dist/lib/source-text.d.ts +34 -0
- package/dist/lib/source-text.d.ts.map +1 -0
- package/dist/lib/source-text.js +80 -0
- package/dist/lib/source-text.js.map +1 -0
- package/dist/lib/specifiers.d.ts +20 -0
- package/dist/lib/specifiers.d.ts.map +1 -0
- package/dist/lib/specifiers.js +130 -0
- package/dist/lib/specifiers.js.map +1 -0
- package/dist/lib/sql-tables.d.ts +166 -0
- package/dist/lib/sql-tables.d.ts.map +1 -0
- package/dist/lib/sql-tables.js +464 -0
- package/dist/lib/sql-tables.js.map +1 -0
- package/dist/lib/switchable-modules.d.ts +54 -0
- package/dist/lib/switchable-modules.d.ts.map +1 -0
- package/dist/lib/switchable-modules.js +104 -0
- package/dist/lib/switchable-modules.js.map +1 -0
- package/dist/lib/tailwind-sources.d.ts +136 -0
- package/dist/lib/tailwind-sources.d.ts.map +1 -0
- package/dist/lib/tailwind-sources.js +307 -0
- package/dist/lib/tailwind-sources.js.map +1 -0
- package/dist/lib/ui-layer.d.ts +54 -0
- package/dist/lib/ui-layer.d.ts.map +1 -0
- package/dist/lib/ui-layer.js +57 -0
- package/dist/lib/ui-layer.js.map +1 -0
- package/dist/lib/workspace-packages.d.ts +186 -0
- package/dist/lib/workspace-packages.d.ts.map +1 -0
- package/dist/lib/workspace-packages.js +351 -0
- package/dist/lib/workspace-packages.js.map +1 -0
- package/dist/new-instance/deploy.d.ts +211 -0
- package/dist/new-instance/deploy.d.ts.map +1 -0
- package/dist/new-instance/deploy.js +1381 -0
- package/dist/new-instance/deploy.js.map +1 -0
- package/dist/new-instance/docs-toolchain.d.ts +66 -0
- package/dist/new-instance/docs-toolchain.d.ts.map +1 -0
- package/dist/new-instance/docs-toolchain.js +69 -0
- package/dist/new-instance/docs-toolchain.js.map +1 -0
- package/dist/new-instance/host.d.ts +124 -0
- package/dist/new-instance/host.d.ts.map +1 -0
- package/dist/new-instance/host.js +276 -0
- package/dist/new-instance/host.js.map +1 -0
- package/dist/new-instance/index.d.ts +118 -0
- package/dist/new-instance/index.d.ts.map +1 -0
- package/dist/new-instance/index.js +567 -0
- package/dist/new-instance/index.js.map +1 -0
- package/dist/new-instance/modules.d.ts +188 -0
- package/dist/new-instance/modules.d.ts.map +1 -0
- package/dist/new-instance/modules.js +392 -0
- package/dist/new-instance/modules.js.map +1 -0
- package/dist/new-instance/template.d.ts +505 -0
- package/dist/new-instance/template.d.ts.map +1 -0
- package/dist/new-instance/template.js +1886 -0
- package/dist/new-instance/template.js.map +1 -0
- package/dist/new-module/emit.d.ts +67 -0
- package/dist/new-module/emit.d.ts.map +1 -0
- package/dist/new-module/emit.js +1393 -0
- package/dist/new-module/emit.js.map +1 -0
- package/dist/new-module/host.d.ts +67 -0
- package/dist/new-module/host.d.ts.map +1 -0
- package/dist/new-module/host.js +224 -0
- package/dist/new-module/host.js.map +1 -0
- package/dist/new-module/index.d.ts +32 -0
- package/dist/new-module/index.d.ts.map +1 -0
- package/dist/new-module/index.js +193 -0
- package/dist/new-module/index.js.map +1 -0
- package/dist/new-module/spec.d.ts +188 -0
- package/dist/new-module/spec.d.ts.map +1 -0
- package/dist/new-module/spec.js +404 -0
- package/dist/new-module/spec.js.map +1 -0
- package/dist/new-module/text.d.ts +15 -0
- package/dist/new-module/text.d.ts.map +1 -0
- package/dist/new-module/text.js +22 -0
- package/dist/new-module/text.js.map +1 -0
- package/dist/new-storefront/dockerfile.d.ts +20 -0
- package/dist/new-storefront/dockerfile.d.ts.map +1 -0
- package/dist/new-storefront/dockerfile.js +131 -0
- package/dist/new-storefront/dockerfile.js.map +1 -0
- package/dist/new-storefront/gitignore.d.ts +23 -0
- package/dist/new-storefront/gitignore.d.ts.map +1 -0
- package/dist/new-storefront/gitignore.js +39 -0
- package/dist/new-storefront/gitignore.js.map +1 -0
- package/dist/new-storefront/index.d.ts +93 -0
- package/dist/new-storefront/index.d.ts.map +1 -0
- package/dist/new-storefront/index.js +329 -0
- package/dist/new-storefront/index.js.map +1 -0
- package/dist/new-storefront/npmrc.d.ts +98 -0
- package/dist/new-storefront/npmrc.d.ts.map +1 -0
- package/dist/new-storefront/npmrc.js +217 -0
- package/dist/new-storefront/npmrc.js.map +1 -0
- package/dist/new-storefront/reference.d.ts +189 -0
- package/dist/new-storefront/reference.d.ts.map +1 -0
- package/dist/new-storefront/reference.js +430 -0
- package/dist/new-storefront/reference.js.map +1 -0
- package/dist/new-storefront/rewrite.d.ts +171 -0
- package/dist/new-storefront/rewrite.d.ts.map +1 -0
- package/dist/new-storefront/rewrite.js +701 -0
- package/dist/new-storefront/rewrite.js.map +1 -0
- package/dist/release-index.json +284 -0
- package/dist/rules/action-route-permissions.d.ts +141 -0
- package/dist/rules/action-route-permissions.d.ts.map +1 -0
- package/dist/rules/action-route-permissions.js +556 -0
- package/dist/rules/action-route-permissions.js.map +1 -0
- package/dist/rules/bundle-pairing.d.ts +74 -0
- package/dist/rules/bundle-pairing.d.ts.map +1 -0
- package/dist/rules/bundle-pairing.js +281 -0
- package/dist/rules/bundle-pairing.js.map +1 -0
- package/dist/rules/channel-resolution.d.ts +17 -0
- package/dist/rules/channel-resolution.d.ts.map +1 -0
- package/dist/rules/channel-resolution.js +382 -0
- package/dist/rules/channel-resolution.js.map +1 -0
- package/dist/rules/command-coverage.d.ts +210 -0
- package/dist/rules/command-coverage.d.ts.map +1 -0
- package/dist/rules/command-coverage.js +714 -0
- package/dist/rules/command-coverage.js.map +1 -0
- package/dist/rules/container-imports.d.ts +60 -0
- package/dist/rules/container-imports.d.ts.map +1 -0
- package/dist/rules/container-imports.js +158 -0
- package/dist/rules/container-imports.js.map +1 -0
- package/dist/rules/default-language-prose.d.ts +212 -0
- package/dist/rules/default-language-prose.d.ts.map +1 -0
- package/dist/rules/default-language-prose.js +710 -0
- package/dist/rules/default-language-prose.js.map +1 -0
- package/dist/rules/diacritic-folds.d.ts +238 -0
- package/dist/rules/diacritic-folds.d.ts.map +1 -0
- package/dist/rules/diacritic-folds.js +681 -0
- package/dist/rules/diacritic-folds.js.map +1 -0
- package/dist/rules/entity-tenant-classification.d.ts +171 -0
- package/dist/rules/entity-tenant-classification.d.ts.map +1 -0
- package/dist/rules/entity-tenant-classification.js +323 -0
- package/dist/rules/entity-tenant-classification.js.map +1 -0
- package/dist/rules/entry-presence.d.ts +142 -0
- package/dist/rules/entry-presence.d.ts.map +1 -0
- package/dist/rules/entry-presence.js +339 -0
- package/dist/rules/entry-presence.js.map +1 -0
- package/dist/rules/entry-scope.d.ts +91 -0
- package/dist/rules/entry-scope.d.ts.map +1 -0
- package/dist/rules/entry-scope.js +404 -0
- package/dist/rules/entry-scope.js.map +1 -0
- package/dist/rules/env-inputs.d.ts +222 -0
- package/dist/rules/env-inputs.d.ts.map +1 -0
- package/dist/rules/env-inputs.js +951 -0
- package/dist/rules/env-inputs.js.map +1 -0
- package/dist/rules/kernel-boundary.d.ts +37 -0
- package/dist/rules/kernel-boundary.d.ts.map +1 -0
- package/dist/rules/kernel-boundary.js +195 -0
- package/dist/rules/kernel-boundary.js.map +1 -0
- package/dist/rules/nul-bytes.d.ts +233 -0
- package/dist/rules/nul-bytes.d.ts.map +1 -0
- package/dist/rules/nul-bytes.js +332 -0
- package/dist/rules/nul-bytes.js.map +1 -0
- package/dist/rules/platform-surface.d.ts +479 -0
- package/dist/rules/platform-surface.d.ts.map +1 -0
- package/dist/rules/platform-surface.js +749 -0
- package/dist/rules/platform-surface.js.map +1 -0
- package/dist/rules/port-catches.d.ts +225 -0
- package/dist/rules/port-catches.d.ts.map +1 -0
- package/dist/rules/port-catches.js +1374 -0
- package/dist/rules/port-catches.js.map +1 -0
- package/dist/rules/port-shape.d.ts +213 -0
- package/dist/rules/port-shape.d.ts.map +1 -0
- package/dist/rules/port-shape.js +670 -0
- package/dist/rules/port-shape.js.map +1 -0
- package/dist/rules/queue-names.d.ts +108 -0
- package/dist/rules/queue-names.d.ts.map +1 -0
- package/dist/rules/queue-names.js +395 -0
- package/dist/rules/queue-names.js.map +1 -0
- package/dist/rules/singleton-identity.d.ts +205 -0
- package/dist/rules/singleton-identity.d.ts.map +1 -0
- package/dist/rules/singleton-identity.js +830 -0
- package/dist/rules/singleton-identity.js.map +1 -0
- package/dist/rules/subscribe-seam.d.ts +121 -0
- package/dist/rules/subscribe-seam.d.ts.map +1 -0
- package/dist/rules/subscribe-seam.js +594 -0
- package/dist/rules/subscribe-seam.js.map +1 -0
- package/dist/rules/transaction-context.d.ts +40 -0
- package/dist/rules/transaction-context.d.ts.map +1 -0
- package/dist/rules/transaction-context.js +294 -0
- package/dist/rules/transaction-context.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI check — **a module's background consumers reach the module's own seam**:
|
|
3
|
+
* an EventBus subscription through `ctx.subscribe` and never a bare
|
|
4
|
+
* `eventBus.on` (issue #107), a BullMQ queue consumer through `ctx.worker` /
|
|
5
|
+
* `defineModuleWorker` and never a `Worker` nobody registered. Constitution
|
|
6
|
+
* XVII, in both halves.
|
|
7
|
+
*
|
|
8
|
+
* The second signal is here rather than in a script of its own because the
|
|
9
|
+
* paragraph four lines below is the one that made it look unnecessary — *"routes
|
|
10
|
+
* have the `ctx.routes` seam; workers have `defineModuleWorker`; subscriptions
|
|
11
|
+
* had nothing"* — and it was wrong about workers in exactly the way it says
|
|
12
|
+
* subscriptions were wrong. `pwa` constructed its push-delivery `Worker` and
|
|
13
|
+
* dropped the value on the floor: in no per-module registry, so
|
|
14
|
+
* `pauseWorkersFor('pwa')` reached nothing and an operator who switched `pwa`
|
|
15
|
+
* off went on having push notifications delivered to their customers' devices.
|
|
16
|
+
* One rule, one population (a module's own sources), one ledger.
|
|
17
|
+
*
|
|
18
|
+
|
|
19
|
+
* `ctx.subscribe` wraps the handler in `subscribeForModule`, which is what makes
|
|
20
|
+
* the module's effective state decide whether the handler runs at all. A
|
|
21
|
+
* registration written as `eventBus.on(...)` keeps its handler attached for the
|
|
22
|
+
* process lifetime, so a module an operator switched off goes on reacting to
|
|
23
|
+
* every event the platform emits.
|
|
24
|
+
*
|
|
25
|
+
* That is worse than a route that keeps answering, because a subscriber
|
|
26
|
+
* **writes**: the sweep that produced this check found twenty-two such
|
|
27
|
+
* registrations across nine modules; **ten** wrote to the platform's own
|
|
28
|
+
* database — an invoice issued and e-mailed, a quote request flipped to
|
|
29
|
+
* Completed, a push message row created and delivered to a device, a shopping
|
|
30
|
+
* list created, a threshold row mirrored, a feed's and a PIM import's next-run
|
|
31
|
+
* stamp written back — and **twenty-one of the twenty-two** mutated something,
|
|
32
|
+
* the exception being `catalog`'s cache flush at the storefront.
|
|
33
|
+
*
|
|
34
|
+
* Routes have `check-kernel-boundary` and the `ctx.routes` seam; workers have
|
|
35
|
+
* `defineModuleWorker`; subscriptions had nothing, which is why twenty-two
|
|
36
|
+
* accumulated while every one of those modules' conversion tasks read done.
|
|
37
|
+
*
|
|
38
|
+
* ## What counts as a subscription
|
|
39
|
+
*
|
|
40
|
+
* A call `<receiver>.on(<event>, <handler>)` in a file that belongs to a module
|
|
41
|
+
* — core under `src/modules`, overlay under `src/apps` — where the receiver
|
|
42
|
+
* reads as an event bus. Three
|
|
43
|
+
* signals, because the receiver is spelled several ways and the check follows
|
|
44
|
+
* the shape rather than one literal:
|
|
45
|
+
*
|
|
46
|
+
* 1. the receiver's trailing identifier is bus-shaped — `eventBus`, `bus`,
|
|
47
|
+
* `events`, `options.eventBus`, `this.deps.eventBus`;
|
|
48
|
+
* 2. the receiver is a cast around one — `(options.eventBus as CategoryEventBus).on`;
|
|
49
|
+
* 3. the first argument is a **domain event name** (`a.b`, `a.b.v1`), which is
|
|
50
|
+
* what distinguishes a bus from a BullMQ worker (`'completed'`), an ioredis
|
|
51
|
+
* subscriber (`'message'`) and a Node stream (`'data'`).
|
|
52
|
+
*
|
|
53
|
+
* The kernel is deliberately out of scope. `src/kernel/settings` and
|
|
54
|
+
* `src/kernel/sales-channels` each attach a cache invalidator with a bare
|
|
55
|
+
* `eventBus.on`, and that is correct: the kernel composes before any module and
|
|
56
|
+
* has no effective state to gate on — there is no operator switch that makes the
|
|
57
|
+
* settings cache stop invalidating.
|
|
58
|
+
*
|
|
59
|
+
* ## What counts as a queue consumer
|
|
60
|
+
*
|
|
61
|
+
* Two findings, because the tree spells the same thing two ways and only one of
|
|
62
|
+
* them names `Worker` at the site that matters:
|
|
63
|
+
*
|
|
64
|
+
* 1. **`ungated-construction`** — `new Worker(...)` in a module's own sources,
|
|
65
|
+
* where `Worker` is the binding the file imported from `bullmq`, and the
|
|
66
|
+
* value neither goes into a seam call nor is `return`ed. Returning it is
|
|
67
|
+
* what a *factory* does, and a factory is not the registration: ten of the
|
|
68
|
+
* fifteen constructions in the tree sit in a `services/queues/*.ts` whose
|
|
69
|
+
* caller wraps them.
|
|
70
|
+
* 2. **`ungated-registration`** — a call to one of those factories whose value
|
|
71
|
+
* goes nowhere. This is the one `pwa` failed, and the one a check keyed on
|
|
72
|
+
* `new Worker(` cannot see at all.
|
|
73
|
+
*
|
|
74
|
+
* "Goes nowhere" is four questions, and each was a real shape in the tree when
|
|
75
|
+
* this landed: it is not inside a seam call; it is not `return`ed; it is not
|
|
76
|
+
* bound to a name this file later hands to a seam; and it is not bound to a name
|
|
77
|
+
* this function **returns** — which is `pwa`'s repaired shape
|
|
78
|
+
* (`const workers = […]; return { plugin, handle, workers }`) and `ksef`'s
|
|
79
|
+
* (`worker = createKsefSubmitWorker(…)`, returned as `workers: worker ? [worker] : []`).
|
|
80
|
+
* The last one is what T051's conversion made the common case: a module's
|
|
81
|
+
* `plugin.ts` collects its workers and its `backend.ts` hands each to
|
|
82
|
+
* `ctx.worker`, so the value crosses a file boundary. The analysis stops at the
|
|
83
|
+
* return — it does not follow the value into the caller — which is stated here
|
|
84
|
+
* rather than pretended away. What it still catches is the drop on the floor.
|
|
85
|
+
*
|
|
86
|
+
* The **seam** is likewise not two literals: `catalog` and `newsletter` take a
|
|
87
|
+
* `registerWorker(worker, options)` callback from their own `backend.ts` whose
|
|
88
|
+
* body is `ctx.worker(worker, options)`, so the forwarder names are derived from
|
|
89
|
+
* the bodies that call the seam, exactly as the factory names are derived from
|
|
90
|
+
* what they return. Neither set is written down; the next module will name both
|
|
91
|
+
* something else.
|
|
92
|
+
*
|
|
93
|
+
* The factory set is **derived**, never a naming convention: pass one walks the
|
|
94
|
+
* whole tree for functions that return a BullMQ `Worker` and records their
|
|
95
|
+
* names, so `createPushDeliveryWorker` is recognised because of what it returns
|
|
96
|
+
* and a `makeThing` that returns one would be too. A convention (`create*Worker`)
|
|
97
|
+
* would have had issue #244's defect — a population defined by the presence of
|
|
98
|
+
* the very habit the rule is about.
|
|
99
|
+
*
|
|
100
|
+
* What it cannot see, stated here rather than discovered later: a worker handed
|
|
101
|
+
* across files to a caller that forgets the seam (the analysis stops at the
|
|
102
|
+
* return), a `Worker` subclass, a construction behind a computed callee, and a
|
|
103
|
+
* `defineModuleWorker` called with the **wrong module id** — that last one is a
|
|
104
|
+
* different rule and `pauseWorkersFor` would find the worker under a name no
|
|
105
|
+
* manifest has. The seam itself is recognised by callee name — `defineModuleWorker`,
|
|
106
|
+
* or any `.worker(…)` — which over-approximates in the direction of "gated": a
|
|
107
|
+
* module that had some *other* collaborator with a `worker(…)` method could hide
|
|
108
|
+
* a bypass inside its arguments. There is no such method in the tree, and
|
|
109
|
+
* narrowing the receiver to `ctx` would refuse the next author who names their
|
|
110
|
+
* `ModuleContext` something else.
|
|
111
|
+
*
|
|
112
|
+
* ## One analysis, two hosts
|
|
113
|
+
*
|
|
114
|
+
* This file is the analysis. `backend/scripts/check-subscribe-seam.ts` hosts it
|
|
115
|
+
* over this repository's source roots; `endora check` hosts it over one module
|
|
116
|
+
* package (`specs/101-endora-check/contracts/package-scope-layout.md` §6).
|
|
117
|
+
*
|
|
118
|
+
* The worker half's exit-2 floor — *no BullMQ worker site at all* — is a
|
|
119
|
+
* statement about a **repository** whose tree is known to hold queue consumers.
|
|
120
|
+
* A single package holding none is the ordinary case, so the package-scope host
|
|
121
|
+
* declares that floor unevaluated on the rule's own line rather than refusing;
|
|
122
|
+
* see `contracts/exit-reduction.md` § 1's partial verdict.
|
|
123
|
+
*/
|
|
124
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
125
|
+
import { join } from 'node:path';
|
|
126
|
+
import ts from 'typescript';
|
|
127
|
+
import { NO_HOST_RESIDENT_MODULES, } from '../lib/module-population.js';
|
|
128
|
+
// `moduleOf` — attribute a file to a module over every root a module can live
|
|
129
|
+
// in — has its one CLI-side home in the relocated container-imports rule. The
|
|
130
|
+
// two copies still standing in `backend/scripts/` (this check's former import
|
|
131
|
+
// from `check-port-dependencies.ts`, and `check-container-imports.ts`' own) are
|
|
132
|
+
// pre-existing residue of the estate's growth, not something this relocation
|
|
133
|
+
// introduced; a third copy here would be.
|
|
134
|
+
import { moduleOf } from './container-imports.js';
|
|
135
|
+
/** An event name the payload of which is a domain event: `a.b`, `a.b.v1`. */
|
|
136
|
+
const DOMAIN_EVENT = /^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$/;
|
|
137
|
+
/** A receiver whose trailing name says "event bus" whatever it is typed as. */
|
|
138
|
+
const BUS_RECEIVER = /^(event_?bus|bus|events|eventEmitter)$/i;
|
|
139
|
+
/** What the key carries when the subscription's event name is not a literal. */
|
|
140
|
+
const DYNAMIC = '<dynamic>';
|
|
141
|
+
/**
|
|
142
|
+
* Bare subscriptions that may stay bare, with the reason and the question that
|
|
143
|
+
* would retire the entry.
|
|
144
|
+
*
|
|
145
|
+
* Keyed `<path under src/>:<event>` rather than by line, so moving code inside a
|
|
146
|
+
* file does not invalidate an entry and re-opening the hole does not silently
|
|
147
|
+
* inherit one. **Two-way**, in the idiom of `PORT_CATCHES_TO_DRAIN` and
|
|
148
|
+
* `WIRING_RESOLUTIONS_TO_DRAIN`: an unledgered bare subscription fails the
|
|
149
|
+
* build, and a ledger entry that no longer describes one fails it too.
|
|
150
|
+
*
|
|
151
|
+
* It is empty, and that is the point: every module subscription in the tree goes
|
|
152
|
+
* through `ctx.subscribe`. An entry here is a module that reacts to events while
|
|
153
|
+
* an operator believes it is switched off, so a reason has to say why that is
|
|
154
|
+
* the least-wrong behaviour rather than that nobody has moved it yet.
|
|
155
|
+
*/
|
|
156
|
+
export const BARE_SUBSCRIPTIONS_TO_DRAIN = {};
|
|
157
|
+
/**
|
|
158
|
+
* Queue consumers that may stay outside the seam, with the reason and the
|
|
159
|
+
* question that would retire the entry.
|
|
160
|
+
*
|
|
161
|
+
* Keyed `<path under src/>:<spelling>`, two-way, and empty for the same reason
|
|
162
|
+
* the subscription ledger is: a worker outside `ctx.worker` is a module doing
|
|
163
|
+
* work while an operator believes it is switched off, and there is no per-worker
|
|
164
|
+
* remedy — the registry is the only thing `pauseWorkersFor` and the presence
|
|
165
|
+
* reconcile can reach. An entry has to say why *that* is the least-wrong
|
|
166
|
+
* behaviour.
|
|
167
|
+
*/
|
|
168
|
+
export const WORKERS_OUTSIDE_THE_SEAM = {};
|
|
169
|
+
/** The seam a module's queue consumer has to reach, in the two spellings. */
|
|
170
|
+
const WORKER_SEAM_CALLEES = new Set(['defineModuleWorker', 'worker']);
|
|
171
|
+
/**
|
|
172
|
+
* Every file the seam rule judges, under `roots`.
|
|
173
|
+
*
|
|
174
|
+
* Exported because both hosts walk: the repository's source roots and one
|
|
175
|
+
* package's. A second copy would be two definitions of one population.
|
|
176
|
+
*/
|
|
177
|
+
export function collectSeamFiles(roots) {
|
|
178
|
+
return roots.flatMap((root) => walk(root));
|
|
179
|
+
}
|
|
180
|
+
function walk(dir, out = []) {
|
|
181
|
+
if (!existsSync(dir))
|
|
182
|
+
return out;
|
|
183
|
+
for (const name of readdirSync(dir)) {
|
|
184
|
+
const full = join(dir, name);
|
|
185
|
+
if (statSync(full).isDirectory()) {
|
|
186
|
+
if (name === 'node_modules' || name === 'dist')
|
|
187
|
+
continue;
|
|
188
|
+
walk(full, out);
|
|
189
|
+
}
|
|
190
|
+
else if (name.endsWith('.ts') && !name.endsWith('.test.ts') && !name.endsWith('.d.ts')) {
|
|
191
|
+
out.push(full);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
196
|
+
/** `<file>:<event>` — the ledger key, and the identity of a site. */
|
|
197
|
+
export function keyOf(found) {
|
|
198
|
+
return `${found.file}:${found.event}`;
|
|
199
|
+
}
|
|
200
|
+
/** The trailing identifier of a receiver: `this.deps.eventBus` → `eventBus`. */
|
|
201
|
+
function tailName(node) {
|
|
202
|
+
if (ts.isIdentifier(node))
|
|
203
|
+
return node.text;
|
|
204
|
+
if (ts.isPropertyAccessExpression(node))
|
|
205
|
+
return node.name.text;
|
|
206
|
+
if (ts.isAsExpression(node) ||
|
|
207
|
+
ts.isNonNullExpression(node) ||
|
|
208
|
+
ts.isParenthesizedExpression(node) ||
|
|
209
|
+
ts.isTypeAssertionExpression(node)) {
|
|
210
|
+
return tailName(node.expression);
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
/** The string an argument denotes, through any number of casts. */
|
|
215
|
+
function stringLiteralOf(node) {
|
|
216
|
+
if (ts.isStringLiteralLike(node))
|
|
217
|
+
return node.text;
|
|
218
|
+
if (ts.isAsExpression(node) ||
|
|
219
|
+
ts.isNonNullExpression(node) ||
|
|
220
|
+
ts.isParenthesizedExpression(node) ||
|
|
221
|
+
ts.isTypeAssertionExpression(node)) {
|
|
222
|
+
return stringLiteralOf(node.expression);
|
|
223
|
+
}
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
/** Every `<bus>.on(<event>, <handler>)` in a module's own sources. */
|
|
227
|
+
export function findBareSubscriptions(input) {
|
|
228
|
+
const found = [];
|
|
229
|
+
const hostResident = input.hostResidentModules ?? NO_HOST_RESIDENT_MODULES;
|
|
230
|
+
for (const [file, text] of input.sources) {
|
|
231
|
+
const moduleId = moduleOf(`/src/${file}`, hostResident);
|
|
232
|
+
// Only a module has an effective state to gate on. A file outside one —
|
|
233
|
+
// the kernel, `http/`, `db/`, a composition root — is not this rule's
|
|
234
|
+
// business.
|
|
235
|
+
if (moduleId === null)
|
|
236
|
+
continue;
|
|
237
|
+
const sf = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);
|
|
238
|
+
const visit = (node) => {
|
|
239
|
+
if (ts.isCallExpression(node) &&
|
|
240
|
+
ts.isPropertyAccessExpression(node.expression) &&
|
|
241
|
+
node.expression.name.text === 'on' &&
|
|
242
|
+
node.arguments.length >= 2) {
|
|
243
|
+
const receiver = tailName(node.expression.expression);
|
|
244
|
+
const [nameArgument] = node.arguments;
|
|
245
|
+
// `'order.status_changed.v1' as never` is the spelling `pwa` used to
|
|
246
|
+
// satisfy an untyped bus, so the cast is unwrapped before the literal
|
|
247
|
+
// is read — otherwise the ledger key would say `<dynamic>` for an event
|
|
248
|
+
// written out in full.
|
|
249
|
+
const literal = nameArgument === undefined ? null : stringLiteralOf(nameArgument);
|
|
250
|
+
const looksLikeBus = receiver !== null && BUS_RECEIVER.test(receiver);
|
|
251
|
+
const looksLikeDomainEvent = literal !== null && DOMAIN_EVENT.test(literal);
|
|
252
|
+
if (looksLikeBus || looksLikeDomainEvent) {
|
|
253
|
+
found.push({
|
|
254
|
+
file,
|
|
255
|
+
line: sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1,
|
|
256
|
+
moduleId,
|
|
257
|
+
event: literal ?? DYNAMIC,
|
|
258
|
+
receiver: receiver ?? '(expression)',
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
node.forEachChild(visit);
|
|
263
|
+
};
|
|
264
|
+
sf.forEachChild(visit);
|
|
265
|
+
}
|
|
266
|
+
found.sort((a, b) => (a.file === b.file ? a.line - b.line : a.file.localeCompare(b.file)));
|
|
267
|
+
return found;
|
|
268
|
+
}
|
|
269
|
+
/** `<file>:<spelling>` — the ledger key, and the identity of a site. */
|
|
270
|
+
export function workerKeyOf(site) {
|
|
271
|
+
return `${site.file}:${site.spelling}`;
|
|
272
|
+
}
|
|
273
|
+
/** The local name a file bound BullMQ's `Worker` to, if it imported one. */
|
|
274
|
+
function bullmqWorkerBinding(sf) {
|
|
275
|
+
let binding = null;
|
|
276
|
+
for (const statement of sf.statements) {
|
|
277
|
+
if (!ts.isImportDeclaration(statement))
|
|
278
|
+
continue;
|
|
279
|
+
if (stringLiteralOf(statement.moduleSpecifier) !== 'bullmq')
|
|
280
|
+
continue;
|
|
281
|
+
const clause = statement.importClause;
|
|
282
|
+
const named = clause?.namedBindings;
|
|
283
|
+
if (!named || !ts.isNamedImports(named))
|
|
284
|
+
continue;
|
|
285
|
+
for (const element of named.elements) {
|
|
286
|
+
// `import { Worker }` and `import { Worker as BullWorker }` alike: what
|
|
287
|
+
// matters is the *imported* name, and the local one is what the site says.
|
|
288
|
+
if ((element.propertyName ?? element.name).text === 'Worker') {
|
|
289
|
+
binding = element.name.text;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return binding;
|
|
294
|
+
}
|
|
295
|
+
/** The callee's own name, whichever of the two shapes it is written in. */
|
|
296
|
+
function calleeName(call) {
|
|
297
|
+
const callee = call.expression;
|
|
298
|
+
if (ts.isIdentifier(callee))
|
|
299
|
+
return callee.text;
|
|
300
|
+
if (ts.isPropertyAccessExpression(callee))
|
|
301
|
+
return callee.name.text;
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
/** True when `node` sits inside the arguments of a call to a seam or a forwarder. */
|
|
305
|
+
function insideSeamCall(node, seams) {
|
|
306
|
+
for (let cursor = node.parent; cursor; cursor = cursor.parent) {
|
|
307
|
+
if (!ts.isCallExpression(cursor))
|
|
308
|
+
continue;
|
|
309
|
+
const name = calleeName(cursor);
|
|
310
|
+
if (name !== null && seams.has(name))
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
/** True when `node`'s value is itself returned — a factory hands it to its caller. */
|
|
316
|
+
function isHandedToCaller(node) {
|
|
317
|
+
for (let cursor = node.parent; cursor; cursor = cursor.parent) {
|
|
318
|
+
if (ts.isReturnStatement(cursor))
|
|
319
|
+
return true;
|
|
320
|
+
if (ts.isArrowFunction(cursor) && cursor.body === node)
|
|
321
|
+
return true;
|
|
322
|
+
if (ts.isFunctionLike(cursor))
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* The name a call's value lands in, through the wrappers that do not change
|
|
329
|
+
* whose value it is: an array or object literal, a conditional, a cast, a
|
|
330
|
+
* `push` onto a collection.
|
|
331
|
+
*
|
|
332
|
+
* `const workers = runWorkers ? [createXWorker(…)] : []` and
|
|
333
|
+
* `worker = createXWorker(…)` both answer with the collection's name, which is
|
|
334
|
+
* what the two rules below then ask about.
|
|
335
|
+
*/
|
|
336
|
+
function boundCollectionName(node) {
|
|
337
|
+
let current = node;
|
|
338
|
+
for (let cursor = node.parent; cursor; cursor = cursor.parent) {
|
|
339
|
+
if (ts.isVariableDeclaration(cursor) && ts.isIdentifier(cursor.name))
|
|
340
|
+
return cursor.name.text;
|
|
341
|
+
if (ts.isBinaryExpression(cursor) &&
|
|
342
|
+
cursor.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
343
|
+
ts.isIdentifier(cursor.left)) {
|
|
344
|
+
return cursor.left.text;
|
|
345
|
+
}
|
|
346
|
+
if (ts.isCallExpression(cursor) && calleeName(cursor) === 'push') {
|
|
347
|
+
const receiver = cursor.expression;
|
|
348
|
+
if (ts.isPropertyAccessExpression(receiver) && ts.isIdentifier(receiver.expression)) {
|
|
349
|
+
return receiver.expression.text;
|
|
350
|
+
}
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
const transparent = ts.isArrayLiteralExpression(cursor) ||
|
|
354
|
+
ts.isObjectLiteralExpression(cursor) ||
|
|
355
|
+
ts.isPropertyAssignment(cursor) ||
|
|
356
|
+
ts.isShorthandPropertyAssignment(cursor) ||
|
|
357
|
+
ts.isConditionalExpression(cursor) ||
|
|
358
|
+
ts.isParenthesizedExpression(cursor) ||
|
|
359
|
+
ts.isAsExpression(cursor) ||
|
|
360
|
+
ts.isNonNullExpression(cursor);
|
|
361
|
+
if (!transparent)
|
|
362
|
+
return null;
|
|
363
|
+
current = cursor;
|
|
364
|
+
}
|
|
365
|
+
void current;
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
/** Every identifier mentioned in a `return` of the function that encloses `node`. */
|
|
369
|
+
function namesReturnedFromEnclosingFunction(node) {
|
|
370
|
+
let fn;
|
|
371
|
+
for (let cursor = node.parent; cursor; cursor = cursor.parent) {
|
|
372
|
+
if (ts.isFunctionLike(cursor)) {
|
|
373
|
+
fn = cursor;
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const names = new Set();
|
|
378
|
+
if (!fn)
|
|
379
|
+
return names;
|
|
380
|
+
const collect = (n) => {
|
|
381
|
+
if (ts.isIdentifier(n))
|
|
382
|
+
names.add(n.text);
|
|
383
|
+
if (ts.isShorthandPropertyAssignment(n))
|
|
384
|
+
names.add(n.name.text);
|
|
385
|
+
n.forEachChild(collect);
|
|
386
|
+
};
|
|
387
|
+
const visit = (n) => {
|
|
388
|
+
if (ts.isFunctionLike(n) && n !== fn)
|
|
389
|
+
return;
|
|
390
|
+
if (ts.isReturnStatement(n) && n.expression)
|
|
391
|
+
collect(n.expression);
|
|
392
|
+
n.forEachChild(visit);
|
|
393
|
+
};
|
|
394
|
+
const body = fn.body;
|
|
395
|
+
if (body && !ts.isBlock(body)) {
|
|
396
|
+
collect(body);
|
|
397
|
+
return names;
|
|
398
|
+
}
|
|
399
|
+
if (body)
|
|
400
|
+
body.forEachChild(visit);
|
|
401
|
+
return names;
|
|
402
|
+
}
|
|
403
|
+
/** The nearest enclosing function's name, for the factory index. */
|
|
404
|
+
function enclosingFunctionName(node) {
|
|
405
|
+
for (let cursor = node.parent; cursor; cursor = cursor.parent) {
|
|
406
|
+
if (ts.isFunctionDeclaration(cursor) || ts.isMethodDeclaration(cursor)) {
|
|
407
|
+
return cursor.name && ts.isIdentifier(cursor.name) ? cursor.name.text : null;
|
|
408
|
+
}
|
|
409
|
+
if (ts.isFunctionExpression(cursor) || ts.isArrowFunction(cursor)) {
|
|
410
|
+
const parent = cursor.parent;
|
|
411
|
+
if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name))
|
|
412
|
+
return parent.name.text;
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Pass one — every function in the walked tree that returns a BullMQ `Worker`.
|
|
420
|
+
*
|
|
421
|
+
* Derived rather than conventional (see the header): the second finding needs to
|
|
422
|
+
* know that `createPushDeliveryWorker(...)` **is** a worker, and the only honest
|
|
423
|
+
* source for that is what the function returns.
|
|
424
|
+
*/
|
|
425
|
+
export function findWorkerFactories(input) {
|
|
426
|
+
const names = new Set();
|
|
427
|
+
for (const [file, text] of input.sources) {
|
|
428
|
+
const sf = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);
|
|
429
|
+
const binding = bullmqWorkerBinding(sf);
|
|
430
|
+
if (binding === null)
|
|
431
|
+
continue;
|
|
432
|
+
const visit = (node) => {
|
|
433
|
+
if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === binding) {
|
|
434
|
+
if (isHandedToCaller(node)) {
|
|
435
|
+
const name = enclosingFunctionName(node);
|
|
436
|
+
if (name !== null)
|
|
437
|
+
names.add(name);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
node.forEachChild(visit);
|
|
441
|
+
};
|
|
442
|
+
sf.forEachChild(visit);
|
|
443
|
+
}
|
|
444
|
+
return names;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Pass one-and-a-half — the names that **forward** to the seam.
|
|
448
|
+
*
|
|
449
|
+
* `catalog` and `newsletter` take a `registerWorker(worker, options)` callback
|
|
450
|
+
* from their own `backend.ts`, whose body is `ctx.worker(worker, options)`. That
|
|
451
|
+
* is the seam reached one hop away, and a rule that knew only the two literal
|
|
452
|
+
* spellings would report both modules as bypassing it. The set is **derived**
|
|
453
|
+
* from the bodies rather than written down, for the reason the factory set is:
|
|
454
|
+
* the next module will name its callback something else.
|
|
455
|
+
*/
|
|
456
|
+
export function findSeamForwarders(input) {
|
|
457
|
+
const names = new Set();
|
|
458
|
+
for (const [file, text] of input.sources) {
|
|
459
|
+
const sf = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);
|
|
460
|
+
const visit = (node) => {
|
|
461
|
+
if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name)) {
|
|
462
|
+
const body = node.initializer;
|
|
463
|
+
if ((ts.isArrowFunction(body) || ts.isFunctionExpression(body)) && callsSeam(body)) {
|
|
464
|
+
names.add(node.name.text);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
node.forEachChild(visit);
|
|
468
|
+
};
|
|
469
|
+
sf.forEachChild(visit);
|
|
470
|
+
}
|
|
471
|
+
return names;
|
|
472
|
+
}
|
|
473
|
+
/** Does this function body call one of the two literal seam spellings? */
|
|
474
|
+
function callsSeam(fn) {
|
|
475
|
+
let found = false;
|
|
476
|
+
const visit = (node) => {
|
|
477
|
+
if (found)
|
|
478
|
+
return;
|
|
479
|
+
if (ts.isCallExpression(node)) {
|
|
480
|
+
const name = calleeName(node);
|
|
481
|
+
if (name !== null && WORKER_SEAM_CALLEES.has(name))
|
|
482
|
+
found = true;
|
|
483
|
+
}
|
|
484
|
+
node.forEachChild(visit);
|
|
485
|
+
};
|
|
486
|
+
fn.forEachChild(visit);
|
|
487
|
+
return found;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Pass two — every queue-consumer site in a module's own sources, gated or not.
|
|
491
|
+
*
|
|
492
|
+
* The whole population is returned, not only the findings: the caller reports
|
|
493
|
+
* how many it read, and a vocabulary that resolved to nothing is exit 2 rather
|
|
494
|
+
* than a clean bill of health (issue #113).
|
|
495
|
+
*/
|
|
496
|
+
export function findWorkerSites(input, factories, forwarders = new Set()) {
|
|
497
|
+
const sites = [];
|
|
498
|
+
const seams = new Set([...WORKER_SEAM_CALLEES, ...forwarders]);
|
|
499
|
+
const hostResident = input.hostResidentModules ?? NO_HOST_RESIDENT_MODULES;
|
|
500
|
+
for (const [file, text] of input.sources) {
|
|
501
|
+
const sf = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);
|
|
502
|
+
const binding = bullmqWorkerBinding(sf);
|
|
503
|
+
const lineOf = (node) => sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
504
|
+
// One file-local pass first: which names does this file hand to a seam? A
|
|
505
|
+
// module that writes `const w = createXWorker(…)` and registers `w` two
|
|
506
|
+
// lines down is right, and the check has to be able to say so.
|
|
507
|
+
const registeredBindings = new Set();
|
|
508
|
+
const collectRegistered = (node) => {
|
|
509
|
+
if (ts.isCallExpression(node)) {
|
|
510
|
+
const name = calleeName(node);
|
|
511
|
+
if (name !== null && seams.has(name)) {
|
|
512
|
+
for (const argument of node.arguments) {
|
|
513
|
+
if (ts.isIdentifier(argument))
|
|
514
|
+
registeredBindings.add(argument.text);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
node.forEachChild(collectRegistered);
|
|
519
|
+
};
|
|
520
|
+
sf.forEachChild(collectRegistered);
|
|
521
|
+
/**
|
|
522
|
+
* Gated when the value reaches the seam here, or leaves this function for a
|
|
523
|
+
* caller that will. Since the T051 conversion the second is the common
|
|
524
|
+
* shape: a module's `plugin.ts` collects its workers and its `backend.ts`
|
|
525
|
+
* hands each to `ctx.worker`, so the value crosses a file boundary and this
|
|
526
|
+
* analysis stops at the return — stated in the header rather than pretended
|
|
527
|
+
* away. What it still catches is the drop on the floor, which is the defect.
|
|
528
|
+
*/
|
|
529
|
+
const isGated = (node) => {
|
|
530
|
+
if (insideSeamCall(node, seams) || isHandedToCaller(node))
|
|
531
|
+
return true;
|
|
532
|
+
const bound = boundCollectionName(node);
|
|
533
|
+
if (bound === null)
|
|
534
|
+
return false;
|
|
535
|
+
return registeredBindings.has(bound) || namesReturnedFromEnclosingFunction(node).has(bound);
|
|
536
|
+
};
|
|
537
|
+
const visit = (node) => {
|
|
538
|
+
if (binding !== null &&
|
|
539
|
+
ts.isNewExpression(node) &&
|
|
540
|
+
ts.isIdentifier(node.expression) &&
|
|
541
|
+
node.expression.text === binding) {
|
|
542
|
+
sites.push({
|
|
543
|
+
file,
|
|
544
|
+
line: lineOf(node),
|
|
545
|
+
moduleId: moduleOf(`/src/${file}`, hostResident),
|
|
546
|
+
kind: 'construction',
|
|
547
|
+
spelling: `new ${binding}`,
|
|
548
|
+
gated: isGated(node),
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
|
|
552
|
+
const callee = node.expression.text;
|
|
553
|
+
if (factories.has(callee)) {
|
|
554
|
+
sites.push({
|
|
555
|
+
file,
|
|
556
|
+
line: lineOf(node),
|
|
557
|
+
moduleId: moduleOf(`/src/${file}`, hostResident),
|
|
558
|
+
kind: 'registration',
|
|
559
|
+
spelling: callee,
|
|
560
|
+
gated: isGated(node),
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
node.forEachChild(visit);
|
|
565
|
+
};
|
|
566
|
+
sf.forEachChild(visit);
|
|
567
|
+
}
|
|
568
|
+
sites.sort((a, b) => (a.file === b.file ? a.line - b.line : a.file.localeCompare(b.file)));
|
|
569
|
+
return sites;
|
|
570
|
+
}
|
|
571
|
+
export function checkWorkerSeam(input, ledger = WORKERS_OUTSIDE_THE_SEAM) {
|
|
572
|
+
const sites = findWorkerSites(input, findWorkerFactories(input), findSeamForwarders(input));
|
|
573
|
+
// Only a module has an effective state to gate on; a factory in a shared
|
|
574
|
+
// directory is judged where it is called.
|
|
575
|
+
const ungated = sites.filter((site) => !site.gated && site.moduleId !== null);
|
|
576
|
+
const keys = new Set(ungated.map(workerKeyOf));
|
|
577
|
+
return {
|
|
578
|
+
sites,
|
|
579
|
+
violations: ungated.filter((site) => ledger[workerKeyOf(site)] === undefined),
|
|
580
|
+
ledgered: ungated.filter((site) => ledger[workerKeyOf(site)] !== undefined),
|
|
581
|
+
stale: Object.keys(ledger).filter((key) => !keys.has(key)),
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
export function checkSubscribeSeam(input, ledger = BARE_SUBSCRIPTIONS_TO_DRAIN) {
|
|
585
|
+
const all = findBareSubscriptions(input);
|
|
586
|
+
const keys = new Set(all.map(keyOf));
|
|
587
|
+
return {
|
|
588
|
+
total: all.length,
|
|
589
|
+
violations: all.filter((entry) => ledger[keyOf(entry)] === undefined),
|
|
590
|
+
ledgered: all.filter((entry) => ledger[keyOf(entry)] !== undefined),
|
|
591
|
+
stale: Object.keys(ledger).filter((key) => !keys.has(key)),
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
//# sourceMappingURL=subscribe-seam.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscribe-seam.js","sourceRoot":"","sources":["../../src/rules/subscribe-seam.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Which lexical scope guarantees a transaction around the finding. */
|
|
2
|
+
export type TransactionScope = 'transactional-callback' | 'command-run';
|
|
3
|
+
/** Why the statement cannot see the transaction it is written inside. */
|
|
4
|
+
export type EscapeShape = 'knex-instance' | 'connection-execute';
|
|
5
|
+
export interface TransactionEscape {
|
|
6
|
+
/** Path under `src/`, POSIX separators. */
|
|
7
|
+
readonly file: string;
|
|
8
|
+
readonly line: number;
|
|
9
|
+
readonly scope: TransactionScope;
|
|
10
|
+
readonly shape: EscapeShape;
|
|
11
|
+
/** `write` when the statement on that line moves rows, per `lib/sql-tables.ts`. */
|
|
12
|
+
readonly direction: 'read' | 'write' | 'unknown';
|
|
13
|
+
/** The statement head, or the expression, for the message and the ledger key. */
|
|
14
|
+
readonly statement: string;
|
|
15
|
+
}
|
|
16
|
+
/** `<file>#<shape>#<statement>` — the ledger key, and the identity of a site. */
|
|
17
|
+
export declare function keyOf(found: TransactionEscape): string;
|
|
18
|
+
export interface TransactionContextInput {
|
|
19
|
+
/** Every source under `src/`, keyed by path relative to `src/`. */
|
|
20
|
+
readonly sources: ReadonlyMap<string, string>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Every TypeScript source under `dir`, with the rule's own prunes applied.
|
|
24
|
+
*
|
|
25
|
+
* Exported because the population is part of the rule, not part of a host: two
|
|
26
|
+
* hosts computing "which files this check reads" two ways is the shape that
|
|
27
|
+
* lets one of them go half-blind.
|
|
28
|
+
*/
|
|
29
|
+
export declare function collectTransactionSources(dir: string, out?: string[]): string[];
|
|
30
|
+
/** Every statement written inside a transaction that does not run inside it. */
|
|
31
|
+
export declare function findTransactionEscapes(input: TransactionContextInput): TransactionEscape[];
|
|
32
|
+
export interface CheckResult {
|
|
33
|
+
readonly total: number;
|
|
34
|
+
readonly violations: readonly TransactionEscape[];
|
|
35
|
+
readonly ledgered: readonly TransactionEscape[];
|
|
36
|
+
/** Ledger keys that no longer describe an escape — the staleness half. */
|
|
37
|
+
readonly stale: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
export declare function checkTransactionContext(input: TransactionContextInput, ledger: Readonly<Record<string, string>>): CheckResult;
|
|
40
|
+
//# sourceMappingURL=transaction-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction-context.d.ts","sourceRoot":"","sources":["../../src/rules/transaction-context.ts"],"names":[],"mappings":"AA6EA,uEAAuE;AACvE,MAAM,MAAM,gBAAgB,GAAG,wBAAwB,GAAG,aAAa,CAAC;AAExE,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACjD,iFAAiF;IACjF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,iFAAiF;AACjF,wBAAgB,KAAK,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAEtD;AAED,MAAM,WAAW,uBAAuB;IACtC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAYnF;AAgHD,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,uBAAuB,GAAG,iBAAiB,EAAE,CAkF1F;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAChD,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,uBAAuB,EAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,WAAW,CASb"}
|