@open-mercato/shared 0.6.7 → 0.6.8-develop.6874.1.982d6097d8

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 (195) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +57 -6
  3. package/build.mjs +2 -4
  4. package/dist/lib/ai/safety-identifier.js +32 -0
  5. package/dist/lib/ai/safety-identifier.js.map +7 -0
  6. package/dist/lib/auth/organizationScope.js +34 -0
  7. package/dist/lib/auth/organizationScope.js.map +7 -0
  8. package/dist/lib/auth/server.js +15 -2
  9. package/dist/lib/auth/server.js.map +2 -2
  10. package/dist/lib/bootstrap/clientOnlyModules.js +55 -0
  11. package/dist/lib/bootstrap/clientOnlyModules.js.map +7 -0
  12. package/dist/lib/bootstrap/dynamicLoader.js +117 -43
  13. package/dist/lib/bootstrap/dynamicLoader.js.map +2 -2
  14. package/dist/lib/commands/command-bus.js +5 -1
  15. package/dist/lib/commands/command-bus.js.map +2 -2
  16. package/dist/lib/commands/command-interceptor-runner.js +2 -2
  17. package/dist/lib/commands/command-interceptor-runner.js.map +2 -2
  18. package/dist/lib/crud/enricher-runner.js +2 -11
  19. package/dist/lib/crud/enricher-runner.js.map +2 -2
  20. package/dist/lib/crud/factory.js +72 -9
  21. package/dist/lib/crud/factory.js.map +2 -2
  22. package/dist/lib/crud/interceptor-runner.js +2 -2
  23. package/dist/lib/crud/interceptor-runner.js.map +2 -2
  24. package/dist/lib/crud/mutation-guard-registry.js +2 -2
  25. package/dist/lib/crud/mutation-guard-registry.js.map +2 -2
  26. package/dist/lib/crud/types.js +4 -0
  27. package/dist/lib/crud/types.js.map +3 -3
  28. package/dist/lib/data/consistency.js +19 -0
  29. package/dist/lib/data/consistency.js.map +7 -0
  30. package/dist/lib/data/engine.js +37 -11
  31. package/dist/lib/data/engine.js.map +2 -2
  32. package/dist/lib/db/entityMetadata.js +26 -0
  33. package/dist/lib/db/entityMetadata.js.map +7 -0
  34. package/dist/lib/db/pg-errors.js +42 -0
  35. package/dist/lib/db/pg-errors.js.map +2 -2
  36. package/dist/lib/di/container.js +48 -6
  37. package/dist/lib/di/container.js.map +2 -2
  38. package/dist/lib/email/send.js +56 -0
  39. package/dist/lib/email/send.js.map +2 -2
  40. package/dist/lib/encryption/subscriber.js +2 -10
  41. package/dist/lib/encryption/subscriber.js.map +2 -2
  42. package/dist/lib/encryption/tenantDataEncryptionService.js +52 -17
  43. package/dist/lib/encryption/tenantDataEncryptionService.js.map +2 -2
  44. package/dist/lib/i18n/config.js +1 -1
  45. package/dist/lib/i18n/config.js.map +2 -2
  46. package/dist/lib/i18n/server.js +4 -4
  47. package/dist/lib/i18n/server.js.map +3 -3
  48. package/dist/lib/logger/extension.js +29 -0
  49. package/dist/lib/logger/extension.js.map +7 -0
  50. package/dist/lib/logger/index.js +47 -3
  51. package/dist/lib/logger/index.js.map +3 -3
  52. package/dist/lib/modules/registry.js +5 -1
  53. package/dist/lib/modules/registry.js.map +2 -2
  54. package/dist/lib/modules/surfaceFingerprint.js +47 -0
  55. package/dist/lib/modules/surfaceFingerprint.js.map +7 -0
  56. package/dist/lib/query/ciphertext-search-warning.js +45 -0
  57. package/dist/lib/query/ciphertext-search-warning.js.map +7 -0
  58. package/dist/lib/query/engine.js +54 -40
  59. package/dist/lib/query/engine.js.map +2 -2
  60. package/dist/lib/query/types.js.map +1 -1
  61. package/dist/lib/redis/connection.js +7 -2
  62. package/dist/lib/redis/connection.js.map +2 -2
  63. package/dist/lib/search/auto-indexing.js +14 -0
  64. package/dist/lib/search/auto-indexing.js.map +7 -0
  65. package/dist/lib/search/availability.js +107 -0
  66. package/dist/lib/search/availability.js.map +7 -0
  67. package/dist/lib/search/config.js +61 -2
  68. package/dist/lib/search/config.js.map +2 -2
  69. package/dist/lib/search/tokenLookup.js +46 -0
  70. package/dist/lib/search/tokenLookup.js.map +7 -0
  71. package/dist/lib/search/tokenize.js +23 -11
  72. package/dist/lib/search/tokenize.js.map +2 -2
  73. package/dist/lib/telemetry/runtime.js +35 -0
  74. package/dist/lib/telemetry/runtime.js.map +7 -0
  75. package/dist/lib/version.js +1 -1
  76. package/dist/lib/version.js.map +1 -1
  77. package/dist/lib/webhooks/body.js +57 -0
  78. package/dist/lib/webhooks/body.js.map +7 -0
  79. package/dist/lib/webhooks/inbound-types.js +1 -0
  80. package/dist/lib/webhooks/inbound-types.js.map +7 -0
  81. package/dist/lib/webhooks/index.js +13 -1
  82. package/dist/lib/webhooks/index.js.map +2 -2
  83. package/dist/lib/webhooks/verify.js +12 -7
  84. package/dist/lib/webhooks/verify.js.map +2 -2
  85. package/dist/modules/analytics.js.map +2 -2
  86. package/dist/modules/overrides.js +50 -1
  87. package/dist/modules/overrides.js.map +2 -2
  88. package/dist/modules/payment_gateways/types.js +8 -1
  89. package/dist/modules/payment_gateways/types.js.map +2 -2
  90. package/dist/modules/registry.js +1 -0
  91. package/dist/modules/registry.js.map +2 -2
  92. package/dist/modules/widgets/extension-points.js +96 -0
  93. package/dist/modules/widgets/extension-points.js.map +7 -0
  94. package/dist/security/enabledModulesRegistry.js +56 -11
  95. package/dist/security/enabledModulesRegistry.js.map +2 -2
  96. package/dist/security/featurePolicy.js +62 -0
  97. package/dist/security/featurePolicy.js.map +7 -0
  98. package/jest.config.cjs +2 -1
  99. package/package.json +19 -9
  100. package/scripts/versionSource.cjs +65 -0
  101. package/src/lib/__tests__/versionSource.test.ts +46 -0
  102. package/src/lib/ai/__tests__/llm-provider-contract.test.ts +59 -0
  103. package/src/lib/ai/__tests__/safety-identifier.test.ts +71 -0
  104. package/src/lib/ai/llm-provider.ts +33 -0
  105. package/src/lib/ai/safety-identifier.ts +73 -0
  106. package/src/lib/auth/__tests__/organizationScope.test.ts +107 -0
  107. package/src/lib/auth/__tests__/server.test.ts +23 -0
  108. package/src/lib/auth/organizationScope.ts +65 -0
  109. package/src/lib/auth/server.ts +23 -2
  110. package/src/lib/bootstrap/__tests__/clientOnlyModules.test.ts +189 -0
  111. package/src/lib/bootstrap/__tests__/dynamicLoader.aliasResolver.test.ts +98 -0
  112. package/src/lib/bootstrap/__tests__/dynamicLoader.appDi.test.ts +211 -0
  113. package/src/lib/bootstrap/__tests__/dynamicLoader.commandInterceptors.test.ts +63 -8
  114. package/src/lib/bootstrap/__tests__/dynamicLoader.generatedCacheRecovery.test.ts +256 -0
  115. package/src/lib/bootstrap/__tests__/dynamicLoader.tsconfig.test.ts +21 -1
  116. package/src/lib/bootstrap/clientOnlyModules.ts +85 -0
  117. package/src/lib/bootstrap/dynamicLoader.ts +213 -65
  118. package/src/lib/commands/__tests__/command-interceptor-runner.test.ts +28 -0
  119. package/src/lib/commands/command-bus.ts +5 -1
  120. package/src/lib/commands/command-interceptor-runner.ts +2 -2
  121. package/src/lib/crud/__tests__/crud-factory.cache-user-scope.test.ts +171 -0
  122. package/src/lib/crud/__tests__/crud-factory.test.ts +351 -0
  123. package/src/lib/crud/__tests__/mutation-guard-registry.test.ts +26 -0
  124. package/src/lib/crud/enricher-runner.ts +2 -11
  125. package/src/lib/crud/factory.ts +82 -6
  126. package/src/lib/crud/interceptor-runner.ts +2 -2
  127. package/src/lib/crud/mutation-guard-registry.ts +2 -2
  128. package/src/lib/crud/types.ts +3 -0
  129. package/src/lib/data/__tests__/consistency.test.ts +38 -0
  130. package/src/lib/data/__tests__/engine.bulk-suppress.test.ts +18 -3
  131. package/src/lib/data/consistency.ts +17 -0
  132. package/src/lib/data/engine.ts +50 -16
  133. package/src/lib/db/__tests__/entityMetadata.test.ts +38 -0
  134. package/src/lib/db/__tests__/pg-errors.test.ts +48 -0
  135. package/src/lib/db/entityMetadata.ts +43 -0
  136. package/src/lib/db/pg-errors.ts +58 -0
  137. package/src/lib/di/__tests__/container-app-di-absent.test.ts +155 -0
  138. package/src/lib/di/__tests__/container-app-di.test.ts +173 -0
  139. package/src/lib/di/__tests__/registrar-error-log.test.ts +154 -0
  140. package/src/lib/di/container.ts +72 -8
  141. package/src/lib/email/__tests__/send.test.ts +37 -1
  142. package/src/lib/email/send.ts +79 -0
  143. package/src/lib/encryption/__tests__/subscriber.test.ts +54 -2
  144. package/src/lib/encryption/__tests__/tenantDataEncryptionService.test.ts +58 -0
  145. package/src/lib/encryption/subscriber.ts +2 -14
  146. package/src/lib/encryption/tenantDataEncryptionService.ts +64 -18
  147. package/src/lib/i18n/__tests__/config.test.ts +8 -0
  148. package/src/lib/i18n/__tests__/server-dictionary-cache.test.ts +30 -0
  149. package/src/lib/i18n/__tests__/server-unbootstrapped.test.ts +29 -0
  150. package/src/lib/i18n/config.ts +2 -2
  151. package/src/lib/i18n/server.ts +6 -2
  152. package/src/lib/logger/__tests__/logger.test.ts +77 -0
  153. package/src/lib/logger/extension.ts +59 -0
  154. package/src/lib/logger/index.ts +59 -1
  155. package/src/lib/modules/__tests__/surfaceFingerprint.test.ts +122 -0
  156. package/src/lib/modules/registry.ts +10 -0
  157. package/src/lib/modules/surfaceFingerprint.ts +87 -0
  158. package/src/lib/query/__tests__/ciphertext-search-warning.test.ts +178 -0
  159. package/src/lib/query/__tests__/engine.test.ts +65 -13
  160. package/src/lib/query/ciphertext-search-warning.ts +95 -0
  161. package/src/lib/query/engine.ts +75 -58
  162. package/src/lib/query/types.ts +4 -5
  163. package/src/lib/redis/__tests__/connection.test.ts +16 -0
  164. package/src/lib/redis/connection.ts +10 -7
  165. package/src/lib/search/__tests__/availability.test.ts +211 -0
  166. package/src/lib/search/__tests__/config.test.ts +177 -0
  167. package/src/lib/search/__tests__/tokenLookup.test.ts +206 -0
  168. package/src/lib/search/__tests__/tokenize.test.ts +49 -0
  169. package/src/lib/search/auto-indexing.ts +22 -0
  170. package/src/lib/search/availability.ts +232 -0
  171. package/src/lib/search/config.ts +106 -8
  172. package/src/lib/search/tokenLookup.ts +133 -0
  173. package/src/lib/search/tokenize.ts +33 -11
  174. package/src/lib/telemetry/runtime.ts +72 -0
  175. package/src/lib/webhooks/__tests__/body.test.ts +95 -0
  176. package/src/lib/webhooks/__tests__/verify.test.ts +20 -1
  177. package/src/lib/webhooks/body.ts +70 -0
  178. package/src/lib/webhooks/inbound-types.ts +125 -0
  179. package/src/lib/webhooks/index.ts +19 -1
  180. package/src/lib/webhooks/verify.ts +17 -9
  181. package/src/modules/__tests__/nav-group-order-override.test.ts +183 -0
  182. package/src/modules/__tests__/registry.test.ts +10 -2
  183. package/src/modules/analytics.ts +7 -0
  184. package/src/modules/customer-auth.ts +1 -0
  185. package/src/modules/encryption.ts +3 -0
  186. package/src/modules/navigation/backendChrome.ts +15 -0
  187. package/src/modules/overrides.ts +103 -0
  188. package/src/modules/payment_gateways/__tests__/types.test.ts +37 -0
  189. package/src/modules/payment_gateways/types.ts +41 -0
  190. package/src/modules/registry.ts +3 -0
  191. package/src/modules/widgets/__tests__/extension-points.test.ts +101 -0
  192. package/src/modules/widgets/extension-points.ts +524 -0
  193. package/src/security/__tests__/featurePolicy.test.ts +166 -0
  194. package/src/security/enabledModulesRegistry.ts +64 -12
  195. package/src/security/featurePolicy.ts +89 -0
