@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
package/build.mjs ADDED
@@ -0,0 +1,101 @@
1
+ import * as esbuild from 'esbuild'
2
+ import { glob } from 'glob'
3
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs'
4
+ import { dirname, join } from 'node:path'
5
+ import { fileURLToPath } from 'node:url'
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url))
8
+
9
+ // Read the package version at build time for injection
10
+ const packageJson = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf-8'))
11
+ const packageVersion = packageJson.version
12
+
13
+ // Plugin to inject version at build time (replaces version.ts content)
14
+ const injectVersion = {
15
+ name: 'inject-version',
16
+ setup(build) {
17
+ build.onLoad({ filter: /lib\/version\.ts$/ }, async () => {
18
+ return {
19
+ contents: `// Build-time generated version
20
+ export const APP_VERSION = '${packageVersion}'
21
+ export const appVersion = APP_VERSION
22
+ `,
23
+ loader: 'ts'
24
+ }
25
+ })
26
+ }
27
+ }
28
+
29
+ const entryPoints = await glob(join(__dirname, 'src/**/*.{ts,tsx}'), {
30
+ ignore: ['**/__tests__/**', '**/*.test.ts', '**/*.test.tsx']
31
+ })
32
+
33
+ // Plugin to add .js extension to relative imports
34
+ const addJsExtension = {
35
+ name: 'add-js-extension',
36
+ setup(build) {
37
+ build.onEnd(async (result) => {
38
+ if (result.errors.length > 0) return
39
+ const outputFiles = await glob(join(__dirname, 'dist/**/*.js'))
40
+ for (const file of outputFiles) {
41
+ const fileDir = dirname(file)
42
+ let content = readFileSync(file, 'utf-8')
43
+ // Add .js to relative imports that don't have an extension
44
+ content = content.replace(
45
+ /from\s+["'](\.[^"']+)["']/g,
46
+ (match, path) => {
47
+ if (path.endsWith('.js') || path.endsWith('.json')) return match
48
+ // Check if it's a directory with index.js
49
+ const resolvedPath = join(fileDir, path)
50
+ if (existsSync(resolvedPath) && existsSync(join(resolvedPath, 'index.js'))) {
51
+ return `from "${path}/index.js"`
52
+ }
53
+ return `from "${path}.js"`
54
+ }
55
+ )
56
+ content = content.replace(
57
+ /import\s*\(\s*["'](\.[^"']+)["']\s*\)/g,
58
+ (match, path) => {
59
+ if (path.endsWith('.js') || path.endsWith('.json')) return match
60
+ // Check if it's a directory with index.js
61
+ const resolvedPath = join(fileDir, path)
62
+ if (existsSync(resolvedPath) && existsSync(join(resolvedPath, 'index.js'))) {
63
+ return `import("${path}/index.js")`
64
+ }
65
+ return `import("${path}.js")`
66
+ }
67
+ )
68
+ // Handle side-effect imports: import "./path" (no from clause)
69
+ content = content.replace(
70
+ /import\s+["'](\.[^"']+)["'];/g,
71
+ (match, path) => {
72
+ if (path.endsWith('.js') || path.endsWith('.json')) return match
73
+ // Check if it's a directory with index.js
74
+ const resolvedPath = join(fileDir, path)
75
+ if (existsSync(resolvedPath) && existsSync(join(resolvedPath, 'index.js'))) {
76
+ return `import "${path}/index.js";`
77
+ }
78
+ return `import "${path}.js";`
79
+ }
80
+ )
81
+ writeFileSync(file, content)
82
+ }
83
+ })
84
+ }
85
+ }
86
+
87
+ const outdir = join(__dirname, 'dist')
88
+
89
+ await esbuild.build({
90
+ entryPoints,
91
+ outdir,
92
+ outbase: join(__dirname, 'src'),
93
+ format: 'esm',
94
+ platform: 'node',
95
+ target: 'node18',
96
+ sourcemap: true,
97
+ jsx: 'automatic',
98
+ plugins: [injectVersion, addJsExtension],
99
+ })
100
+
101
+ console.log('shared built successfully')
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1,47 @@
1
+ function buildScopedWhere(base, scope) {
2
+ const where = { ...base };
3
+ const orgField = scope.orgField === null ? null : scope.orgField || "organizationId";
4
+ const tenantField = scope.tenantField === null ? null : scope.tenantField || "tenantId";
5
+ const softField = scope.softDeleteField === null ? null : scope.softDeleteField || "deletedAt";
6
+ if (orgField) {
7
+ if (scope.organizationIds !== void 0) {
8
+ const ids = (scope.organizationIds ?? []).filter((id) => typeof id === "string" && id.length > 0);
9
+ if (ids.length === 0) {
10
+ where[orgField] = { $in: [] };
11
+ } else if (ids.length === 1) {
12
+ where[orgField] = ids[0];
13
+ } else {
14
+ where[orgField] = { $in: ids };
15
+ }
16
+ } else if (scope.organizationId !== void 0) {
17
+ where[orgField] = scope.organizationId;
18
+ }
19
+ }
20
+ if (tenantField && scope.tenantId !== void 0) where[tenantField] = scope.tenantId;
21
+ if (softField) where[softField] = null;
22
+ return where;
23
+ }
24
+ function extractScopeFromAuth(auth) {
25
+ if (!auth) return {};
26
+ return { organizationId: auth.orgId ?? null, tenantId: auth.tenantId ?? null };
27
+ }
28
+ async function findOneScoped(em, entity, id, scope) {
29
+ const orgField = scope.orgField || "organizationId";
30
+ const tenantField = scope.tenantField || "tenantId";
31
+ const where = { id };
32
+ if (scope.organizationId != null) where[orgField] = scope.organizationId;
33
+ if (scope.tenantId != null) where[tenantField] = scope.tenantId;
34
+ return em.getRepository(entity).findOne(where);
35
+ }
36
+ async function softDelete(em, entity) {
37
+ ;
38
+ entity.deletedAt = /* @__PURE__ */ new Date();
39
+ await em.persistAndFlush(entity);
40
+ }
41
+ export {
42
+ buildScopedWhere,
43
+ extractScopeFromAuth,
44
+ findOneScoped,
45
+ softDelete
46
+ };
47
+ //# sourceMappingURL=crud.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/api/crud.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/core'\n\ntype Scope = { organizationId?: string | null; organizationIds?: string[] | null; tenantId?: string | null }\n\nexport function buildScopedWhere(\n base: Record<string, any>,\n scope: Scope & { orgField?: string | null; tenantField?: string | null; softDeleteField?: string | null }\n): Record<string, any> {\n const where: any = { ...base }\n const orgField = scope.orgField === null ? null : (scope.orgField as string) || 'organizationId'\n const tenantField = scope.tenantField === null ? null : (scope.tenantField as string) || 'tenantId'\n const softField = scope.softDeleteField === null ? null : (scope.softDeleteField as string) || 'deletedAt'\n\n if (orgField) {\n if (scope.organizationIds !== undefined) {\n const ids = (scope.organizationIds ?? []).filter((id): id is string => typeof id === 'string' && id.length > 0)\n if (ids.length === 0) {\n where[orgField] = { $in: [] }\n } else if (ids.length === 1) {\n where[orgField] = ids[0]\n } else {\n where[orgField] = { $in: ids }\n }\n } else if (scope.organizationId !== undefined) {\n where[orgField] = scope.organizationId\n }\n }\n\n if (tenantField && scope.tenantId !== undefined) where[tenantField] = scope.tenantId\n if (softField) where[softField] = null\n return where\n}\n\nexport function extractScopeFromAuth(auth: { orgId?: string | null; tenantId?: string | null } | null | undefined): { organizationId?: string | null; tenantId?: string | null } {\n if (!auth) return {}\n return { organizationId: auth.orgId ?? null, tenantId: auth.tenantId ?? null }\n}\n\nexport async function findOneScoped<T extends { id: string }>(\n em: EntityManager,\n entity: { new (): T },\n id: string,\n scope: Scope & { orgField?: keyof T; tenantField?: keyof T }\n): Promise<T | null> {\n const orgField = (scope.orgField as string) || 'organizationId'\n const tenantField = (scope.tenantField as string) || 'tenantId'\n const where: any = { id }\n if (scope.organizationId != null) where[orgField] = scope.organizationId\n if (scope.tenantId != null) where[tenantField] = scope.tenantId\n return em.getRepository(entity).findOne(where as any)\n}\n\nexport async function softDelete<T extends { deletedAt?: Date | null }>(\n em: EntityManager,\n entity: T\n): Promise<void> {\n ;(entity as any).deletedAt = new Date()\n await em.persistAndFlush(entity)\n}\n"],
5
+ "mappings": "AAIO,SAAS,iBACd,MACA,OACqB;AACrB,QAAM,QAAa,EAAE,GAAG,KAAK;AAC7B,QAAM,WAAW,MAAM,aAAa,OAAO,OAAQ,MAAM,YAAuB;AAChF,QAAM,cAAc,MAAM,gBAAgB,OAAO,OAAQ,MAAM,eAA0B;AACzF,QAAM,YAAY,MAAM,oBAAoB,OAAO,OAAQ,MAAM,mBAA8B;AAE/F,MAAI,UAAU;AACZ,QAAI,MAAM,oBAAoB,QAAW;AACvC,YAAM,OAAO,MAAM,mBAAmB,CAAC,GAAG,OAAO,CAAC,OAAqB,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAC9G,UAAI,IAAI,WAAW,GAAG;AACpB,cAAM,QAAQ,IAAI,EAAE,KAAK,CAAC,EAAE;AAAA,MAC9B,WAAW,IAAI,WAAW,GAAG;AAC3B,cAAM,QAAQ,IAAI,IAAI,CAAC;AAAA,MACzB,OAAO;AACL,cAAM,QAAQ,IAAI,EAAE,KAAK,IAAI;AAAA,MAC/B;AAAA,IACF,WAAW,MAAM,mBAAmB,QAAW;AAC7C,YAAM,QAAQ,IAAI,MAAM;AAAA,IAC1B;AAAA,EACF;AAEA,MAAI,eAAe,MAAM,aAAa,OAAW,OAAM,WAAW,IAAI,MAAM;AAC5E,MAAI,UAAW,OAAM,SAAS,IAAI;AAClC,SAAO;AACT;AAEO,SAAS,qBAAqB,MAA4I;AAC/K,MAAI,CAAC,KAAM,QAAO,CAAC;AACnB,SAAO,EAAE,gBAAgB,KAAK,SAAS,MAAM,UAAU,KAAK,YAAY,KAAK;AAC/E;AAEA,eAAsB,cACpB,IACA,QACA,IACA,OACmB;AACnB,QAAM,WAAY,MAAM,YAAuB;AAC/C,QAAM,cAAe,MAAM,eAA0B;AACrD,QAAM,QAAa,EAAE,GAAG;AACxB,MAAI,MAAM,kBAAkB,KAAM,OAAM,QAAQ,IAAI,MAAM;AAC1D,MAAI,MAAM,YAAY,KAAM,OAAM,WAAW,IAAI,MAAM;AACvD,SAAO,GAAG,cAAc,MAAM,EAAE,QAAQ,KAAY;AACtD;AAEA,eAAsB,WACpB,IACA,QACe;AACf;AAAC,EAAC,OAAe,YAAY,oBAAI,KAAK;AACtC,QAAM,GAAG,gBAAgB,MAAM;AACjC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,140 @@
1
+ import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
2
+ import { splitCustomFieldPayload } from "@open-mercato/shared/lib/crud/custom-fields";
3
+ const DEFAULT_MESSAGES = {
4
+ tenantRequired: { key: "errors.tenant_required", fallback: "Tenant context is required." },
5
+ organizationRequired: { key: "errors.organization_required", fallback: "Organization context is required." },
6
+ idRequired: { key: "errors.id_required", fallback: "Record identifier is required." },
7
+ tenantForbidden: { key: "errors.tenant_forbidden", fallback: "You are not allowed to target this tenant." }
8
+ };
9
+ function resolveMessage(messages, key) {
10
+ const override = messages?.[key];
11
+ if (override && typeof override.key === "string" && override.key.length > 0) {
12
+ return {
13
+ key: override.key,
14
+ fallback: override.fallback ?? DEFAULT_MESSAGES[key].fallback
15
+ };
16
+ }
17
+ return DEFAULT_MESSAGES[key];
18
+ }
19
+ function withScopedPayload(payload, ctx, translate, options = {}) {
20
+ const requireOrganization = options.requireOrganization !== false;
21
+ const hasGlobalOrgAccess = ctx.organizationScope?.allowedIds === null;
22
+ const source = payload ? { ...payload } : {};
23
+ const tenantId = source?.tenantId ?? ctx.auth?.tenantId ?? null;
24
+ if (!tenantId) {
25
+ const msg = resolveMessage(options.messages, "tenantRequired");
26
+ throw new CrudHttpError(400, { error: translate(msg.key, msg.fallback) });
27
+ }
28
+ const resolvedOrg = source?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
29
+ if (requireOrganization && !hasGlobalOrgAccess && !resolvedOrg) {
30
+ const msg = resolveMessage(options.messages, "organizationRequired");
31
+ throw new CrudHttpError(400, { error: translate(msg.key, msg.fallback) });
32
+ }
33
+ const scoped = {
34
+ ...source,
35
+ tenantId
36
+ };
37
+ if (resolvedOrg) scoped.organizationId = resolvedOrg;
38
+ return scoped;
39
+ }
40
+ function parseScopedCommandInput(schema, payload, ctx, translate, options = {}) {
41
+ const scoped = withScopedPayload(
42
+ payload && typeof payload === "object" ? payload : {},
43
+ ctx,
44
+ translate,
45
+ options
46
+ );
47
+ const actorTenantId = normalizeTenant(ctx.auth?.tenantId);
48
+ const requestedTenantId = normalizeTenant(scoped.tenantId);
49
+ const isSuperAdmin = authIsSuperAdmin(ctx.auth);
50
+ if (!isSuperAdmin) {
51
+ if (actorTenantId) {
52
+ if (!requestedTenantId || requestedTenantId !== actorTenantId) {
53
+ const msg = resolveMessage(options.messages, "tenantForbidden");
54
+ throw new CrudHttpError(403, { error: translate(msg.key, msg.fallback) });
55
+ }
56
+ } else if (requestedTenantId) {
57
+ const msg = resolveMessage(options.messages, "tenantForbidden");
58
+ throw new CrudHttpError(403, { error: translate(msg.key, msg.fallback) });
59
+ }
60
+ }
61
+ const { base, custom } = splitCustomFieldPayload(scoped);
62
+ const hasCustomFields = custom && Object.keys(custom).length > 0;
63
+ const candidates = hasCustomFields ? [base, { ...base, customFields: custom }] : [base];
64
+ let parsed;
65
+ let lastError;
66
+ for (const candidate of candidates) {
67
+ try {
68
+ parsed = schema.parse(candidate);
69
+ break;
70
+ } catch (err) {
71
+ lastError = err;
72
+ }
73
+ }
74
+ if (!parsed) {
75
+ if (lastError instanceof Error) throw lastError;
76
+ throw new CrudHttpError(400, { error: translate("errors.invalid_input", "Invalid input") });
77
+ }
78
+ const parsedWithCustom = hasCustomFields ? Object.assign({}, parsed, { customFields: custom }) : parsed;
79
+ return parsedWithCustom;
80
+ }
81
+ function normalizeTenant(candidate) {
82
+ if (typeof candidate === "string" && candidate.trim().length > 0) return candidate.trim();
83
+ return null;
84
+ }
85
+ function authIsSuperAdmin(auth) {
86
+ if (!auth) return false;
87
+ return auth.isSuperAdmin === true;
88
+ }
89
+ function requireRecordId(candidate, ctx, translate, options = {}) {
90
+ const fieldName = "id";
91
+ const id = typeof candidate === "string" ? candidate.trim() : candidate && typeof candidate === "object" ? typeof candidate[fieldName] === "string" ? String(candidate[fieldName]) : null : null;
92
+ if (id && id.length > 0) return id;
93
+ const msg = resolveMessage(options.messages, "idRequired");
94
+ throw new CrudHttpError(400, { error: translate(msg.key, msg.fallback) });
95
+ }
96
+ function resolveCrudRecordId(parsed, ctx, translate, options = {}) {
97
+ const fieldName = options.fieldName ?? "id";
98
+ const queryParam = options.queryParam ?? fieldName;
99
+ const tryRequire = (value) => {
100
+ try {
101
+ return requireRecordId(value, ctx, translate, options);
102
+ } catch {
103
+ return null;
104
+ }
105
+ };
106
+ if (parsed && typeof parsed === "object") {
107
+ const body = parsed.body;
108
+ const fromBody = body && typeof body === "object" ? tryRequire(body) : null;
109
+ if (fromBody) return fromBody;
110
+ const fallback = tryRequire(parsed);
111
+ if (fallback) return fallback;
112
+ const query = parsed.query;
113
+ if (query && typeof query === "object") {
114
+ const candidate = query[queryParam];
115
+ if (typeof candidate === "string" && candidate.trim().length > 0) return candidate.trim();
116
+ }
117
+ }
118
+ if (ctx.request instanceof Request) {
119
+ const value = new URL(ctx.request.url).searchParams.get(queryParam);
120
+ if (value && value.trim().length > 0) return value.trim();
121
+ }
122
+ const msg = resolveMessage(options.messages, "idRequired");
123
+ throw new CrudHttpError(400, { error: translate(msg.key, msg.fallback) });
124
+ }
125
+ function createScopedApiHelpers(baseOptions) {
126
+ return {
127
+ withScopedPayload: (payload, ctx, translate, options = {}) => withScopedPayload(payload, ctx, translate, { ...baseOptions, ...options }),
128
+ parseScopedCommandInput: (schema, payload, ctx, translate, options = {}) => parseScopedCommandInput(schema, payload, ctx, translate, { ...baseOptions, ...options }),
129
+ requireRecordId: (candidate, ctx, translate, options = {}) => requireRecordId(candidate, ctx, translate, { ...baseOptions, ...options }),
130
+ resolveCrudRecordId: (parsed, ctx, translate, options = {}) => resolveCrudRecordId(parsed, ctx, translate, { ...baseOptions, ...options })
131
+ };
132
+ }
133
+ export {
134
+ createScopedApiHelpers,
135
+ parseScopedCommandInput,
136
+ requireRecordId,
137
+ resolveCrudRecordId,
138
+ withScopedPayload
139
+ };
140
+ //# sourceMappingURL=scoped.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/api/scoped.ts"],
4
+ "sourcesContent": ["import type { CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { splitCustomFieldPayload } from '@open-mercato/shared/lib/crud/custom-fields'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport type { z } from 'zod'\n\nexport type ScopedContext = (CommandRuntimeContext | CrudCtx) & {\n auth: { tenantId?: string | null; orgId?: string | null } | null\n selectedOrganizationId?: string | null\n}\n\nexport type TranslateFn = (key: string, fallback?: string) => string\n\nexport type ScopedMessage = {\n key: string\n fallback: string\n}\n\nexport type ScopedPayloadMessages = {\n tenantRequired?: ScopedMessage\n organizationRequired?: ScopedMessage\n idRequired?: ScopedMessage\n tenantForbidden?: ScopedMessage\n}\n\nexport type ScopedPayloadOptions = {\n requireOrganization?: boolean\n messages?: ScopedPayloadMessages\n}\n\nconst DEFAULT_MESSAGES: Required<ScopedPayloadMessages> = {\n tenantRequired: { key: 'errors.tenant_required', fallback: 'Tenant context is required.' },\n organizationRequired: { key: 'errors.organization_required', fallback: 'Organization context is required.' },\n idRequired: { key: 'errors.id_required', fallback: 'Record identifier is required.' },\n tenantForbidden: { key: 'errors.tenant_forbidden', fallback: 'You are not allowed to target this tenant.' },\n}\n\nfunction resolveMessage(messages: ScopedPayloadMessages | undefined, key: keyof ScopedPayloadMessages): ScopedMessage {\n const override = messages?.[key]\n if (override && typeof override.key === 'string' && override.key.length > 0) {\n return {\n key: override.key,\n fallback: override.fallback ?? DEFAULT_MESSAGES[key]!.fallback,\n }\n }\n return DEFAULT_MESSAGES[key]!\n}\n\nexport function withScopedPayload<T extends Record<string, unknown>>(\n payload: T | null | undefined,\n ctx: ScopedContext,\n translate: TranslateFn,\n options: ScopedPayloadOptions = {}\n): T & { tenantId: string; organizationId?: string } {\n const requireOrganization = options.requireOrganization !== false\n const hasGlobalOrgAccess = ctx.organizationScope?.allowedIds === null\n const source = payload ? { ...payload } : {}\n const tenantId = (source as { tenantId?: string })?.tenantId ?? ctx.auth?.tenantId ?? null\n if (!tenantId) {\n const msg = resolveMessage(options.messages, 'tenantRequired')\n throw new CrudHttpError(400, { error: translate(msg.key, msg.fallback) })\n }\n\n const resolvedOrg =\n (source as { organizationId?: string })?.organizationId ??\n ctx.selectedOrganizationId ??\n ctx.auth?.orgId ??\n null\n\n if (requireOrganization && !hasGlobalOrgAccess && !resolvedOrg) {\n const msg = resolveMessage(options.messages, 'organizationRequired')\n throw new CrudHttpError(400, { error: translate(msg.key, msg.fallback) })\n }\n\n const scoped = {\n ...source,\n tenantId,\n } as T & { tenantId: string; organizationId?: string }\n\n if (resolvedOrg) scoped.organizationId = resolvedOrg\n\n return scoped\n}\n\nexport function parseScopedCommandInput<TSchema extends z.ZodTypeAny>(\n schema: TSchema,\n payload: unknown,\n ctx: ScopedContext,\n translate: TranslateFn,\n options: ScopedPayloadOptions = {}\n): z.infer<TSchema> & { customFields?: Record<string, unknown> } {\n const scoped = withScopedPayload(\n (payload && typeof payload === 'object' ? payload : {}) as Record<string, unknown>,\n ctx,\n translate,\n options\n )\n const actorTenantId = normalizeTenant(ctx.auth?.tenantId)\n const requestedTenantId = normalizeTenant(scoped.tenantId)\n const isSuperAdmin = authIsSuperAdmin(ctx.auth)\n if (!isSuperAdmin) {\n if (actorTenantId) {\n if (!requestedTenantId || requestedTenantId !== actorTenantId) {\n const msg = resolveMessage(options.messages, 'tenantForbidden')\n throw new CrudHttpError(403, { error: translate(msg.key, msg.fallback) })\n }\n } else if (requestedTenantId) {\n const msg = resolveMessage(options.messages, 'tenantForbidden')\n throw new CrudHttpError(403, { error: translate(msg.key, msg.fallback) })\n }\n }\n const { base, custom } = splitCustomFieldPayload(scoped)\n const hasCustomFields = custom && Object.keys(custom).length > 0\n const candidates: Array<Record<string, unknown>> = hasCustomFields\n ? [base, { ...base, customFields: custom }]\n : [base]\n\n let parsed: z.infer<TSchema> | undefined\n let lastError: unknown\n for (const candidate of candidates) {\n try {\n parsed = schema.parse(candidate) as z.infer<TSchema>\n break\n } catch (err) {\n lastError = err\n }\n }\n if (!parsed) {\n if (lastError instanceof Error) throw lastError\n throw new CrudHttpError(400, { error: translate('errors.invalid_input', 'Invalid input') })\n }\n\n const parsedWithCustom = hasCustomFields\n ? Object.assign({}, parsed, { customFields: custom })\n : parsed\n\n return parsedWithCustom as z.infer<TSchema> & { customFields?: Record<string, unknown> }\n}\n\nfunction normalizeTenant(candidate: unknown): string | null {\n if (typeof candidate === 'string' && candidate.trim().length > 0) return candidate.trim()\n return null\n}\n\nfunction authIsSuperAdmin(auth: ScopedContext['auth']): boolean {\n if (!auth) return false\n return (auth as Record<string, unknown>).isSuperAdmin === true\n}\n\nexport function requireRecordId(\n candidate: unknown,\n ctx: ScopedContext,\n translate: TranslateFn,\n options: ScopedPayloadOptions = {}\n): string {\n const fieldName = 'id'\n const id =\n typeof candidate === 'string'\n ? candidate.trim()\n : candidate && typeof candidate === 'object'\n ? typeof (candidate as Record<string, unknown>)[fieldName] === 'string'\n ? String((candidate as Record<string, unknown>)[fieldName])\n : null\n : null\n if (id && id.length > 0) return id\n const msg = resolveMessage(options.messages, 'idRequired')\n throw new CrudHttpError(400, { error: translate(msg.key, msg.fallback) })\n}\n\nexport function resolveCrudRecordId(\n parsed: unknown,\n ctx: ScopedContext,\n translate: TranslateFn,\n options: ScopedPayloadOptions & { fieldName?: string; queryParam?: string } = {}\n): string {\n const fieldName = options.fieldName ?? 'id'\n const queryParam = options.queryParam ?? fieldName\n\n const tryRequire = (value: unknown): string | null => {\n try {\n return requireRecordId(value, ctx, translate, options)\n } catch {\n return null\n }\n }\n\n if (parsed && typeof parsed === 'object') {\n const body = (parsed as Record<string, unknown>).body\n const fromBody = body && typeof body === 'object' ? tryRequire(body) : null\n if (fromBody) return fromBody\n\n const fallback = tryRequire(parsed)\n if (fallback) return fallback\n\n const query = (parsed as Record<string, unknown>).query\n if (query && typeof query === 'object') {\n const candidate = (query as Record<string, unknown>)[queryParam]\n if (typeof candidate === 'string' && candidate.trim().length > 0) return candidate.trim()\n }\n }\n\n if (ctx.request instanceof Request) {\n const value = new URL(ctx.request.url).searchParams.get(queryParam)\n if (value && value.trim().length > 0) return value.trim()\n }\n\n const msg = resolveMessage(options.messages, 'idRequired')\n throw new CrudHttpError(400, { error: translate(msg.key, msg.fallback) })\n}\n\nexport function createScopedApiHelpers(baseOptions?: ScopedPayloadOptions) {\n return {\n withScopedPayload: <T extends Record<string, unknown>>(\n payload: T | null | undefined,\n ctx: ScopedContext,\n translate: TranslateFn,\n options: ScopedPayloadOptions = {}\n ) => withScopedPayload(payload, ctx, translate, { ...baseOptions, ...options }),\n parseScopedCommandInput: <TSchema extends z.ZodTypeAny>(\n schema: TSchema,\n payload: unknown,\n ctx: ScopedContext,\n translate: TranslateFn,\n options: ScopedPayloadOptions = {}\n ) => parseScopedCommandInput(schema, payload, ctx, translate, { ...baseOptions, ...options }),\n requireRecordId: (\n candidate: unknown,\n ctx: ScopedContext,\n translate: TranslateFn,\n options: ScopedPayloadOptions = {}\n ) => requireRecordId(candidate, ctx, translate, { ...baseOptions, ...options }),\n resolveCrudRecordId: (\n parsed: unknown,\n ctx: ScopedContext,\n translate: TranslateFn,\n options: ScopedPayloadOptions & { fieldName?: string; queryParam?: string } = {}\n ) => resolveCrudRecordId(parsed, ctx, translate, { ...baseOptions, ...options }),\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,34 @@
1
+ import crypto from "node:crypto";
2
+ function base64url(input) {
3
+ return (typeof input === "string" ? Buffer.from(input) : input).toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
4
+ }
5
+ function signJwt(payload, secret = process.env.JWT_SECRET, expiresInSec = 60 * 60 * 8) {
6
+ if (!secret) throw new Error("JWT_SECRET is not set");
7
+ const header = { alg: "HS256", typ: "JWT" };
8
+ const now = Math.floor(Date.now() / 1e3);
9
+ const body = { iat: now, exp: now + expiresInSec, ...payload };
10
+ const encHeader = base64url(JSON.stringify(header));
11
+ const encBody = base64url(JSON.stringify(body));
12
+ const data = `${encHeader}.${encBody}`;
13
+ const sig = crypto.createHmac("sha256", secret).update(data).digest();
14
+ const encSig = base64url(sig);
15
+ return `${data}.${encSig}`;
16
+ }
17
+ function verifyJwt(token, secret = process.env.JWT_SECRET) {
18
+ if (!secret) throw new Error("JWT_SECRET is not set");
19
+ const parts = token.split(".");
20
+ if (parts.length !== 3) return null;
21
+ const [h, p, s] = parts;
22
+ const data = `${h}.${p}`;
23
+ const expected = base64url(crypto.createHmac("sha256", secret).update(data).digest());
24
+ if (!crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected))) return null;
25
+ const payload = JSON.parse(Buffer.from(p, "base64").toString("utf8"));
26
+ const now = Math.floor(Date.now() / 1e3);
27
+ if (payload.exp && now > payload.exp) return null;
28
+ return payload;
29
+ }
30
+ export {
31
+ signJwt,
32
+ verifyJwt
33
+ };
34
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/auth/jwt.ts"],
4
+ "sourcesContent": ["import crypto from 'node:crypto'\n\nfunction base64url(input: Buffer | string) {\n return (typeof input === 'string' ? Buffer.from(input) : input)\n .toString('base64')\n .replace(/=/g, '')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n}\n\nexport type JwtPayload = Record<string, any>\n\nexport function signJwt(payload: JwtPayload, secret = process.env.JWT_SECRET!, expiresInSec = 60 * 60 * 8) {\n if (!secret) throw new Error('JWT_SECRET is not set')\n const header = { alg: 'HS256', typ: 'JWT' }\n const now = Math.floor(Date.now() / 1000)\n const body = { iat: now, exp: now + expiresInSec, ...payload }\n const encHeader = base64url(JSON.stringify(header))\n const encBody = base64url(JSON.stringify(body))\n const data = `${encHeader}.${encBody}`\n const sig = crypto.createHmac('sha256', secret).update(data).digest()\n const encSig = base64url(sig)\n return `${data}.${encSig}`\n}\n\nexport function verifyJwt(token: string, secret = process.env.JWT_SECRET!) {\n if (!secret) throw new Error('JWT_SECRET is not set')\n const parts = token.split('.')\n if (parts.length !== 3) return null\n const [h, p, s] = parts\n const data = `${h}.${p}`\n const expected = base64url(crypto.createHmac('sha256', secret).update(data).digest())\n if (!crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected))) return null\n const payload = JSON.parse(Buffer.from(p, 'base64').toString('utf8'))\n const now = Math.floor(Date.now() / 1000)\n if (payload.exp && now > payload.exp) return null\n return payload\n}\n\n"],
5
+ "mappings": "AAAA,OAAO,YAAY;AAEnB,SAAS,UAAU,OAAwB;AACzC,UAAQ,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,OACtD,SAAS,QAAQ,EACjB,QAAQ,MAAM,EAAE,EAChB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG;AACvB;AAIO,SAAS,QAAQ,SAAqB,SAAS,QAAQ,IAAI,YAAa,eAAe,KAAK,KAAK,GAAG;AACzG,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,uBAAuB;AACpD,QAAM,SAAS,EAAE,KAAK,SAAS,KAAK,MAAM;AAC1C,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,OAAO,EAAE,KAAK,KAAK,KAAK,MAAM,cAAc,GAAG,QAAQ;AAC7D,QAAM,YAAY,UAAU,KAAK,UAAU,MAAM,CAAC;AAClD,QAAM,UAAU,UAAU,KAAK,UAAU,IAAI,CAAC;AAC9C,QAAM,OAAO,GAAG,SAAS,IAAI,OAAO;AACpC,QAAM,MAAM,OAAO,WAAW,UAAU,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO;AACpE,QAAM,SAAS,UAAU,GAAG;AAC5B,SAAO,GAAG,IAAI,IAAI,MAAM;AAC1B;AAEO,SAAS,UAAU,OAAe,SAAS,QAAQ,IAAI,YAAa;AACzE,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,uBAAuB;AACpD,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,CAAC,GAAG,GAAG,CAAC,IAAI;AAClB,QAAM,OAAO,GAAG,CAAC,IAAI,CAAC;AACtB,QAAM,WAAW,UAAU,OAAO,WAAW,UAAU,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO,CAAC;AACpF,MAAI,CAAC,OAAO,gBAAgB,OAAO,KAAK,CAAC,GAAG,OAAO,KAAK,QAAQ,CAAC,EAAG,QAAO;AAC3E,QAAM,UAAU,KAAK,MAAM,OAAO,KAAK,GAAG,QAAQ,EAAE,SAAS,MAAM,CAAC;AACpE,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,MAAI,QAAQ,OAAO,MAAM,QAAQ,IAAK,QAAO;AAC7C,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,157 @@
1
+ import { cookies } from "next/headers";
2
+ import { verifyJwt } from "./jwt.js";
3
+ const TENANT_COOKIE_NAME = "om_selected_tenant";
4
+ const ORGANIZATION_COOKIE_NAME = "om_selected_org";
5
+ const ALL_ORGANIZATIONS_COOKIE_VALUE = "__all__";
6
+ const SUPERADMIN_ROLE = "superadmin";
7
+ function decodeCookieValue(raw) {
8
+ if (raw === void 0) return null;
9
+ try {
10
+ const decoded = decodeURIComponent(raw);
11
+ return decoded ?? null;
12
+ } catch {
13
+ return raw ?? null;
14
+ }
15
+ }
16
+ function readCookieFromHeader(header, name) {
17
+ if (!header) return void 0;
18
+ const parts = header.split(";");
19
+ for (const part of parts) {
20
+ const trimmed = part.trim();
21
+ if (trimmed.startsWith(`${name}=`)) {
22
+ return trimmed.slice(name.length + 1);
23
+ }
24
+ }
25
+ return void 0;
26
+ }
27
+ function resolveTenantOverride(raw) {
28
+ if (raw === void 0) return { applied: false, value: null };
29
+ const decoded = decodeCookieValue(raw);
30
+ if (!decoded) return { applied: true, value: null };
31
+ const trimmed = decoded.trim();
32
+ if (!trimmed) return { applied: true, value: null };
33
+ return { applied: true, value: trimmed };
34
+ }
35
+ function resolveOrganizationOverride(raw) {
36
+ if (raw === void 0) return { applied: false, value: null };
37
+ const decoded = decodeCookieValue(raw);
38
+ if (!decoded || decoded === ALL_ORGANIZATIONS_COOKIE_VALUE) {
39
+ return { applied: true, value: null };
40
+ }
41
+ const trimmed = decoded.trim();
42
+ if (!trimmed || trimmed === ALL_ORGANIZATIONS_COOKIE_VALUE) {
43
+ return { applied: true, value: null };
44
+ }
45
+ return { applied: true, value: trimmed };
46
+ }
47
+ function isSuperAdminAuth(auth) {
48
+ if (!auth) return false;
49
+ if (auth.isSuperAdmin === true) return true;
50
+ const roles = Array.isArray(auth?.roles) ? auth.roles : [];
51
+ return roles.some((role) => typeof role === "string" && role.trim().toLowerCase() === SUPERADMIN_ROLE);
52
+ }
53
+ function applySuperAdminScope(auth, tenantCookie, orgCookie) {
54
+ if (!auth || !isSuperAdminAuth(auth)) return auth;
55
+ const tenantOverride = resolveTenantOverride(tenantCookie);
56
+ const orgOverride = resolveOrganizationOverride(orgCookie);
57
+ if (!tenantOverride.applied && !orgOverride.applied) return auth;
58
+ const baseAuth = auth;
59
+ const next = { ...baseAuth };
60
+ if (tenantOverride.applied) {
61
+ if (!("actorTenantId" in next)) next.actorTenantId = auth?.tenantId ?? null;
62
+ next.tenantId = tenantOverride.value;
63
+ }
64
+ if (orgOverride.applied) {
65
+ if (!("actorOrgId" in next)) next.actorOrgId = auth?.orgId ?? null;
66
+ next.orgId = orgOverride.value;
67
+ }
68
+ next.isSuperAdmin = true;
69
+ const existingRoles = Array.isArray(next.roles) ? next.roles : [];
70
+ if (!existingRoles.some((role) => typeof role === "string" && role.trim().toLowerCase() === SUPERADMIN_ROLE)) {
71
+ next.roles = [...existingRoles, "superadmin"];
72
+ }
73
+ return next;
74
+ }
75
+ async function resolveApiKeyAuth(secret) {
76
+ if (!secret) return null;
77
+ try {
78
+ const { createRequestContainer } = await import("@open-mercato/shared/lib/di/container");
79
+ const container = await createRequestContainer();
80
+ const em = container.resolve("em");
81
+ const { findApiKeyBySecret } = await import("@open-mercato/core/modules/api_keys/services/apiKeyService");
82
+ const { Role } = await import("@open-mercato/core/modules/auth/data/entities");
83
+ const record = await findApiKeyBySecret(em, secret);
84
+ if (!record) return null;
85
+ const roleIds = Array.isArray(record.rolesJson) ? record.rolesJson.filter((value) => typeof value === "string" && value.length > 0) : [];
86
+ const roles = roleIds.length ? await em.find(Role, { id: { $in: roleIds } }) : [];
87
+ const roleNames = roles.map((role) => role.name).filter((name) => typeof name === "string" && name.length > 0);
88
+ try {
89
+ record.lastUsedAt = /* @__PURE__ */ new Date();
90
+ await em.persistAndFlush(record);
91
+ } catch {
92
+ }
93
+ return {
94
+ sub: `api_key:${record.id}`,
95
+ tenantId: record.tenantId ?? null,
96
+ orgId: record.organizationId ?? null,
97
+ roles: roleNames,
98
+ isApiKey: true,
99
+ keyId: record.id,
100
+ keyName: record.name
101
+ };
102
+ } catch {
103
+ return null;
104
+ }
105
+ }
106
+ function extractApiKey(req) {
107
+ const header = (req.headers.get("x-api-key") || "").trim();
108
+ if (header) return header;
109
+ const authHeader = (req.headers.get("authorization") || "").trim();
110
+ if (authHeader.toLowerCase().startsWith("apikey ")) {
111
+ return authHeader.slice(7).trim();
112
+ }
113
+ return null;
114
+ }
115
+ async function getAuthFromCookies() {
116
+ const cookieStore = await cookies();
117
+ const token = cookieStore.get("auth_token")?.value;
118
+ if (!token) return null;
119
+ try {
120
+ const payload = verifyJwt(token);
121
+ if (!payload) return null;
122
+ const tenantCookie = cookieStore.get(TENANT_COOKIE_NAME)?.value;
123
+ const orgCookie = cookieStore.get(ORGANIZATION_COOKIE_NAME)?.value;
124
+ return applySuperAdminScope(payload, tenantCookie, orgCookie);
125
+ } catch {
126
+ return null;
127
+ }
128
+ }
129
+ async function getAuthFromRequest(req) {
130
+ const cookieHeader = req.headers.get("cookie") || "";
131
+ const tenantCookie = readCookieFromHeader(cookieHeader, TENANT_COOKIE_NAME);
132
+ const orgCookie = readCookieFromHeader(cookieHeader, ORGANIZATION_COOKIE_NAME);
133
+ const authHeader = (req.headers.get("authorization") || "").trim();
134
+ let token;
135
+ if (authHeader.toLowerCase().startsWith("bearer ")) token = authHeader.slice(7).trim();
136
+ if (!token) {
137
+ const match = cookieHeader.match(/(?:^|;\s*)auth_token=([^;]+)/);
138
+ if (match) token = decodeURIComponent(match[1]);
139
+ }
140
+ if (token) {
141
+ try {
142
+ const payload = verifyJwt(token);
143
+ if (payload) return applySuperAdminScope(payload, tenantCookie, orgCookie);
144
+ } catch {
145
+ }
146
+ }
147
+ const apiKey = extractApiKey(req);
148
+ if (!apiKey) return null;
149
+ const apiAuth = await resolveApiKeyAuth(apiKey);
150
+ if (!apiAuth) return null;
151
+ return applySuperAdminScope(apiAuth, tenantCookie, orgCookie);
152
+ }
153
+ export {
154
+ getAuthFromCookies,
155
+ getAuthFromRequest
156
+ };
157
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/auth/server.ts"],
4
+ "sourcesContent": ["import { cookies } from 'next/headers'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { verifyJwt } from './jwt'\n\nconst TENANT_COOKIE_NAME = 'om_selected_tenant'\nconst ORGANIZATION_COOKIE_NAME = 'om_selected_org'\nconst ALL_ORGANIZATIONS_COOKIE_VALUE = '__all__'\nconst SUPERADMIN_ROLE = 'superadmin'\n\nexport type AuthContext = {\n sub: string\n tenantId: string | null\n orgId: string | null\n email?: string\n roles?: string[]\n isApiKey?: boolean\n keyId?: string\n keyName?: string\n [k: string]: unknown\n} | null\n\ntype CookieOverride = { applied: boolean; value: string | null }\n\nfunction decodeCookieValue(raw: string | undefined): string | null {\n if (raw === undefined) return null\n try {\n const decoded = decodeURIComponent(raw)\n return decoded ?? null\n } catch {\n return raw ?? null\n }\n}\n\nfunction readCookieFromHeader(header: string | null | undefined, name: string): string | undefined {\n if (!header) return undefined\n const parts = header.split(';')\n for (const part of parts) {\n const trimmed = part.trim()\n if (trimmed.startsWith(`${name}=`)) {\n return trimmed.slice(name.length + 1)\n }\n }\n return undefined\n}\n\nfunction resolveTenantOverride(raw: string | undefined): CookieOverride {\n if (raw === undefined) return { applied: false, value: null }\n const decoded = decodeCookieValue(raw)\n if (!decoded) return { applied: true, value: null }\n const trimmed = decoded.trim()\n if (!trimmed) return { applied: true, value: null }\n return { applied: true, value: trimmed }\n}\n\nfunction resolveOrganizationOverride(raw: string | undefined): CookieOverride {\n if (raw === undefined) return { applied: false, value: null }\n const decoded = decodeCookieValue(raw)\n if (!decoded || decoded === ALL_ORGANIZATIONS_COOKIE_VALUE) {\n return { applied: true, value: null }\n }\n const trimmed = decoded.trim()\n if (!trimmed || trimmed === ALL_ORGANIZATIONS_COOKIE_VALUE) {\n return { applied: true, value: null }\n }\n return { applied: true, value: trimmed }\n}\n\nfunction isSuperAdminAuth(auth: AuthContext | null | undefined): boolean {\n if (!auth) return false\n if ((auth as Record<string, unknown>).isSuperAdmin === true) return true\n const roles = Array.isArray(auth?.roles) ? auth.roles : []\n return roles.some((role) => typeof role === 'string' && role.trim().toLowerCase() === SUPERADMIN_ROLE)\n}\n\nfunction applySuperAdminScope(\n auth: AuthContext,\n tenantCookie: string | undefined,\n orgCookie: string | undefined\n): AuthContext {\n if (!auth || !isSuperAdminAuth(auth)) return auth\n\n const tenantOverride = resolveTenantOverride(tenantCookie)\n const orgOverride = resolveOrganizationOverride(orgCookie)\n if (!tenantOverride.applied && !orgOverride.applied) return auth\n\n type MutableAuthContext = Exclude<AuthContext, null> & {\n actorTenantId?: string | null\n actorOrgId?: string | null\n }\n const baseAuth = auth as Exclude<AuthContext, null>\n const next: MutableAuthContext = { ...baseAuth }\n if (tenantOverride.applied) {\n if (!('actorTenantId' in next)) next.actorTenantId = auth?.tenantId ?? null\n next.tenantId = tenantOverride.value\n }\n if (orgOverride.applied) {\n if (!('actorOrgId' in next)) next.actorOrgId = auth?.orgId ?? null\n next.orgId = orgOverride.value\n }\n next.isSuperAdmin = true\n const existingRoles = Array.isArray(next.roles) ? next.roles : []\n if (!existingRoles.some((role) => typeof role === 'string' && role.trim().toLowerCase() === SUPERADMIN_ROLE)) {\n next.roles = [...existingRoles, 'superadmin']\n }\n return next\n}\n\nasync function resolveApiKeyAuth(secret: string): Promise<AuthContext> {\n if (!secret) return null\n try {\n const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const { findApiKeyBySecret } = await import('@open-mercato/core/modules/api_keys/services/apiKeyService')\n const { Role } = await import('@open-mercato/core/modules/auth/data/entities')\n\n const record = await findApiKeyBySecret(em, secret)\n if (!record) return null\n\n const roleIds = Array.isArray(record.rolesJson)\n ? record.rolesJson.filter((value): value is string => typeof value === 'string' && value.length > 0)\n : []\n const roles = roleIds.length\n ? await em.find(Role, { id: { $in: roleIds } })\n : []\n const roleNames = roles.map((role) => role.name).filter((name): name is string => typeof name === 'string' && name.length > 0)\n\n try {\n record.lastUsedAt = new Date()\n await em.persistAndFlush(record)\n } catch {\n // best-effort update; ignore write failures\n }\n\n return {\n sub: `api_key:${record.id}`,\n tenantId: record.tenantId ?? null,\n orgId: record.organizationId ?? null,\n roles: roleNames,\n isApiKey: true,\n keyId: record.id,\n keyName: record.name,\n }\n } catch {\n return null\n }\n}\n\nfunction extractApiKey(req: Request): string | null {\n const header = (req.headers.get('x-api-key') || '').trim()\n if (header) return header\n const authHeader = (req.headers.get('authorization') || '').trim()\n if (authHeader.toLowerCase().startsWith('apikey ')) {\n return authHeader.slice(7).trim()\n }\n return null\n}\n\nexport async function getAuthFromCookies(): Promise<AuthContext> {\n const cookieStore = await cookies()\n const token = cookieStore.get('auth_token')?.value\n if (!token) return null\n try {\n const payload = verifyJwt(token) as AuthContext\n if (!payload) return null\n const tenantCookie = cookieStore.get(TENANT_COOKIE_NAME)?.value\n const orgCookie = cookieStore.get(ORGANIZATION_COOKIE_NAME)?.value\n return applySuperAdminScope(payload, tenantCookie, orgCookie)\n } catch {\n return null\n }\n}\n\nexport async function getAuthFromRequest(req: Request): Promise<AuthContext> {\n const cookieHeader = req.headers.get('cookie') || ''\n const tenantCookie = readCookieFromHeader(cookieHeader, TENANT_COOKIE_NAME)\n const orgCookie = readCookieFromHeader(cookieHeader, ORGANIZATION_COOKIE_NAME)\n const authHeader = (req.headers.get('authorization') || '').trim()\n let token: string | undefined\n if (authHeader.toLowerCase().startsWith('bearer ')) token = authHeader.slice(7).trim()\n if (!token) {\n const match = cookieHeader.match(/(?:^|;\\s*)auth_token=([^;]+)/)\n if (match) token = decodeURIComponent(match[1])\n }\n if (token) {\n try {\n const payload = verifyJwt(token) as AuthContext\n if (payload) return applySuperAdminScope(payload, tenantCookie, orgCookie)\n } catch {\n // fall back to API key detection\n }\n }\n\n const apiKey = extractApiKey(req)\n if (!apiKey) return null\n const apiAuth = await resolveApiKeyAuth(apiKey)\n if (!apiAuth) return null\n return applySuperAdminScope(apiAuth, tenantCookie, orgCookie)\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,22 @@
1
+ const TRUE_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "y", "on", "enable", "enabled"]);
2
+ const FALSE_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "n", "off", "disable", "disabled"]);
3
+ function parseBooleanToken(raw) {
4
+ if (typeof raw !== "string") return null;
5
+ const trimmed = raw.trim();
6
+ if (!trimmed) return null;
7
+ const normalized = trimmed.toLowerCase();
8
+ if (TRUE_VALUES.has(normalized)) return true;
9
+ if (FALSE_VALUES.has(normalized)) return false;
10
+ return null;
11
+ }
12
+ function parseBooleanWithDefault(raw, fallback) {
13
+ const parsed = parseBooleanToken(raw);
14
+ return parsed === null ? fallback : parsed;
15
+ }
16
+ export {
17
+ FALSE_VALUES,
18
+ TRUE_VALUES,
19
+ parseBooleanToken,
20
+ parseBooleanWithDefault
21
+ };
22
+ //# sourceMappingURL=boolean.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/boolean.ts"],
4
+ "sourcesContent": ["export const TRUE_VALUES = new Set(['1', 'true', 'yes', 'y', 'on', 'enable', 'enabled'])\nexport const FALSE_VALUES = new Set(['0', 'false', 'no', 'n', 'off', 'disable', 'disabled'])\n\nexport function parseBooleanToken(raw: string | null | undefined): boolean | null {\n if (typeof raw !== 'string') return null\n const trimmed = raw.trim()\n if (!trimmed) return null\n const normalized = trimmed.toLowerCase()\n if (TRUE_VALUES.has(normalized)) return true\n if (FALSE_VALUES.has(normalized)) return false\n return null\n}\n\nexport function parseBooleanWithDefault(raw: string | null | undefined, fallback: boolean): boolean {\n const parsed = parseBooleanToken(raw)\n return parsed === null ? fallback : parsed\n}\n"],
5
+ "mappings": "AAAO,MAAM,cAAc,oBAAI,IAAI,CAAC,KAAK,QAAQ,OAAO,KAAK,MAAM,UAAU,SAAS,CAAC;AAChF,MAAM,eAAe,oBAAI,IAAI,CAAC,KAAK,SAAS,MAAM,KAAK,OAAO,WAAW,UAAU,CAAC;AAEpF,SAAS,kBAAkB,KAAgD;AAChF,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAM,UAAU,IAAI,KAAK;AACzB,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,aAAa,QAAQ,YAAY;AACvC,MAAI,YAAY,IAAI,UAAU,EAAG,QAAO;AACxC,MAAI,aAAa,IAAI,UAAU,EAAG,QAAO;AACzC,SAAO;AACT;AAEO,SAAS,wBAAwB,KAAgC,UAA4B;AAClG,QAAM,SAAS,kBAAkB,GAAG;AACpC,SAAO,WAAW,OAAO,WAAW;AACtC;",
6
+ "names": []
7
+ }