@endora-commerce/contracts 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 +34 -0
- package/dist/actor.d.ts +79 -0
- package/dist/actor.d.ts.map +1 -0
- package/dist/actor.js +41 -0
- package/dist/actor.js.map +1 -0
- package/dist/addresses.d.ts +134 -0
- package/dist/addresses.d.ts.map +1 -0
- package/dist/addresses.js +16 -0
- package/dist/addresses.js.map +1 -0
- package/dist/admin-actions.d.ts +367 -0
- package/dist/admin-actions.d.ts.map +1 -0
- package/dist/admin-actions.js +287 -0
- package/dist/admin-actions.js.map +1 -0
- package/dist/admin-contributions.d.ts +518 -0
- package/dist/admin-contributions.d.ts.map +1 -0
- package/dist/admin-contributions.js +495 -0
- package/dist/admin-contributions.js.map +1 -0
- package/dist/admin-i18n.d.ts +135 -0
- package/dist/admin-i18n.d.ts.map +1 -0
- package/dist/admin-i18n.js +72 -0
- package/dist/admin-i18n.js.map +1 -0
- package/dist/admin-notifications.d.ts +55 -0
- package/dist/admin-notifications.d.ts.map +1 -0
- package/dist/admin-notifications.js +16 -0
- package/dist/admin-notifications.js.map +1 -0
- package/dist/admin-roles.d.ts +125 -0
- package/dist/admin-roles.d.ts.map +1 -0
- package/dist/admin-roles.js +2 -0
- package/dist/admin-roles.js.map +1 -0
- package/dist/admin-users.d.ts +178 -0
- package/dist/admin-users.d.ts.map +1 -0
- package/dist/admin-users.js +14 -0
- package/dist/admin-users.js.map +1 -0
- package/dist/admin.d.ts +243 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +246 -0
- package/dist/admin.js.map +1 -0
- package/dist/analytics.d.ts +123 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +68 -0
- package/dist/analytics.js.map +1 -0
- package/dist/api-keys.d.ts +97 -0
- package/dist/api-keys.d.ts.map +1 -0
- package/dist/api-keys.js +64 -0
- package/dist/api-keys.js.map +1 -0
- package/dist/assets-library.d.ts +684 -0
- package/dist/assets-library.d.ts.map +1 -0
- package/dist/assets-library.js +181 -0
- package/dist/assets-library.js.map +1 -0
- package/dist/audit-logs.d.ts +141 -0
- package/dist/audit-logs.d.ts.map +1 -0
- package/dist/audit-logs.js +31 -0
- package/dist/audit-logs.js.map +1 -0
- package/dist/auth.d.ts +174 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +27 -0
- package/dist/auth.js.map +1 -0
- package/dist/blog.d.ts +669 -0
- package/dist/blog.d.ts.map +1 -0
- package/dist/blog.js +360 -0
- package/dist/blog.js.map +1 -0
- package/dist/capabilities.d.ts +40 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +38 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/carts.d.ts +1367 -0
- package/dist/carts.d.ts.map +1 -0
- package/dist/carts.js +405 -0
- package/dist/carts.js.map +1 -0
- package/dist/catalog.d.ts +2855 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +1543 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cms.d.ts +872 -0
- package/dist/cms.d.ts.map +1 -0
- package/dist/cms.js +468 -0
- package/dist/cms.js.map +1 -0
- package/dist/common.d.ts +82 -0
- package/dist/common.d.ts.map +1 -0
- package/dist/common.js +72 -0
- package/dist/common.js.map +1 -0
- package/dist/comparisons.d.ts +487 -0
- package/dist/comparisons.d.ts.map +1 -0
- package/dist/comparisons.js +221 -0
- package/dist/comparisons.js.map +1 -0
- package/dist/credentials.d.ts +292 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +142 -0
- package/dist/credentials.js.map +1 -0
- package/dist/credit-limits.d.ts +111 -0
- package/dist/credit-limits.d.ts.map +1 -0
- package/dist/credit-limits.js +35 -0
- package/dist/credit-limits.js.map +1 -0
- package/dist/currencies.d.ts +127 -0
- package/dist/currencies.d.ts.map +1 -0
- package/dist/currencies.js +20 -0
- package/dist/currencies.js.map +1 -0
- package/dist/custom-fields.d.ts +345 -0
- package/dist/custom-fields.d.ts.map +1 -0
- package/dist/custom-fields.js +185 -0
- package/dist/custom-fields.js.map +1 -0
- package/dist/customer-accounts.d.ts +690 -0
- package/dist/customer-accounts.d.ts.map +1 -0
- package/dist/customer-accounts.js +41 -0
- package/dist/customer-accounts.js.map +1 -0
- package/dist/customers.d.ts +305 -0
- package/dist/customers.d.ts.map +1 -0
- package/dist/customers.js +158 -0
- package/dist/customers.js.map +1 -0
- package/dist/dictionary.d.ts +580 -0
- package/dist/dictionary.d.ts.map +1 -0
- package/dist/dictionary.js +297 -0
- package/dist/dictionary.js.map +1 -0
- package/dist/email-address.d.ts +62 -0
- package/dist/email-address.d.ts.map +1 -0
- package/dist/email-address.js +64 -0
- package/dist/email-address.js.map +1 -0
- package/dist/email.d.ts +175 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +45 -0
- package/dist/email.js.map +1 -0
- package/dist/envelopes.d.ts +15 -0
- package/dist/envelopes.d.ts.map +1 -0
- package/dist/envelopes.js +16 -0
- package/dist/envelopes.js.map +1 -0
- package/dist/environment-inputs.d.ts +306 -0
- package/dist/environment-inputs.d.ts.map +1 -0
- package/dist/environment-inputs.js +277 -0
- package/dist/environment-inputs.js.map +1 -0
- package/dist/erp-connector.d.ts +52 -0
- package/dist/erp-connector.d.ts.map +1 -0
- package/dist/erp-connector.js +34 -0
- package/dist/erp-connector.js.map +1 -0
- package/dist/errors.d.ts +455 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +532 -0
- package/dist/errors.js.map +1 -0
- package/dist/google-analytics.d.ts +181 -0
- package/dist/google-analytics.d.ts.map +1 -0
- package/dist/google-analytics.js +176 -0
- package/dist/google-analytics.js.map +1 -0
- package/dist/google-tag-manager.d.ts +111 -0
- package/dist/google-tag-manager.d.ts.map +1 -0
- package/dist/google-tag-manager.js +129 -0
- package/dist/google-tag-manager.js.map +1 -0
- package/dist/i18n.d.ts +69 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +59 -0
- package/dist/i18n.js.map +1 -0
- package/dist/import-export.d.ts +63 -0
- package/dist/import-export.d.ts.map +1 -0
- package/dist/import-export.js +37 -0
- package/dist/import-export.js.map +1 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory.d.ts +673 -0
- package/dist/inventory.d.ts.map +1 -0
- package/dist/inventory.js +412 -0
- package/dist/inventory.js.map +1 -0
- package/dist/invoice-ledger.d.ts +366 -0
- package/dist/invoice-ledger.d.ts.map +1 -0
- package/dist/invoice-ledger.js +114 -0
- package/dist/invoice-ledger.js.map +1 -0
- package/dist/invoices.d.ts +845 -0
- package/dist/invoices.d.ts.map +1 -0
- package/dist/invoices.js +314 -0
- package/dist/invoices.js.map +1 -0
- package/dist/kernel.d.ts +49 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +19 -0
- package/dist/kernel.js.map +1 -0
- package/dist/languages.d.ts +122 -0
- package/dist/languages.d.ts.map +1 -0
- package/dist/languages.js +24 -0
- package/dist/languages.js.map +1 -0
- package/dist/linkedin-ads.d.ts +167 -0
- package/dist/linkedin-ads.d.ts.map +1 -0
- package/dist/linkedin-ads.js +156 -0
- package/dist/linkedin-ads.js.map +1 -0
- package/dist/megamenu.d.ts +556 -0
- package/dist/megamenu.d.ts.map +1 -0
- package/dist/megamenu.js +186 -0
- package/dist/megamenu.js.map +1 -0
- package/dist/meta-ads.d.ts +126 -0
- package/dist/meta-ads.d.ts.map +1 -0
- package/dist/meta-ads.js +112 -0
- package/dist/meta-ads.js.map +1 -0
- package/dist/mfa.d.ts +274 -0
- package/dist/mfa.d.ts.map +1 -0
- package/dist/mfa.js +187 -0
- package/dist/mfa.js.map +1 -0
- package/dist/modules.d.ts +1706 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +1390 -0
- package/dist/modules.js.map +1 -0
- package/dist/newsletter.d.ts +611 -0
- package/dist/newsletter.d.ts.map +1 -0
- package/dist/newsletter.js +345 -0
- package/dist/newsletter.js.map +1 -0
- package/dist/orders.d.ts +1175 -0
- package/dist/orders.d.ts.map +1 -0
- package/dist/orders.js +630 -0
- package/dist/orders.js.map +1 -0
- package/dist/organizations.d.ts +938 -0
- package/dist/organizations.d.ts.map +1 -0
- package/dist/organizations.js +418 -0
- package/dist/organizations.js.map +1 -0
- package/dist/pagination.d.ts +21 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +22 -0
- package/dist/pagination.js.map +1 -0
- package/dist/payment-methods.d.ts +472 -0
- package/dist/payment-methods.d.ts.map +1 -0
- package/dist/payment-methods.js +175 -0
- package/dist/payment-methods.js.map +1 -0
- package/dist/payment-return-url.d.ts +53 -0
- package/dist/payment-return-url.d.ts.map +1 -0
- package/dist/payment-return-url.js +35 -0
- package/dist/payment-return-url.js.map +1 -0
- package/dist/payments.d.ts +386 -0
- package/dist/payments.d.ts.map +1 -0
- package/dist/payments.js +84 -0
- package/dist/payments.js.map +1 -0
- package/dist/pim-connector.d.ts +60 -0
- package/dist/pim-connector.d.ts.map +1 -0
- package/dist/pim-connector.js +43 -0
- package/dist/pim-connector.js.map +1 -0
- package/dist/pim-field-path.d.ts +6 -0
- package/dist/pim-field-path.d.ts.map +1 -0
- package/dist/pim-field-path.js +101 -0
- package/dist/pim-field-path.js.map +1 -0
- package/dist/platform-language.d.ts +20 -0
- package/dist/platform-language.d.ts.map +1 -0
- package/dist/platform-language.js +22 -0
- package/dist/platform-language.js.map +1 -0
- package/dist/price-lists.d.ts +685 -0
- package/dist/price-lists.d.ts.map +1 -0
- package/dist/price-lists.js +330 -0
- package/dist/price-lists.js.map +1 -0
- package/dist/product-feeds.d.ts +2837 -0
- package/dist/product-feeds.d.ts.map +1 -0
- package/dist/product-feeds.js +1504 -0
- package/dist/product-feeds.js.map +1 -0
- package/dist/product-scope-overrides.d.ts +134 -0
- package/dist/product-scope-overrides.d.ts.map +1 -0
- package/dist/product-scope-overrides.js +82 -0
- package/dist/product-scope-overrides.js.map +1 -0
- package/dist/product-value-resolver.d.ts +88 -0
- package/dist/product-value-resolver.d.ts.map +1 -0
- package/dist/product-value-resolver.js +128 -0
- package/dist/product-value-resolver.js.map +1 -0
- package/dist/promotions.d.ts +678 -0
- package/dist/promotions.d.ts.map +1 -0
- package/dist/promotions.js +479 -0
- package/dist/promotions.js.map +1 -0
- package/dist/prompt-actions.d.ts +582 -0
- package/dist/prompt-actions.d.ts.map +1 -0
- package/dist/prompt-actions.js +221 -0
- package/dist/prompt-actions.js.map +1 -0
- package/dist/pwa.d.ts +293 -0
- package/dist/pwa.d.ts.map +1 -0
- package/dist/pwa.js +204 -0
- package/dist/pwa.js.map +1 -0
- package/dist/quick-order.d.ts +340 -0
- package/dist/quick-order.d.ts.map +1 -0
- package/dist/quick-order.js +177 -0
- package/dist/quick-order.js.map +1 -0
- package/dist/quote-requests.d.ts +538 -0
- package/dist/quote-requests.d.ts.map +1 -0
- package/dist/quote-requests.js +308 -0
- package/dist/quote-requests.js.map +1 -0
- package/dist/returns.d.ts +774 -0
- package/dist/returns.d.ts.map +1 -0
- package/dist/returns.js +389 -0
- package/dist/returns.js.map +1 -0
- package/dist/sales-channels.d.ts +392 -0
- package/dist/sales-channels.d.ts.map +1 -0
- package/dist/sales-channels.js +285 -0
- package/dist/sales-channels.js.map +1 -0
- package/dist/scope-notice.d.ts +60 -0
- package/dist/scope-notice.d.ts.map +1 -0
- package/dist/scope-notice.js +56 -0
- package/dist/scope-notice.js.map +1 -0
- package/dist/search.d.ts +321 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +160 -0
- package/dist/search.js.map +1 -0
- package/dist/seo.d.ts +113 -0
- package/dist/seo.d.ts.map +1 -0
- package/dist/seo.js +63 -0
- package/dist/seo.js.map +1 -0
- package/dist/settings.d.ts +453 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +337 -0
- package/dist/settings.js.map +1 -0
- package/dist/shipments.d.ts +140 -0
- package/dist/shipments.d.ts.map +1 -0
- package/dist/shipments.js +14 -0
- package/dist/shipments.js.map +1 -0
- package/dist/shipping-methods.d.ts +350 -0
- package/dist/shipping-methods.d.ts.map +1 -0
- package/dist/shipping-methods.js +99 -0
- package/dist/shipping-methods.js.map +1 -0
- package/dist/shopping-lists.d.ts +122 -0
- package/dist/shopping-lists.d.ts.map +1 -0
- package/dist/shopping-lists.js +92 -0
- package/dist/shopping-lists.js.map +1 -0
- package/dist/taxes.d.ts +106 -0
- package/dist/taxes.d.ts.map +1 -0
- package/dist/taxes.js +80 -0
- package/dist/taxes.js.map +1 -0
- package/dist/text-normalization.d.ts +199 -0
- package/dist/text-normalization.d.ts.map +1 -0
- package/dist/text-normalization.js +205 -0
- package/dist/text-normalization.js.map +1 -0
- package/dist/transactional-emails.d.ts +459 -0
- package/dist/transactional-emails.d.ts.map +1 -0
- package/dist/transactional-emails.js +212 -0
- package/dist/transactional-emails.js.map +1 -0
- package/dist/webhooks.d.ts +69 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +53 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,1706 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type ModuleSettingsManifest } from './settings.js';
|
|
3
|
+
/**
|
|
4
|
+
* Module identifier — must equal the manifest file's parent folder name.
|
|
5
|
+
* Two-character ids are allowed (e.g. `_lifecycle` after underscore allowance).
|
|
6
|
+
* Underscore-prefixed ids are reserved for platform-internal modules
|
|
7
|
+
* (constitutional exemption alongside `auth` and `example`).
|
|
8
|
+
*/
|
|
9
|
+
export declare const moduleIdRe: RegExp;
|
|
10
|
+
/** Semver-lite — `MAJOR.MINOR.PATCH` plus an optional `-prerelease` suffix. */
|
|
11
|
+
export declare const moduleVersionRe: RegExp;
|
|
12
|
+
/**
|
|
13
|
+
* Per-module Admin UI translation declaration (feature 019).
|
|
14
|
+
* When present, the lifecycle install hook reads
|
|
15
|
+
* `<modulePath>/<bundlesDir>/<lang>.json` for every supported Admin UI
|
|
16
|
+
* language and registers the bundle into `translation_bundles`. Default
|
|
17
|
+
* `bundlesDir` is `'i18n'` — every module that ships translations is
|
|
18
|
+
* expected to follow this convention.
|
|
19
|
+
*/
|
|
20
|
+
export declare const ModuleI18nManifestSchema: z.ZodObject<{
|
|
21
|
+
bundlesDir: z.ZodDefault<z.ZodString>;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
export type ModuleI18nManifest = z.infer<typeof ModuleI18nManifestSchema>;
|
|
24
|
+
/**
|
|
25
|
+
* Per-module documentation declaration (feature 100 / roadmap F12).
|
|
26
|
+
*
|
|
27
|
+
* The same shape as {@link ModuleI18nManifestSchema} and for the same reason: a
|
|
28
|
+
* directory at the **package root**, in the package's `files` list, with no
|
|
29
|
+
* `exports` subpath, located by joining `dir` to `dirname(manifestPath)`. The
|
|
30
|
+
* anchor is the platform's, so nothing in the module names a package, a
|
|
31
|
+
* repository root or a build directory in order to find its own pages
|
|
32
|
+
* (`specs/100-module-owned-documentation/contracts/module-documentation-layer.md`
|
|
33
|
+
* R2.1–R2.3).
|
|
34
|
+
*
|
|
35
|
+
* A declared directory that is not on disk is a **refusal**, naming the module —
|
|
36
|
+
* never "this module ships no documentation". That distinction is the whole of
|
|
37
|
+
* the repair `backend/src/manifest-locations.ts` was written for: the `_i18n`
|
|
38
|
+
* boot reconciler logs and skips an absent bundles directory, so a packaged
|
|
39
|
+
* module rendered every palette entry as a raw key with no error anywhere.
|
|
40
|
+
*/
|
|
41
|
+
export declare const ModuleDocsManifestSchema: z.ZodObject<{
|
|
42
|
+
dir: z.ZodDefault<z.ZodString>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
export type ModuleDocsManifest = z.infer<typeof ModuleDocsManifestSchema>;
|
|
45
|
+
/**
|
|
46
|
+
* `docs: false` — this module ships no documentation, deliberately.
|
|
47
|
+
*
|
|
48
|
+
* **Absent and `false` are not the same state**, and the documentation check
|
|
49
|
+
* distinguishes them: absent is a module nobody has decided about, `false` is a
|
|
50
|
+
* decision. The argument is `check:bundle-pairing`'s, one population over — a
|
|
51
|
+
* universal obligation over a population where some members legitimately owe
|
|
52
|
+
* nothing is repaired by empty files whose only effect is to make a check pass.
|
|
53
|
+
* Some modules are infrastructure other modules consume and may honestly
|
|
54
|
+
* document nothing.
|
|
55
|
+
*/
|
|
56
|
+
export declare const ModuleDocsDeclarationSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
57
|
+
dir: z.ZodDefault<z.ZodString>;
|
|
58
|
+
}, z.core.$strip>, z.ZodLiteral<false>]>;
|
|
59
|
+
export type ModuleDocsDeclaration = z.infer<typeof ModuleDocsDeclarationSchema>;
|
|
60
|
+
/**
|
|
61
|
+
* What a module's demo body is handed.
|
|
62
|
+
*
|
|
63
|
+
* One field, deliberately. The body gets its module's own composed
|
|
64
|
+
* `ModuleContext` and nothing else: everything it wants an operator to read
|
|
65
|
+
* comes back in {@link DemoSeedResult}, which the runner formats once (§3.7),
|
|
66
|
+
* so there is no `out`/`err` pair here and a body must not reach for
|
|
67
|
+
* `process.stdout`. That is the difference from {@link ModuleCliCommandContext},
|
|
68
|
+
* which injects both because a command's output *is* its result.
|
|
69
|
+
*
|
|
70
|
+
* `Ctx` is a type parameter for the reason {@link ModuleCliCommand}'s is: a
|
|
71
|
+
* module names `ModuleContext` from `@endora-commerce/platform/kernel`, and the
|
|
72
|
+
* contracts package may not. A declaration reaching the host is typed
|
|
73
|
+
* `ModuleDemoManifest<never>` — the schema's inference — and every module's
|
|
74
|
+
* `ModuleDemoManifest<ModuleContext>` is assignable to it, so the host casts
|
|
75
|
+
* once at the invocation, exactly as `collectModuleCommands` does.
|
|
76
|
+
*/
|
|
77
|
+
export interface ModuleDemoContext<Ctx = unknown> {
|
|
78
|
+
/** The module's own composed `ModuleContext`. */
|
|
79
|
+
ctx: Ctx;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* One line of a module's per-module accounting.
|
|
83
|
+
*
|
|
84
|
+
* `entity` is the class name the module wrote, in the module's own words; the
|
|
85
|
+
* runner neither derives nor validates it. Structured rather than free text
|
|
86
|
+
* because it is the only way SC-007's idempotence is assertable without
|
|
87
|
+
* diffing a database: seeding twice must report the same counts.
|
|
88
|
+
*/
|
|
89
|
+
export interface DemoEntityCount {
|
|
90
|
+
readonly entity: string;
|
|
91
|
+
readonly count: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* A sign-in detail the demo created, printed by the runner at the end of a run.
|
|
95
|
+
*
|
|
96
|
+
* Structured rather than a sentence in `notes` so the runner formats it once
|
|
97
|
+
* and a client's scaffolded composition does not have to know how the platform
|
|
98
|
+
* lays credentials out.
|
|
99
|
+
*/
|
|
100
|
+
export interface DemoCredential {
|
|
101
|
+
readonly label: string;
|
|
102
|
+
readonly value: string;
|
|
103
|
+
}
|
|
104
|
+
/** What a module's `seed` reports. Never a throw-or-succeed (§3.7). */
|
|
105
|
+
export interface DemoSeedResult {
|
|
106
|
+
readonly created: readonly DemoEntityCount[];
|
|
107
|
+
readonly credentials?: readonly DemoCredential[];
|
|
108
|
+
/** What this module chose not to do, and why. */
|
|
109
|
+
readonly notes?: readonly string[];
|
|
110
|
+
}
|
|
111
|
+
/** What a module's `reset` reports. */
|
|
112
|
+
export interface DemoResetResult {
|
|
113
|
+
readonly removed: readonly DemoEntityCount[];
|
|
114
|
+
readonly notes?: readonly string[];
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The demo declaration a module carries in its `manifest.ts` (§1.3).
|
|
118
|
+
*
|
|
119
|
+
* ## The body is reached by a relative `await import()`, never a top-level one
|
|
120
|
+
*
|
|
121
|
+
* §1.4, and it is `cliCommands`' rule for `cliCommands`' reason: a manifest is
|
|
122
|
+
* loaded by every process that composes the platform — and by the check scripts
|
|
123
|
+
* and `src/db/configured-migrations.ts`, which import the generated index — so a
|
|
124
|
+
* demo body imported at the top of `manifest.ts` is a service graph pulled into
|
|
125
|
+
* all of them. Write it as
|
|
126
|
+
*
|
|
127
|
+
* ```ts
|
|
128
|
+
* const demo: ModuleDemoManifest<ModuleContext> = {
|
|
129
|
+
* summary: 'A demo warehouse and stock for the seeded products.',
|
|
130
|
+
* seed: async (context) => (await import('./backend/demo/seed.js')).seedDemo(context),
|
|
131
|
+
* reset: async (context) => (await import('./backend/demo/reset.js')).resetDemo(context),
|
|
132
|
+
* };
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* and pass it to `defineModuleManifest`. The typed `const` is what gives the
|
|
136
|
+
* author `context.ctx: ModuleContext`; declared inline the parameter infers
|
|
137
|
+
* from the schema and is `never`.
|
|
138
|
+
*
|
|
139
|
+
* A relative import inside the package lands in `dist` through the existing
|
|
140
|
+
* emit, so this declaration needs **no `exports` subpath, no `files` entry and
|
|
141
|
+
* no change to the manifest generator** (§1.5).
|
|
142
|
+
*
|
|
143
|
+
* ## What a body may do
|
|
144
|
+
*
|
|
145
|
+
* §2.1–§2.2: write only tables its own module owns, read no other module's
|
|
146
|
+
* table, resolve no other module's port, import from no other module's package.
|
|
147
|
+
* Wiring that spans modules is a composition and belongs to the instance
|
|
148
|
+
* (§5, D-209) — `megamenu`'s demo menu mirroring `catalog`'s demo categories is
|
|
149
|
+
* the measured case, and `megamenu` does not declare `catalog`.
|
|
150
|
+
*/
|
|
151
|
+
export interface ModuleDemoManifest<Ctx = unknown> {
|
|
152
|
+
/**
|
|
153
|
+
* One line of English prose: what this module contributes to the demo. The
|
|
154
|
+
* runner prints it per module (§3.7).
|
|
155
|
+
*/
|
|
156
|
+
summary: string;
|
|
157
|
+
/** Create this module's demo rows. Idempotent by contract (§2.4). */
|
|
158
|
+
seed(context: ModuleDemoContext<Ctx>): Promise<DemoSeedResult>;
|
|
159
|
+
/**
|
|
160
|
+
* Withdraw exactly what {@link ModuleDemoManifest.seed} created, and nothing
|
|
161
|
+
* an operator created (§2.5).
|
|
162
|
+
*
|
|
163
|
+
* Separate from `seed` rather than a flag on it, because FR-007's guarantee
|
|
164
|
+
* is per module and a flag makes one function answer two questions.
|
|
165
|
+
*/
|
|
166
|
+
reset(context: ModuleDemoContext<Ctx>): Promise<DemoResetResult>;
|
|
167
|
+
/**
|
|
168
|
+
* Module ids this module's demo prefers to run after — **advisory** (§4.3).
|
|
169
|
+
*
|
|
170
|
+
* `permissions[].requires`' shape under D-175, chosen for the same reason:
|
|
171
|
+
* the field carries a coupling the dependency graph cannot express and the
|
|
172
|
+
* graph must not be widened to express it. Nothing else reads it, it puts no
|
|
173
|
+
* module in `dependencies`, it creates no lifecycle edge, it does not stand
|
|
174
|
+
* in the way of an operator switching the named module off, and it changes no
|
|
175
|
+
* migration order. An entry naming a module that is not installed orders
|
|
176
|
+
* nothing and is not a finding (§4.4).
|
|
177
|
+
*
|
|
178
|
+
* It is deliberately not spelled `dependsOn`, `requires` or `dependencies`:
|
|
179
|
+
* the name has to be unmistakably not the lifecycle one.
|
|
180
|
+
*/
|
|
181
|
+
after?: readonly string[] | undefined;
|
|
182
|
+
/**
|
|
183
|
+
* The package this module's demo data lives in — **the escape hatch** (§6,
|
|
184
|
+
* D-5), and a package **name as a string**, never an `import` specifier.
|
|
185
|
+
*
|
|
186
|
+
* ## Why a string, and it is measured rather than stylistic
|
|
187
|
+
*
|
|
188
|
+
* A module package's `package.json` is generated
|
|
189
|
+
* (`backend/scripts/lib/module-package-manifest.ts`), and `peerNamesOf`
|
|
190
|
+
* records every specifier `namedSpecifiers` yields **with no filter on kind**
|
|
191
|
+
* — a walk that recognises `dynamic-import`
|
|
192
|
+
* (`packages/cli/src/lib/specifiers.ts`, `callee.kind ===
|
|
193
|
+
* ts.SyntaxKind.ImportKeyword`). So a literal
|
|
194
|
+
* `await import('@endora-commerce/mod-<id>-demo')` written anywhere in the
|
|
195
|
+
* module's sources is emitted as a **required** peer, and pnpm then installs
|
|
196
|
+
* the demo package for every client — the exact opposite of what this field
|
|
197
|
+
* is for. Both halves re-verified against those two files on 2026-09-09.
|
|
198
|
+
*
|
|
199
|
+
* The name is therefore resolved by the **runner**, whose resolution the
|
|
200
|
+
* specifier walk does not read. It is the same reason `cliCommands` keeps its
|
|
201
|
+
* body behind a relative `await import()` rather than a top-level one.
|
|
202
|
+
*
|
|
203
|
+
* ## What a runner owes it
|
|
204
|
+
*
|
|
205
|
+
* §6.3 requires three answers and forbids collapsing the second into the
|
|
206
|
+
* third: *resolvable and loads* — this module's demo data is the package's;
|
|
207
|
+
* *not resolvable* — reported by name as **not installed**, the module
|
|
208
|
+
* contributes nothing and the run continues; *resolvable and fails to load* —
|
|
209
|
+
* a failure, per §3.8. §6.4 requires the probe to happen **before** the
|
|
210
|
+
* import, because a bare `catch` around both turns a broken demo package into
|
|
211
|
+
* a silent "not installed", which is the fail-open shape
|
|
212
|
+
* `check:port-catches` refuses one seam over.
|
|
213
|
+
*
|
|
214
|
+
* `packages/platform/src/demo/{packages,runner}.ts` answer all three
|
|
215
|
+
* (feature 113, T235). The probe is `require.resolve`, which does not
|
|
216
|
+
* evaluate; the import is a separate call, in the one `try` whose `catch`
|
|
217
|
+
* re-throws unconditionally as `DemoRunFailedError`.
|
|
218
|
+
*
|
|
219
|
+
* ## What the package owes back
|
|
220
|
+
*
|
|
221
|
+
* It exports **`demo`**: an object with a `summary` string and `seed` and
|
|
222
|
+
* `reset` functions — the shape declared here, minus the two fields that stay
|
|
223
|
+
* the module's. When it loads it *replaces* this declaration's `summary`,
|
|
224
|
+
* `seed` and `reset`, which it must, because §6.2 bars the module's own
|
|
225
|
+
* sources from naming the package at all and a declared body therefore could
|
|
226
|
+
* not reach the data. `after` is **not** read from the package: ordering is
|
|
227
|
+
* decided from the declarations before anything is loaded, so a package's own
|
|
228
|
+
* would arrive after the sequence it wants to change.
|
|
229
|
+
*/
|
|
230
|
+
package?: string | undefined;
|
|
231
|
+
}
|
|
232
|
+
export declare const ModuleDemoManifestSchema: z.ZodObject<{
|
|
233
|
+
summary: z.ZodString;
|
|
234
|
+
seed: z.ZodType<(context: ModuleDemoContext<never>) => Promise<DemoSeedResult>, unknown, z.core.$ZodTypeInternals<(context: ModuleDemoContext<never>) => Promise<DemoSeedResult>, unknown>>;
|
|
235
|
+
reset: z.ZodType<(context: ModuleDemoContext<never>) => Promise<DemoResetResult>, unknown, z.core.$ZodTypeInternals<(context: ModuleDemoContext<never>) => Promise<DemoResetResult>, unknown>>;
|
|
236
|
+
after: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
237
|
+
package: z.ZodOptional<z.ZodString>;
|
|
238
|
+
}, z.core.$strip>;
|
|
239
|
+
/**
|
|
240
|
+
* `demo: false` — this module has nothing to demonstrate, deliberately.
|
|
241
|
+
*
|
|
242
|
+
* **Absent and `false` are not the same state** (§1.2). It is
|
|
243
|
+
* {@link ModuleDocsDeclarationSchema}'s rule and it exists for the same reason:
|
|
244
|
+
* a universal obligation over a population where some members legitimately owe
|
|
245
|
+
* nothing is repaired by empty files whose only effect is to make a check pass.
|
|
246
|
+
* `pim_connector` and `email` genuinely have nothing to show.
|
|
247
|
+
*/
|
|
248
|
+
export declare const ModuleDemoDeclarationSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
249
|
+
summary: z.ZodString;
|
|
250
|
+
seed: z.ZodType<(context: ModuleDemoContext<never>) => Promise<DemoSeedResult>, unknown, z.core.$ZodTypeInternals<(context: ModuleDemoContext<never>) => Promise<DemoSeedResult>, unknown>>;
|
|
251
|
+
reset: z.ZodType<(context: ModuleDemoContext<never>) => Promise<DemoResetResult>, unknown, z.core.$ZodTypeInternals<(context: ModuleDemoContext<never>) => Promise<DemoResetResult>, unknown>>;
|
|
252
|
+
after: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
253
|
+
package: z.ZodOptional<z.ZodString>;
|
|
254
|
+
}, z.core.$strip>, z.ZodLiteral<false>]>;
|
|
255
|
+
export type ModuleDemoDeclaration = z.infer<typeof ModuleDemoDeclarationSchema>;
|
|
256
|
+
/**
|
|
257
|
+
* Operator-activation declaration — feature 073, Constitution XVII.
|
|
258
|
+
*
|
|
259
|
+
* The second of the two orthogonal presence axes. Platform availability lives
|
|
260
|
+
* in `module_registrations` and is owned by whoever operates the deployment;
|
|
261
|
+
* this block declares the *business* operator's control, which is an ordinary
|
|
262
|
+
* `Setting` row reconciled from the manifest.
|
|
263
|
+
*
|
|
264
|
+
* It used to sit beside a `license` tier, and the two were kept apart because
|
|
265
|
+
* conflating a build-time entitlement with a runtime toggle would make an
|
|
266
|
+
* operator's switch look like a licensing decision. That tier is gone (D-194
|
|
267
|
+
* removed the edition meta-packages it existed for), so activation is now the
|
|
268
|
+
* only presence declaration a manifest carries.
|
|
269
|
+
*
|
|
270
|
+
* Exactly one of the two forms is valid — enforced in `defineModuleManifest`
|
|
271
|
+
* rather than by the schema, because a Zod union of two non-strict objects
|
|
272
|
+
* accepts a value carrying both.
|
|
273
|
+
*/
|
|
274
|
+
export declare const ModuleActivationSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
275
|
+
settingCode: z.ZodString;
|
|
276
|
+
default: z.ZodBoolean;
|
|
277
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
278
|
+
nonDeactivatable: z.ZodLiteral<true>;
|
|
279
|
+
reason: z.ZodString;
|
|
280
|
+
}, z.core.$strip>]>;
|
|
281
|
+
export type ModuleActivation = z.infer<typeof ModuleActivationSchema>;
|
|
282
|
+
/**
|
|
283
|
+
* A runtime dependency the declaring module deliberately keeps out of
|
|
284
|
+
* `dependencies` — feature 073, Amendment A1.
|
|
285
|
+
*
|
|
286
|
+
* The two are not two spellings of one thing. `dependencies` is read by the
|
|
287
|
+
* **topological install order** (`db/migration-order.ts`, the lifecycle's
|
|
288
|
+
* `ModuleDepGraph`), and a mutual pair declared there closes a cycle that fails
|
|
289
|
+
* the build: `addresses` must install after `organizations` because every
|
|
290
|
+
* stored address is organization-scoped, so `organizations` cannot also declare
|
|
291
|
+
* `addresses`, however real the port edge is. Withholding the declaration used
|
|
292
|
+
* to make the edge invisible to everything else too — the flip-time refusals
|
|
293
|
+
* saw no reason to stop an operator switching the owner off underneath a live
|
|
294
|
+
* resolver.
|
|
295
|
+
*
|
|
296
|
+
* So the edge is declared here instead: **read by the gating and refusal
|
|
297
|
+
* graph, ignored by the install order.** That is the whole trade, stated in the
|
|
298
|
+
* manifest that makes it rather than in a build script's constant, so a
|
|
299
|
+
* refusal and a CI check cannot drift apart on which edges exist.
|
|
300
|
+
*/
|
|
301
|
+
export declare const ModuleAcknowledgedDependencySchema: z.ZodObject<{
|
|
302
|
+
moduleId: z.ZodString;
|
|
303
|
+
port: z.ZodString;
|
|
304
|
+
reason: z.ZodString;
|
|
305
|
+
}, z.core.$strip>;
|
|
306
|
+
export type ModuleAcknowledgedDependency = z.infer<typeof ModuleAcknowledgedDependencySchema>;
|
|
307
|
+
/**
|
|
308
|
+
* An edge that is real to the container but does not bind the operator — D-44.
|
|
309
|
+
*
|
|
310
|
+
* `dependencies` is read as three claims at once: install-and-migration order,
|
|
311
|
+
* "the container resolution is declared", and "an operator may not switch the
|
|
312
|
+
* owner off underneath me". `acknowledgedDependencies` withdraws the first.
|
|
313
|
+
* This withdraws the third, and only the third: a module declares here that it
|
|
314
|
+
* reads a name `moduleId` owns and that it has a defined behaviour when
|
|
315
|
+
* `moduleId` is not there, so the flip-time refusal has nothing to protect.
|
|
316
|
+
*
|
|
317
|
+
* Read by `check-port-dependencies.ts`, which needs the ownership claim and
|
|
318
|
+
* nothing else, and — when the deactivation-consequence dialog ships — by
|
|
319
|
+
* `/platform/modules`, which renders {@link whenAbsent}. Read by **nothing
|
|
320
|
+
* else**: not `ModuleDepGraph`, not `db/migration-order.ts`, and not
|
|
321
|
+
* `ModuleGatingGraph` in either direction. A cross-module foreign key therefore
|
|
322
|
+
* still forces a `dependencies` entry, and `fk-dependency-drift.test.ts` still
|
|
323
|
+
* fails for one declared here instead.
|
|
324
|
+
*
|
|
325
|
+
* The three kinds are the three ways an edge can exist without the bind bit:
|
|
326
|
+
*
|
|
327
|
+
* - **`contributes-to`** — the declaring module pushes an inert descriptor
|
|
328
|
+
* into `moduleId`'s ungated registry at boot. It has no failure mode in
|
|
329
|
+
* either direction: an absent contributor's descriptor is filtered by the
|
|
330
|
+
* host at enumeration, and an absent host's registry is a table nobody
|
|
331
|
+
* walks. `whenAbsent` is forbidden, because nothing degrades.
|
|
332
|
+
* - **`degrades-without`** — the declaring module reads an answer from
|
|
333
|
+
* `moduleId`, checks presence before it does, and keeps working with less.
|
|
334
|
+
* `whenAbsent` is required and states that behaviour, which is what an
|
|
335
|
+
* off-state test for the edge is held to.
|
|
336
|
+
* - **`refuses-without`** — the declaring module reads a **gated port**, has
|
|
337
|
+
* no fallback for it, and lets the 503 `MODULE_DISABLED` refusal reach the
|
|
338
|
+
* caller. The operation stops; the rest of the declaring module keeps
|
|
339
|
+
* working; the owner's activation control keeps working. `whenAbsent` is
|
|
340
|
+
* required and names **what** refuses, because that is the whole payload:
|
|
341
|
+
* the deactivation-consequence ledger classifies the edge `fails-closed`
|
|
342
|
+
* and the operator's confirmation dialog renders this sentence.
|
|
343
|
+
*
|
|
344
|
+
* The third kind was an omission rather than a narrowing, and it is worth
|
|
345
|
+
* saying why, because the gap is invisible from the manifest side. A read with
|
|
346
|
+
* no fallback had only one spelling — `dependencies` (or
|
|
347
|
+
* `acknowledgedDependencies`) — and both carry the bind, so a dependent that
|
|
348
|
+
* cannot itself be switched off turned the *owner's* activation control into a
|
|
349
|
+
* dead switch: the operator flips it, the flip-time refusal names a module
|
|
350
|
+
* that will never go away, and nothing happens. That is a worse answer than
|
|
351
|
+
* either alternative, since a control that lies is not a control. So the
|
|
352
|
+
* missing spelling is "refuse, and do not bind", which is what this kind is;
|
|
353
|
+
* the outcome it produces (`fails-closed`) has been in the ledger's vocabulary
|
|
354
|
+
* since feature 074 and was reachable only for edges that also bound.
|
|
355
|
+
*
|
|
356
|
+
* **The half of the claim about the owner's control is already unspellable**,
|
|
357
|
+
* and it is worth knowing where: rule 2 of `assertNonBindingRules` refuses any
|
|
358
|
+
* non-binding edge whose target the same manifest also names in
|
|
359
|
+
* `dependencies` or `acknowledgedDependencies` — one edge, one claim, in one
|
|
360
|
+
* place. So a `refuses-without` entry cannot sit beside the bind it denies;
|
|
361
|
+
* a module that wants both is telling the operator two things at once and is
|
|
362
|
+
* refused before the ledger ever sees it. `check-port-dependencies.ts` re-
|
|
363
|
+
* derives the same fact from the manifests as a second net, for a manifest
|
|
364
|
+
* built without this helper.
|
|
365
|
+
*
|
|
366
|
+
* The other two halves are the check's alone, because both are properties of
|
|
367
|
+
* the *tree* rather than of the manifest: the name is registered with
|
|
368
|
+
* `di.providePort` (an ungated registration has no refusal to propagate), and
|
|
369
|
+
* the resolution happens at call time (a gated port resolved at boot stops the
|
|
370
|
+
* next start rather than one request — the ledger's
|
|
371
|
+
* `gated-port-before-first-request`, which is assigned before any declaration
|
|
372
|
+
* is consulted and which no entry can therefore rescue).
|
|
373
|
+
*
|
|
374
|
+
* The fourth quadrant — order without bind — stays deliberately unspellable
|
|
375
|
+
* (Constitution IV). An edge that needs both goes back to `dependencies`, and
|
|
376
|
+
* the bind comes back with it.
|
|
377
|
+
*/
|
|
378
|
+
export declare const ModuleNonBindingDependencySchema: z.ZodObject<{
|
|
379
|
+
moduleId: z.ZodString;
|
|
380
|
+
name: z.ZodString;
|
|
381
|
+
kind: z.ZodEnum<{
|
|
382
|
+
"contributes-to": "contributes-to";
|
|
383
|
+
"degrades-without": "degrades-without";
|
|
384
|
+
"refuses-without": "refuses-without";
|
|
385
|
+
}>;
|
|
386
|
+
whenAbsent: z.ZodOptional<z.ZodString>;
|
|
387
|
+
reason: z.ZodString;
|
|
388
|
+
}, z.core.$strip>;
|
|
389
|
+
export type ModuleNonBindingDependency = z.infer<typeof ModuleNonBindingDependencySchema>;
|
|
390
|
+
/**
|
|
391
|
+
* One module a deployment knowingly does not ship — D-101's declared escape.
|
|
392
|
+
*
|
|
393
|
+
* A deployment may compose fewer modules than its manifests declare; what it may
|
|
394
|
+
* not do is arrive there silently, so the omission is declared in a committed,
|
|
395
|
+
* reviewed file (`backend/src/apps/<deployment>/divergence.ts`) and the boot
|
|
396
|
+
* refuses an omission that is not in it — or an entry for a module the
|
|
397
|
+
* deployment does ship, which is the same ledger read the other way.
|
|
398
|
+
*
|
|
399
|
+
* This is `ReducedDeploymentDeclaration` under its own name (D-205), and it is
|
|
400
|
+
* unchanged in substance: a module id, and a reason long enough to be an
|
|
401
|
+
* argument. What changed is where it sits — inside
|
|
402
|
+
* {@link DeploymentDivergenceDeclarationSchema}'s `omittedModules`, beside the
|
|
403
|
+
* other two things a deployment declares about itself.
|
|
404
|
+
*/
|
|
405
|
+
export declare const OmittedModuleSchema: z.ZodObject<{
|
|
406
|
+
moduleId: z.ZodString;
|
|
407
|
+
reason: z.ZodString;
|
|
408
|
+
}, z.core.$strip>;
|
|
409
|
+
export type OmittedModule = z.infer<typeof OmittedModuleSchema>;
|
|
410
|
+
/**
|
|
411
|
+
* Everything a deployment declares about how it means to differ from core.
|
|
412
|
+
*
|
|
413
|
+
* `backend/src/apps/<deployment>/divergence.ts`, exporting `divergence`. The
|
|
414
|
+
* file was `reduced-deployment.ts` until it grew past omissions (D-205):
|
|
415
|
+
* *reduced* encodes a direction that is wrong for an addition, wrong for a
|
|
416
|
+
* substitution and wrong for an ordering, while `divergence` is already the
|
|
417
|
+
* word the generator's own header uses for the derived artefact beside it.
|
|
418
|
+
*
|
|
419
|
+
* The shape lives here rather than in `_lifecycle` because the file carrying it
|
|
420
|
+
* belongs to a **deployment**, and a deployment naming a module's internals is
|
|
421
|
+
* the coupling that outlives the module.
|
|
422
|
+
*
|
|
423
|
+
* **It holds judgement, ordering and prose — never population.** The single test
|
|
424
|
+
* for a field is whether the platform can derive it: the deployment's module
|
|
425
|
+
* list is the overlay walk's answer and the divergences themselves are the
|
|
426
|
+
* report's, so neither belongs here
|
|
427
|
+
* (`specs/107-override-report-and-ladder/contracts/deployment-declaration.md` §5).
|
|
428
|
+
*
|
|
429
|
+
* Every field defaults to empty, so a declaration that leaves one out means
|
|
430
|
+
* "none of these" rather than "unparseable" — the reading an absent file already
|
|
431
|
+
* gets. A deployment that diverges by nothing still ships the file with all
|
|
432
|
+
* three written out, because the mechanism is easier to find than to remember.
|
|
433
|
+
*/
|
|
434
|
+
export declare const DeploymentDivergenceDeclarationSchema: z.ZodObject<{
|
|
435
|
+
omittedModules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
436
|
+
moduleId: z.ZodString;
|
|
437
|
+
reason: z.ZodString;
|
|
438
|
+
}, z.core.$strip>>>;
|
|
439
|
+
decorationOrder: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
440
|
+
reasons: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
441
|
+
}, z.core.$strict>;
|
|
442
|
+
export type DeploymentDivergenceDeclaration = z.infer<typeof DeploymentDivergenceDeclarationSchema>;
|
|
443
|
+
/**
|
|
444
|
+
* One kind of divergence a deployment's tree can hold
|
|
445
|
+
* (`specs/107-override-report-and-ladder/data-model.md` §2.3).
|
|
446
|
+
*
|
|
447
|
+
* Nine, and every one of them is one seam of `ModuleContext` — seven read off
|
|
448
|
+
* the members themselves, plus `port-consumed` (which is `lazyPort` over the
|
|
449
|
+
* cradle rather than a member) and `omission` (which comes from the declaration
|
|
450
|
+
* and from no seam at all). `routes`, `ungatedRoutes`, `onBoot` and the manifest
|
|
451
|
+
* declarations are deliberately absent for one uniform reason: each is a module
|
|
452
|
+
* acting on its **own** surface, which is not a divergence from core. They are
|
|
453
|
+
* named in {@link DivergenceBoundary.notRecorded} so a reader can tell "not a
|
|
454
|
+
* divergence" from "not looked at".
|
|
455
|
+
*/
|
|
456
|
+
export type DivergenceKind = 'omission' | 'registration' | 'port-provided' | 'port-consumed' | 'subscription' | 'interceptor' | 'decoration' | 'root-plugin' | 'worker';
|
|
457
|
+
/**
|
|
458
|
+
* `<kind>:<module>:<subject>` — the three facts that identify a divergence
|
|
459
|
+
* independently of where it is written.
|
|
460
|
+
*
|
|
461
|
+
* **Never a file path and never a line.** A path-keyed ledger goes stale on
|
|
462
|
+
* every move and a line-keyed one reds on any insertion above the site; the
|
|
463
|
+
* subject is the string the platform itself uses to identify the thing — a
|
|
464
|
+
* registration name, an endpoint identity, a module id. An interceptor's key
|
|
465
|
+
* carries `#<phase>`, because one module may register a `pre` and a `post`
|
|
466
|
+
* against one endpoint and they are two divergences with two reasons.
|
|
467
|
+
*/
|
|
468
|
+
export type DivergenceKey = string;
|
|
469
|
+
/** Kind-specific facts, and only the ones the derivation actually has. */
|
|
470
|
+
export type DivergenceDetail = {
|
|
471
|
+
readonly kind: 'decoration';
|
|
472
|
+
/**
|
|
473
|
+
* 1-based position in the wrapping chain, innermost first — and `null` in
|
|
474
|
+
* the committed artefact, deliberately rather than by omission.
|
|
475
|
+
*
|
|
476
|
+
* **Depth is a fact about a composition, not about a tree.** A static walk
|
|
477
|
+
* knows that two overlay modules decorate one name; it does not know which
|
|
478
|
+
* wrapped which, because that is what `decorationOrder` and the composer's
|
|
479
|
+
* emission order decide together. The runtime half of the report
|
|
480
|
+
* (`contracts/divergence-report.md` §7) fills it in from
|
|
481
|
+
* `ComposedModules.decorations`; recording a guess here would be the
|
|
482
|
+
* report asserting something it cannot know.
|
|
483
|
+
*/
|
|
484
|
+
readonly depth: number | null;
|
|
485
|
+
} | {
|
|
486
|
+
readonly kind: 'interceptor';
|
|
487
|
+
readonly phase: 'pre' | 'post';
|
|
488
|
+
readonly order: number;
|
|
489
|
+
readonly id: string;
|
|
490
|
+
/** Does any route registration in the composition match this identity? */
|
|
491
|
+
readonly targetMatched: boolean;
|
|
492
|
+
} | {
|
|
493
|
+
readonly kind: 'subscription';
|
|
494
|
+
} | {
|
|
495
|
+
readonly kind: 'port-provided';
|
|
496
|
+
} | {
|
|
497
|
+
readonly kind: 'port-consumed';
|
|
498
|
+
} | {
|
|
499
|
+
readonly kind: 'registration';
|
|
500
|
+
} | {
|
|
501
|
+
readonly kind: 'worker';
|
|
502
|
+
} | {
|
|
503
|
+
readonly kind: 'root-plugin';
|
|
504
|
+
readonly declaredReason: string;
|
|
505
|
+
} | {
|
|
506
|
+
readonly kind: 'omission';
|
|
507
|
+
};
|
|
508
|
+
/** One divergence: what, who wrote it, who owns it, at what cost, and why. */
|
|
509
|
+
export interface DivergenceEntry {
|
|
510
|
+
readonly key: DivergenceKey;
|
|
511
|
+
readonly kind: DivergenceKind;
|
|
512
|
+
/** The overlay module that wrote it; `'core'` for an omission. */
|
|
513
|
+
readonly module: string;
|
|
514
|
+
/** Registration name, endpoint identity, event name, queue name, module id. */
|
|
515
|
+
readonly subject: string;
|
|
516
|
+
/**
|
|
517
|
+
* The module that owns `subject`; `null` when a composition root registered
|
|
518
|
+
* it. A name nobody registers is a **finding**, not an entry, so `null` here
|
|
519
|
+
* always means "root-supplied" and never "unknown".
|
|
520
|
+
*/
|
|
521
|
+
readonly owner: string | null;
|
|
522
|
+
/**
|
|
523
|
+
* Which rung of the escalation ladder this seam is
|
|
524
|
+
* (`specs/107-override-report-and-ladder/contracts/escalation-ladder.md` §2),
|
|
525
|
+
* or `null` for a kind that sits on no rung.
|
|
526
|
+
*
|
|
527
|
+
* `null` is three kinds and they are the three the ladder's own table marks
|
|
528
|
+
* `—`: `registration` and `worker` are a module contributing its **own**
|
|
529
|
+
* surface, and `omission` comes from the declaration rather than from a seam.
|
|
530
|
+
* The ladder ranks ways of changing what *core* does, so a rung number on
|
|
531
|
+
* those would be a cost this repository does not claim they have. A
|
|
532
|
+
* `ModuleContext` member that the rung table classifies **not at all** is a
|
|
533
|
+
* different state and is the `unclassified-seam` finding.
|
|
534
|
+
*/
|
|
535
|
+
readonly rung: number | null;
|
|
536
|
+
/** Kind-specific facts. Never free-form. */
|
|
537
|
+
readonly detail: DivergenceDetail;
|
|
538
|
+
/** The deployment's own sentence, from its declaration's `reasons` map. */
|
|
539
|
+
readonly reason: string;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* What the artefact does not cover, stated rather than implied (FR-018).
|
|
543
|
+
*
|
|
544
|
+
* A report that lists nine seams and says nothing about the rest is
|
|
545
|
+
* indistinguishable from a complete one. This is the difference between a
|
|
546
|
+
* boundary statement and a silence, and it is why the two hand-written lists
|
|
547
|
+
* below are hand-written: they carry a *reason* each, which no walk can produce.
|
|
548
|
+
*/
|
|
549
|
+
export interface DivergenceBoundary {
|
|
550
|
+
/** Seams this artefact records. Derived — the kinds above. */
|
|
551
|
+
readonly recorded: readonly DivergenceKind[];
|
|
552
|
+
/** Seams that exist and are a module's own business, with why. */
|
|
553
|
+
readonly notRecorded: ReadonlyArray<{
|
|
554
|
+
readonly seam: string;
|
|
555
|
+
readonly why: string;
|
|
556
|
+
}>;
|
|
557
|
+
/** Facts only a running process can answer, with why. */
|
|
558
|
+
readonly runtimeOnly: ReadonlyArray<{
|
|
559
|
+
readonly fact: string;
|
|
560
|
+
readonly why: string;
|
|
561
|
+
}>;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* The derived record of how one deployment's tree diverges from core (D-30).
|
|
565
|
+
*
|
|
566
|
+
* Committed, per deployment, in two renderings from one derivation: a `.ts` a
|
|
567
|
+
* program reads and a `.md` a human reads. Deterministic — repo-relative paths,
|
|
568
|
+
* sorted arrays, no timestamps — so identical inputs produce byte-identical
|
|
569
|
+
* output and `overlay:check` can byte-compare both.
|
|
570
|
+
*
|
|
571
|
+
* The shape is published here rather than in `backend/src/overlay/` for the
|
|
572
|
+
* reason {@link DeploymentDivergenceDeclarationSchema} is: it is a deployment's
|
|
573
|
+
* artefact, and the runtime half of the report
|
|
574
|
+
* (`specs/107-override-report-and-ladder/contracts/divergence-report.md` §7)
|
|
575
|
+
* shares it. No Zod schema, deliberately: nothing parses this at a boundary —
|
|
576
|
+
* it is generated by one program and byte-compared by another, both of which
|
|
577
|
+
* have the type.
|
|
578
|
+
*/
|
|
579
|
+
export interface DivergenceReport {
|
|
580
|
+
/** Deployment name, or `'core'` for the bare-core build. */
|
|
581
|
+
readonly deployment: string;
|
|
582
|
+
/**
|
|
583
|
+
* The overlay root read, repo-relative; `null` for bare core.
|
|
584
|
+
*
|
|
585
|
+
* Still an object rather than a bare `overlayRoot`, for v2's stated reason: a
|
|
586
|
+
* deployment build has one input path and recording it is what makes the
|
|
587
|
+
* artefact reproducible.
|
|
588
|
+
*/
|
|
589
|
+
readonly generatedFrom: {
|
|
590
|
+
readonly overlayRoot: string | null;
|
|
591
|
+
};
|
|
592
|
+
/**
|
|
593
|
+
* Overlay-only module ids this deployment adds, sorted. (v2's `newModules`.)
|
|
594
|
+
*
|
|
595
|
+
* A field of its own rather than entries of kind `overlay-module`, because an
|
|
596
|
+
* overlay module is the *container* of the other divergences rather than one
|
|
597
|
+
* of them — and every entry names the overlay module it came from anyway.
|
|
598
|
+
*/
|
|
599
|
+
readonly overlayModules: readonly string[];
|
|
600
|
+
/** Every divergence found, sorted by key. */
|
|
601
|
+
readonly entries: readonly DivergenceEntry[];
|
|
602
|
+
/** What this artefact does not cover, stated rather than implied. FR-018. */
|
|
603
|
+
readonly boundary: DivergenceBoundary;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Refusal-token grammar for {@link ModuleErrorCodeDeclarationSchema}.
|
|
607
|
+
*
|
|
608
|
+
* One code, several reasons — `specs/082-error-code-ownership/contracts/error-code-ownership.md`
|
|
609
|
+
* §1.4. The envelope reads `details.code` and looks up `errors.<CODE>.<token>`,
|
|
610
|
+
* or `errors.<CODE>` when the raise carries no token.
|
|
611
|
+
*
|
|
612
|
+
* **It is a choice between two keys and not a fall-back**, which this note said
|
|
613
|
+
* it was until D-190 (`specs/080-f4-real-scope/rulings.md`) measured it:
|
|
614
|
+
* `localizeErrorEnvelope` composes one key, asks for it once and never re-asks.
|
|
615
|
+
* So a code every raise of which carries a token has no reader for its
|
|
616
|
+
* `errors.<CODE>` sentence — the operator never sees it, and deleting it is
|
|
617
|
+
* still wrong, because `check:error-translations` asks its P1 question at that
|
|
618
|
+
* key and at no other.
|
|
619
|
+
*/
|
|
620
|
+
export declare const errorCodeTokenRe: RegExp;
|
|
621
|
+
/**
|
|
622
|
+
* One error code a module claims as its own
|
|
623
|
+
* (`specs/090-module-owned-error-codes/contracts/error-code-declaration.md` §1.1).
|
|
624
|
+
*
|
|
625
|
+
* **No `message` field, and that is a decision.** The English sentence a caller
|
|
626
|
+
* sees when nothing is translated is the one the raising code wrote: it already
|
|
627
|
+
* exists, it is written where the condition is known, and it can interpolate.
|
|
628
|
+
* A manifest message would be a third English sentence for one condition, and
|
|
629
|
+
* the two would drift exactly as a permission's `label` and its
|
|
630
|
+
* `adminRoles.permission.<code>` bundle key already do. The translated
|
|
631
|
+
* sentences live in the declaring module's own `i18n/<language>.json` under
|
|
632
|
+
* `errors.<CODE>`, which is where the envelope already looks.
|
|
633
|
+
*
|
|
634
|
+
* **`tokens` is declared rather than inferred** because a static reader that
|
|
635
|
+
* does not know the token set cannot tell `errors.CART_COUPON_REJECTED.expired`
|
|
636
|
+
* from a key whose tail is not a code at all — which is a finding. Fourteen keys
|
|
637
|
+
* in `invoices` and `carts` have this shape today.
|
|
638
|
+
*/
|
|
639
|
+
export declare const ModuleErrorCodeDeclarationSchema: z.ZodObject<{
|
|
640
|
+
code: z.ZodString;
|
|
641
|
+
tokens: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
642
|
+
}, z.core.$strip>;
|
|
643
|
+
export type ModuleErrorCodeDeclaration = z.infer<typeof ModuleErrorCodeDeclarationSchema>;
|
|
644
|
+
/**
|
|
645
|
+
* One capability this module **owns** and declares mutually exclusive
|
|
646
|
+
* (`specs/132-connector-family-discovery/contracts/module-capabilities.md` R3.1).
|
|
647
|
+
*
|
|
648
|
+
* The owner declares exclusivity, never the member, and three things follow that
|
|
649
|
+
* are otherwise loose ends. The refusal code stays on the semantic owner, which
|
|
650
|
+
* is what D-95.2 requires — a member raises it and must **not** declare it. A
|
|
651
|
+
* member cannot make a capability exclusive by accident, and cannot un-make it.
|
|
652
|
+
* And if the owner module is not installed in a deployment, the capability is
|
|
653
|
+
* simply not exclusive there, which is the honest answer rather than a refusal:
|
|
654
|
+
* without the shared layer there is no lock row and nothing to enforce with
|
|
655
|
+
* (R3.5).
|
|
656
|
+
*/
|
|
657
|
+
export declare const ExclusiveCapabilitySchema: z.ZodObject<{
|
|
658
|
+
key: z.ZodString;
|
|
659
|
+
errorCode: z.ZodString;
|
|
660
|
+
}, z.core.$strip>;
|
|
661
|
+
export type ExclusiveCapability = z.infer<typeof ExclusiveCapabilitySchema>;
|
|
662
|
+
export declare const ModuleManifestSchema: z.ZodObject<{
|
|
663
|
+
id: z.ZodString;
|
|
664
|
+
name: z.ZodString;
|
|
665
|
+
description: z.ZodOptional<z.ZodString>;
|
|
666
|
+
version: z.ZodString;
|
|
667
|
+
dependencies: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
668
|
+
acknowledgedDependencies: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
669
|
+
moduleId: z.ZodString;
|
|
670
|
+
port: z.ZodString;
|
|
671
|
+
reason: z.ZodString;
|
|
672
|
+
}, z.core.$strip>>>;
|
|
673
|
+
nonBindingDependencies: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
674
|
+
moduleId: z.ZodString;
|
|
675
|
+
name: z.ZodString;
|
|
676
|
+
kind: z.ZodEnum<{
|
|
677
|
+
"contributes-to": "contributes-to";
|
|
678
|
+
"degrades-without": "degrades-without";
|
|
679
|
+
"refuses-without": "refuses-without";
|
|
680
|
+
}>;
|
|
681
|
+
whenAbsent: z.ZodOptional<z.ZodString>;
|
|
682
|
+
reason: z.ZodString;
|
|
683
|
+
}, z.core.$strip>>>;
|
|
684
|
+
activation: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
685
|
+
settingCode: z.ZodString;
|
|
686
|
+
default: z.ZodBoolean;
|
|
687
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
688
|
+
nonDeactivatable: z.ZodLiteral<true>;
|
|
689
|
+
reason: z.ZodString;
|
|
690
|
+
}, z.core.$strip>]>>;
|
|
691
|
+
settings: z.ZodOptional<z.ZodObject<{
|
|
692
|
+
moduleCode: z.ZodString;
|
|
693
|
+
groups: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
694
|
+
code: z.ZodString;
|
|
695
|
+
name: z.ZodString;
|
|
696
|
+
salesChannelCodes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
697
|
+
isSystemProtected: z.ZodOptional<z.ZodBoolean>;
|
|
698
|
+
}, z.core.$strip>>>;
|
|
699
|
+
settings: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
700
|
+
code: z.ZodString;
|
|
701
|
+
name: z.ZodString;
|
|
702
|
+
description: z.ZodOptional<z.ZodString>;
|
|
703
|
+
groupCode: z.ZodOptional<z.ZodString>;
|
|
704
|
+
valueType: z.ZodEnum<{
|
|
705
|
+
string: "string";
|
|
706
|
+
number: "number";
|
|
707
|
+
boolean: "boolean";
|
|
708
|
+
json: "json";
|
|
709
|
+
string_list: "string_list";
|
|
710
|
+
secret: "secret";
|
|
711
|
+
credential_ref: "credential_ref";
|
|
712
|
+
}>;
|
|
713
|
+
defaultValue: z.ZodUnknown;
|
|
714
|
+
previousDefaultValues: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
715
|
+
salesChannelCodes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
716
|
+
enumOptions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
717
|
+
configurationType: z.ZodOptional<z.ZodString>;
|
|
718
|
+
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
719
|
+
}, z.core.$strip>>>;
|
|
720
|
+
}, z.core.$strip>>;
|
|
721
|
+
i18n: z.ZodOptional<z.ZodObject<{
|
|
722
|
+
bundlesDir: z.ZodDefault<z.ZodString>;
|
|
723
|
+
}, z.core.$strip>>;
|
|
724
|
+
docs: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
725
|
+
dir: z.ZodDefault<z.ZodString>;
|
|
726
|
+
}, z.core.$strip>, z.ZodLiteral<false>]>>;
|
|
727
|
+
demo: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
728
|
+
summary: z.ZodString;
|
|
729
|
+
seed: z.ZodType<(context: ModuleDemoContext<never>) => Promise<DemoSeedResult>, unknown, z.core.$ZodTypeInternals<(context: ModuleDemoContext<never>) => Promise<DemoSeedResult>, unknown>>;
|
|
730
|
+
reset: z.ZodType<(context: ModuleDemoContext<never>) => Promise<DemoResetResult>, unknown, z.core.$ZodTypeInternals<(context: ModuleDemoContext<never>) => Promise<DemoResetResult>, unknown>>;
|
|
731
|
+
after: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
732
|
+
package: z.ZodOptional<z.ZodString>;
|
|
733
|
+
}, z.core.$strip>, z.ZodLiteral<false>]>>;
|
|
734
|
+
actions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
735
|
+
id: z.ZodString;
|
|
736
|
+
labelKey: z.ZodString;
|
|
737
|
+
descriptionKey: z.ZodOptional<z.ZodString>;
|
|
738
|
+
icon: z.ZodEnum<{
|
|
739
|
+
Plus: "Plus";
|
|
740
|
+
Sparkles: "Sparkles";
|
|
741
|
+
Settings: "Settings";
|
|
742
|
+
Search: "Search";
|
|
743
|
+
Boxes: "Boxes";
|
|
744
|
+
Layers: "Layers";
|
|
745
|
+
Menu: "Menu";
|
|
746
|
+
PlusCircle: "PlusCircle";
|
|
747
|
+
PlusSquare: "PlusSquare";
|
|
748
|
+
FilePlus: "FilePlus";
|
|
749
|
+
FolderPlus: "FolderPlus";
|
|
750
|
+
Upload: "Upload";
|
|
751
|
+
FileUp: "FileUp";
|
|
752
|
+
CloudUpload: "CloudUpload";
|
|
753
|
+
Download: "Download";
|
|
754
|
+
FileDown: "FileDown";
|
|
755
|
+
FileText: "FileText";
|
|
756
|
+
BookOpen: "BookOpen";
|
|
757
|
+
Rss: "Rss";
|
|
758
|
+
Package: "Package";
|
|
759
|
+
Tag: "Tag";
|
|
760
|
+
ShoppingCart: "ShoppingCart";
|
|
761
|
+
Receipt: "Receipt";
|
|
762
|
+
CreditCard: "CreditCard";
|
|
763
|
+
Users: "Users";
|
|
764
|
+
UserPlus: "UserPlus";
|
|
765
|
+
Inbox: "Inbox";
|
|
766
|
+
ListChecks: "ListChecks";
|
|
767
|
+
ClipboardList: "ClipboardList";
|
|
768
|
+
Image: "Image";
|
|
769
|
+
Video: "Video";
|
|
770
|
+
LayoutDashboard: "LayoutDashboard";
|
|
771
|
+
PanelLeft: "PanelLeft";
|
|
772
|
+
KeyRound: "KeyRound";
|
|
773
|
+
ShieldCheck: "ShieldCheck";
|
|
774
|
+
Edit: "Edit";
|
|
775
|
+
Archive: "Archive";
|
|
776
|
+
Box: "Box";
|
|
777
|
+
Truck: "Truck";
|
|
778
|
+
CircleDollarSign: "CircleDollarSign";
|
|
779
|
+
Activity: "Activity";
|
|
780
|
+
LineChart: "LineChart";
|
|
781
|
+
Smartphone: "Smartphone";
|
|
782
|
+
Webhook: "Webhook";
|
|
783
|
+
Scale: "Scale";
|
|
784
|
+
PlugZap: "PlugZap";
|
|
785
|
+
PercentDiamond: "PercentDiamond";
|
|
786
|
+
Newspaper: "Newspaper";
|
|
787
|
+
Languages: "Languages";
|
|
788
|
+
Eraser: "Eraser";
|
|
789
|
+
Warehouse: "Warehouse";
|
|
790
|
+
TrendingDown: "TrendingDown";
|
|
791
|
+
Bell: "Bell";
|
|
792
|
+
PackageOpen: "PackageOpen";
|
|
793
|
+
Building2: "Building2";
|
|
794
|
+
Store: "Store";
|
|
795
|
+
ClipboardCheck: "ClipboardCheck";
|
|
796
|
+
}>;
|
|
797
|
+
targetRoute: z.ZodString;
|
|
798
|
+
requiredPermission: z.ZodOptional<z.ZodString>;
|
|
799
|
+
keywords: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
800
|
+
weight: z.ZodDefault<z.ZodNumber>;
|
|
801
|
+
}, z.core.$strip>>>;
|
|
802
|
+
permissions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
803
|
+
code: z.ZodString;
|
|
804
|
+
module: z.ZodOptional<z.ZodString>;
|
|
805
|
+
label: z.ZodString;
|
|
806
|
+
description: z.ZodOptional<z.ZodString>;
|
|
807
|
+
requires: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
808
|
+
}, z.core.$strip>>>;
|
|
809
|
+
transactionalEmails: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
810
|
+
code: z.ZodString;
|
|
811
|
+
name: z.ZodString;
|
|
812
|
+
description: z.ZodOptional<z.ZodString>;
|
|
813
|
+
group: z.ZodOptional<z.ZodString>;
|
|
814
|
+
variables: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
815
|
+
key: z.ZodString;
|
|
816
|
+
label: z.ZodString;
|
|
817
|
+
sampleValue: z.ZodOptional<z.ZodString>;
|
|
818
|
+
description: z.ZodOptional<z.ZodString>;
|
|
819
|
+
}, z.core.$strip>>>;
|
|
820
|
+
}, z.core.$strip>>>;
|
|
821
|
+
capabilities: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
822
|
+
exclusiveCapabilities: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
823
|
+
key: z.ZodString;
|
|
824
|
+
errorCode: z.ZodString;
|
|
825
|
+
}, z.core.$strip>>>;
|
|
826
|
+
errorCodes: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
827
|
+
code: z.ZodString;
|
|
828
|
+
tokens: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
829
|
+
}, z.core.$strip>>>;
|
|
830
|
+
blocks: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
831
|
+
name: z.ZodString;
|
|
832
|
+
labelKey: z.ZodString;
|
|
833
|
+
descriptionKey: z.ZodOptional<z.ZodString>;
|
|
834
|
+
category: z.ZodString;
|
|
835
|
+
contexts: z.ZodArray<z.ZodEnum<{
|
|
836
|
+
invoice: "invoice";
|
|
837
|
+
email: "email";
|
|
838
|
+
cms: "cms";
|
|
839
|
+
newsletter: "newsletter";
|
|
840
|
+
}>>;
|
|
841
|
+
fields: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
842
|
+
type: z.ZodEnum<{
|
|
843
|
+
number: "number";
|
|
844
|
+
object: "object";
|
|
845
|
+
array: "array";
|
|
846
|
+
text: "text";
|
|
847
|
+
textarea: "textarea";
|
|
848
|
+
select: "select";
|
|
849
|
+
radio: "radio";
|
|
850
|
+
external: "external";
|
|
851
|
+
uuid: "uuid";
|
|
852
|
+
richtext: "richtext";
|
|
853
|
+
}>;
|
|
854
|
+
label: z.ZodOptional<z.ZodString>;
|
|
855
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
856
|
+
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
857
|
+
label: z.ZodString;
|
|
858
|
+
value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
859
|
+
}, z.core.$strip>>>;
|
|
860
|
+
refKind: z.ZodOptional<z.ZodString>;
|
|
861
|
+
}, z.core.$strip>>;
|
|
862
|
+
defaultProps: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
863
|
+
responsiveFields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
864
|
+
previewIcon: z.ZodOptional<z.ZodString>;
|
|
865
|
+
weight: z.ZodOptional<z.ZodNumber>;
|
|
866
|
+
}, z.core.$strip>>>;
|
|
867
|
+
blockCategories: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
868
|
+
key: z.ZodString;
|
|
869
|
+
titleKey: z.ZodString;
|
|
870
|
+
contexts: z.ZodArray<z.ZodEnum<{
|
|
871
|
+
invoice: "invoice";
|
|
872
|
+
email: "email";
|
|
873
|
+
cms: "cms";
|
|
874
|
+
newsletter: "newsletter";
|
|
875
|
+
}>>;
|
|
876
|
+
weight: z.ZodOptional<z.ZodNumber>;
|
|
877
|
+
visible: z.ZodOptional<z.ZodBoolean>;
|
|
878
|
+
}, z.core.$strip>>>;
|
|
879
|
+
env: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
880
|
+
name: z.ZodString;
|
|
881
|
+
describes: z.ZodObject<{
|
|
882
|
+
en: z.ZodString;
|
|
883
|
+
pl: z.ZodString;
|
|
884
|
+
}, z.core.$strip>;
|
|
885
|
+
requirement: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
886
|
+
kind: z.ZodLiteral<"required">;
|
|
887
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
888
|
+
kind: z.ZodLiteral<"requiredWhen">;
|
|
889
|
+
input: z.ZodString;
|
|
890
|
+
equals: z.ZodString;
|
|
891
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
892
|
+
kind: z.ZodLiteral<"optional">;
|
|
893
|
+
without: z.ZodObject<{
|
|
894
|
+
en: z.ZodString;
|
|
895
|
+
pl: z.ZodString;
|
|
896
|
+
}, z.core.$strip>;
|
|
897
|
+
}, z.core.$strip>], "kind">;
|
|
898
|
+
secret: z.ZodBoolean;
|
|
899
|
+
generable: z.ZodBoolean;
|
|
900
|
+
owner: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
901
|
+
kind: z.ZodLiteral<"platform">;
|
|
902
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
903
|
+
kind: z.ZodLiteral<"application">;
|
|
904
|
+
application: z.ZodEnum<{
|
|
905
|
+
admin: "admin";
|
|
906
|
+
backend: "backend";
|
|
907
|
+
storefront: "storefront";
|
|
908
|
+
}>;
|
|
909
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
910
|
+
kind: z.ZodLiteral<"module">;
|
|
911
|
+
moduleId: z.ZodString;
|
|
912
|
+
}, z.core.$strip>], "kind">;
|
|
913
|
+
consumers: z.ZodArray<z.ZodEnum<{
|
|
914
|
+
admin: "admin";
|
|
915
|
+
backend: "backend";
|
|
916
|
+
storefront: "storefront";
|
|
917
|
+
}>>;
|
|
918
|
+
addressOf: z.ZodNullable<z.ZodEnum<{
|
|
919
|
+
admin: "admin";
|
|
920
|
+
backend: "backend";
|
|
921
|
+
storefront: "storefront";
|
|
922
|
+
}>>;
|
|
923
|
+
}, z.core.$strip>>>;
|
|
924
|
+
}, z.core.$strip>;
|
|
925
|
+
export type ModuleManifest = z.infer<typeof ModuleManifestSchema>;
|
|
926
|
+
/**
|
|
927
|
+
* Identity-with-validation helper for module authors. Modules export a
|
|
928
|
+
* single `manifest` constant via this helper so TypeScript inference is
|
|
929
|
+
* preserved and the loader can ingest the validated payload directly.
|
|
930
|
+
*/
|
|
931
|
+
export declare function defineModuleManifest(m: ModuleManifest): ModuleManifest;
|
|
932
|
+
/**
|
|
933
|
+
* Logger surface a hook may use. Implementations attach the module id as a
|
|
934
|
+
* tag at the orchestrator level so the hook author writes plain messages.
|
|
935
|
+
*
|
|
936
|
+
* **This is not `ctx.log`.** It is the logger of the three surfaces below — the
|
|
937
|
+
* install/uninstall hook context and the two lifecycle-participant events — all
|
|
938
|
+
* of which the orchestrator calls, and it takes a message and nothing else.
|
|
939
|
+
* `ModuleContext.log`, which a module writes to from `registerModule`, is a
|
|
940
|
+
* `PlatformLogger` (`@endora-commerce/platform/kernel`) and takes a bound object
|
|
941
|
+
* first: `ctx.log.info({ orderId }, 'message')`.
|
|
942
|
+
*
|
|
943
|
+
* The two used to share this name, which is how a scaffolded module came to
|
|
944
|
+
* call `ctx.log.info('…')` with one argument against a two-argument type. Keep
|
|
945
|
+
* the shapes' names apart; they are not interchangeable in either direction.
|
|
946
|
+
*/
|
|
947
|
+
export interface ModuleLifecycleLogger {
|
|
948
|
+
info(msg: string): void;
|
|
949
|
+
warn(msg: string): void;
|
|
950
|
+
error(msg: string): void;
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Context passed to install/uninstall hooks. The orchestrator owns the
|
|
954
|
+
* lifetime of every field — hooks MUST use the provided `em` rather than
|
|
955
|
+
* forking their own, so writes participate in the same transaction.
|
|
956
|
+
*/
|
|
957
|
+
export interface ModuleLifecycleContext<EM = unknown, Redis = unknown> {
|
|
958
|
+
em: EM;
|
|
959
|
+
redis: Redis;
|
|
960
|
+
log: ModuleLifecycleLogger;
|
|
961
|
+
module: {
|
|
962
|
+
id: string;
|
|
963
|
+
version: string;
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
export type ModuleInstallHook<EM = unknown, Redis = unknown> = (ctx: ModuleLifecycleContext<EM, Redis>) => Promise<void>;
|
|
967
|
+
export type ModuleUninstallHook<EM = unknown, Redis = unknown> = (ctx: ModuleLifecycleContext<EM, Redis> & {
|
|
968
|
+
hard: boolean;
|
|
969
|
+
}) => Promise<void>;
|
|
970
|
+
/**
|
|
971
|
+
* What a participant is told when **another** module is installed.
|
|
972
|
+
*
|
|
973
|
+
* `moduleId` is the module the operator asked to install, never the
|
|
974
|
+
* participant's own — that is the whole difference between this and an install
|
|
975
|
+
* hook, and it is why a participant could not be one. An install hook answers
|
|
976
|
+
* *"my module is arriving"*; a participant answers *"a module is arriving and I
|
|
977
|
+
* keep a projection of every module".*
|
|
978
|
+
*/
|
|
979
|
+
export interface ModuleInstalledEvent<EM = unknown> {
|
|
980
|
+
/** The module being installed. */
|
|
981
|
+
moduleId: string;
|
|
982
|
+
/** That module's manifest, already validated. */
|
|
983
|
+
manifest: ModuleManifest;
|
|
984
|
+
/**
|
|
985
|
+
* The directory holding that module's manifest file — what a participant
|
|
986
|
+
* that reads the module's own files off disk (bundles, templates) joins its
|
|
987
|
+
* relative directory onto.
|
|
988
|
+
*/
|
|
989
|
+
modulePath: string;
|
|
990
|
+
/**
|
|
991
|
+
* The orchestrator's EntityManager. A participant MUST write through it
|
|
992
|
+
* rather than forking its own, so its rows join the operation the orchestrator
|
|
993
|
+
* is performing instead of committing beside it.
|
|
994
|
+
*/
|
|
995
|
+
em: EM;
|
|
996
|
+
log: ModuleLifecycleLogger;
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* What a participant is told when another module is **hard**-uninstalled.
|
|
1000
|
+
*
|
|
1001
|
+
* A soft uninstall never reaches a participant: soft preserves the module's
|
|
1002
|
+
* data so a re-install picks it up unchanged, and a projection of the manifest
|
|
1003
|
+
* is data on those terms.
|
|
1004
|
+
*/
|
|
1005
|
+
export interface ModuleHardUninstalledEvent<EM = unknown> {
|
|
1006
|
+
/** The module being removed. */
|
|
1007
|
+
moduleId: string;
|
|
1008
|
+
/**
|
|
1009
|
+
* That module's manifest, or `null` when the registry holds a row for a
|
|
1010
|
+
* module whose manifest is no longer on this instance — an orphan. Removing a
|
|
1011
|
+
* projection is exactly the case that must still work then, so the manifest
|
|
1012
|
+
* is nullable here and not on the install side.
|
|
1013
|
+
*/
|
|
1014
|
+
manifest: ModuleManifest | null;
|
|
1015
|
+
/** The orchestrator's EntityManager — see {@link ModuleInstalledEvent.em}. */
|
|
1016
|
+
em: EM;
|
|
1017
|
+
log: ModuleLifecycleLogger;
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* A module's declared interest in **every other module's** lifecycle.
|
|
1021
|
+
*
|
|
1022
|
+
* Two modules keep a table that projects what the manifests declare — `_i18n`
|
|
1023
|
+
* projects `manifest.i18n` into `translation_bundles`, `admin_actions` projects
|
|
1024
|
+
* `manifest.actions` into `module_actions` — and both projections have to move
|
|
1025
|
+
* when *any* module is installed or hard-uninstalled. That is not an install
|
|
1026
|
+
* hook (which fires for its own module) and it cannot be a port (the lifecycle
|
|
1027
|
+
* orchestrator serves a platform command, which composes no container to
|
|
1028
|
+
* resolve one from). It is a third export of `manifest.ts`, walked by the same
|
|
1029
|
+
* generator, so it reaches core, overlay and an installed package on identical
|
|
1030
|
+
* terms.
|
|
1031
|
+
*
|
|
1032
|
+
* **Both methods are required**, deliberately. Feature detection through an
|
|
1033
|
+
* optional method is what D-97.3 refuses on a published port, and the reason
|
|
1034
|
+
* carries here: a participant with nothing to do on one edge writes an empty
|
|
1035
|
+
* body, which is a decision a reader can see, while an omitted method is
|
|
1036
|
+
* indistinguishable from one somebody forgot.
|
|
1037
|
+
*
|
|
1038
|
+
* Keep the implementation in `manifest.ts` **light** — `await import()` the
|
|
1039
|
+
* service the body needs. The generated manifest index is imported by the check
|
|
1040
|
+
* scripts and by `src/db/configured-migrations.ts`, so a participant that
|
|
1041
|
+
* statically imported an ORM-dependent service graph would pull it into every
|
|
1042
|
+
* one of them.
|
|
1043
|
+
*/
|
|
1044
|
+
export interface ModuleLifecycleParticipant<EM = unknown> {
|
|
1045
|
+
/**
|
|
1046
|
+
* Runs after the installed module's settings are reconciled and before its
|
|
1047
|
+
* own install hook. A throw aborts the install and reverts its migrations,
|
|
1048
|
+
* which is the property FR-016 rests on: an operator installing a module with
|
|
1049
|
+
* an unreadable bundle is told while they can still choose not to install it.
|
|
1050
|
+
*/
|
|
1051
|
+
onModuleInstalled(event: ModuleInstalledEvent<EM>): Promise<void>;
|
|
1052
|
+
/** Runs on `uninstall --hard` only. */
|
|
1053
|
+
onModuleHardUninstalled(event: ModuleHardUninstalledEvent<EM>): Promise<void>;
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* The shape a command's name has to take: lowercase, hyphen-separated.
|
|
1057
|
+
*
|
|
1058
|
+
* A command is addressed as `<module id> <command name>` on the host's argv, so
|
|
1059
|
+
* the name shares the module id's alphabet minus the underscore — an operator
|
|
1060
|
+
* types `carts abandonment-sweep`, and `check:naming`'s route-segment rule is
|
|
1061
|
+
* the same shape for the same reason. The host validates against this rather
|
|
1062
|
+
* than accepting whatever a package declared: a name with a space in it is
|
|
1063
|
+
* unaddressable, and a name that differs from the one printed by `--list` is
|
|
1064
|
+
* worse than one that is refused.
|
|
1065
|
+
*/
|
|
1066
|
+
export declare const MODULE_CLI_COMMAND_NAME_RE: RegExp;
|
|
1067
|
+
/**
|
|
1068
|
+
* What a command handler is given.
|
|
1069
|
+
*
|
|
1070
|
+
* `ctx` is the module's own `ModuleContext` — a kernel type this package
|
|
1071
|
+
* deliberately does not import, so it arrives through the generic exactly as an
|
|
1072
|
+
* `EntityManager` does on the lifecycle hooks above. A handler resolves what it
|
|
1073
|
+
* needs from it with
|
|
1074
|
+
* `lazyPort<T>(ctx, 'literalName')`, character-for-character what `backend.ts`
|
|
1075
|
+
* writes, which is what keeps `check:port-dependencies` able to see the edge. A
|
|
1076
|
+
* cradle read would be invisible to it.
|
|
1077
|
+
*
|
|
1078
|
+
* `out` and `err` are the command's interface, injected rather than reached for:
|
|
1079
|
+
* a handler that writes to `process.stdout` directly cannot be driven from a
|
|
1080
|
+
* test without capturing the process's streams, and the host is the one place
|
|
1081
|
+
* that knows whether this invocation has a terminal.
|
|
1082
|
+
*/
|
|
1083
|
+
export interface ModuleCliCommandContext<Ctx = unknown> {
|
|
1084
|
+
/** The module's own composed `ModuleContext`. */
|
|
1085
|
+
ctx: Ctx;
|
|
1086
|
+
/** Everything the operator typed after `<module id> <command name>`. */
|
|
1087
|
+
argv: readonly string[];
|
|
1088
|
+
/** One line of human-readable output. The host adds the newline. */
|
|
1089
|
+
out(line: string): void;
|
|
1090
|
+
/** One line of diagnostics. The host adds the newline. */
|
|
1091
|
+
err(line: string): void;
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* An operator command a module declares and **the host runs** (D-160.9).
|
|
1095
|
+
*
|
|
1096
|
+
* Checked against Magento 2, which is this repository's module benchmark: a
|
|
1097
|
+
* Magento module ships a command class plus a declaration in its `di.xml` under
|
|
1098
|
+
* `CommandListInterface`, and `bin/magento` — the host binary — bootstraps the
|
|
1099
|
+
* application and constructs each command with its dependencies injected. The
|
|
1100
|
+
* module never bootstraps the host. That is one-to-one with what D-157.8 had
|
|
1101
|
+
* already ruled here: the command is declared where `installHook` is declared,
|
|
1102
|
+
* an export of the module's `manifest.ts`, picked up by the same tree walk, and
|
|
1103
|
+
* one shape covers core, overlay and package.
|
|
1104
|
+
*
|
|
1105
|
+
* A package could not do it any other way. A file under `node_modules` can name
|
|
1106
|
+
* no specifier that resolves to the instance's `backend/src/composition.ts`, and
|
|
1107
|
+
* a core script that names it creates a module → root → module cycle. So the
|
|
1108
|
+
* invocation inverts: the host composes once and calls the module.
|
|
1109
|
+
*
|
|
1110
|
+
* **It is not a Command Bus Command** (Constitution XIII), and the field is
|
|
1111
|
+
* spelled `cliCommands` rather than `commands` so that the two cannot be read
|
|
1112
|
+
* for one another — `backend/src/commands/` and every module's own `commands/`
|
|
1113
|
+
* directory already hold the audited domain writes. A CLI command that performs
|
|
1114
|
+
* a domain write runs one of those, resolved from `ctx`, exactly as a route
|
|
1115
|
+
* handler does.
|
|
1116
|
+
*
|
|
1117
|
+
* Keep the declaration in `manifest.ts` **light**, for the reason
|
|
1118
|
+
* {@link ModuleLifecycleParticipant} gives: the generated manifest index is
|
|
1119
|
+
* imported by the check scripts and by `src/db/configured-migrations.ts`, so
|
|
1120
|
+
* `run` should `await import()` the file that holds the body rather than
|
|
1121
|
+
* pulling a service graph into all of them.
|
|
1122
|
+
*/
|
|
1123
|
+
export interface ModuleCliCommand<Ctx = unknown> {
|
|
1124
|
+
/** Unique within the module. Must match {@link MODULE_CLI_COMMAND_NAME_RE}. */
|
|
1125
|
+
name: string;
|
|
1126
|
+
/** One line, printed by the host's `--list`. Written for an operator. */
|
|
1127
|
+
summary: string;
|
|
1128
|
+
/**
|
|
1129
|
+
* The full usage text, printed by the host for `--help`.
|
|
1130
|
+
*
|
|
1131
|
+
* A **data property**, not a method, and answered by the host **before it
|
|
1132
|
+
* composes**: `--list` and `--help` are questions about the declaration, and
|
|
1133
|
+
* a tool has to be able to say what it does before it can do it. D-102 made
|
|
1134
|
+
* that a condition rather than a nicety for `audit_logs read` — its credential
|
|
1135
|
+
* is host access, not a working connection string — and the same property is
|
|
1136
|
+
* why D-157.8 rejected path-convention dispatch, which *"nothing can list …
|
|
1137
|
+
* for `--help`"*.
|
|
1138
|
+
*
|
|
1139
|
+
* Omit it and the host prints {@link summary}. An optional *data* property is
|
|
1140
|
+
* outside what D-97.3 refuses: that rule is about optional **methods** on a
|
|
1141
|
+
* published port, where `lazyPort`'s proxy makes feature detection impossible
|
|
1142
|
+
* by construction.
|
|
1143
|
+
*/
|
|
1144
|
+
help?: string;
|
|
1145
|
+
/**
|
|
1146
|
+
* The body. Returns the process exit code — `0` for success, non-zero for a
|
|
1147
|
+
* failure the command itself detected (bad argv, a strict-mode violation).
|
|
1148
|
+
*
|
|
1149
|
+
* Required to return one rather than `void`: a command that means "1" and
|
|
1150
|
+
* returns nothing is indistinguishable from one that succeeded, and the shell
|
|
1151
|
+
* that runs it in a deploy hook reads only the code.
|
|
1152
|
+
*
|
|
1153
|
+
* A throw is the other failure channel and needs no handling here: the host
|
|
1154
|
+
* reports it and exits non-zero. In particular a command must **not** wrap a
|
|
1155
|
+
* port call in a `catch` — that swallows `ModuleDisabledError` and turns
|
|
1156
|
+
* fail-closed into fail-open (`check:port-catches`).
|
|
1157
|
+
*/
|
|
1158
|
+
run(context: ModuleCliCommandContext<Ctx>): Promise<number>;
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* The shape an audit action token has: `<object>.<verb>`, both snake_case.
|
|
1162
|
+
*
|
|
1163
|
+
* `product.create`, `stock_level.bulk_import`, `prompt_action.execute`. It is
|
|
1164
|
+
* the value stored in `audit_log_entries.action`, and it is matched here rather
|
|
1165
|
+
* than accepted as any string because the declaration is the *only* thing that
|
|
1166
|
+
* puts a token into the dashboard query's `$in` — a typo used to be caught by a
|
|
1167
|
+
* reviewer reading a hand-written array, and there is no array to read now.
|
|
1168
|
+
*
|
|
1169
|
+
* naming:allow-snake-case — the token is persisted verbatim in
|
|
1170
|
+
* `audit_log_entries.action` and is written by `Command.action`, so this is the
|
|
1171
|
+
* existing wire value rather than a new API field.
|
|
1172
|
+
*/
|
|
1173
|
+
export declare const auditActionRe: RegExp;
|
|
1174
|
+
/**
|
|
1175
|
+
* One audit action a module offers to the admin home dashboard's
|
|
1176
|
+
* recent-activity card.
|
|
1177
|
+
*
|
|
1178
|
+
* `labelKey` is **relative to the declaring module's i18n namespace**, exactly
|
|
1179
|
+
* as a command-palette action's `labelKey` is: the module ships
|
|
1180
|
+
* `activity.verb.product.create` in its own `i18n/en.json` and `pl.json`, the
|
|
1181
|
+
* card resolves it as `t('<moduleId>', '<labelKey>')`. That is what lets a
|
|
1182
|
+
* third-party package render a verb in the operator's language without the host
|
|
1183
|
+
* shipping a string for it.
|
|
1184
|
+
*
|
|
1185
|
+
* `icon` comes from {@link KnownIconNameSchema}, so the admin maps it through
|
|
1186
|
+
* the one `icon-map.ts` it already has and a package cannot name a component
|
|
1187
|
+
* the SPA does not bundle.
|
|
1188
|
+
*/
|
|
1189
|
+
export declare const RecentActivityEntrySchema: z.ZodObject<{
|
|
1190
|
+
action: z.ZodString;
|
|
1191
|
+
icon: z.ZodEnum<{
|
|
1192
|
+
Plus: "Plus";
|
|
1193
|
+
Sparkles: "Sparkles";
|
|
1194
|
+
Settings: "Settings";
|
|
1195
|
+
Search: "Search";
|
|
1196
|
+
Boxes: "Boxes";
|
|
1197
|
+
Layers: "Layers";
|
|
1198
|
+
Menu: "Menu";
|
|
1199
|
+
PlusCircle: "PlusCircle";
|
|
1200
|
+
PlusSquare: "PlusSquare";
|
|
1201
|
+
FilePlus: "FilePlus";
|
|
1202
|
+
FolderPlus: "FolderPlus";
|
|
1203
|
+
Upload: "Upload";
|
|
1204
|
+
FileUp: "FileUp";
|
|
1205
|
+
CloudUpload: "CloudUpload";
|
|
1206
|
+
Download: "Download";
|
|
1207
|
+
FileDown: "FileDown";
|
|
1208
|
+
FileText: "FileText";
|
|
1209
|
+
BookOpen: "BookOpen";
|
|
1210
|
+
Rss: "Rss";
|
|
1211
|
+
Package: "Package";
|
|
1212
|
+
Tag: "Tag";
|
|
1213
|
+
ShoppingCart: "ShoppingCart";
|
|
1214
|
+
Receipt: "Receipt";
|
|
1215
|
+
CreditCard: "CreditCard";
|
|
1216
|
+
Users: "Users";
|
|
1217
|
+
UserPlus: "UserPlus";
|
|
1218
|
+
Inbox: "Inbox";
|
|
1219
|
+
ListChecks: "ListChecks";
|
|
1220
|
+
ClipboardList: "ClipboardList";
|
|
1221
|
+
Image: "Image";
|
|
1222
|
+
Video: "Video";
|
|
1223
|
+
LayoutDashboard: "LayoutDashboard";
|
|
1224
|
+
PanelLeft: "PanelLeft";
|
|
1225
|
+
KeyRound: "KeyRound";
|
|
1226
|
+
ShieldCheck: "ShieldCheck";
|
|
1227
|
+
Edit: "Edit";
|
|
1228
|
+
Archive: "Archive";
|
|
1229
|
+
Box: "Box";
|
|
1230
|
+
Truck: "Truck";
|
|
1231
|
+
CircleDollarSign: "CircleDollarSign";
|
|
1232
|
+
Activity: "Activity";
|
|
1233
|
+
LineChart: "LineChart";
|
|
1234
|
+
Smartphone: "Smartphone";
|
|
1235
|
+
Webhook: "Webhook";
|
|
1236
|
+
Scale: "Scale";
|
|
1237
|
+
PlugZap: "PlugZap";
|
|
1238
|
+
PercentDiamond: "PercentDiamond";
|
|
1239
|
+
Newspaper: "Newspaper";
|
|
1240
|
+
Languages: "Languages";
|
|
1241
|
+
Eraser: "Eraser";
|
|
1242
|
+
Warehouse: "Warehouse";
|
|
1243
|
+
TrendingDown: "TrendingDown";
|
|
1244
|
+
Bell: "Bell";
|
|
1245
|
+
PackageOpen: "PackageOpen";
|
|
1246
|
+
Building2: "Building2";
|
|
1247
|
+
Store: "Store";
|
|
1248
|
+
ClipboardCheck: "ClipboardCheck";
|
|
1249
|
+
}>;
|
|
1250
|
+
labelKey: z.ZodString;
|
|
1251
|
+
}, z.core.$strip>;
|
|
1252
|
+
export type RecentActivityEntry = z.infer<typeof RecentActivityEntrySchema>;
|
|
1253
|
+
/**
|
|
1254
|
+
* A module's declaration that its activity is **eligible** for the dashboard's
|
|
1255
|
+
* recent-activity card — D-163.1, the first of the ruling's two axes.
|
|
1256
|
+
*
|
|
1257
|
+
* It is a declaration and not a decision. Whether a declared module's rows
|
|
1258
|
+
* actually appear is the operator's, held in
|
|
1259
|
+
* {@link recentActivityVisibilitySettingCode}'s Setting and defaulting to
|
|
1260
|
+
* visible — Constitution XVII's two-axis shape applied to a narrower object.
|
|
1261
|
+
* Neither axis overwrites the other: a module author cannot put entries on
|
|
1262
|
+
* somebody's home screen by fiat, and an operator cannot be surprised by a card
|
|
1263
|
+
* they did not configure.
|
|
1264
|
+
*
|
|
1265
|
+
* It replaces four hand-maintained tables that had already drifted apart inside
|
|
1266
|
+
* core (D-163): the server allow-list that filtered the dashboard query, the
|
|
1267
|
+
* action → module prefix map, the route's `module` enum and the admin's
|
|
1268
|
+
* `ACTIVITY_RENDERING`. Every one of them is derived from this now, so a
|
|
1269
|
+
* package's row reaches the card and a fifth hand-written entry has nowhere to
|
|
1270
|
+
* be written.
|
|
1271
|
+
*
|
|
1272
|
+
* Declared as an export of `manifest.ts` beside `installHook`,
|
|
1273
|
+
* `lifecycleParticipant` and `cliCommands`, walked by the same generator, so
|
|
1274
|
+
* core, overlay and an installed package declare one on identical terms.
|
|
1275
|
+
*/
|
|
1276
|
+
export declare const ModuleRecentActivitySchema: z.ZodObject<{
|
|
1277
|
+
entries: z.ZodArray<z.ZodObject<{
|
|
1278
|
+
action: z.ZodString;
|
|
1279
|
+
icon: z.ZodEnum<{
|
|
1280
|
+
Plus: "Plus";
|
|
1281
|
+
Sparkles: "Sparkles";
|
|
1282
|
+
Settings: "Settings";
|
|
1283
|
+
Search: "Search";
|
|
1284
|
+
Boxes: "Boxes";
|
|
1285
|
+
Layers: "Layers";
|
|
1286
|
+
Menu: "Menu";
|
|
1287
|
+
PlusCircle: "PlusCircle";
|
|
1288
|
+
PlusSquare: "PlusSquare";
|
|
1289
|
+
FilePlus: "FilePlus";
|
|
1290
|
+
FolderPlus: "FolderPlus";
|
|
1291
|
+
Upload: "Upload";
|
|
1292
|
+
FileUp: "FileUp";
|
|
1293
|
+
CloudUpload: "CloudUpload";
|
|
1294
|
+
Download: "Download";
|
|
1295
|
+
FileDown: "FileDown";
|
|
1296
|
+
FileText: "FileText";
|
|
1297
|
+
BookOpen: "BookOpen";
|
|
1298
|
+
Rss: "Rss";
|
|
1299
|
+
Package: "Package";
|
|
1300
|
+
Tag: "Tag";
|
|
1301
|
+
ShoppingCart: "ShoppingCart";
|
|
1302
|
+
Receipt: "Receipt";
|
|
1303
|
+
CreditCard: "CreditCard";
|
|
1304
|
+
Users: "Users";
|
|
1305
|
+
UserPlus: "UserPlus";
|
|
1306
|
+
Inbox: "Inbox";
|
|
1307
|
+
ListChecks: "ListChecks";
|
|
1308
|
+
ClipboardList: "ClipboardList";
|
|
1309
|
+
Image: "Image";
|
|
1310
|
+
Video: "Video";
|
|
1311
|
+
LayoutDashboard: "LayoutDashboard";
|
|
1312
|
+
PanelLeft: "PanelLeft";
|
|
1313
|
+
KeyRound: "KeyRound";
|
|
1314
|
+
ShieldCheck: "ShieldCheck";
|
|
1315
|
+
Edit: "Edit";
|
|
1316
|
+
Archive: "Archive";
|
|
1317
|
+
Box: "Box";
|
|
1318
|
+
Truck: "Truck";
|
|
1319
|
+
CircleDollarSign: "CircleDollarSign";
|
|
1320
|
+
Activity: "Activity";
|
|
1321
|
+
LineChart: "LineChart";
|
|
1322
|
+
Smartphone: "Smartphone";
|
|
1323
|
+
Webhook: "Webhook";
|
|
1324
|
+
Scale: "Scale";
|
|
1325
|
+
PlugZap: "PlugZap";
|
|
1326
|
+
PercentDiamond: "PercentDiamond";
|
|
1327
|
+
Newspaper: "Newspaper";
|
|
1328
|
+
Languages: "Languages";
|
|
1329
|
+
Eraser: "Eraser";
|
|
1330
|
+
Warehouse: "Warehouse";
|
|
1331
|
+
TrendingDown: "TrendingDown";
|
|
1332
|
+
Bell: "Bell";
|
|
1333
|
+
PackageOpen: "PackageOpen";
|
|
1334
|
+
Building2: "Building2";
|
|
1335
|
+
Store: "Store";
|
|
1336
|
+
ClipboardCheck: "ClipboardCheck";
|
|
1337
|
+
}>;
|
|
1338
|
+
labelKey: z.ZodString;
|
|
1339
|
+
}, z.core.$strip>>;
|
|
1340
|
+
}, z.core.$strip>;
|
|
1341
|
+
export type ModuleRecentActivity = z.infer<typeof ModuleRecentActivitySchema>;
|
|
1342
|
+
/**
|
|
1343
|
+
* Identity-with-validation helper for module authors, the twin of
|
|
1344
|
+
* {@link defineModuleManifest}.
|
|
1345
|
+
*/
|
|
1346
|
+
export declare function defineModuleRecentActivity(declaration: ModuleRecentActivity): ModuleRecentActivity;
|
|
1347
|
+
/** The suffix every recent-activity visibility Setting code ends in. */
|
|
1348
|
+
export declare const RECENT_ACTIVITY_VISIBILITY_SETTING_SUFFIX = "recent_activity_visible";
|
|
1349
|
+
/**
|
|
1350
|
+
* Raised when a module's id cannot carry a Setting code — see
|
|
1351
|
+
* {@link recentActivityVisibilitySettingCode}.
|
|
1352
|
+
*/
|
|
1353
|
+
export declare class RecentActivitySettingCodeInvalid extends Error {
|
|
1354
|
+
readonly name = "RecentActivitySettingCodeInvalid";
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* The Setting that holds the operator's choice for one declaring module.
|
|
1358
|
+
*
|
|
1359
|
+
* **Derived, never declared.** `activation.settingCode` is declared because a
|
|
1360
|
+
* module that already shipped an ad-hoc control had to be able to adopt it;
|
|
1361
|
+
* there is no such history here, and a declared code would be a fifth place a
|
|
1362
|
+
* module could disagree with the platform about its own name. D-163.1 also
|
|
1363
|
+
* fixes the default — visible — so there is nothing else for a declaration to
|
|
1364
|
+
* carry.
|
|
1365
|
+
*/
|
|
1366
|
+
export declare function recentActivityVisibilitySettingCode(moduleId: string): string;
|
|
1367
|
+
/**
|
|
1368
|
+
* The settings manifest the platform reconciles for a module, which is the
|
|
1369
|
+
* module's own declaration plus the one Setting its recent-activity eligibility
|
|
1370
|
+
* implies.
|
|
1371
|
+
*
|
|
1372
|
+
* Two callers and one derivation, deliberately (D-100): the boot reconcile
|
|
1373
|
+
* walks every shipped module's settings, and the lifecycle orchestrator's
|
|
1374
|
+
* `install` reconciles exactly the arriving module's. A package has only the
|
|
1375
|
+
* second — since D-157.6(b) `install` is its sole author — so a second copy of
|
|
1376
|
+
* this merge would mean a packaged module's control existing on one path and
|
|
1377
|
+
* not the other.
|
|
1378
|
+
*
|
|
1379
|
+
* Returns `undefined` when the module declares neither, so a caller can keep
|
|
1380
|
+
* treating "no settings" as an absent value.
|
|
1381
|
+
*/
|
|
1382
|
+
export declare function settingsManifestWithRecentActivity(manifest: ModuleManifest, recentActivity: ModuleRecentActivity | undefined): ModuleSettingsManifest | undefined;
|
|
1383
|
+
/**
|
|
1384
|
+
* The two properties of a module-registry entry the boot settings reconcile
|
|
1385
|
+
* reads — see {@link SettingsManifestCollectionPort}.
|
|
1386
|
+
*/
|
|
1387
|
+
export interface SettingsManifestSource {
|
|
1388
|
+
readonly manifest: ModuleManifest;
|
|
1389
|
+
/**
|
|
1390
|
+
* The module's recent-activity eligibility (feature 080, T042j / D-163.1).
|
|
1391
|
+
* It implies one Setting — the operator's choice of whether this module's
|
|
1392
|
+
* entries reach the dashboard card — which is derived rather than declared,
|
|
1393
|
+
* so a module that adds the eligibility export gets the control with it.
|
|
1394
|
+
*/
|
|
1395
|
+
readonly recentActivity?: ModuleRecentActivity | undefined;
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Container name: `settingsManifestCollectionPort`. Owner: `settings`.
|
|
1399
|
+
*
|
|
1400
|
+
* The boot-time reconcile's input list, assembled from the module registry the
|
|
1401
|
+
* caller hands in.
|
|
1402
|
+
*
|
|
1403
|
+
* **Two owners, one list, and that is why this is a port.** Which modules a
|
|
1404
|
+
* deployment ships is a composition-root input — core plus this deployment's
|
|
1405
|
+
* overlay modules, never an installed package — so the registry arrives as an
|
|
1406
|
+
* argument. How that registry becomes a reconcile list is `settings`' own rule:
|
|
1407
|
+
* the settings module's manifest goes first, because every other manifest's
|
|
1408
|
+
* entries fall back to its `general` group and the group has to exist before
|
|
1409
|
+
* they are inserted, and each module code appears exactly once. A root that
|
|
1410
|
+
* imported the derivation would be a root that has to be edited when the rule
|
|
1411
|
+
* changes, and there are two of them.
|
|
1412
|
+
*
|
|
1413
|
+
* Nothing is gated on the module axis here on purpose: a module that is
|
|
1414
|
+
* switched off keeps its settings rows and keeps its group on `/settings`,
|
|
1415
|
+
* because a deactivation is not an uninstall (Constitution XVII) and the
|
|
1416
|
+
* operator has to be able to switch it back on.
|
|
1417
|
+
*
|
|
1418
|
+
* **Owner off:** the seam fails closed — resolving this port throws
|
|
1419
|
+
* `ModuleDisabledError`. It is resolved once, at boot, where a throw ends the
|
|
1420
|
+
* process rather than answering a request, which is the ruled-correct
|
|
1421
|
+
* behaviour for a composition that cannot be what the code says it is. Whether
|
|
1422
|
+
* `settings` has an off state at all is its manifest's `activation` to say, not
|
|
1423
|
+
* this line's: a module declaring `nonDeactivatable` never enters one.
|
|
1424
|
+
*/
|
|
1425
|
+
export interface SettingsManifestCollectionPort {
|
|
1426
|
+
collect(registry: ReadonlyArray<SettingsManifestSource>): ModuleSettingsManifest[];
|
|
1427
|
+
}
|
|
1428
|
+
/** Aggregate of what a module's `manifest.ts` may export at runtime. */
|
|
1429
|
+
export interface ModuleManifestExports<EM = unknown, Redis = unknown, Ctx = unknown> {
|
|
1430
|
+
manifest: ModuleManifest;
|
|
1431
|
+
installHook?: ModuleInstallHook<EM, Redis>;
|
|
1432
|
+
uninstallHook?: ModuleUninstallHook<EM, Redis>;
|
|
1433
|
+
/**
|
|
1434
|
+
* This module's interest in every *other* module's lifecycle — see
|
|
1435
|
+
* {@link ModuleLifecycleParticipant}. Additive and optional: the modules that
|
|
1436
|
+
* declare one are the two that keep a projection of the manifest set, and
|
|
1437
|
+
* every other module's `manifest.ts` is unchanged.
|
|
1438
|
+
*/
|
|
1439
|
+
lifecycleParticipant?: ModuleLifecycleParticipant<EM>;
|
|
1440
|
+
/**
|
|
1441
|
+
* The operator commands this module declares — see {@link ModuleCliCommand}.
|
|
1442
|
+
* Additive and optional: a module with no operator command exports nothing
|
|
1443
|
+
* and is unchanged.
|
|
1444
|
+
*/
|
|
1445
|
+
cliCommands?: readonly ModuleCliCommand<Ctx>[];
|
|
1446
|
+
/**
|
|
1447
|
+
* This module's declaration that its activity is eligible for the admin home
|
|
1448
|
+
* dashboard's recent-activity card — see {@link ModuleRecentActivitySchema}.
|
|
1449
|
+
* Additive and optional: a module that declares none contributes no token,
|
|
1450
|
+
* owns no visibility Setting and is unchanged.
|
|
1451
|
+
*/
|
|
1452
|
+
recentActivity?: ModuleRecentActivity;
|
|
1453
|
+
}
|
|
1454
|
+
export declare const RegistryStateSchema: z.ZodEnum<{
|
|
1455
|
+
installing: "installing";
|
|
1456
|
+
installed: "installed";
|
|
1457
|
+
disabled: "disabled";
|
|
1458
|
+
uninstalled: "uninstalled";
|
|
1459
|
+
}>;
|
|
1460
|
+
export type RegistryState = z.infer<typeof RegistryStateSchema>;
|
|
1461
|
+
/** Persisted shape of a row in `module_registrations` (admin HTTP DTO). */
|
|
1462
|
+
export declare const ModuleRegistryRecordSchema: z.ZodObject<{
|
|
1463
|
+
moduleId: z.ZodString;
|
|
1464
|
+
state: z.ZodEnum<{
|
|
1465
|
+
installing: "installing";
|
|
1466
|
+
installed: "installed";
|
|
1467
|
+
disabled: "disabled";
|
|
1468
|
+
uninstalled: "uninstalled";
|
|
1469
|
+
}>;
|
|
1470
|
+
version: z.ZodString;
|
|
1471
|
+
installedAt: z.ZodISODateTime;
|
|
1472
|
+
lastStateChangeAt: z.ZodISODateTime;
|
|
1473
|
+
lastInstallFailedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
1474
|
+
lastInstallError: z.ZodNullable<z.ZodString>;
|
|
1475
|
+
}, z.core.$strip>;
|
|
1476
|
+
export type ModuleRegistryRecord = z.infer<typeof ModuleRegistryRecordSchema>;
|
|
1477
|
+
export declare const ModuleListItemFlagSchema: z.ZodEnum<{
|
|
1478
|
+
orphan: "orphan";
|
|
1479
|
+
"pending-upgrade": "pending-upgrade";
|
|
1480
|
+
"dep-missing": "dep-missing";
|
|
1481
|
+
"dep-disabled": "dep-disabled";
|
|
1482
|
+
}>;
|
|
1483
|
+
export type ModuleListItemFlag = z.infer<typeof ModuleListItemFlagSchema>;
|
|
1484
|
+
export declare const ModuleListItemStateSchema: z.ZodEnum<{
|
|
1485
|
+
installing: "installing";
|
|
1486
|
+
installed: "installed";
|
|
1487
|
+
disabled: "disabled";
|
|
1488
|
+
uninstalled: "uninstalled";
|
|
1489
|
+
"not-installed": "not-installed";
|
|
1490
|
+
}>;
|
|
1491
|
+
export declare const ModuleListItemSchema: z.ZodObject<{
|
|
1492
|
+
id: z.ZodString;
|
|
1493
|
+
name: z.ZodString;
|
|
1494
|
+
description: z.ZodNullable<z.ZodString>;
|
|
1495
|
+
version: z.ZodObject<{
|
|
1496
|
+
registered: z.ZodNullable<z.ZodString>;
|
|
1497
|
+
onDisk: z.ZodNullable<z.ZodString>;
|
|
1498
|
+
}, z.core.$strip>;
|
|
1499
|
+
state: z.ZodEnum<{
|
|
1500
|
+
installing: "installing";
|
|
1501
|
+
installed: "installed";
|
|
1502
|
+
disabled: "disabled";
|
|
1503
|
+
uninstalled: "uninstalled";
|
|
1504
|
+
"not-installed": "not-installed";
|
|
1505
|
+
}>;
|
|
1506
|
+
dependencies: z.ZodArray<z.ZodString>;
|
|
1507
|
+
flags: z.ZodArray<z.ZodEnum<{
|
|
1508
|
+
orphan: "orphan";
|
|
1509
|
+
"pending-upgrade": "pending-upgrade";
|
|
1510
|
+
"dep-missing": "dep-missing";
|
|
1511
|
+
"dep-disabled": "dep-disabled";
|
|
1512
|
+
}>>;
|
|
1513
|
+
installedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
1514
|
+
lastStateChangeAt: z.ZodNullable<z.ZodISODateTime>;
|
|
1515
|
+
}, z.core.$strip>;
|
|
1516
|
+
export type ModuleListItem = z.infer<typeof ModuleListItemSchema>;
|
|
1517
|
+
export declare const ModuleListResponseSchema: z.ZodObject<{
|
|
1518
|
+
modules: z.ZodArray<z.ZodObject<{
|
|
1519
|
+
id: z.ZodString;
|
|
1520
|
+
name: z.ZodString;
|
|
1521
|
+
description: z.ZodNullable<z.ZodString>;
|
|
1522
|
+
version: z.ZodObject<{
|
|
1523
|
+
registered: z.ZodNullable<z.ZodString>;
|
|
1524
|
+
onDisk: z.ZodNullable<z.ZodString>;
|
|
1525
|
+
}, z.core.$strip>;
|
|
1526
|
+
state: z.ZodEnum<{
|
|
1527
|
+
installing: "installing";
|
|
1528
|
+
installed: "installed";
|
|
1529
|
+
disabled: "disabled";
|
|
1530
|
+
uninstalled: "uninstalled";
|
|
1531
|
+
"not-installed": "not-installed";
|
|
1532
|
+
}>;
|
|
1533
|
+
dependencies: z.ZodArray<z.ZodString>;
|
|
1534
|
+
flags: z.ZodArray<z.ZodEnum<{
|
|
1535
|
+
orphan: "orphan";
|
|
1536
|
+
"pending-upgrade": "pending-upgrade";
|
|
1537
|
+
"dep-missing": "dep-missing";
|
|
1538
|
+
"dep-disabled": "dep-disabled";
|
|
1539
|
+
}>>;
|
|
1540
|
+
installedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
1541
|
+
lastStateChangeAt: z.ZodNullable<z.ZodISODateTime>;
|
|
1542
|
+
}, z.core.$strip>>;
|
|
1543
|
+
}, z.core.$strip>;
|
|
1544
|
+
export type ModuleListResponse = z.infer<typeof ModuleListResponseSchema>;
|
|
1545
|
+
export declare const ModuleListQuerySchema: z.ZodObject<{
|
|
1546
|
+
state: z.ZodOptional<z.ZodEnum<{
|
|
1547
|
+
installing: "installing";
|
|
1548
|
+
installed: "installed";
|
|
1549
|
+
disabled: "disabled";
|
|
1550
|
+
uninstalled: "uninstalled";
|
|
1551
|
+
}>>;
|
|
1552
|
+
flag: z.ZodOptional<z.ZodEnum<{
|
|
1553
|
+
orphan: "orphan";
|
|
1554
|
+
"pending-upgrade": "pending-upgrade";
|
|
1555
|
+
}>>;
|
|
1556
|
+
}, z.core.$strip>;
|
|
1557
|
+
export type ModuleListQuery = z.infer<typeof ModuleListQuerySchema>;
|
|
1558
|
+
/**
|
|
1559
|
+
* One module's presence as the server computed it. `present` is the
|
|
1560
|
+
* conjunction of the two axes, precomputed server-side: neither frontend
|
|
1561
|
+
* recombines them, which is what makes "off means absent" one decision rather
|
|
1562
|
+
* than two implementations that can disagree.
|
|
1563
|
+
*
|
|
1564
|
+
* The axes stay separately visible because Constitution XVII requires the
|
|
1565
|
+
* Admin UI to render them differently — *installed but switched off* shows an
|
|
1566
|
+
* actionable control, *not available at platform level* shows absent or
|
|
1567
|
+
* blocked-with-a-reason.
|
|
1568
|
+
*/
|
|
1569
|
+
export declare const ModulePresenceSchema: z.ZodObject<{
|
|
1570
|
+
id: z.ZodString;
|
|
1571
|
+
present: z.ZodBoolean;
|
|
1572
|
+
platformState: z.ZodUnion<[z.ZodEnum<{
|
|
1573
|
+
installing: "installing";
|
|
1574
|
+
installed: "installed";
|
|
1575
|
+
disabled: "disabled";
|
|
1576
|
+
uninstalled: "uninstalled";
|
|
1577
|
+
}>, z.ZodLiteral<"not-installed">]>;
|
|
1578
|
+
activated: z.ZodBoolean;
|
|
1579
|
+
deactivatable: z.ZodBoolean;
|
|
1580
|
+
nonDeactivatableReason: z.ZodNullable<z.ZodString>;
|
|
1581
|
+
}, z.core.$strip>;
|
|
1582
|
+
export type ModulePresence = z.infer<typeof ModulePresenceSchema>;
|
|
1583
|
+
/** `GET /api/v1/admin/module-presence` — every admin, no permission code. */
|
|
1584
|
+
export declare const AdminModulePresenceResponseSchema: z.ZodObject<{
|
|
1585
|
+
modules: z.ZodArray<z.ZodObject<{
|
|
1586
|
+
id: z.ZodString;
|
|
1587
|
+
present: z.ZodBoolean;
|
|
1588
|
+
platformState: z.ZodUnion<[z.ZodEnum<{
|
|
1589
|
+
installing: "installing";
|
|
1590
|
+
installed: "installed";
|
|
1591
|
+
disabled: "disabled";
|
|
1592
|
+
uninstalled: "uninstalled";
|
|
1593
|
+
}>, z.ZodLiteral<"not-installed">]>;
|
|
1594
|
+
activated: z.ZodBoolean;
|
|
1595
|
+
deactivatable: z.ZodBoolean;
|
|
1596
|
+
nonDeactivatableReason: z.ZodNullable<z.ZodString>;
|
|
1597
|
+
}, z.core.$strip>>;
|
|
1598
|
+
degraded: z.ZodBoolean;
|
|
1599
|
+
}, z.core.$strip>;
|
|
1600
|
+
export type AdminModulePresenceResponse = z.infer<typeof AdminModulePresenceResponseSchema>;
|
|
1601
|
+
/** The storefront needs no axis detail — only whether to render at all. */
|
|
1602
|
+
export declare const StorefrontModulePresenceSchema: z.ZodObject<{
|
|
1603
|
+
id: z.ZodString;
|
|
1604
|
+
present: z.ZodBoolean;
|
|
1605
|
+
}, z.core.$strip>;
|
|
1606
|
+
export type StorefrontModulePresence = z.infer<typeof StorefrontModulePresenceSchema>;
|
|
1607
|
+
/** `GET /api/v1/storefront/module-presence` — public, tag `modules:presence`. */
|
|
1608
|
+
export declare const StorefrontModulePresenceResponseSchema: z.ZodObject<{
|
|
1609
|
+
modules: z.ZodArray<z.ZodObject<{
|
|
1610
|
+
id: z.ZodString;
|
|
1611
|
+
present: z.ZodBoolean;
|
|
1612
|
+
}, z.core.$strip>>;
|
|
1613
|
+
}, z.core.$strip>;
|
|
1614
|
+
export type StorefrontModulePresenceResponse = z.infer<typeof StorefrontModulePresenceResponseSchema>;
|
|
1615
|
+
/**
|
|
1616
|
+
* `POST /api/v1/admin/modules/:id/activation` — the operator axis, and the
|
|
1617
|
+
* only door to it. The ordinary settings write path refuses an activation
|
|
1618
|
+
* code, so this endpoint's audited Command is where every flip is recorded.
|
|
1619
|
+
*/
|
|
1620
|
+
export declare const ModuleActivationRequestSchema: z.ZodObject<{
|
|
1621
|
+
active: z.ZodBoolean;
|
|
1622
|
+
}, z.core.$strip>;
|
|
1623
|
+
export type ModuleActivationRequest = z.infer<typeof ModuleActivationRequestSchema>;
|
|
1624
|
+
/** The module's presence *after* the flip, so no client recomputes it. */
|
|
1625
|
+
export declare const ModuleActivationResponseSchema: z.ZodObject<{
|
|
1626
|
+
module: z.ZodObject<{
|
|
1627
|
+
id: z.ZodString;
|
|
1628
|
+
present: z.ZodBoolean;
|
|
1629
|
+
platformState: z.ZodUnion<[z.ZodEnum<{
|
|
1630
|
+
installing: "installing";
|
|
1631
|
+
installed: "installed";
|
|
1632
|
+
disabled: "disabled";
|
|
1633
|
+
uninstalled: "uninstalled";
|
|
1634
|
+
}>, z.ZodLiteral<"not-installed">]>;
|
|
1635
|
+
activated: z.ZodBoolean;
|
|
1636
|
+
deactivatable: z.ZodBoolean;
|
|
1637
|
+
nonDeactivatableReason: z.ZodNullable<z.ZodString>;
|
|
1638
|
+
}, z.core.$strip>;
|
|
1639
|
+
}, z.core.$strip>;
|
|
1640
|
+
export type ModuleActivationResponse = z.infer<typeof ModuleActivationResponseSchema>;
|
|
1641
|
+
/**
|
|
1642
|
+
* `GET /api/v1/admin/modules/:id/deactivation-impact` — the live half of the
|
|
1643
|
+
* confirmation an operator is shown before switching a module off.
|
|
1644
|
+
*
|
|
1645
|
+
* Feature 074's consequence rows are **static**: one sentence per present
|
|
1646
|
+
* dependent, taken from that dependent's `whenAbsent` declaration, so the
|
|
1647
|
+
* dialog can be rendered from the ledger with no database read. This response
|
|
1648
|
+
* carries the facts that only a live read can answer, and today there is
|
|
1649
|
+
* exactly one — how many people hold a second factor (the owner's ruling on
|
|
1650
|
+
* D-96.5).
|
|
1651
|
+
*
|
|
1652
|
+
* Three properties of the shape, each deliberate:
|
|
1653
|
+
*
|
|
1654
|
+
* - **Named after the fact, not after the module.** `mfa` owns the table and
|
|
1655
|
+
* answers the question through a port; the wire shape says what the number
|
|
1656
|
+
* means. When a second module needs a live datum this becomes a list — one
|
|
1657
|
+
* entry per fact — which is a change to make when there are two, not now
|
|
1658
|
+
* (Constitution IV).
|
|
1659
|
+
* - **Nullable, always.** `null` means "not available", not "zero": the module
|
|
1660
|
+
* is already off, or the read failed. A count that cannot be fetched must
|
|
1661
|
+
* never stop an operator switching a module off, so the caller renders the
|
|
1662
|
+
* rest of the dialog and says the number is unavailable.
|
|
1663
|
+
* - **Read while the module is still on.** The dialog precedes the flip, so
|
|
1664
|
+
* the gate on the owning port is open when the question is asked. That is
|
|
1665
|
+
* what makes a live count implementable at all — see `MfaEnrolmentCountPort`.
|
|
1666
|
+
*/
|
|
1667
|
+
export declare const ModuleDeactivationImpactSchema: z.ZodObject<{
|
|
1668
|
+
moduleId: z.ZodString;
|
|
1669
|
+
activeSecondFactorUsers: z.ZodNullable<z.ZodObject<{
|
|
1670
|
+
admins: z.ZodNumber;
|
|
1671
|
+
customers: z.ZodNumber;
|
|
1672
|
+
}, z.core.$strip>>;
|
|
1673
|
+
}, z.core.$strip>;
|
|
1674
|
+
export type ModuleDeactivationImpact = z.infer<typeof ModuleDeactivationImpactSchema>;
|
|
1675
|
+
/**
|
|
1676
|
+
* One row of the interceptor execution plan served by
|
|
1677
|
+
* `GET /api/v1/admin/api-interceptors`. Items are sorted in execution order:
|
|
1678
|
+
* target, then phase (pre before post), then order + (module, id) tie-break.
|
|
1679
|
+
*/
|
|
1680
|
+
export declare const apiInterceptorEntrySchema: z.ZodObject<{
|
|
1681
|
+
target: z.ZodString;
|
|
1682
|
+
phase: z.ZodEnum<{
|
|
1683
|
+
pre: "pre";
|
|
1684
|
+
post: "post";
|
|
1685
|
+
}>;
|
|
1686
|
+
order: z.ZodNumber;
|
|
1687
|
+
module: z.ZodString;
|
|
1688
|
+
id: z.ZodString;
|
|
1689
|
+
moduleEnabled: z.ZodBoolean;
|
|
1690
|
+
}, z.core.$strip>;
|
|
1691
|
+
export type ApiInterceptorEntry = z.infer<typeof apiInterceptorEntrySchema>;
|
|
1692
|
+
export declare const apiInterceptorListSchema: z.ZodObject<{
|
|
1693
|
+
items: z.ZodArray<z.ZodObject<{
|
|
1694
|
+
target: z.ZodString;
|
|
1695
|
+
phase: z.ZodEnum<{
|
|
1696
|
+
pre: "pre";
|
|
1697
|
+
post: "post";
|
|
1698
|
+
}>;
|
|
1699
|
+
order: z.ZodNumber;
|
|
1700
|
+
module: z.ZodString;
|
|
1701
|
+
id: z.ZodString;
|
|
1702
|
+
moduleEnabled: z.ZodBoolean;
|
|
1703
|
+
}, z.core.$strip>>;
|
|
1704
|
+
}, z.core.$strip>;
|
|
1705
|
+
export type ApiInterceptorList = z.infer<typeof apiInterceptorListSchema>;
|
|
1706
|
+
//# sourceMappingURL=modules.d.ts.map
|