@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.
Files changed (327) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -0
  3. package/dist/actor.d.ts +79 -0
  4. package/dist/actor.d.ts.map +1 -0
  5. package/dist/actor.js +41 -0
  6. package/dist/actor.js.map +1 -0
  7. package/dist/addresses.d.ts +134 -0
  8. package/dist/addresses.d.ts.map +1 -0
  9. package/dist/addresses.js +16 -0
  10. package/dist/addresses.js.map +1 -0
  11. package/dist/admin-actions.d.ts +367 -0
  12. package/dist/admin-actions.d.ts.map +1 -0
  13. package/dist/admin-actions.js +287 -0
  14. package/dist/admin-actions.js.map +1 -0
  15. package/dist/admin-contributions.d.ts +518 -0
  16. package/dist/admin-contributions.d.ts.map +1 -0
  17. package/dist/admin-contributions.js +495 -0
  18. package/dist/admin-contributions.js.map +1 -0
  19. package/dist/admin-i18n.d.ts +135 -0
  20. package/dist/admin-i18n.d.ts.map +1 -0
  21. package/dist/admin-i18n.js +72 -0
  22. package/dist/admin-i18n.js.map +1 -0
  23. package/dist/admin-notifications.d.ts +55 -0
  24. package/dist/admin-notifications.d.ts.map +1 -0
  25. package/dist/admin-notifications.js +16 -0
  26. package/dist/admin-notifications.js.map +1 -0
  27. package/dist/admin-roles.d.ts +125 -0
  28. package/dist/admin-roles.d.ts.map +1 -0
  29. package/dist/admin-roles.js +2 -0
  30. package/dist/admin-roles.js.map +1 -0
  31. package/dist/admin-users.d.ts +178 -0
  32. package/dist/admin-users.d.ts.map +1 -0
  33. package/dist/admin-users.js +14 -0
  34. package/dist/admin-users.js.map +1 -0
  35. package/dist/admin.d.ts +243 -0
  36. package/dist/admin.d.ts.map +1 -0
  37. package/dist/admin.js +246 -0
  38. package/dist/admin.js.map +1 -0
  39. package/dist/analytics.d.ts +123 -0
  40. package/dist/analytics.d.ts.map +1 -0
  41. package/dist/analytics.js +68 -0
  42. package/dist/analytics.js.map +1 -0
  43. package/dist/api-keys.d.ts +97 -0
  44. package/dist/api-keys.d.ts.map +1 -0
  45. package/dist/api-keys.js +64 -0
  46. package/dist/api-keys.js.map +1 -0
  47. package/dist/assets-library.d.ts +684 -0
  48. package/dist/assets-library.d.ts.map +1 -0
  49. package/dist/assets-library.js +181 -0
  50. package/dist/assets-library.js.map +1 -0
  51. package/dist/audit-logs.d.ts +141 -0
  52. package/dist/audit-logs.d.ts.map +1 -0
  53. package/dist/audit-logs.js +31 -0
  54. package/dist/audit-logs.js.map +1 -0
  55. package/dist/auth.d.ts +174 -0
  56. package/dist/auth.d.ts.map +1 -0
  57. package/dist/auth.js +27 -0
  58. package/dist/auth.js.map +1 -0
  59. package/dist/blog.d.ts +669 -0
  60. package/dist/blog.d.ts.map +1 -0
  61. package/dist/blog.js +360 -0
  62. package/dist/blog.js.map +1 -0
  63. package/dist/capabilities.d.ts +40 -0
  64. package/dist/capabilities.d.ts.map +1 -0
  65. package/dist/capabilities.js +38 -0
  66. package/dist/capabilities.js.map +1 -0
  67. package/dist/carts.d.ts +1367 -0
  68. package/dist/carts.d.ts.map +1 -0
  69. package/dist/carts.js +405 -0
  70. package/dist/carts.js.map +1 -0
  71. package/dist/catalog.d.ts +2855 -0
  72. package/dist/catalog.d.ts.map +1 -0
  73. package/dist/catalog.js +1543 -0
  74. package/dist/catalog.js.map +1 -0
  75. package/dist/cms.d.ts +872 -0
  76. package/dist/cms.d.ts.map +1 -0
  77. package/dist/cms.js +468 -0
  78. package/dist/cms.js.map +1 -0
  79. package/dist/common.d.ts +82 -0
  80. package/dist/common.d.ts.map +1 -0
  81. package/dist/common.js +72 -0
  82. package/dist/common.js.map +1 -0
  83. package/dist/comparisons.d.ts +487 -0
  84. package/dist/comparisons.d.ts.map +1 -0
  85. package/dist/comparisons.js +221 -0
  86. package/dist/comparisons.js.map +1 -0
  87. package/dist/credentials.d.ts +292 -0
  88. package/dist/credentials.d.ts.map +1 -0
  89. package/dist/credentials.js +142 -0
  90. package/dist/credentials.js.map +1 -0
  91. package/dist/credit-limits.d.ts +111 -0
  92. package/dist/credit-limits.d.ts.map +1 -0
  93. package/dist/credit-limits.js +35 -0
  94. package/dist/credit-limits.js.map +1 -0
  95. package/dist/currencies.d.ts +127 -0
  96. package/dist/currencies.d.ts.map +1 -0
  97. package/dist/currencies.js +20 -0
  98. package/dist/currencies.js.map +1 -0
  99. package/dist/custom-fields.d.ts +345 -0
  100. package/dist/custom-fields.d.ts.map +1 -0
  101. package/dist/custom-fields.js +185 -0
  102. package/dist/custom-fields.js.map +1 -0
  103. package/dist/customer-accounts.d.ts +690 -0
  104. package/dist/customer-accounts.d.ts.map +1 -0
  105. package/dist/customer-accounts.js +41 -0
  106. package/dist/customer-accounts.js.map +1 -0
  107. package/dist/customers.d.ts +305 -0
  108. package/dist/customers.d.ts.map +1 -0
  109. package/dist/customers.js +158 -0
  110. package/dist/customers.js.map +1 -0
  111. package/dist/dictionary.d.ts +580 -0
  112. package/dist/dictionary.d.ts.map +1 -0
  113. package/dist/dictionary.js +297 -0
  114. package/dist/dictionary.js.map +1 -0
  115. package/dist/email-address.d.ts +62 -0
  116. package/dist/email-address.d.ts.map +1 -0
  117. package/dist/email-address.js +64 -0
  118. package/dist/email-address.js.map +1 -0
  119. package/dist/email.d.ts +175 -0
  120. package/dist/email.d.ts.map +1 -0
  121. package/dist/email.js +45 -0
  122. package/dist/email.js.map +1 -0
  123. package/dist/envelopes.d.ts +15 -0
  124. package/dist/envelopes.d.ts.map +1 -0
  125. package/dist/envelopes.js +16 -0
  126. package/dist/envelopes.js.map +1 -0
  127. package/dist/environment-inputs.d.ts +306 -0
  128. package/dist/environment-inputs.d.ts.map +1 -0
  129. package/dist/environment-inputs.js +277 -0
  130. package/dist/environment-inputs.js.map +1 -0
  131. package/dist/erp-connector.d.ts +52 -0
  132. package/dist/erp-connector.d.ts.map +1 -0
  133. package/dist/erp-connector.js +34 -0
  134. package/dist/erp-connector.js.map +1 -0
  135. package/dist/errors.d.ts +455 -0
  136. package/dist/errors.d.ts.map +1 -0
  137. package/dist/errors.js +532 -0
  138. package/dist/errors.js.map +1 -0
  139. package/dist/google-analytics.d.ts +181 -0
  140. package/dist/google-analytics.d.ts.map +1 -0
  141. package/dist/google-analytics.js +176 -0
  142. package/dist/google-analytics.js.map +1 -0
  143. package/dist/google-tag-manager.d.ts +111 -0
  144. package/dist/google-tag-manager.d.ts.map +1 -0
  145. package/dist/google-tag-manager.js +129 -0
  146. package/dist/google-tag-manager.js.map +1 -0
  147. package/dist/i18n.d.ts +69 -0
  148. package/dist/i18n.d.ts.map +1 -0
  149. package/dist/i18n.js +59 -0
  150. package/dist/i18n.js.map +1 -0
  151. package/dist/import-export.d.ts +63 -0
  152. package/dist/import-export.d.ts.map +1 -0
  153. package/dist/import-export.js +37 -0
  154. package/dist/import-export.js.map +1 -0
  155. package/dist/index.d.ts +82 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +126 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/inventory.d.ts +673 -0
  160. package/dist/inventory.d.ts.map +1 -0
  161. package/dist/inventory.js +412 -0
  162. package/dist/inventory.js.map +1 -0
  163. package/dist/invoice-ledger.d.ts +366 -0
  164. package/dist/invoice-ledger.d.ts.map +1 -0
  165. package/dist/invoice-ledger.js +114 -0
  166. package/dist/invoice-ledger.js.map +1 -0
  167. package/dist/invoices.d.ts +845 -0
  168. package/dist/invoices.d.ts.map +1 -0
  169. package/dist/invoices.js +314 -0
  170. package/dist/invoices.js.map +1 -0
  171. package/dist/kernel.d.ts +49 -0
  172. package/dist/kernel.d.ts.map +1 -0
  173. package/dist/kernel.js +19 -0
  174. package/dist/kernel.js.map +1 -0
  175. package/dist/languages.d.ts +122 -0
  176. package/dist/languages.d.ts.map +1 -0
  177. package/dist/languages.js +24 -0
  178. package/dist/languages.js.map +1 -0
  179. package/dist/linkedin-ads.d.ts +167 -0
  180. package/dist/linkedin-ads.d.ts.map +1 -0
  181. package/dist/linkedin-ads.js +156 -0
  182. package/dist/linkedin-ads.js.map +1 -0
  183. package/dist/megamenu.d.ts +556 -0
  184. package/dist/megamenu.d.ts.map +1 -0
  185. package/dist/megamenu.js +186 -0
  186. package/dist/megamenu.js.map +1 -0
  187. package/dist/meta-ads.d.ts +126 -0
  188. package/dist/meta-ads.d.ts.map +1 -0
  189. package/dist/meta-ads.js +112 -0
  190. package/dist/meta-ads.js.map +1 -0
  191. package/dist/mfa.d.ts +274 -0
  192. package/dist/mfa.d.ts.map +1 -0
  193. package/dist/mfa.js +187 -0
  194. package/dist/mfa.js.map +1 -0
  195. package/dist/modules.d.ts +1706 -0
  196. package/dist/modules.d.ts.map +1 -0
  197. package/dist/modules.js +1390 -0
  198. package/dist/modules.js.map +1 -0
  199. package/dist/newsletter.d.ts +611 -0
  200. package/dist/newsletter.d.ts.map +1 -0
  201. package/dist/newsletter.js +345 -0
  202. package/dist/newsletter.js.map +1 -0
  203. package/dist/orders.d.ts +1175 -0
  204. package/dist/orders.d.ts.map +1 -0
  205. package/dist/orders.js +630 -0
  206. package/dist/orders.js.map +1 -0
  207. package/dist/organizations.d.ts +938 -0
  208. package/dist/organizations.d.ts.map +1 -0
  209. package/dist/organizations.js +418 -0
  210. package/dist/organizations.js.map +1 -0
  211. package/dist/pagination.d.ts +21 -0
  212. package/dist/pagination.d.ts.map +1 -0
  213. package/dist/pagination.js +22 -0
  214. package/dist/pagination.js.map +1 -0
  215. package/dist/payment-methods.d.ts +472 -0
  216. package/dist/payment-methods.d.ts.map +1 -0
  217. package/dist/payment-methods.js +175 -0
  218. package/dist/payment-methods.js.map +1 -0
  219. package/dist/payment-return-url.d.ts +53 -0
  220. package/dist/payment-return-url.d.ts.map +1 -0
  221. package/dist/payment-return-url.js +35 -0
  222. package/dist/payment-return-url.js.map +1 -0
  223. package/dist/payments.d.ts +386 -0
  224. package/dist/payments.d.ts.map +1 -0
  225. package/dist/payments.js +84 -0
  226. package/dist/payments.js.map +1 -0
  227. package/dist/pim-connector.d.ts +60 -0
  228. package/dist/pim-connector.d.ts.map +1 -0
  229. package/dist/pim-connector.js +43 -0
  230. package/dist/pim-connector.js.map +1 -0
  231. package/dist/pim-field-path.d.ts +6 -0
  232. package/dist/pim-field-path.d.ts.map +1 -0
  233. package/dist/pim-field-path.js +101 -0
  234. package/dist/pim-field-path.js.map +1 -0
  235. package/dist/platform-language.d.ts +20 -0
  236. package/dist/platform-language.d.ts.map +1 -0
  237. package/dist/platform-language.js +22 -0
  238. package/dist/platform-language.js.map +1 -0
  239. package/dist/price-lists.d.ts +685 -0
  240. package/dist/price-lists.d.ts.map +1 -0
  241. package/dist/price-lists.js +330 -0
  242. package/dist/price-lists.js.map +1 -0
  243. package/dist/product-feeds.d.ts +2837 -0
  244. package/dist/product-feeds.d.ts.map +1 -0
  245. package/dist/product-feeds.js +1504 -0
  246. package/dist/product-feeds.js.map +1 -0
  247. package/dist/product-scope-overrides.d.ts +134 -0
  248. package/dist/product-scope-overrides.d.ts.map +1 -0
  249. package/dist/product-scope-overrides.js +82 -0
  250. package/dist/product-scope-overrides.js.map +1 -0
  251. package/dist/product-value-resolver.d.ts +88 -0
  252. package/dist/product-value-resolver.d.ts.map +1 -0
  253. package/dist/product-value-resolver.js +128 -0
  254. package/dist/product-value-resolver.js.map +1 -0
  255. package/dist/promotions.d.ts +678 -0
  256. package/dist/promotions.d.ts.map +1 -0
  257. package/dist/promotions.js +479 -0
  258. package/dist/promotions.js.map +1 -0
  259. package/dist/prompt-actions.d.ts +582 -0
  260. package/dist/prompt-actions.d.ts.map +1 -0
  261. package/dist/prompt-actions.js +221 -0
  262. package/dist/prompt-actions.js.map +1 -0
  263. package/dist/pwa.d.ts +293 -0
  264. package/dist/pwa.d.ts.map +1 -0
  265. package/dist/pwa.js +204 -0
  266. package/dist/pwa.js.map +1 -0
  267. package/dist/quick-order.d.ts +340 -0
  268. package/dist/quick-order.d.ts.map +1 -0
  269. package/dist/quick-order.js +177 -0
  270. package/dist/quick-order.js.map +1 -0
  271. package/dist/quote-requests.d.ts +538 -0
  272. package/dist/quote-requests.d.ts.map +1 -0
  273. package/dist/quote-requests.js +308 -0
  274. package/dist/quote-requests.js.map +1 -0
  275. package/dist/returns.d.ts +774 -0
  276. package/dist/returns.d.ts.map +1 -0
  277. package/dist/returns.js +389 -0
  278. package/dist/returns.js.map +1 -0
  279. package/dist/sales-channels.d.ts +392 -0
  280. package/dist/sales-channels.d.ts.map +1 -0
  281. package/dist/sales-channels.js +285 -0
  282. package/dist/sales-channels.js.map +1 -0
  283. package/dist/scope-notice.d.ts +60 -0
  284. package/dist/scope-notice.d.ts.map +1 -0
  285. package/dist/scope-notice.js +56 -0
  286. package/dist/scope-notice.js.map +1 -0
  287. package/dist/search.d.ts +321 -0
  288. package/dist/search.d.ts.map +1 -0
  289. package/dist/search.js +160 -0
  290. package/dist/search.js.map +1 -0
  291. package/dist/seo.d.ts +113 -0
  292. package/dist/seo.d.ts.map +1 -0
  293. package/dist/seo.js +63 -0
  294. package/dist/seo.js.map +1 -0
  295. package/dist/settings.d.ts +453 -0
  296. package/dist/settings.d.ts.map +1 -0
  297. package/dist/settings.js +337 -0
  298. package/dist/settings.js.map +1 -0
  299. package/dist/shipments.d.ts +140 -0
  300. package/dist/shipments.d.ts.map +1 -0
  301. package/dist/shipments.js +14 -0
  302. package/dist/shipments.js.map +1 -0
  303. package/dist/shipping-methods.d.ts +350 -0
  304. package/dist/shipping-methods.d.ts.map +1 -0
  305. package/dist/shipping-methods.js +99 -0
  306. package/dist/shipping-methods.js.map +1 -0
  307. package/dist/shopping-lists.d.ts +122 -0
  308. package/dist/shopping-lists.d.ts.map +1 -0
  309. package/dist/shopping-lists.js +92 -0
  310. package/dist/shopping-lists.js.map +1 -0
  311. package/dist/taxes.d.ts +106 -0
  312. package/dist/taxes.d.ts.map +1 -0
  313. package/dist/taxes.js +80 -0
  314. package/dist/taxes.js.map +1 -0
  315. package/dist/text-normalization.d.ts +199 -0
  316. package/dist/text-normalization.d.ts.map +1 -0
  317. package/dist/text-normalization.js +205 -0
  318. package/dist/text-normalization.js.map +1 -0
  319. package/dist/transactional-emails.d.ts +459 -0
  320. package/dist/transactional-emails.d.ts.map +1 -0
  321. package/dist/transactional-emails.js +212 -0
  322. package/dist/transactional-emails.js.map +1 -0
  323. package/dist/webhooks.d.ts +69 -0
  324. package/dist/webhooks.d.ts.map +1 -0
  325. package/dist/webhooks.js +53 -0
  326. package/dist/webhooks.js.map +1 -0
  327. 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