@@ -31,6 +31,7 @@ type FeatureRegistry = {
31
31
  enabledModuleSet: Set<string>
32
32
  featureToModule: Map<string, string>
33
33
  prefixToModule: Map<string, string>
34
+ concreteFeatureIds: string[]
34
35
  }
35
36
 
36
37
  let cachedRegistry: FeatureRegistry | null = null
@@ -41,23 +42,63 @@ function buildRegistry(modules: readonly Module[]): FeatureRegistry {
41
42
  const enabledModuleSet = new Set(enabledModuleIds)
42
43
  const featureToModule = new Map<string, string>()
43
44
  const prefixToModule = new Map<string, string>()
45
+ const concreteFeatureIds: string[] = []
46
+ const concreteFeatureSet = new Set<string>()
47
+
48
+ const addConcreteFeature = (featureId: string, owningModule: string, authoritative: boolean) => {
49
+ if (!featureId || featureId === '*' || featureId.endsWith('.*')) return
50
+ if (!concreteFeatureSet.has(featureId)) {
51
+ concreteFeatureSet.add(featureId)
52
+ concreteFeatureIds.push(featureId)
53
+ }
54
+ if (authoritative || !featureToModule.has(featureId)) {
55
+ featureToModule.set(featureId, owningModule)
56
+ }
57
+ const dot = featureId.indexOf('.')
58
+ if (dot > 0) {
59
+ const prefix = featureId.slice(0, dot)
60
+ if (!prefixToModule.has(prefix)) prefixToModule.set(prefix, owningModule)
61
+ }
62
+ }
63
+
44
64
  for (const mod of modules) {
45
65
  const features = mod.features
46
- if (!Array.isArray(features)) continue
47
- for (const feature of features) {
48
- if (!feature || typeof feature.id !== 'string' || !feature.id) continue
49
- const declared = typeof feature.module === 'string' && feature.module.length > 0
50
- ? feature.module
51
- : mod.id
52
- featureToModule.set(feature.id, declared)
53
- const dot = feature.id.indexOf('.')
54
- if (dot > 0) {
55
- const prefix = feature.id.slice(0, dot)
56
- if (!prefixToModule.has(prefix)) prefixToModule.set(prefix, declared)
66
+ if (Array.isArray(features)) {
67
+ for (const feature of features) {
68
+ if (!feature || typeof feature.id !== 'string' || !feature.id) continue
69
+ const declared = typeof feature.module === 'string' && feature.module.length > 0
70
+ ? feature.module
71
+ : mod.id
72
+ addConcreteFeature(feature.id, declared, true)
73
+ }
74
+ }
75
+
76
+ const customerDefaults = mod.setup?.defaultCustomerRoleFeatures
77
+ if (customerDefaults) {
78
+ for (const roleFeatures of Object.values(customerDefaults)) {
79
+ if (!Array.isArray(roleFeatures)) continue
80
+ for (const featureId of roleFeatures) {
81
+ if (typeof featureId === 'string') addConcreteFeature(featureId, mod.id, false)
82
+ }
57
83
  }
58
84
  }
85
+
86
+ if (Array.isArray(mod.frontendRoutes)) {
87
+ for (const route of mod.frontendRoutes) {
88
+ if (!Array.isArray(route.requireCustomerFeatures)) continue
89
+ for (const featureId of route.requireCustomerFeatures) {
90
+ if (typeof featureId === 'string') addConcreteFeature(featureId, mod.id, false)
91
+ }
92
+ }
93
+ }
94
+ }
95
+ return {
96
+ enabledModuleIds,
97
+ enabledModuleSet,
98
+ featureToModule,
99
+ prefixToModule,
100
+ concreteFeatureIds,
59
101
  }
60
- return { enabledModuleIds, enabledModuleSet, featureToModule, prefixToModule }
61
102
  }
62
103
 
63
104
  function getRegistry(): FeatureRegistry | null {
@@ -93,6 +134,17 @@ export function getEnabledModuleIds(): string[] {
93
134
  return registry ? [...registry.enabledModuleIds] : []
94
135
  }
95
136
 
137
+ /** @internal Infrastructure input for concrete feature-policy projection. */
138
+ export function getConcreteFeatureIds(): string[] {
139
+ const registry = getRegistry()
140
+ return registry ? [...registry.concreteFeatureIds] : []
141
+ }
142
+
143
+ /** @internal Distinguishes an empty registry from an unavailable bootstrap registry. */
144
+ export function hasEnabledModulesRegistry(): boolean {
145
+ return getRegistry() !== null
146
+ }
147
+
96
148
  /**
97
149
  * Filters a raw granted-features list down to the grants whose owning
98
150
  * module is currently enabled. Expands `*` (superadmin) into one wildcard
@@ -0,0 +1,89 @@
1
+ import { hasAllFeatures as matchesAllFeatures } from './features'
2
+ import {
3
+ filterGrantsByEnabledModules,
4
+ getConcreteFeatureIds,
5
+ getEnabledModuleIds,
6
+ getOwningModuleId,
7
+ hasEnabledModulesRegistry,
8
+ } from './enabledModulesRegistry'
9
+ import { composeAclFeatureOverrides } from '../modules/overrides'
10
+
11
+ export type FeaturePolicySubject = {
12
+ grantedFeatures: readonly string[]
13
+ unrestricted?: boolean
14
+ scopeAllowed?: boolean
15
+ }
16
+
17
+ export function getRemovedAclFeatureIds(): string[] {
18
+ return Object.entries(composeAclFeatureOverrides())
19
+ .filter(([, override]) => override === null)
20
+ .map(([featureId]) => featureId)
21
+ }
22
+
23
+ export function isAclFeatureRemoved(featureId: string): boolean {
24
+ return composeAclFeatureOverrides()[featureId] === null
25
+ }
26
+
27
+ function isFeatureEnabled(featureId: string): boolean {
28
+ if (!hasEnabledModulesRegistry()) return true
29
+ const enabledModuleIds = getEnabledModuleIds()
30
+ return enabledModuleIds.includes(getOwningModuleId(featureId))
31
+ }
32
+
33
+ export function authorizeFeatures(
34
+ required: readonly string[],
35
+ subject: FeaturePolicySubject,
36
+ ): boolean {
37
+ if (required.length === 0) return true
38
+ if (subject.scopeAllowed === false) return false
39
+ if (required.some((featureId) => (
40
+ isAclFeatureRemoved(featureId) || !isFeatureEnabled(featureId)
41
+ ))) {
42
+ return false
43
+ }
44
+ if (subject.unrestricted === true) return true
45
+ return matchesAllFeatures(
46
+ filterGrantsByEnabledModules(subject.grantedFeatures),
47
+ required,
48
+ )
49
+ }
50
+
51
+ export function resolveEffectiveFeatures(
52
+ grantedFeatures: readonly string[],
53
+ ): string[] {
54
+ const filteredGrants = filterGrantsByEnabledModules(grantedFeatures)
55
+ .filter((featureId) => !isAclFeatureRemoved(featureId))
56
+
57
+ if (!hasEnabledModulesRegistry()) {
58
+ return filteredGrants.filter((featureId, index, features) => (
59
+ featureId !== '*'
60
+ && !featureId.endsWith('.*')
61
+ && features.indexOf(featureId) === index
62
+ ))
63
+ }
64
+
65
+ const result: string[] = []
66
+ const seen = new Set<string>()
67
+ const addFeature = (featureId: string) => {
68
+ if (
69
+ seen.has(featureId)
70
+ || isAclFeatureRemoved(featureId)
71
+ || !isFeatureEnabled(featureId)
72
+ ) {
73
+ return
74
+ }
75
+ seen.add(featureId)
76
+ result.push(featureId)
77
+ }
78
+
79
+ for (const featureId of getConcreteFeatureIds()) {
80
+ if (matchesAllFeatures(filteredGrants, [featureId])) addFeature(featureId)
81
+ }
82
+
83
+ for (const featureId of filteredGrants) {
84
+ if (featureId === '*' || featureId.endsWith('.*')) continue
85
+ addFeature(featureId)
86
+ }
87
+
88
+ return result
89
+ }