@open-mercato/shared 0.4.2-canary-c02407ff85

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 (324) hide show
  1. package/build.mjs +101 -0
  2. package/dist/index.js +1 -0
  3. package/dist/index.js.map +7 -0
  4. package/dist/lib/api/crud.js +47 -0
  5. package/dist/lib/api/crud.js.map +7 -0
  6. package/dist/lib/api/scoped.js +140 -0
  7. package/dist/lib/api/scoped.js.map +7 -0
  8. package/dist/lib/auth/jwt.js +34 -0
  9. package/dist/lib/auth/jwt.js.map +7 -0
  10. package/dist/lib/auth/server.js +157 -0
  11. package/dist/lib/auth/server.js.map +7 -0
  12. package/dist/lib/boolean.js +22 -0
  13. package/dist/lib/boolean.js.map +7 -0
  14. package/dist/lib/bootstrap/appResolver.js +43 -0
  15. package/dist/lib/bootstrap/appResolver.js.map +7 -0
  16. package/dist/lib/bootstrap/dynamicLoader.js +108 -0
  17. package/dist/lib/bootstrap/dynamicLoader.js.map +7 -0
  18. package/dist/lib/bootstrap/factory.js +59 -0
  19. package/dist/lib/bootstrap/factory.js.map +7 -0
  20. package/dist/lib/bootstrap/index.js +11 -0
  21. package/dist/lib/bootstrap/index.js.map +7 -0
  22. package/dist/lib/bootstrap/types.js +1 -0
  23. package/dist/lib/bootstrap/types.js.map +7 -0
  24. package/dist/lib/cache/segments.js +36 -0
  25. package/dist/lib/cache/segments.js.map +7 -0
  26. package/dist/lib/cli/progress.js +46 -0
  27. package/dist/lib/cli/progress.js.map +7 -0
  28. package/dist/lib/commands/command-bus.js +285 -0
  29. package/dist/lib/commands/command-bus.js.map +7 -0
  30. package/dist/lib/commands/customFieldSnapshots.js +66 -0
  31. package/dist/lib/commands/customFieldSnapshots.js.map +7 -0
  32. package/dist/lib/commands/helpers.js +98 -0
  33. package/dist/lib/commands/helpers.js.map +7 -0
  34. package/dist/lib/commands/index.js +8 -0
  35. package/dist/lib/commands/index.js.map +7 -0
  36. package/dist/lib/commands/operationMetadata.js +32 -0
  37. package/dist/lib/commands/operationMetadata.js.map +7 -0
  38. package/dist/lib/commands/registry.js +43 -0
  39. package/dist/lib/commands/registry.js.map +7 -0
  40. package/dist/lib/commands/scope.js +44 -0
  41. package/dist/lib/commands/scope.js.map +7 -0
  42. package/dist/lib/commands/types.js +8 -0
  43. package/dist/lib/commands/types.js.map +7 -0
  44. package/dist/lib/crud/cache-stats.js +98 -0
  45. package/dist/lib/crud/cache-stats.js.map +7 -0
  46. package/dist/lib/crud/cache.js +175 -0
  47. package/dist/lib/crud/cache.js.map +7 -0
  48. package/dist/lib/crud/custom-fields-client.js +52 -0
  49. package/dist/lib/crud/custom-fields-client.js.map +7 -0
  50. package/dist/lib/crud/custom-fields.js +467 -0
  51. package/dist/lib/crud/custom-fields.js.map +7 -0
  52. package/dist/lib/crud/errors.js +24 -0
  53. package/dist/lib/crud/errors.js.map +7 -0
  54. package/dist/lib/crud/exporters.js +154 -0
  55. package/dist/lib/crud/exporters.js.map +7 -0
  56. package/dist/lib/crud/factory.js +1311 -0
  57. package/dist/lib/crud/factory.js.map +7 -0
  58. package/dist/lib/crud/types.js +1 -0
  59. package/dist/lib/crud/types.js.map +7 -0
  60. package/dist/lib/custom-fields/normalize.js +36 -0
  61. package/dist/lib/custom-fields/normalize.js.map +7 -0
  62. package/dist/lib/data/engine.js +396 -0
  63. package/dist/lib/data/engine.js.map +7 -0
  64. package/dist/lib/db/escapeLikePattern.js +5 -0
  65. package/dist/lib/db/escapeLikePattern.js.map +7 -0
  66. package/dist/lib/db/mikro.js +82 -0
  67. package/dist/lib/db/mikro.js.map +7 -0
  68. package/dist/lib/di/container.js +94 -0
  69. package/dist/lib/di/container.js.map +7 -0
  70. package/dist/lib/email/send.js +12 -0
  71. package/dist/lib/email/send.js.map +7 -0
  72. package/dist/lib/encryption/aes.js +58 -0
  73. package/dist/lib/encryption/aes.js.map +7 -0
  74. package/dist/lib/encryption/customFieldValues.js +49 -0
  75. package/dist/lib/encryption/customFieldValues.js.map +7 -0
  76. package/dist/lib/encryption/entityFields.js +26 -0
  77. package/dist/lib/encryption/entityFields.js.map +7 -0
  78. package/dist/lib/encryption/entityIds.js +80 -0
  79. package/dist/lib/encryption/entityIds.js.map +7 -0
  80. package/dist/lib/encryption/find.js +45 -0
  81. package/dist/lib/encryption/find.js.map +7 -0
  82. package/dist/lib/encryption/indexDoc.js +69 -0
  83. package/dist/lib/encryption/indexDoc.js.map +7 -0
  84. package/dist/lib/encryption/kms.js +282 -0
  85. package/dist/lib/encryption/kms.js.map +7 -0
  86. package/dist/lib/encryption/subscriber.js +330 -0
  87. package/dist/lib/encryption/subscriber.js.map +7 -0
  88. package/dist/lib/encryption/tenantDataEncryptionService.js +252 -0
  89. package/dist/lib/encryption/tenantDataEncryptionService.js.map +7 -0
  90. package/dist/lib/encryption/toggles.js +18 -0
  91. package/dist/lib/encryption/toggles.js.map +7 -0
  92. package/dist/lib/entities/naming.js +9 -0
  93. package/dist/lib/entities/naming.js.map +7 -0
  94. package/dist/lib/entities/system-entities.js +43 -0
  95. package/dist/lib/entities/system-entities.js.map +7 -0
  96. package/dist/lib/frontend/organizationEvents.js +41 -0
  97. package/dist/lib/frontend/organizationEvents.js.map +7 -0
  98. package/dist/lib/frontend/useOrganizationScope.js +32 -0
  99. package/dist/lib/frontend/useOrganizationScope.js.map +7 -0
  100. package/dist/lib/hotkeys/index.js +128 -0
  101. package/dist/lib/hotkeys/index.js.map +7 -0
  102. package/dist/lib/i18n/app-dictionaries.js +17 -0
  103. package/dist/lib/i18n/app-dictionaries.js.map +7 -0
  104. package/dist/lib/i18n/config.js +7 -0
  105. package/dist/lib/i18n/config.js.map +7 -0
  106. package/dist/lib/i18n/context.js +50 -0
  107. package/dist/lib/i18n/context.js.map +7 -0
  108. package/dist/lib/i18n/server.js +68 -0
  109. package/dist/lib/i18n/server.js.map +7 -0
  110. package/dist/lib/i18n/translate.js +45 -0
  111. package/dist/lib/i18n/translate.js.map +7 -0
  112. package/dist/lib/indexers/error-log.js +82 -0
  113. package/dist/lib/indexers/error-log.js.map +7 -0
  114. package/dist/lib/indexers/status-log.js +80 -0
  115. package/dist/lib/indexers/status-log.js.map +7 -0
  116. package/dist/lib/lib/auth/jwt.js +34 -0
  117. package/dist/lib/lib/auth/jwt.js.map +7 -0
  118. package/dist/lib/lib/auth/server.js +77 -0
  119. package/dist/lib/lib/auth/server.js.map +7 -0
  120. package/dist/lib/lib/email/send.js +12 -0
  121. package/dist/lib/lib/email/send.js.map +7 -0
  122. package/dist/lib/lib/i18n/config.js +7 -0
  123. package/dist/lib/lib/i18n/config.js.map +7 -0
  124. package/dist/lib/lib/i18n/context.js +31 -0
  125. package/dist/lib/lib/i18n/context.js.map +7 -0
  126. package/dist/lib/lib/utils.js +9 -0
  127. package/dist/lib/lib/utils.js.map +7 -0
  128. package/dist/lib/location/countries.js +68 -0
  129. package/dist/lib/location/countries.js.map +7 -0
  130. package/dist/lib/modules/index.js +6 -0
  131. package/dist/lib/modules/index.js.map +7 -0
  132. package/dist/lib/modules/registry.js +18 -0
  133. package/dist/lib/modules/registry.js.map +7 -0
  134. package/dist/lib/openapi/crud.js +137 -0
  135. package/dist/lib/openapi/crud.js.map +7 -0
  136. package/dist/lib/openapi/generator.js +1131 -0
  137. package/dist/lib/openapi/generator.js.map +7 -0
  138. package/dist/lib/openapi/index.js +10 -0
  139. package/dist/lib/openapi/index.js.map +7 -0
  140. package/dist/lib/openapi/sanitize.js +110 -0
  141. package/dist/lib/openapi/sanitize.js.map +7 -0
  142. package/dist/lib/openapi/types.js +1 -0
  143. package/dist/lib/openapi/types.js.map +7 -0
  144. package/dist/lib/profiler/index.js +258 -0
  145. package/dist/lib/profiler/index.js.map +7 -0
  146. package/dist/lib/query/engine.js +729 -0
  147. package/dist/lib/query/engine.js.map +7 -0
  148. package/dist/lib/query/join-utils.js +195 -0
  149. package/dist/lib/query/join-utils.js.map +7 -0
  150. package/dist/lib/query/types.js +9 -0
  151. package/dist/lib/query/types.js.map +7 -0
  152. package/dist/lib/search/config.js +32 -0
  153. package/dist/lib/search/config.js.map +7 -0
  154. package/dist/lib/search/tokenize.js +34 -0
  155. package/dist/lib/search/tokenize.js.map +7 -0
  156. package/dist/lib/slugify.js +24 -0
  157. package/dist/lib/slugify.js.map +7 -0
  158. package/dist/lib/testing/bootstrap.js +51 -0
  159. package/dist/lib/testing/bootstrap.js.map +7 -0
  160. package/dist/lib/testing/index.js +17 -0
  161. package/dist/lib/testing/index.js.map +7 -0
  162. package/dist/lib/testing/renderWithProviders.js +15 -0
  163. package/dist/lib/testing/renderWithProviders.js.map +7 -0
  164. package/dist/lib/url.js +12 -0
  165. package/dist/lib/url.js.map +7 -0
  166. package/dist/lib/utils.js +13 -0
  167. package/dist/lib/utils.js.map +7 -0
  168. package/dist/lib/version.js +7 -0
  169. package/dist/lib/version.js.map +7 -0
  170. package/dist/modules/dashboard/widgets.js +1 -0
  171. package/dist/modules/dashboard/widgets.js.map +7 -0
  172. package/dist/modules/dsl.js +30 -0
  173. package/dist/modules/dsl.js.map +7 -0
  174. package/dist/modules/entities/kinds.js +22 -0
  175. package/dist/modules/entities/kinds.js.map +7 -0
  176. package/dist/modules/entities/options.js +26 -0
  177. package/dist/modules/entities/options.js.map +7 -0
  178. package/dist/modules/entities/validation.js +102 -0
  179. package/dist/modules/entities/validation.js.map +7 -0
  180. package/dist/modules/entities/validators.js +88 -0
  181. package/dist/modules/entities/validators.js.map +7 -0
  182. package/dist/modules/entities.js +1 -0
  183. package/dist/modules/entities.js.map +7 -0
  184. package/dist/modules/navigation/sidebarPreferences.js +50 -0
  185. package/dist/modules/navigation/sidebarPreferences.js.map +7 -0
  186. package/dist/modules/perspectives/types.js +1 -0
  187. package/dist/modules/perspectives/types.js.map +7 -0
  188. package/dist/modules/registry.js +96 -0
  189. package/dist/modules/registry.js.map +7 -0
  190. package/dist/modules/search.js +15 -0
  191. package/dist/modules/search.js.map +7 -0
  192. package/dist/modules/vector.js +1 -0
  193. package/dist/modules/vector.js.map +7 -0
  194. package/dist/modules/widgets/injection-loader.js +180 -0
  195. package/dist/modules/widgets/injection-loader.js.map +7 -0
  196. package/dist/modules/widgets/injection.js +1 -0
  197. package/dist/modules/widgets/injection.js.map +7 -0
  198. package/dist/security/features.js +23 -0
  199. package/dist/security/features.js.map +7 -0
  200. package/dist/types/pg.d.js +1 -0
  201. package/dist/types/pg.d.js.map +7 -0
  202. package/dist/types/react-email.d.js +1 -0
  203. package/dist/types/react-email.d.js.map +7 -0
  204. package/dist/types/resend.d.js +1 -0
  205. package/dist/types/resend.d.js.map +7 -0
  206. package/jest.config.cjs +22 -0
  207. package/package.json +88 -0
  208. package/src/index.ts +0 -0
  209. package/src/lib/api/__tests__/scoped.test.ts +38 -0
  210. package/src/lib/api/crud.ts +59 -0
  211. package/src/lib/api/scoped.ts +239 -0
  212. package/src/lib/auth/jwt.ts +39 -0
  213. package/src/lib/auth/server.ts +199 -0
  214. package/src/lib/boolean.ts +17 -0
  215. package/src/lib/bootstrap/appResolver.ts +85 -0
  216. package/src/lib/bootstrap/dynamicLoader.ts +177 -0
  217. package/src/lib/bootstrap/factory.ts +108 -0
  218. package/src/lib/bootstrap/index.ts +23 -0
  219. package/src/lib/bootstrap/types.ts +31 -0
  220. package/src/lib/cache/segments.ts +56 -0
  221. package/src/lib/cli/progress.ts +55 -0
  222. package/src/lib/commands/__tests__/command-bus.test.ts +84 -0
  223. package/src/lib/commands/__tests__/helpers.test.ts +42 -0
  224. package/src/lib/commands/command-bus.ts +349 -0
  225. package/src/lib/commands/customFieldSnapshots.ts +86 -0
  226. package/src/lib/commands/helpers.ts +143 -0
  227. package/src/lib/commands/index.ts +4 -0
  228. package/src/lib/commands/operationMetadata.ts +40 -0
  229. package/src/lib/commands/registry.ts +46 -0
  230. package/src/lib/commands/scope.ts +59 -0
  231. package/src/lib/commands/types.ts +63 -0
  232. package/src/lib/crud/__tests__/crud-factory.test.ts +333 -0
  233. package/src/lib/crud/__tests__/custom-fields.test.ts +150 -0
  234. package/src/lib/crud/cache-stats.ts +127 -0
  235. package/src/lib/crud/cache.ts +205 -0
  236. package/src/lib/crud/custom-fields-client.ts +54 -0
  237. package/src/lib/crud/custom-fields.ts +607 -0
  238. package/src/lib/crud/errors.ts +23 -0
  239. package/src/lib/crud/exporters.ts +188 -0
  240. package/src/lib/crud/factory.ts +1622 -0
  241. package/src/lib/crud/types.ts +29 -0
  242. package/src/lib/custom-fields/normalize.ts +45 -0
  243. package/src/lib/data/engine.ts +562 -0
  244. package/src/lib/db/escapeLikePattern.ts +2 -0
  245. package/src/lib/db/mikro.ts +100 -0
  246. package/src/lib/di/container.ts +105 -0
  247. package/src/lib/email/send.ts +18 -0
  248. package/src/lib/encryption/__tests__/customFieldValues.test.ts +63 -0
  249. package/src/lib/encryption/__tests__/indexDoc.test.ts +115 -0
  250. package/src/lib/encryption/aes.ts +64 -0
  251. package/src/lib/encryption/customFieldValues.ts +67 -0
  252. package/src/lib/encryption/entityFields.ts +39 -0
  253. package/src/lib/encryption/entityIds.ts +107 -0
  254. package/src/lib/encryption/find.ts +81 -0
  255. package/src/lib/encryption/indexDoc.ts +104 -0
  256. package/src/lib/encryption/kms.ts +337 -0
  257. package/src/lib/encryption/subscriber.ts +416 -0
  258. package/src/lib/encryption/tenantDataEncryptionService.ts +313 -0
  259. package/src/lib/encryption/toggles.ts +15 -0
  260. package/src/lib/entities/naming.ts +6 -0
  261. package/src/lib/entities/system-entities.ts +43 -0
  262. package/src/lib/frontend/organizationEvents.ts +55 -0
  263. package/src/lib/frontend/useOrganizationScope.ts +30 -0
  264. package/src/lib/hotkeys/index.ts +168 -0
  265. package/src/lib/i18n/app-dictionaries.ts +18 -0
  266. package/src/lib/i18n/config.ts +4 -0
  267. package/src/lib/i18n/context.tsx +66 -0
  268. package/src/lib/i18n/server.ts +74 -0
  269. package/src/lib/i18n/translate.ts +54 -0
  270. package/src/lib/indexers/error-log.ts +106 -0
  271. package/src/lib/indexers/status-log.ts +119 -0
  272. package/src/lib/lib/auth/jwt.ts +39 -0
  273. package/src/lib/lib/auth/server.ts +94 -0
  274. package/src/lib/lib/email/send.ts +18 -0
  275. package/src/lib/lib/i18n/config.ts +4 -0
  276. package/src/lib/lib/i18n/context.tsx +38 -0
  277. package/src/lib/lib/utils.ts +6 -0
  278. package/src/lib/location/countries.ts +97 -0
  279. package/src/lib/modules/index.ts +1 -0
  280. package/src/lib/modules/registry.ts +18 -0
  281. package/src/lib/openapi/crud.ts +218 -0
  282. package/src/lib/openapi/generator.ts +1311 -0
  283. package/src/lib/openapi/index.ts +4 -0
  284. package/src/lib/openapi/sanitize.ts +137 -0
  285. package/src/lib/openapi/types.ts +79 -0
  286. package/src/lib/profiler/index.ts +371 -0
  287. package/src/lib/query/__tests__/engine.test.ts +274 -0
  288. package/src/lib/query/engine.ts +837 -0
  289. package/src/lib/query/join-utils.ts +238 -0
  290. package/src/lib/query/types.ts +121 -0
  291. package/src/lib/search/config.ts +49 -0
  292. package/src/lib/search/tokenize.ts +45 -0
  293. package/src/lib/slugify.ts +28 -0
  294. package/src/lib/testing/bootstrap.ts +124 -0
  295. package/src/lib/testing/index.ts +15 -0
  296. package/src/lib/testing/renderWithProviders.tsx +31 -0
  297. package/src/lib/url.ts +12 -0
  298. package/src/lib/utils.ts +17 -0
  299. package/src/lib/version.ts +5 -0
  300. package/src/modules/__tests__/dsl.test.ts +35 -0
  301. package/src/modules/__tests__/registry.test.ts +300 -0
  302. package/src/modules/dashboard/widgets.ts +57 -0
  303. package/src/modules/dsl.ts +32 -0
  304. package/src/modules/entities/__tests__/validation.test.ts +52 -0
  305. package/src/modules/entities/kinds.ts +20 -0
  306. package/src/modules/entities/options.ts +36 -0
  307. package/src/modules/entities/validation.ts +118 -0
  308. package/src/modules/entities/validators.ts +93 -0
  309. package/src/modules/entities.ts +102 -0
  310. package/src/modules/navigation/sidebarPreferences.ts +62 -0
  311. package/src/modules/perspectives/types.ts +40 -0
  312. package/src/modules/registry.ts +249 -0
  313. package/src/modules/search.ts +325 -0
  314. package/src/modules/vector.ts +122 -0
  315. package/src/modules/widgets/__tests__/injection.test.ts +48 -0
  316. package/src/modules/widgets/injection-loader.ts +235 -0
  317. package/src/modules/widgets/injection.ts +120 -0
  318. package/src/security/features.ts +22 -0
  319. package/src/types/pg.d.ts +2 -0
  320. package/src/types/react-email.d.ts +2 -0
  321. package/src/types/resend.d.ts +2 -0
  322. package/tsconfig.build.json +11 -0
  323. package/tsconfig.json +9 -0
  324. package/watch.mjs +6 -0
