@open-mercato/shared 0.6.7-develop.6860.1.f796b22e80 → 0.6.7

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 (199) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +6 -57
  3. package/build.mjs +4 -2
  4. package/dist/lib/auth/server.js +2 -15
  5. package/dist/lib/auth/server.js.map +2 -2
  6. package/dist/lib/bootstrap/dynamicLoader.js +43 -117
  7. package/dist/lib/bootstrap/dynamicLoader.js.map +2 -2
  8. package/dist/lib/commands/command-bus.js +1 -5
  9. package/dist/lib/commands/command-bus.js.map +2 -2
  10. package/dist/lib/commands/command-interceptor-runner.js +2 -2
  11. package/dist/lib/commands/command-interceptor-runner.js.map +2 -2
  12. package/dist/lib/crud/enricher-runner.js +11 -2
  13. package/dist/lib/crud/enricher-runner.js.map +2 -2
  14. package/dist/lib/crud/factory.js +4 -63
  15. package/dist/lib/crud/factory.js.map +2 -2
  16. package/dist/lib/crud/interceptor-runner.js +2 -2
  17. package/dist/lib/crud/interceptor-runner.js.map +2 -2
  18. package/dist/lib/crud/mutation-guard-registry.js +2 -2
  19. package/dist/lib/crud/mutation-guard-registry.js.map +2 -2
  20. package/dist/lib/crud/types.js +0 -4
  21. package/dist/lib/crud/types.js.map +3 -3
  22. package/dist/lib/data/engine.js +11 -37
  23. package/dist/lib/data/engine.js.map +2 -2
  24. package/dist/lib/db/mikro.js +12 -3
  25. package/dist/lib/db/mikro.js.map +2 -2
  26. package/dist/lib/db/pg-errors.js +0 -42
  27. package/dist/lib/db/pg-errors.js.map +2 -2
  28. package/dist/lib/di/container.js +6 -48
  29. package/dist/lib/di/container.js.map +2 -2
  30. package/dist/lib/email/send.js +0 -56
  31. package/dist/lib/email/send.js.map +2 -2
  32. package/dist/lib/encryption/subscriber.js +10 -2
  33. package/dist/lib/encryption/subscriber.js.map +2 -2
  34. package/dist/lib/encryption/tenantDataEncryptionService.js +17 -52
  35. package/dist/lib/encryption/tenantDataEncryptionService.js.map +2 -2
  36. package/dist/lib/i18n/config.js +1 -1
  37. package/dist/lib/i18n/config.js.map +2 -2
  38. package/dist/lib/i18n/server.js +4 -4
  39. package/dist/lib/i18n/server.js.map +3 -3
  40. package/dist/lib/logger/index.js +3 -47
  41. package/dist/lib/logger/index.js.map +3 -3
  42. package/dist/lib/modules/registry.js +1 -5
  43. package/dist/lib/modules/registry.js.map +2 -2
  44. package/dist/lib/query/engine.js +40 -54
  45. package/dist/lib/query/engine.js.map +2 -2
  46. package/dist/lib/query/types.js.map +1 -1
  47. package/dist/lib/redis/connection.js +2 -7
  48. package/dist/lib/redis/connection.js.map +2 -2
  49. package/dist/lib/search/config.js +2 -61
  50. package/dist/lib/search/config.js.map +2 -2
  51. package/dist/lib/search/tokenize.js +11 -23
  52. package/dist/lib/search/tokenize.js.map +2 -2
  53. package/dist/lib/version.js +1 -1
  54. package/dist/lib/version.js.map +1 -1
  55. package/dist/lib/webhooks/index.js +1 -13
  56. package/dist/lib/webhooks/index.js.map +2 -2
  57. package/dist/lib/webhooks/verify.js +7 -12
  58. package/dist/lib/webhooks/verify.js.map +2 -2
  59. package/dist/modules/analytics.js.map +2 -2
  60. package/dist/modules/overrides.js +1 -50
  61. package/dist/modules/overrides.js.map +2 -2
  62. package/dist/modules/payment_gateways/types.js +1 -8
  63. package/dist/modules/payment_gateways/types.js.map +2 -2
  64. package/dist/modules/registry.js +0 -1
  65. package/dist/modules/registry.js.map +2 -2
  66. package/dist/security/enabledModulesRegistry.js +11 -56
  67. package/dist/security/enabledModulesRegistry.js.map +2 -2
  68. package/jest.config.cjs +1 -2
  69. package/package.json +9 -19
  70. package/src/lib/ai/llm-provider.ts +0 -33
  71. package/src/lib/auth/__tests__/server.test.ts +0 -23
  72. package/src/lib/auth/server.ts +2 -23
  73. package/src/lib/bootstrap/__tests__/dynamicLoader.commandInterceptors.test.ts +8 -63
  74. package/src/lib/bootstrap/__tests__/dynamicLoader.tsconfig.test.ts +1 -21
  75. package/src/lib/bootstrap/dynamicLoader.ts +65 -213
  76. package/src/lib/commands/__tests__/command-interceptor-runner.test.ts +0 -28
  77. package/src/lib/commands/command-bus.ts +1 -5
  78. package/src/lib/commands/command-interceptor-runner.ts +2 -2
  79. package/src/lib/crud/__tests__/crud-factory.test.ts +0 -298
  80. package/src/lib/crud/__tests__/mutation-guard-registry.test.ts +0 -26
  81. package/src/lib/crud/enricher-runner.ts +11 -2
  82. package/src/lib/crud/factory.ts +1 -69
  83. package/src/lib/crud/interceptor-runner.ts +2 -2
  84. package/src/lib/crud/mutation-guard-registry.ts +2 -2
  85. package/src/lib/crud/types.ts +0 -3
  86. package/src/lib/data/__tests__/engine.bulk-suppress.test.ts +3 -18
  87. package/src/lib/data/engine.ts +16 -50
  88. package/src/lib/db/__tests__/mikro.test.ts +25 -0
  89. package/src/lib/db/mikro.ts +38 -13
  90. package/src/lib/db/pg-errors.ts +0 -58
  91. package/src/lib/di/container.ts +8 -72
  92. package/src/lib/email/__tests__/send.test.ts +1 -37
  93. package/src/lib/email/send.ts +0 -79
  94. package/src/lib/encryption/__tests__/subscriber.test.ts +2 -54
  95. package/src/lib/encryption/__tests__/tenantDataEncryptionService.test.ts +0 -58
  96. package/src/lib/encryption/subscriber.ts +14 -2
  97. package/src/lib/encryption/tenantDataEncryptionService.ts +18 -64
  98. package/src/lib/i18n/config.ts +2 -2
  99. package/src/lib/i18n/server.ts +2 -6
  100. package/src/lib/logger/__tests__/logger.test.ts +0 -77
  101. package/src/lib/logger/index.ts +1 -59
  102. package/src/lib/modules/registry.ts +0 -10
  103. package/src/lib/query/__tests__/engine.test.ts +13 -65
  104. package/src/lib/query/engine.ts +58 -75
  105. package/src/lib/query/types.ts +5 -4
  106. package/src/lib/redis/__tests__/connection.test.ts +0 -16
  107. package/src/lib/redis/connection.ts +7 -10
  108. package/src/lib/search/__tests__/config.test.ts +0 -177
  109. package/src/lib/search/config.ts +8 -106
  110. package/src/lib/search/tokenize.ts +11 -33
  111. package/src/lib/webhooks/__tests__/verify.test.ts +1 -20
  112. package/src/lib/webhooks/index.ts +1 -19
  113. package/src/lib/webhooks/verify.ts +9 -17
  114. package/src/modules/__tests__/registry.test.ts +2 -10
  115. package/src/modules/analytics.ts +0 -7
  116. package/src/modules/customer-auth.ts +0 -1
  117. package/src/modules/encryption.ts +0 -3
  118. package/src/modules/navigation/backendChrome.ts +0 -15
  119. package/src/modules/overrides.ts +0 -103
  120. package/src/modules/payment_gateways/types.ts +0 -41
  121. package/src/modules/registry.ts +0 -3
  122. package/src/security/enabledModulesRegistry.ts +12 -64
  123. package/dist/lib/ai/safety-identifier.js +0 -32
  124. package/dist/lib/ai/safety-identifier.js.map +0 -7
  125. package/dist/lib/auth/organizationScope.js +0 -34
  126. package/dist/lib/auth/organizationScope.js.map +0 -7
  127. package/dist/lib/bootstrap/clientOnlyModules.js +0 -55
  128. package/dist/lib/bootstrap/clientOnlyModules.js.map +0 -7
  129. package/dist/lib/data/consistency.js +0 -19
  130. package/dist/lib/data/consistency.js.map +0 -7
  131. package/dist/lib/db/entityMetadata.js +0 -26
  132. package/dist/lib/db/entityMetadata.js.map +0 -7
  133. package/dist/lib/logger/extension.js +0 -29
  134. package/dist/lib/logger/extension.js.map +0 -7
  135. package/dist/lib/modules/surfaceFingerprint.js +0 -47
  136. package/dist/lib/modules/surfaceFingerprint.js.map +0 -7
  137. package/dist/lib/query/ciphertext-search-warning.js +0 -45
  138. package/dist/lib/query/ciphertext-search-warning.js.map +0 -7
  139. package/dist/lib/search/auto-indexing.js +0 -14
  140. package/dist/lib/search/auto-indexing.js.map +0 -7
  141. package/dist/lib/search/availability.js +0 -107
  142. package/dist/lib/search/availability.js.map +0 -7
  143. package/dist/lib/search/tokenLookup.js +0 -46
  144. package/dist/lib/search/tokenLookup.js.map +0 -7
  145. package/dist/lib/telemetry/runtime.js +0 -35
  146. package/dist/lib/telemetry/runtime.js.map +0 -7
  147. package/dist/lib/webhooks/body.js +0 -57
  148. package/dist/lib/webhooks/body.js.map +0 -7
  149. package/dist/lib/webhooks/inbound-types.js +0 -1
  150. package/dist/lib/webhooks/inbound-types.js.map +0 -7
  151. package/dist/modules/widgets/extension-points.js +0 -96
  152. package/dist/modules/widgets/extension-points.js.map +0 -7
  153. package/dist/security/featurePolicy.js +0 -62
  154. package/dist/security/featurePolicy.js.map +0 -7
  155. package/scripts/versionSource.cjs +0 -65
  156. package/src/lib/__tests__/versionSource.test.ts +0 -46
  157. package/src/lib/ai/__tests__/llm-provider-contract.test.ts +0 -59
  158. package/src/lib/ai/__tests__/safety-identifier.test.ts +0 -71
  159. package/src/lib/ai/safety-identifier.ts +0 -73
  160. package/src/lib/auth/__tests__/organizationScope.test.ts +0 -107
  161. package/src/lib/auth/organizationScope.ts +0 -65
  162. package/src/lib/bootstrap/__tests__/clientOnlyModules.test.ts +0 -189
  163. package/src/lib/bootstrap/__tests__/dynamicLoader.aliasResolver.test.ts +0 -98
  164. package/src/lib/bootstrap/__tests__/dynamicLoader.appDi.test.ts +0 -211
  165. package/src/lib/bootstrap/__tests__/dynamicLoader.generatedCacheRecovery.test.ts +0 -192
  166. package/src/lib/bootstrap/clientOnlyModules.ts +0 -85
  167. package/src/lib/crud/__tests__/crud-factory.cache-user-scope.test.ts +0 -171
  168. package/src/lib/data/__tests__/consistency.test.ts +0 -38
  169. package/src/lib/data/consistency.ts +0 -17
  170. package/src/lib/db/__tests__/entityMetadata.test.ts +0 -38
  171. package/src/lib/db/__tests__/pg-errors.test.ts +0 -48
  172. package/src/lib/db/entityMetadata.ts +0 -43
  173. package/src/lib/di/__tests__/container-app-di-absent.test.ts +0 -155
  174. package/src/lib/di/__tests__/container-app-di.test.ts +0 -173
  175. package/src/lib/di/__tests__/registrar-error-log.test.ts +0 -154
  176. package/src/lib/i18n/__tests__/config.test.ts +0 -8
  177. package/src/lib/i18n/__tests__/server-dictionary-cache.test.ts +0 -30
  178. package/src/lib/i18n/__tests__/server-unbootstrapped.test.ts +0 -29
  179. package/src/lib/logger/extension.ts +0 -59
  180. package/src/lib/modules/__tests__/surfaceFingerprint.test.ts +0 -122
  181. package/src/lib/modules/surfaceFingerprint.ts +0 -87
  182. package/src/lib/query/__tests__/ciphertext-search-warning.test.ts +0 -178
  183. package/src/lib/query/ciphertext-search-warning.ts +0 -95
  184. package/src/lib/search/__tests__/availability.test.ts +0 -211
  185. package/src/lib/search/__tests__/tokenLookup.test.ts +0 -206
  186. package/src/lib/search/__tests__/tokenize.test.ts +0 -49
  187. package/src/lib/search/auto-indexing.ts +0 -22
  188. package/src/lib/search/availability.ts +0 -232
  189. package/src/lib/search/tokenLookup.ts +0 -133
  190. package/src/lib/telemetry/runtime.ts +0 -72
  191. package/src/lib/webhooks/__tests__/body.test.ts +0 -95
  192. package/src/lib/webhooks/body.ts +0 -70
  193. package/src/lib/webhooks/inbound-types.ts +0 -125
  194. package/src/modules/__tests__/nav-group-order-override.test.ts +0 -183
  195. package/src/modules/payment_gateways/__tests__/types.test.ts +0 -37
  196. package/src/modules/widgets/__tests__/extension-points.test.ts +0 -101
  197. package/src/modules/widgets/extension-points.ts +0 -524
  198. package/src/security/__tests__/featurePolicy.test.ts +0 -166
  199. package/src/security/featurePolicy.ts +0 -89
@@ -1,125 +0,0 @@
1
- /**
2
- * Inbound webhook handler types (SPEC: 2026-03-23-inbound-webhook-handlers).
3
- *
4
- * These mirror the event-subscriber DX: a module exports `webhook-sources.ts`
5
- * (one or more `WebhookSourceConfig`) and `webhook-handlers/*.ts` files that each
6
- * export `metadata: WebhookHandlerMeta` plus a default handler function.
7
- */
8
-
9
- /** Raw inbound request passed to a source verifier. */
10
- export interface InboundWebhookRequest {
11
- /** Raw request body, required for signature verification. */
12
- body: string
13
- /** Lower-cased request headers. */
14
- headers: Record<string, string>
15
- /** Parsed request body (best-effort JSON). */
16
- parsedBody: Record<string, unknown>
17
- }
18
-
19
- /** Optional descriptor of the credential fields a source needs (drives the admin UI). */
20
- export interface WebhookSourceCredentialField {
21
- key: string
22
- label: string
23
- secret?: boolean
24
- required?: boolean
25
- }
26
-
27
- /**
28
- * Configuration for an external webhook source (e.g. `stripe`, `resend`).
29
- * Declared in a module's `webhook-sources.ts` via the `webhookSources` export.
30
- */
31
- export interface WebhookSourceConfig {
32
- /** Unique source identifier, e.g. `stripe`. Also the inbound path segment. */
33
- key: string
34
- /** Human-readable label. */
35
- label: string
36
- /**
37
- * Verify the authenticity of an inbound webhook.
38
- * Return true if valid, false to reject with 401. Throwing rejects with 400/500.
39
- */
40
- verifier: (
41
- request: InboundWebhookRequest,
42
- credentials: Record<string, string>,
43
- ) => Promise<boolean>
44
- /** Extract the event type from the parsed body/headers. */
45
- eventTypeExtractor: (
46
- body: Record<string, unknown>,
47
- headers: Record<string, string>,
48
- ) => string
49
- /** Extract a unique message id for deduplication. Return undefined if unavailable. */
50
- messageIdExtractor?: (
51
- body: Record<string, unknown>,
52
- headers: Record<string, string>,
53
- ) => string | undefined
54
- /** Optionally derive tenant scope from the payload/headers. */
55
- scopeExtractor?: (
56
- body: Record<string, unknown>,
57
- headers: Record<string, string>,
58
- ) => { tenantId?: string; organizationId?: string }
59
- /** Credential fields this source needs; used by the source-credential admin UI. */
60
- credentialFields?: WebhookSourceCredentialField[]
61
- }
62
-
63
- /** Metadata exported by every `webhook-handlers/*.ts` file. */
64
- export interface WebhookHandlerMeta {
65
- /** Source key this handler listens to, e.g. `stripe`. */
66
- source: string
67
- /** Event-type pattern (supports wildcards: `*`, `payment_intent.*`). */
68
- event: string
69
- /** Unique handler id, e.g. `payments:stripe-payment-succeeded`. */
70
- id: string
71
- /** If true (default), handler runs via the queue-backed dispatcher. */
72
- persistent?: boolean
73
- }
74
-
75
- /** Payload handed to a webhook handler. */
76
- export interface WebhookHandlerPayload {
77
- /** Parsed webhook body. */
78
- data: Record<string, unknown>
79
- /** Extracted event type. */
80
- eventType: string
81
- /** Source key. */
82
- sourceKey: string
83
- /** Selected request headers. */
84
- headers: Record<string, string>
85
- /** WebhookIngestion record id. */
86
- ingestionId: string
87
- /** Tenant scope. */
88
- tenantId: string
89
- organizationId: string
90
- }
91
-
92
- /** DI accessor handed to a webhook handler. */
93
- export interface WebhookHandlerContext {
94
- resolve: <T>(name: string) => T
95
- }
96
-
97
- /** A webhook handler function (default export of a `webhook-handlers/*.ts` file). */
98
- export type WebhookHandler = (
99
- payload: WebhookHandlerPayload,
100
- ctx: WebhookHandlerContext,
101
- ) => Promise<void>
102
-
103
- /** A generated registry entry binding handler metadata to a lazy module loader. */
104
- export interface WebhookHandlerRegistryEntry {
105
- meta: WebhookHandlerMeta
106
- handler: () => Promise<{ default: WebhookHandler }>
107
- }
108
-
109
- /** Per-handler execution detail recorded on a WebhookIngestion. */
110
- export interface WebhookHandlerResult {
111
- handlerId: string
112
- module: string
113
- status: 'success' | 'failed'
114
- errorMessage?: string
115
- durationMs: number
116
- startedAt: string
117
- }
118
-
119
- /** Lifecycle status of an inbound webhook ingestion. */
120
- export type WebhookIngestionStatus =
121
- | 'received'
122
- | 'processing'
123
- | 'processed'
124
- | 'failed'
125
- | 'duplicate'
@@ -1,183 +0,0 @@
1
- /** @jest-environment node */
2
-
3
- // `defaultGroupOrder` in `auth/lib/backendChrome.tsx` ranks any group it lists ahead of any group it
4
- // does not, regardless of an app's own page `priority`/`order` — so a downstream app could not place its
5
- // own primary module above the shipped groups by any documented means. `overrides.nav.groupOrder` wires
6
- // that as a real override domain, which `BACKWARD_COMPATIBILITY.md` §2 explicitly reserves for additive
7
- // wiring.
8
-
9
- const mockLoggerWarn = jest.fn()
10
-
11
- jest.mock('../../lib/logger', () => ({
12
- createLogger: () => {
13
- const child = { warn: (...args: unknown[]) => mockLoggerWarn(...args), error: jest.fn(), info: jest.fn(), debug: jest.fn() }
14
- return { child: () => child, warn: child.warn, error: child.error, info: child.info, debug: child.debug }
15
- },
16
- }))
17
-
18
- import {
19
- applyModuleOverridesFromEnabledModules,
20
- applyNavGroupOrderOverrides,
21
- getNavGroupOrderOverride,
22
- resetModuleContractOverridesForTests,
23
- resetModuleOverrideAppliersForTests,
24
- } from '../overrides'
25
-
26
- function reset() {
27
- resetModuleOverrideAppliersForTests()
28
- resetModuleContractOverridesForTests()
29
- mockLoggerWarn.mockClear()
30
- }
31
-
32
- beforeEach(reset)
33
- afterEach(reset)
34
-
35
- const collisionWarnings = () =>
36
- mockLoggerWarn.mock.calls.filter((call) => String(call[0]).includes('nav.groupOrder declared by more than one'))
37
-
38
- describe('nav.groupOrder override domain', () => {
39
- it('is unset when no module declares it', () => {
40
- applyModuleOverridesFromEnabledModules([{ id: 'catalog' }, { id: 'sales', overrides: {} }])
41
-
42
- expect(getNavGroupOrderOverride()).toBeNull()
43
- })
44
-
45
- it('captures the ids a module declares, in order — proving the domain is wired', () => {
46
- applyModuleOverridesFromEnabledModules([
47
- { id: 'app', overrides: { nav: { groupOrder: ['app.nav.group', 'catalog.nav.group'] } } },
48
- ])
49
-
50
- expect(getNavGroupOrderOverride()).toEqual(['app.nav.group', 'catalog.nav.group'])
51
- // An unwired domain would be dropped with a "not yet wired" warning instead of being captured.
52
- expect(mockLoggerWarn.mock.calls.filter((call) => String(call[0]).includes('not yet wired'))).toEqual([])
53
- })
54
-
55
- it('ignores an empty list, leaving the shipped ordering in charge', () => {
56
- applyModuleOverridesFromEnabledModules([{ id: 'app', overrides: { nav: { groupOrder: [] } } }])
57
-
58
- expect(getNavGroupOrderOverride()).toBeNull()
59
- })
60
-
61
- it('drops blank entries and de-duplicates while preserving first position', () => {
62
- applyModuleOverridesFromEnabledModules([
63
- {
64
- id: 'app',
65
- overrides: { nav: { groupOrder: [' app.nav.group ', '', ' ', 'app.nav.group', 'catalog.nav.group'] } },
66
- },
67
- ])
68
-
69
- expect(getNavGroupOrderOverride()).toEqual(['app.nav.group', 'catalog.nav.group'])
70
- })
71
-
72
- it('ignores a non-array value rather than throwing', () => {
73
- applyModuleOverridesFromEnabledModules([
74
- { id: 'app', overrides: { nav: { groupOrder: 'app.nav.group' as never } } },
75
- ])
76
-
77
- expect(getNavGroupOrderOverride()).toBeNull()
78
- })
79
-
80
- it('lets the later module win when two declare an order, and says so', () => {
81
- applyModuleOverridesFromEnabledModules([
82
- { id: 'first', overrides: { nav: { groupOrder: ['first.nav.group'] } } },
83
- { id: 'second', overrides: { nav: { groupOrder: ['second.nav.group'] } } },
84
- ])
85
-
86
- expect(getNavGroupOrderOverride()).toEqual(['second.nav.group'])
87
- expect(collisionWarnings()).toHaveLength(1)
88
- })
89
-
90
- it('does not warn when the same module declares it twice', () => {
91
- applyModuleOverridesFromEnabledModules([
92
- { id: 'app', overrides: { nav: { groupOrder: ['a.nav.group'] } } },
93
- { id: 'app', overrides: { nav: { groupOrder: ['b.nav.group'] } } },
94
- ])
95
-
96
- expect(getNavGroupOrderOverride()).toEqual(['b.nav.group'])
97
- expect(collisionWarnings()).toEqual([])
98
- })
99
-
100
- it('is cleared by the store reset hook so suites cannot leak into each other', () => {
101
- applyModuleOverridesFromEnabledModules([
102
- { id: 'app', overrides: { nav: { groupOrder: ['app.nav.group'] } } },
103
- ])
104
- expect(getNavGroupOrderOverride()).not.toBeNull()
105
-
106
- resetModuleContractOverridesForTests()
107
-
108
- expect(getNavGroupOrderOverride()).toBeNull()
109
- })
110
- })
111
-
112
- describe('nav.groupOrder programmatic tier', () => {
113
- it('takes precedence over the modules.ts declaration', () => {
114
- applyModuleOverridesFromEnabledModules([
115
- { id: 'app', overrides: { nav: { groupOrder: ['from-modules.nav.group'] } } },
116
- ])
117
- applyNavGroupOrderOverrides(['from-code.nav.group'])
118
-
119
- expect(getNavGroupOrderOverride()).toEqual(['from-code.nav.group'])
120
- })
121
-
122
- it('falls back to the modules.ts declaration when cleared with null', () => {
123
- applyModuleOverridesFromEnabledModules([
124
- { id: 'app', overrides: { nav: { groupOrder: ['from-modules.nav.group'] } } },
125
- ])
126
- applyNavGroupOrderOverrides(['from-code.nav.group'])
127
- applyNavGroupOrderOverrides(null)
128
-
129
- expect(getNavGroupOrderOverride()).toEqual(['from-modules.nav.group'])
130
- })
131
-
132
- it('applies the same normalisation as the modules.ts tier', () => {
133
- applyNavGroupOrderOverrides([' a.nav.group ', '', 'a.nav.group', 'b.nav.group'])
134
-
135
- expect(getNavGroupOrderOverride()).toEqual(['a.nav.group', 'b.nav.group'])
136
- })
137
-
138
- it('treats an all-blank list as no override', () => {
139
- applyNavGroupOrderOverrides([' ', ''])
140
-
141
- expect(getNavGroupOrderOverride()).toBeNull()
142
- })
143
-
144
- it('works before any module override has been dispatched', () => {
145
- applyNavGroupOrderOverrides(['standalone.nav.group'])
146
-
147
- expect(getNavGroupOrderOverride()).toEqual(['standalone.nav.group'])
148
- })
149
- })
150
-
151
- describe('nav.groupOrder survives module duplication', () => {
152
- // Regression for `.ai/lessons.md`, "Global registries in publishable packages must use
153
- // `globalThis`". This domain's writer (app bootstrap) and reader (`@open-mercato/core`'s backend
154
- // chrome) sit in different packages, and standalone builds can evaluate `@open-mercato/shared`
155
- // through more than one module instance. `jest.isolateModules` reproduces that: a second, freshly
156
- // loaded copy of the module must still observe what the first copy stored.
157
- it('a separately loaded module instance sees the value written by bootstrap', () => {
158
- applyModuleOverridesFromEnabledModules([
159
- { id: 'app', overrides: { nav: { groupOrder: ['bootstrap.nav.group'] } } },
160
- ])
161
-
162
- let observedFromSecondInstance: readonly string[] | null | undefined
163
- jest.isolateModules(() => {
164
- const freshModule = require('../overrides') as typeof import('../overrides')
165
- observedFromSecondInstance = freshModule.getNavGroupOrderOverride()
166
- })
167
-
168
- // A module-local variable would leave this second instance blind to the bootstrap value.
169
- expect(observedFromSecondInstance).toEqual(['bootstrap.nav.group'])
170
- })
171
-
172
- it('a programmatic override is visible to a separately loaded instance too', () => {
173
- applyNavGroupOrderOverrides(['programmatic.nav.group'])
174
-
175
- let observed: readonly string[] | null | undefined
176
- jest.isolateModules(() => {
177
- const freshModule = require('../overrides') as typeof import('../overrides')
178
- observed = freshModule.getNavGroupOrderOverride()
179
- })
180
-
181
- expect(observed).toEqual(['programmatic.nav.group'])
182
- })
183
- })
@@ -1,37 +0,0 @@
1
- import {
2
- clearWebhookHandlers,
3
- getWebhookHandler,
4
- registerWebhookHandler,
5
- type VerifyWebhookInput,
6
- type WebhookEvent,
7
- } from '../types'
8
-
9
- const handler = async (_input: VerifyWebhookInput): Promise<WebhookEvent> => ({
10
- eventType: 'payment.updated',
11
- eventId: 'evt-1',
12
- data: {},
13
- idempotencyKey: 'evt-1',
14
- timestamp: new Date(0),
15
- })
16
-
17
- describe('payment gateway webhook registration', () => {
18
- beforeEach(() => {
19
- clearWebhookHandlers()
20
- })
21
-
22
- it('preserves an optional valid body limit on the registration', () => {
23
- registerWebhookHandler('limited', handler, { maxBodyBytes: 64 * 1024 })
24
-
25
- expect(getWebhookHandler('limited')?.maxBodyBytes).toBe(64 * 1024)
26
- })
27
-
28
- it.each([0, -1, 1.5, Number.MAX_SAFE_INTEGER])(
29
- 'rejects an invalid body limit: %s',
30
- (maxBodyBytes) => {
31
- expect(() => registerWebhookHandler('invalid', handler, { maxBodyBytes })).toThrow(
32
- '[internal] Payment gateway webhook maxBodyBytes must be a positive safe integer',
33
- )
34
- expect(getWebhookHandler('invalid')).toBeUndefined()
35
- },
36
- )
37
- })
@@ -1,101 +0,0 @@
1
- import {
2
- CRUD_FORM_EXTENSION_SURFACES,
3
- CRUD_FORM_LIFECYCLE_PHASES,
4
- CRUD_FORM_OPERATIONS,
5
- DATA_TABLE_EXTENSION_SURFACES,
6
- crudFormExtensionHost,
7
- crudFormExtensionSpotId,
8
- dataTableExtensionHost,
9
- dataTableExtensionSpotId,
10
- defineModuleExtensionPoints,
11
- extensionSpotChildId,
12
- injectionExtensionHost,
13
- resolveExtensionPointPattern,
14
- } from '@open-mercato/shared/modules/widgets/extension-points'
15
-
16
- describe('module extension point declarations', () => {
17
- it('preserves exact ids and immutable declarations', () => {
18
- const extensionPoints = defineModuleExtensionPoints({
19
- moduleId: 'catalog',
20
- hosts: {
21
- products: dataTableExtensionHost({
22
- baseSpotId: 'data-table:catalog.products',
23
- tableId: 'catalog.products.list',
24
- source: 'components/products/ProductsDataTable.tsx',
25
- }),
26
- productForm: crudFormExtensionHost({
27
- entityId: 'catalog.product',
28
- spotId: 'crud-form:catalog.product',
29
- source: 'backend/catalog/products/[id]/page.tsx',
30
- }),
31
- },
32
- })
33
-
34
- expect(extensionPoints.moduleId).toBe('catalog')
35
- expect(extensionPoints.hosts.products.tableId).toBe('catalog.products.list')
36
- expect(Object.isFrozen(extensionPoints)).toBe(true)
37
- expect(Object.isFrozen(extensionPoints.hosts)).toBe(true)
38
- })
39
-
40
- it('requires named parameters for dynamic patterns', () => {
41
- // @ts-expect-error patterned declarations require named parameters
42
- expect(() => injectionExtensionHost({
43
- family: 'integration',
44
- pattern: 'integrations.detail:{integrationId}',
45
- supported: ['render-widget'],
46
- source: 'backend/integrations/[id]/page.tsx',
47
- })).toThrow('patterned injection extension hosts require named parameters')
48
- })
49
-
50
- it('describes only the surfaces bound by DataTable and CrudForm', () => {
51
- expect(DATA_TABLE_EXTENSION_SURFACES.filter((surface) => surface.bound).map((surface) => surface.key)).toEqual([
52
- 'header',
53
- 'footer',
54
- 'toolbar',
55
- 'searchTrailing',
56
- 'columns',
57
- 'rowActions',
58
- 'bulkActions',
59
- 'filters',
60
- 'replacement',
61
- ])
62
- expect(DATA_TABLE_EXTENSION_SURFACES.find((surface) => surface.key === 'emptyState')?.bound).toBe(false)
63
- expect(CRUD_FORM_EXTENSION_SURFACES.filter((surface) => !surface.bound).map((surface) => surface.key)).toEqual([
64
- 'beforeFields',
65
- 'afterFields',
66
- 'footer',
67
- 'sidebar',
68
- 'group',
69
- 'fieldBefore',
70
- 'fieldAfter',
71
- ])
72
- expect(CRUD_FORM_LIFECYCLE_PHASES).toEqual([
73
- 'transformValidation',
74
- 'transformDisplayData',
75
- 'onBeforeNavigate',
76
- 'onAppEvent',
77
- 'onVisibilityChange',
78
- 'onBeforeDelete',
79
- 'onDelete',
80
- 'onAfterDelete',
81
- 'onDeleteError',
82
- 'onFieldChange',
83
- 'transformFormData',
84
- 'onBeforeSave',
85
- 'onSave',
86
- 'onAfterSave',
87
- ])
88
- expect(CRUD_FORM_OPERATIONS).toEqual(['create', 'update', 'delete'])
89
- })
90
-
91
- it('builds standard family ids without changing punctuation', () => {
92
- expect(dataTableExtensionSpotId('catalog.products.list', 'columns')).toBe(
93
- 'data-table:catalog.products.list:columns',
94
- )
95
- expect(crudFormExtensionSpotId('catalog.product', 'fields')).toBe('crud-form:catalog.product:fields')
96
- expect(extensionSpotChildId('legacy:custom-host', 'header')).toBe('legacy:custom-host:header')
97
- expect(resolveExtensionPointPattern('integrations.detail:{integrationId}', {
98
- integrationId: 'stripe',
99
- })).toBe('integrations.detail:stripe')
100
- })
101
- })