@@ -0,0 +1,93 @@
1
+ import { z } from 'zod'
2
+ import { CUSTOM_FIELD_KINDS } from './kinds'
3
+ import { validationRulesArraySchema } from './validation'
4
+
5
+ export const entityIdRegex = /^[a-z0-9_]+:[a-z0-9_]+$/
6
+ export const fieldsetCodeRegex = /^[a-z0-9_\-]+$/
7
+
8
+ export const upsertCustomEntitySchema = z.object({
9
+ entityId: z.string().regex(
10
+ entityIdRegex,
11
+ 'Enter the entity id in the format: module_name:entity_id with your prefered entity and module names'
12
+ ),
13
+ label: z.string().min(1).max(200),
14
+ description: z.string().max(2000).optional().nullable(),
15
+ labelField: z.string().min(1).max(100).regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/).optional(),
16
+ defaultEditor: z.enum(['markdown','simpleMarkdown','htmlRichText']).optional(),
17
+ showInSidebar: z.boolean().default(false),
18
+ isActive: z.boolean().optional(),
19
+ })
20
+
21
+ export const upsertCustomFieldDefSchema = z.object({
22
+ entityId: z.string().regex(entityIdRegex),
23
+ key: z.string().min(1).max(100).regex(/^[a-z0-9_]+$/, 'snake_case only'),
24
+ kind: z.enum(CUSTOM_FIELD_KINDS),
25
+ configJson: z
26
+ .object({
27
+ // optional UI/behavioral hints
28
+ label: z.string().max(200).optional(),
29
+ description: z.string().max(2000).optional(),
30
+ options: z.array(z.union([z.string(), z.number()])).optional(),
31
+ optionsUrl: z.string().url().optional(),
32
+ multi: z.boolean().optional(),
33
+ editor: z.string().optional(),
34
+ input: z.string().optional(),
35
+ filterable: z.boolean().optional(),
36
+ formEditable: z.boolean().optional(),
37
+ listVisible: z.boolean().optional(),
38
+ priority: z.number().optional(),
39
+ encrypted: z.boolean().optional(),
40
+ relatedEntityId: z.string().optional(),
41
+ dictionaryId: z.string().uuid().optional(),
42
+ dictionaryInlineCreate: z.boolean().optional(),
43
+ // validation rules
44
+ validation: validationRulesArraySchema.optional(),
45
+ fieldset: z.string().regex(fieldsetCodeRegex).optional(),
46
+ group: z
47
+ .object({
48
+ code: z.string().regex(fieldsetCodeRegex),
49
+ title: z.string().max(200).optional(),
50
+ hint: z.string().max(500).optional(),
51
+ })
52
+ .optional(),
53
+ })
54
+ .passthrough()
55
+ .optional(),
56
+ isActive: z.boolean().optional(),
57
+ })
58
+
59
+ export const customFieldsetGroupSchema = z.object({
60
+ code: z.string().regex(fieldsetCodeRegex),
61
+ title: z.string().max(200).optional(),
62
+ hint: z.string().max(500).optional(),
63
+ })
64
+
65
+ export const customFieldsetSchema = z.object({
66
+ code: z.string().regex(fieldsetCodeRegex),
67
+ label: z.string().min(1).max(255),
68
+ icon: z.string().max(100).optional(),
69
+ description: z.string().max(2000).optional(),
70
+ groups: z.array(customFieldsetGroupSchema).optional(),
71
+ })
72
+
73
+ export const customFieldEntityConfigSchema = z.object({
74
+ fieldsets: z.array(customFieldsetSchema).max(20).optional(),
75
+ singleFieldsetPerRecord: z.boolean().optional(),
76
+ })
77
+
78
+ export const encryptionFieldRuleSchema = z.object({
79
+ field: z.string().min(1).max(200),
80
+ hashField: z.string().min(1).max(200).optional().nullable(),
81
+ })
82
+
83
+ export const upsertEncryptionMapSchema = z.object({
84
+ entityId: z.string().regex(entityIdRegex),
85
+ tenantId: z.string().uuid().nullable().optional(),
86
+ organizationId: z.string().uuid().nullable().optional(),
87
+ fields: z.array(encryptionFieldRuleSchema).min(1),
88
+ isActive: z.boolean().optional(),
89
+ })
90
+
91
+ export type UpsertCustomEntityInput = z.infer<typeof upsertCustomEntitySchema>
92
+ export type UpsertCustomFieldDefInput = z.infer<typeof upsertCustomFieldDefSchema>
93
+ export type UpsertEncryptionMapInput = z.infer<typeof upsertEncryptionMapSchema>
@@ -0,0 +1,102 @@
1
+ // Shared entity/extension/custom-field types used by generators and DI
2
+
3
+ export type EntityId = string // format: '<module>:<entity>' e.g., 'auth:user'
4
+
5
+ export type EntityExtension = {
6
+ // Base entity to extend, e.g., 'auth:user'
7
+ base: EntityId
8
+ // The extension entity that holds extra columns/relations, defined by the extending module
9
+ // Usually one-to-one keyed by base PK; other cardinalities allowed via explicit join keys
10
+ extension: EntityId
11
+ // Join description for query builder to link base <-> extension
12
+ join: {
13
+ baseKey: string // column name on base (e.g., 'id')
14
+ extensionKey: string // column name on extension (e.g., 'user_id')
15
+ }
16
+ cardinality?: 'one-to-one' | 'one-to-many' | 'many-to-one' | 'many-to-many'
17
+ required?: boolean
18
+ description?: string
19
+ }
20
+
21
+ export type CustomFieldKind =
22
+ | 'text'
23
+ | 'multiline'
24
+ | 'integer'
25
+ | 'float'
26
+ | 'boolean'
27
+ | 'select'
28
+ | 'currency'
29
+ | 'relation'
30
+ | 'attachment'
31
+ | 'dictionary'
32
+
33
+ export type CustomFieldDefinition = {
34
+ id?: string // stable id; generated if omitted
35
+ key: string // unique within entity (snake_case)
36
+ kind: CustomFieldKind
37
+ label?: string
38
+ description?: string
39
+ fieldset?: string
40
+ group?: {
41
+ code: string
42
+ title?: string
43
+ hint?: string
44
+ }
45
+ required?: boolean
46
+ multi?: boolean // allow multiple values
47
+ options?: Array<
48
+ string | number | boolean | { value: string | number | boolean; label?: string | null }
49
+ >
50
+ // Optional dynamic options source for selects/tags relations
51
+ optionsUrl?: string
52
+ defaultValue?: string | number | boolean | null
53
+ filterable?: boolean
54
+ // whether field should be editable in generated CRUD forms
55
+ formEditable?: boolean
56
+ indexed?: boolean
57
+ listVisible?: boolean
58
+ // Optional UI hints for generated forms/filters
59
+ // Editors for multiline-rich text fields:
60
+ // - 'markdown' -> UIW Markdown editor
61
+ // - 'simpleMarkdown' -> minimal toolbar markdown
62
+ // - 'htmlRichText' -> contenteditable rich text
63
+ editor?: 'markdown' | 'simpleMarkdown' | 'htmlRichText'
64
+ // Input hint for plain text fields (e.g., tags input when multi=true)
65
+ // Allow additional custom renderers (e.g., listbox from modules)
66
+ input?: string
67
+ // Relation helper metadata
68
+ relatedEntityId?: string
69
+ // Backed by global dictionaries module
70
+ dictionaryId?: string
71
+ dictionaryInlineCreate?: boolean
72
+ // Advanced validation rules applied in UI + API
73
+ validation?: Array<{ rule: string; param?: unknown; message?: string }>
74
+ // Attachments config passthrough (handled by attachments module)
75
+ maxAttachmentSizeMb?: number
76
+ acceptExtensions?: string[]
77
+ }
78
+
79
+ export type CustomFieldSet = {
80
+ entity: EntityId
81
+ fields: CustomFieldDefinition[]
82
+ // Optional: module id or other provenance
83
+ source?: string
84
+ }
85
+
86
+ export type EntityRegistrySpec = {
87
+ // Static, per-module declared extensions
88
+ extensions?: EntityExtension[]
89
+ // Static, per-module declared custom fields (seeded via migrations/CLI)
90
+ customFieldSets?: CustomFieldSet[]
91
+ }
92
+
93
+ export type CustomEntitySpec = {
94
+ id: EntityId
95
+ label?: string
96
+ description?: string
97
+ labelField?: string
98
+ defaultEditor?: string
99
+ showInSidebar?: boolean
100
+ global?: boolean
101
+ fields?: CustomFieldDefinition[]
102
+ }
@@ -0,0 +1,62 @@
1
+ import { slugify } from '../../lib/slugify'
2
+
3
+ export const SIDEBAR_PREFERENCES_VERSION = 2
4
+
5
+ export type SidebarPreferencesSettings = {
6
+ version: number
7
+ groupOrder?: string[]
8
+ groupLabels?: Record<string, string>
9
+ itemLabels?: Record<string, string>
10
+ hiddenItems?: string[]
11
+ }
12
+
13
+ export type SidebarPreferencesPayload = {
14
+ locale: string
15
+ settings: SidebarPreferencesSettings
16
+ }
17
+
18
+ export function normalizeSidebarSettings(settings?: SidebarPreferencesSettings | null): SidebarPreferencesSettings {
19
+ if (!settings || typeof settings !== 'object') {
20
+ return { version: SIDEBAR_PREFERENCES_VERSION, groupOrder: [], groupLabels: {}, itemLabels: {}, hiddenItems: [] }
21
+ }
22
+ const version = typeof settings.version === 'number' ? settings.version : SIDEBAR_PREFERENCES_VERSION
23
+ const groupOrder = Array.isArray(settings.groupOrder) ? settings.groupOrder.filter((v): v is string => typeof v === 'string') : []
24
+ const groupLabels = normalizeRecord(settings.groupLabels)
25
+ const itemLabels = normalizeRecord(settings.itemLabels)
26
+ const hiddenItems = normalizeStringArray(settings.hiddenItems)
27
+ return {
28
+ version,
29
+ groupOrder,
30
+ groupLabels,
31
+ itemLabels,
32
+ hiddenItems,
33
+ }
34
+ }
35
+
36
+ function normalizeRecord(record: Record<string, unknown> | undefined): Record<string, string> {
37
+ if (!record || typeof record !== 'object') return {}
38
+ const out: Record<string, string> = {}
39
+ for (const [key, value] of Object.entries(record)) {
40
+ if (typeof value !== 'string') continue
41
+ out[key] = value
42
+ }
43
+ return out
44
+ }
45
+
46
+ function normalizeStringArray(values: unknown): string[] {
47
+ if (!Array.isArray(values)) return []
48
+ const seen = new Set<string>()
49
+ const out: string[] = []
50
+ for (const value of values) {
51
+ if (typeof value !== 'string') continue
52
+ const trimmed = value.trim()
53
+ if (!trimmed || seen.has(trimmed)) continue
54
+ seen.add(trimmed)
55
+ out.push(trimmed)
56
+ }
57
+ return out
58
+ }
59
+
60
+ export function slugifySidebarId(source: string): string {
61
+ return slugify(source, { allowedChars: '' }) || 'group'
62
+ }
@@ -0,0 +1,40 @@
1
+ export type PerspectiveSettings = {
2
+ columnOrder?: string[]
3
+ columnVisibility?: Record<string, boolean>
4
+ filters?: Record<string, unknown>
5
+ sorting?: Array<{ id: string; desc?: boolean }>
6
+ pageSize?: number
7
+ searchValue?: string
8
+ }
9
+
10
+ export type PerspectiveDto = {
11
+ id: string
12
+ name: string
13
+ tableId: string
14
+ settings: PerspectiveSettings
15
+ isDefault: boolean
16
+ createdAt: string
17
+ updatedAt?: string | null
18
+ }
19
+
20
+ export type RolePerspectiveDto = PerspectiveDto & {
21
+ roleId: string
22
+ tenantId: string | null
23
+ organizationId: string | null
24
+ roleName?: string | null
25
+ }
26
+
27
+ export type PerspectivesIndexResponse = {
28
+ tableId: string
29
+ perspectives: PerspectiveDto[]
30
+ defaultPerspectiveId: string | null
31
+ rolePerspectives: RolePerspectiveDto[]
32
+ roles: Array<{ id: string; name: string; hasPerspective: boolean; hasDefault: boolean }>
33
+ canApplyToRoles: boolean
34
+ }
35
+
36
+ export type PerspectiveSaveResponse = {
37
+ perspective: PerspectiveDto
38
+ rolePerspectives: RolePerspectiveDto[]
39
+ clearedRoleIds: string[]
40
+ }
@@ -0,0 +1,249 @@
1
+ import type { ReactNode } from 'react'
2
+ import type { OpenApiRouteDoc, OpenApiMethodDoc } from '@open-mercato/shared/lib/openapi/types'
3
+ import type { DashboardWidgetModule } from './dashboard/widgets'
4
+ import type { InjectionWidgetModule, ModuleInjectionTable } from './widgets/injection'
5
+
6
+ // Context passed to dynamic metadata guards
7
+ export type RouteVisibilityContext = { path?: string; auth?: any }
8
+
9
+ // Metadata you can export from page.meta.ts or directly from a server page
10
+ export type PageMetadata = {
11
+ requireAuth?: boolean
12
+ requireRoles?: readonly string[]
13
+ // Optional fine-grained feature requirements
14
+ requireFeatures?: readonly string[]
15
+ // Titles and grouping (aliases supported)
16
+ title?: string
17
+ titleKey?: string
18
+ pageTitle?: string
19
+ pageTitleKey?: string
20
+ group?: string
21
+ groupKey?: string
22
+ pageGroup?: string
23
+ pageGroupKey?: string
24
+ // Ordering and visuals
25
+ order?: number
26
+ pageOrder?: number
27
+ icon?: ReactNode
28
+ navHidden?: boolean
29
+ // Dynamic flags
30
+ visible?: (ctx: RouteVisibilityContext) => boolean | Promise<boolean>
31
+ enabled?: (ctx: RouteVisibilityContext) => boolean | Promise<boolean>
32
+ // Optional static breadcrumb trail for header
33
+ breadcrumb?: Array<{ label: string; labelKey?: string; href?: string }>
34
+ }
35
+
36
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
37
+
38
+ export type ApiHandler = (req: Request, ctx?: any) => Promise<Response> | Response
39
+
40
+ export type ModuleRoute = {
41
+ pattern?: string
42
+ path?: string
43
+ requireAuth?: boolean
44
+ requireRoles?: string[]
45
+ // Optional fine-grained feature requirements
46
+ requireFeatures?: string[]
47
+ title?: string
48
+ titleKey?: string
49
+ group?: string
50
+ groupKey?: string
51
+ icon?: ReactNode
52
+ order?: number
53
+ priority?: number
54
+ navHidden?: boolean
55
+ visible?: (ctx: RouteVisibilityContext) => boolean | Promise<boolean>
56
+ enabled?: (ctx: RouteVisibilityContext) => boolean | Promise<boolean>
57
+ breadcrumb?: Array<{ label: string; labelKey?: string; href?: string }>
58
+ Component: (props: any) => ReactNode | Promise<ReactNode>
59
+ }
60
+
61
+ export type ModuleApiLegacy = {
62
+ method: HttpMethod
63
+ path: string
64
+ handler: ApiHandler
65
+ docs?: OpenApiMethodDoc
66
+ }
67
+
68
+ export type ModuleApiRouteFile = {
69
+ path: string
70
+ handlers: Partial<Record<HttpMethod, ApiHandler>>
71
+ requireAuth?: boolean
72
+ requireRoles?: string[]
73
+ // Optional fine-grained feature requirements for the entire route file
74
+ // Note: per-method feature requirements should be expressed inside metadata
75
+ requireFeatures?: string[]
76
+ docs?: OpenApiRouteDoc
77
+ metadata?: Partial<Record<HttpMethod, unknown>>
78
+ }
79
+
80
+ export type ModuleApi = ModuleApiLegacy | ModuleApiRouteFile
81
+
82
+ export type ModuleCli = {
83
+ command: string
84
+ run: (argv: string[]) => Promise<void> | void
85
+ }
86
+
87
+ export type ModuleInfo = {
88
+ name?: string
89
+ title?: string
90
+ version?: string
91
+ description?: string
92
+ author?: string
93
+ license?: string
94
+ homepage?: string
95
+ copyright?: string
96
+ // Optional hard dependencies: module ids that must be enabled
97
+ requires?: string[]
98
+ }
99
+
100
+ export type ModuleDashboardWidgetEntry = {
101
+ moduleId: string
102
+ key: string
103
+ source: 'app' | 'package'
104
+ loader: () => Promise<DashboardWidgetModule<any>>
105
+ }
106
+
107
+ export type ModuleInjectionWidgetEntry = {
108
+ moduleId: string
109
+ key: string
110
+ source: 'app' | 'package'
111
+ loader: () => Promise<InjectionWidgetModule<any, any>>
112
+ }
113
+
114
+ export type Module = {
115
+ id: string
116
+ info?: ModuleInfo
117
+ backendRoutes?: ModuleRoute[]
118
+ frontendRoutes?: ModuleRoute[]
119
+ apis?: ModuleApi[]
120
+ cli?: ModuleCli[]
121
+ translations?: Record<string, Record<string, string>>
122
+ // Optional: per-module feature declarations discovered from acl.ts (module root)
123
+ features?: Array<{ id: string; title: string; module: string }>
124
+ // Auto-discovered event subscribers
125
+ subscribers?: Array<{
126
+ id: string
127
+ event: string
128
+ persistent?: boolean
129
+ // Imported function reference; will be registered into event bus
130
+ handler: (payload: any, ctx: any) => Promise<void> | void
131
+ }>
132
+ // Auto-discovered queue workers
133
+ workers?: Array<{
134
+ id: string
135
+ queue: string
136
+ concurrency: number
137
+ // Imported function reference; will be called by the queue worker
138
+ handler: (job: unknown, ctx: unknown) => Promise<void> | void
139
+ }>
140
+ // Optional: per-module declared entity extensions and custom fields (static)
141
+ // Extensions discovered from data/extensions.ts; Custom fields discovered from ce.ts (entities[].fields)
142
+ entityExtensions?: import('./entities').EntityExtension[]
143
+ customFieldSets?: import('./entities').CustomFieldSet[]
144
+ // Optional: per-module declared custom entities (virtual/logical entities)
145
+ // Discovered from ce.ts (module root). Each entry represents an entityId with optional label/description.
146
+ customEntities?: Array<{ id: string; label?: string; description?: string }>
147
+ dashboardWidgets?: ModuleDashboardWidgetEntry[]
148
+ injectionWidgets?: ModuleInjectionWidgetEntry[]
149
+ injectionTable?: ModuleInjectionTable
150
+ }
151
+
152
+ function normPath(s: string) {
153
+ return (s.startsWith('/') ? s : '/' + s).replace(/\/+$/, '') || '/'
154
+ }
155
+
156
+ function matchPattern(pattern: string, pathname: string): Record<string, string | string[]> | undefined {
157
+ const p = normPath(pattern)
158
+ const u = normPath(pathname)
159
+ const pSegs = p.split('/').slice(1)
160
+ const uSegs = u.split('/').slice(1)
161
+ const params: Record<string, string | string[]> = {}
162
+ let i = 0
163
+ for (let j = 0; j < pSegs.length; j++, i++) {
164
+ const seg = pSegs[j]
165
+ const mCatchAll = seg.match(/^\[\.\.\.(.+)\]$/)
166
+ const mOptCatch = seg.match(/^\[\[\.\.\.(.+)\]\]$/)
167
+ const mDyn = seg.match(/^\[(.+)\]$/)
168
+ if (mCatchAll) {
169
+ const key = mCatchAll[1]
170
+ if (i >= uSegs.length) return undefined
171
+ params[key] = uSegs.slice(i)
172
+ i = uSegs.length
173
+ return i === uSegs.length ? params : undefined
174
+ } else if (mOptCatch) {
175
+ const key = mOptCatch[1]
176
+ params[key] = i < uSegs.length ? uSegs.slice(i) : []
177
+ i = uSegs.length
178
+ return params
179
+ } else if (mDyn) {
180
+ if (i >= uSegs.length) return undefined
181
+ params[mDyn[1]] = uSegs[i]
182
+ } else {
183
+ if (i >= uSegs.length || uSegs[i] !== seg) return undefined
184
+ }
185
+ }
186
+ if (i !== uSegs.length) return undefined
187
+ return params
188
+ }
189
+
190
+ function getPattern(r: ModuleRoute) {
191
+ return r.pattern ?? r.path ?? '/'
192
+ }
193
+
194
+ export function findFrontendMatch(modules: Module[], pathname: string): { route: ModuleRoute; params: Record<string, string | string[]> } | undefined {
195
+ for (const m of modules) {
196
+ const routes = m.frontendRoutes ?? []
197
+ for (const r of routes) {
198
+ const params = matchPattern(getPattern(r), pathname)
199
+ if (params) return { route: r, params }
200
+ }
201
+ }
202
+ }
203
+
204
+ export function findBackendMatch(modules: Module[], pathname: string): { route: ModuleRoute; params: Record<string, string | string[]> } | undefined {
205
+ for (const m of modules) {
206
+ const routes = m.backendRoutes ?? []
207
+ for (const r of routes) {
208
+ const params = matchPattern(getPattern(r), pathname)
209
+ if (params) return { route: r, params }
210
+ }
211
+ }
212
+ }
213
+
214
+ export function findApi(modules: Module[], method: HttpMethod, pathname: string): { handler: ApiHandler; params: Record<string, string | string[]>; requireAuth?: boolean; requireRoles?: string[]; metadata?: any } | undefined {
215
+ for (const m of modules) {
216
+ const apis = m.apis ?? []
217
+ for (const a of apis) {
218
+ if ('handlers' in a) {
219
+ const params = matchPattern(a.path, pathname)
220
+ const handler = (a.handlers as any)[method]
221
+ if (params && handler) return { handler, params, requireAuth: a.requireAuth, requireRoles: (a as any).requireRoles, metadata: (a as any).metadata }
222
+ } else {
223
+ const al = a as ModuleApiLegacy
224
+ if (al.method === method && al.path === pathname) {
225
+ return { handler: al.handler, params: {} }
226
+ }
227
+ }
228
+ }
229
+ }
230
+ }
231
+
232
+ // CLI modules registry - shared between CLI and module workers
233
+ let _cliModules: Module[] | null = null
234
+
235
+ export function registerCliModules(modules: Module[]) {
236
+ if (_cliModules !== null && process.env.NODE_ENV === 'development') {
237
+ console.debug('[Bootstrap] CLI modules re-registered (this may occur during HMR)')
238
+ }
239
+ _cliModules = modules
240
+ }
241
+
242
+ export function getCliModules(): Module[] {
243
+ // Return empty array if not registered - allows generate command to work without bootstrap
244
+ return _cliModules ?? []
245
+ }
246
+
247
+ export function hasCliModules(): boolean {
248
+ return _cliModules !== null && _cliModules.length > 0
249
+ }