@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,128 @@
1
+ "use client";
2
+ const scopes = /* @__PURE__ */ new Map();
3
+ const MODIFIER_SYNONYMS = {
4
+ cmd: "meta",
5
+ command: "meta",
6
+ option: "alt",
7
+ opt: "alt",
8
+ control: "ctrl",
9
+ ctrl: "ctrl",
10
+ shift: "shift",
11
+ meta: "meta",
12
+ alt: "alt"
13
+ };
14
+ let listenersAttached = false;
15
+ const THIRTY_FPS_INTERVAL = 1e3 / 30;
16
+ function normalizeToken(token) {
17
+ const trimmed = token.trim().toLowerCase();
18
+ if (!trimmed) return "";
19
+ if (trimmed in MODIFIER_SYNONYMS) return MODIFIER_SYNONYMS[trimmed];
20
+ if (trimmed === "return") return "enter";
21
+ if (trimmed === "space") return " ";
22
+ return trimmed;
23
+ }
24
+ function serializeCombination(tokens) {
25
+ const filtered = tokens.filter(Boolean);
26
+ filtered.sort();
27
+ return filtered.join("+");
28
+ }
29
+ function parseHotkeys(hotkeys) {
30
+ return new Set(
31
+ hotkeys.split(/\s+/).map(
32
+ (combo) => serializeCombination(
33
+ combo.split("+").map(normalizeToken).filter(Boolean)
34
+ )
35
+ ).filter(Boolean)
36
+ );
37
+ }
38
+ function createRegistration(hotkeys, callback, debounce) {
39
+ const combos = parseHotkeys(hotkeys);
40
+ return {
41
+ combos,
42
+ callback,
43
+ debounce: Math.max(debounce, THIRTY_FPS_INTERVAL),
44
+ lastTriggered: 0
45
+ };
46
+ }
47
+ function activeCombination(event) {
48
+ const keys = [];
49
+ if (event.metaKey) keys.push("meta");
50
+ if (event.ctrlKey) keys.push("ctrl");
51
+ if (event.altKey) keys.push("alt");
52
+ if (event.shiftKey) keys.push("shift");
53
+ const key = normalizeToken(event.key);
54
+ if (key && !(key in MODIFIER_SYNONYMS)) {
55
+ keys.push(key.length === 1 ? key : normalizeToken(key));
56
+ } else if (keys.length === 0) {
57
+ return null;
58
+ }
59
+ return serializeCombination(keys);
60
+ }
61
+ function handleKeydown(event) {
62
+ if (event.defaultPrevented) return;
63
+ const combo = activeCombination(event);
64
+ if (!combo) return;
65
+ const now = Date.now();
66
+ scopes.forEach((registrations) => {
67
+ registrations.forEach((registration) => {
68
+ if (!registration.combos.has(combo)) return;
69
+ if (event.repeat && now - registration.lastTriggered < registration.debounce) return;
70
+ if (now - registration.lastTriggered < registration.debounce) return;
71
+ registration.lastTriggered = now;
72
+ registration.callback(event);
73
+ });
74
+ });
75
+ }
76
+ function handleKeyup() {
77
+ }
78
+ function ensureListeners() {
79
+ if (listenersAttached) return;
80
+ if (typeof document === "undefined") return;
81
+ document.addEventListener("keydown", handleKeydown);
82
+ document.addEventListener("keyup", handleKeyup);
83
+ listenersAttached = true;
84
+ }
85
+ function detachListenersIfIdle() {
86
+ if (!listenersAttached) return;
87
+ if (scopes.size > 0) return;
88
+ if (typeof document === "undefined") return;
89
+ document.removeEventListener("keydown", handleKeydown);
90
+ document.removeEventListener("keyup", handleKeyup);
91
+ listenersAttached = false;
92
+ }
93
+ function registerHotkey(hotkeys, scopeName, callback, debounceTimeInMilliseconds = 150) {
94
+ if (typeof document === "undefined") {
95
+ return {
96
+ bind() {
97
+ },
98
+ unbind() {
99
+ }
100
+ };
101
+ }
102
+ const registration = createRegistration(hotkeys, callback, debounceTimeInMilliseconds);
103
+ let scope = scopes.get(scopeName);
104
+ const bind = () => {
105
+ if (!scope) {
106
+ scope = /* @__PURE__ */ new Set();
107
+ scopes.set(scopeName, scope);
108
+ }
109
+ scope.add(registration);
110
+ ensureListeners();
111
+ };
112
+ const unbind = () => {
113
+ const existingScope = scopes.get(scopeName);
114
+ if (existingScope) {
115
+ existingScope.delete(registration);
116
+ if (existingScope.size === 0) {
117
+ scopes.delete(scopeName);
118
+ }
119
+ }
120
+ detachListenersIfIdle();
121
+ };
122
+ bind();
123
+ return { bind, unbind };
124
+ }
125
+ export {
126
+ registerHotkey
127
+ };
128
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/hotkeys/index.ts"],
4
+ "sourcesContent": ["\"use client\"\n\ntype HotkeyRegistration = {\n combos: Set<string>\n callback: (event: KeyboardEvent) => void\n debounce: number\n lastTriggered: number\n}\n\nconst scopes = new Map<string, Set<HotkeyRegistration>>()\n\nconst MODIFIER_SYNONYMS: Record<string, string> = {\n cmd: 'meta',\n command: 'meta',\n option: 'alt',\n opt: 'alt',\n control: 'ctrl',\n ctrl: 'ctrl',\n shift: 'shift',\n meta: 'meta',\n alt: 'alt',\n}\n\nlet listenersAttached = false\n\nconst THIRTY_FPS_INTERVAL = 1000 / 30\n\nfunction normalizeToken(token: string): string {\n const trimmed = token.trim().toLowerCase()\n if (!trimmed) return ''\n if (trimmed in MODIFIER_SYNONYMS) return MODIFIER_SYNONYMS[trimmed]\n if (trimmed === 'return') return 'enter'\n if (trimmed === 'space') return ' '\n return trimmed\n}\n\nfunction serializeCombination(tokens: string[]): string {\n const filtered = tokens.filter(Boolean)\n filtered.sort()\n return filtered.join('+')\n}\n\nfunction parseHotkeys(hotkeys: string): Set<string> {\n return new Set(\n hotkeys\n .split(/\\s+/)\n .map((combo) =>\n serializeCombination(\n combo\n .split('+')\n .map(normalizeToken)\n .filter(Boolean),\n ),\n )\n .filter(Boolean),\n )\n}\n\nfunction createRegistration(\n hotkeys: string,\n callback: (event: KeyboardEvent) => void,\n debounce: number,\n): HotkeyRegistration {\n const combos = parseHotkeys(hotkeys)\n return {\n combos,\n callback,\n debounce: Math.max(debounce, THIRTY_FPS_INTERVAL),\n lastTriggered: 0,\n }\n}\n\nfunction activeCombination(event: KeyboardEvent): string | null {\n const keys: string[] = []\n if (event.metaKey) keys.push('meta')\n if (event.ctrlKey) keys.push('ctrl')\n if (event.altKey) keys.push('alt')\n if (event.shiftKey) keys.push('shift')\n\n const key = normalizeToken(event.key)\n if (key && !(key in MODIFIER_SYNONYMS)) {\n keys.push(key.length === 1 ? key : normalizeToken(key))\n } else if (keys.length === 0) {\n // Ignore pure modifier presses\n return null\n }\n\n return serializeCombination(keys)\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.defaultPrevented) return\n const combo = activeCombination(event)\n if (!combo) return\n\n const now = Date.now()\n scopes.forEach((registrations) => {\n registrations.forEach((registration) => {\n if (!registration.combos.has(combo)) return\n if (event.repeat && now - registration.lastTriggered < registration.debounce) return\n if (now - registration.lastTriggered < registration.debounce) return\n registration.lastTriggered = now\n registration.callback(event)\n })\n })\n}\n\nfunction handleKeyup() {\n // No-op placeholder for future extensibility (mirrors API pattern from article reference)\n}\n\nfunction ensureListeners() {\n if (listenersAttached) return\n if (typeof document === 'undefined') return\n document.addEventListener('keydown', handleKeydown)\n document.addEventListener('keyup', handleKeyup)\n listenersAttached = true\n}\n\nfunction detachListenersIfIdle() {\n if (!listenersAttached) return\n if (scopes.size > 0) return\n if (typeof document === 'undefined') return\n document.removeEventListener('keydown', handleKeydown)\n document.removeEventListener('keyup', handleKeyup)\n listenersAttached = false\n}\n\nexport function registerHotkey(\n hotkeys: string,\n scopeName: string,\n callback: (event: KeyboardEvent) => void,\n debounceTimeInMilliseconds = 150,\n) {\n if (typeof document === 'undefined') {\n return {\n bind() {},\n unbind() {},\n }\n }\n\n const registration = createRegistration(hotkeys, callback, debounceTimeInMilliseconds)\n let scope = scopes.get(scopeName)\n\n const bind = () => {\n if (!scope) {\n scope = new Set()\n scopes.set(scopeName, scope)\n }\n scope.add(registration)\n ensureListeners()\n }\n\n const unbind = () => {\n const existingScope = scopes.get(scopeName)\n if (existingScope) {\n existingScope.delete(registration)\n if (existingScope.size === 0) {\n scopes.delete(scopeName)\n }\n }\n detachListenersIfIdle()\n }\n\n bind()\n\n return { bind, unbind }\n}\n"],
5
+ "mappings": ";AASA,MAAM,SAAS,oBAAI,IAAqC;AAExD,MAAM,oBAA4C;AAAA,EAChD,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AACP;AAEA,IAAI,oBAAoB;AAExB,MAAM,sBAAsB,MAAO;AAEnC,SAAS,eAAe,OAAuB;AAC7C,QAAM,UAAU,MAAM,KAAK,EAAE,YAAY;AACzC,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,WAAW,kBAAmB,QAAO,kBAAkB,OAAO;AAClE,MAAI,YAAY,SAAU,QAAO;AACjC,MAAI,YAAY,QAAS,QAAO;AAChC,SAAO;AACT;AAEA,SAAS,qBAAqB,QAA0B;AACtD,QAAM,WAAW,OAAO,OAAO,OAAO;AACtC,WAAS,KAAK;AACd,SAAO,SAAS,KAAK,GAAG;AAC1B;AAEA,SAAS,aAAa,SAA8B;AAClD,SAAO,IAAI;AAAA,IACT,QACG,MAAM,KAAK,EACX;AAAA,MAAI,CAAC,UACJ;AAAA,QACE,MACG,MAAM,GAAG,EACT,IAAI,cAAc,EAClB,OAAO,OAAO;AAAA,MACnB;AAAA,IACF,EACC,OAAO,OAAO;AAAA,EACnB;AACF;AAEA,SAAS,mBACP,SACA,UACA,UACoB;AACpB,QAAM,SAAS,aAAa,OAAO;AACnC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,KAAK,IAAI,UAAU,mBAAmB;AAAA,IAChD,eAAe;AAAA,EACjB;AACF;AAEA,SAAS,kBAAkB,OAAqC;AAC9D,QAAM,OAAiB,CAAC;AACxB,MAAI,MAAM,QAAS,MAAK,KAAK,MAAM;AACnC,MAAI,MAAM,QAAS,MAAK,KAAK,MAAM;AACnC,MAAI,MAAM,OAAQ,MAAK,KAAK,KAAK;AACjC,MAAI,MAAM,SAAU,MAAK,KAAK,OAAO;AAErC,QAAM,MAAM,eAAe,MAAM,GAAG;AACpC,MAAI,OAAO,EAAE,OAAO,oBAAoB;AACtC,SAAK,KAAK,IAAI,WAAW,IAAI,MAAM,eAAe,GAAG,CAAC;AAAA,EACxD,WAAW,KAAK,WAAW,GAAG;AAE5B,WAAO;AAAA,EACT;AAEA,SAAO,qBAAqB,IAAI;AAClC;AAEA,SAAS,cAAc,OAAsB;AAC3C,MAAI,MAAM,iBAAkB;AAC5B,QAAM,QAAQ,kBAAkB,KAAK;AACrC,MAAI,CAAC,MAAO;AAEZ,QAAM,MAAM,KAAK,IAAI;AACrB,SAAO,QAAQ,CAAC,kBAAkB;AAChC,kBAAc,QAAQ,CAAC,iBAAiB;AACtC,UAAI,CAAC,aAAa,OAAO,IAAI,KAAK,EAAG;AACrC,UAAI,MAAM,UAAU,MAAM,aAAa,gBAAgB,aAAa,SAAU;AAC9E,UAAI,MAAM,aAAa,gBAAgB,aAAa,SAAU;AAC9D,mBAAa,gBAAgB;AAC7B,mBAAa,SAAS,KAAK;AAAA,IAC7B,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,cAAc;AAEvB;AAEA,SAAS,kBAAkB;AACzB,MAAI,kBAAmB;AACvB,MAAI,OAAO,aAAa,YAAa;AACrC,WAAS,iBAAiB,WAAW,aAAa;AAClD,WAAS,iBAAiB,SAAS,WAAW;AAC9C,sBAAoB;AACtB;AAEA,SAAS,wBAAwB;AAC/B,MAAI,CAAC,kBAAmB;AACxB,MAAI,OAAO,OAAO,EAAG;AACrB,MAAI,OAAO,aAAa,YAAa;AACrC,WAAS,oBAAoB,WAAW,aAAa;AACrD,WAAS,oBAAoB,SAAS,WAAW;AACjD,sBAAoB;AACtB;AAEO,SAAS,eACd,SACA,WACA,UACA,6BAA6B,KAC7B;AACA,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO;AAAA,MACL,OAAO;AAAA,MAAC;AAAA,MACR,SAAS;AAAA,MAAC;AAAA,IACZ;AAAA,EACF;AAEA,QAAM,eAAe,mBAAmB,SAAS,UAAU,0BAA0B;AACrF,MAAI,QAAQ,OAAO,IAAI,SAAS;AAEhC,QAAM,OAAO,MAAM;AACjB,QAAI,CAAC,OAAO;AACV,cAAQ,oBAAI,IAAI;AAChB,aAAO,IAAI,WAAW,KAAK;AAAA,IAC7B;AACA,UAAM,IAAI,YAAY;AACtB,oBAAgB;AAAA,EAClB;AAEA,QAAM,SAAS,MAAM;AACnB,UAAM,gBAAgB,OAAO,IAAI,SAAS;AAC1C,QAAI,eAAe;AACjB,oBAAc,OAAO,YAAY;AACjC,UAAI,cAAc,SAAS,GAAG;AAC5B,eAAO,OAAO,SAAS;AAAA,MACzB;AAAA,IACF;AACA,0BAAsB;AAAA,EACxB;AAEA,OAAK;AAEL,SAAO,EAAE,MAAM,OAAO;AACxB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ let _appDictionaryLoader = null;
2
+ function registerAppDictionaryLoader(loader) {
3
+ _appDictionaryLoader = loader;
4
+ }
5
+ async function loadAppDictionary(locale) {
6
+ if (!_appDictionaryLoader) return {};
7
+ try {
8
+ return await _appDictionaryLoader(locale);
9
+ } catch {
10
+ return {};
11
+ }
12
+ }
13
+ export {
14
+ loadAppDictionary,
15
+ registerAppDictionaryLoader
16
+ };
17
+ //# sourceMappingURL=app-dictionaries.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/i18n/app-dictionaries.ts"],
4
+ "sourcesContent": ["import type { Locale } from './config'\n\ntype DictionaryLoader = (locale: Locale) => Promise<Record<string, unknown>>\n\nlet _appDictionaryLoader: DictionaryLoader | null = null\n\nexport function registerAppDictionaryLoader(loader: DictionaryLoader): void {\n _appDictionaryLoader = loader\n}\n\nexport async function loadAppDictionary(locale: Locale): Promise<Record<string, unknown>> {\n if (!_appDictionaryLoader) return {}\n try {\n return await _appDictionaryLoader(locale)\n } catch {\n return {}\n }\n}\n"],
5
+ "mappings": "AAIA,IAAI,uBAAgD;AAE7C,SAAS,4BAA4B,QAAgC;AAC1E,yBAAuB;AACzB;AAEA,eAAsB,kBAAkB,QAAkD;AACxF,MAAI,CAAC,qBAAsB,QAAO,CAAC;AACnC,MAAI;AACF,WAAO,MAAM,qBAAqB,MAAM;AAAA,EAC1C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,7 @@
1
+ const locales = ["en", "pl", "es", "de"];
2
+ const defaultLocale = "en";
3
+ export {
4
+ defaultLocale,
5
+ locales
6
+ };
7
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/i18n/config.ts"],
4
+ "sourcesContent": ["export type Locale = 'en' | 'pl' | 'es' | 'de'\n\nexport const locales: Locale[] = ['en', 'pl', 'es', 'de']\nexport const defaultLocale: Locale = 'en'\n"],
5
+ "mappings": "AAEO,MAAM,UAAoB,CAAC,MAAM,MAAM,MAAM,IAAI;AACjD,MAAM,gBAAwB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,50 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useMemo } from "react";
4
+ const I18nContext = createContext(null);
5
+ function format(template, params) {
6
+ if (!params) return template;
7
+ return template.replace(/\{\{(\w+)\}\}|\{(\w+)\}/g, (_, doubleKey, singleKey) => {
8
+ const key = doubleKey ?? singleKey;
9
+ if (!key) return _;
10
+ const value = params[key];
11
+ if (value === void 0) {
12
+ return doubleKey ? `{{${key}}}` : `{${key}}`;
13
+ }
14
+ return String(value);
15
+ });
16
+ }
17
+ function I18nProvider({ children, locale, dict }) {
18
+ const value = useMemo(() => ({
19
+ locale,
20
+ t: (key, fallbackOrParams, params) => {
21
+ let fallback;
22
+ let resolvedParams;
23
+ if (typeof fallbackOrParams === "string") {
24
+ fallback = fallbackOrParams;
25
+ resolvedParams = params;
26
+ } else {
27
+ resolvedParams = fallbackOrParams ?? params;
28
+ }
29
+ const template = dict[key] ?? fallback ?? key;
30
+ return format(template, resolvedParams);
31
+ }
32
+ }), [locale, dict]);
33
+ return /* @__PURE__ */ jsx(I18nContext.Provider, { value, children });
34
+ }
35
+ function useT() {
36
+ const ctx = useContext(I18nContext);
37
+ if (!ctx) throw new Error("useT must be used within I18nProvider");
38
+ return ctx.t;
39
+ }
40
+ function useLocale() {
41
+ const ctx = useContext(I18nContext);
42
+ if (!ctx) throw new Error("useLocale must be used within I18nProvider");
43
+ return ctx.locale;
44
+ }
45
+ export {
46
+ I18nProvider,
47
+ useLocale,
48
+ useT
49
+ };
50
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/i18n/context.tsx"],
4
+ "sourcesContent": ["\"use client\"\nimport React, { createContext, useContext, useMemo } from 'react'\nimport type { Locale } from './config'\n\nexport type Dict = Record<string, string>\n\nexport type TranslateParams = Record<string, string | number>\n\nexport type TranslateFn = (\n key: string,\n fallbackOrParams?: string | TranslateParams,\n params?: TranslateParams\n) => string\n\nexport type I18nContextValue = {\n locale: Locale\n t: TranslateFn\n}\n\nconst I18nContext = createContext<I18nContextValue | null>(null)\n\nfunction format(template: string, params?: TranslateParams) {\n if (!params) return template\n return template.replace(/\\{\\{(\\w+)\\}\\}|\\{(\\w+)\\}/g, (_, doubleKey, singleKey) => {\n const key = doubleKey ?? singleKey\n if (!key) return _\n const value = params[key]\n if (value === undefined) {\n return doubleKey ? `{{${key}}}` : `{${key}}`\n }\n return String(value)\n })\n}\n\nexport function I18nProvider({ children, locale, dict }: { children: React.ReactNode; locale: Locale; dict: Dict }) {\n const value = useMemo<I18nContextValue>(() => ({\n locale,\n t: (key, fallbackOrParams, params) => {\n let fallback: string | undefined\n let resolvedParams: TranslateParams | undefined\n\n if (typeof fallbackOrParams === 'string') {\n fallback = fallbackOrParams\n resolvedParams = params\n } else {\n resolvedParams = fallbackOrParams ?? params\n }\n\n const template = dict[key] ?? fallback ?? key\n return format(template, resolvedParams)\n },\n }), [locale, dict])\n return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>\n}\n\nexport function useT() {\n const ctx = useContext(I18nContext)\n if (!ctx) throw new Error('useT must be used within I18nProvider')\n return ctx.t\n}\n\nexport function useLocale() {\n const ctx = useContext(I18nContext)\n if (!ctx) throw new Error('useLocale must be used within I18nProvider')\n return ctx.locale\n}\n"],
5
+ "mappings": ";AAoDS;AAnDT,SAAgB,eAAe,YAAY,eAAe;AAkB1D,MAAM,cAAc,cAAuC,IAAI;AAE/D,SAAS,OAAO,UAAkB,QAA0B;AAC1D,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,SAAS,QAAQ,4BAA4B,CAAC,GAAG,WAAW,cAAc;AAC/E,UAAM,MAAM,aAAa;AACzB,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,UAAU,QAAW;AACvB,aAAO,YAAY,KAAK,GAAG,OAAO,IAAI,GAAG;AAAA,IAC3C;AACA,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEO,SAAS,aAAa,EAAE,UAAU,QAAQ,KAAK,GAA8D;AAClH,QAAM,QAAQ,QAA0B,OAAO;AAAA,IAC7C;AAAA,IACA,GAAG,CAAC,KAAK,kBAAkB,WAAW;AACpC,UAAI;AACJ,UAAI;AAEJ,UAAI,OAAO,qBAAqB,UAAU;AACxC,mBAAW;AACX,yBAAiB;AAAA,MACnB,OAAO;AACL,yBAAiB,oBAAoB;AAAA,MACvC;AAEA,YAAM,WAAW,KAAK,GAAG,KAAK,YAAY;AAC1C,aAAO,OAAO,UAAU,cAAc;AAAA,IACxC;AAAA,EACF,IAAI,CAAC,QAAQ,IAAI,CAAC;AAClB,SAAO,oBAAC,YAAY,UAAZ,EAAqB,OAAe,UAAS;AACvD;AAEO,SAAS,OAAO;AACrB,QAAM,MAAM,WAAW,WAAW;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,uCAAuC;AACjE,SAAO,IAAI;AACb;AAEO,SAAS,YAAY;AAC1B,QAAM,MAAM,WAAW,WAAW;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,4CAA4C;AACtE,SAAO,IAAI;AACb;",
6
+ "names": []
7
+ }
@@ -0,0 +1,68 @@
1
+ import { defaultLocale, locales } from "./config.js";
2
+ import { createFallbackTranslator, createTranslator } from "./translate.js";
3
+ import { getModules } from "../modules/registry.js";
4
+ import { loadAppDictionary } from "./app-dictionaries.js";
5
+ import { registerModules, getModules as getModules2 } from "../modules/registry.js";
6
+ import { registerAppDictionaryLoader } from "./app-dictionaries.js";
7
+ function flattenDictionary(source, prefix = "") {
8
+ if (!source || typeof source !== "object" || Array.isArray(source)) return {};
9
+ const result = {};
10
+ for (const [key, value] of Object.entries(source)) {
11
+ if (!key) continue;
12
+ const nextKey = prefix ? `${prefix}.${key}` : key;
13
+ if (typeof value === "string") {
14
+ result[nextKey] = value;
15
+ } else if (value && typeof value === "object" && !Array.isArray(value)) {
16
+ Object.assign(result, flattenDictionary(value, nextKey));
17
+ }
18
+ }
19
+ return result;
20
+ }
21
+ async function detectLocale() {
22
+ try {
23
+ const { cookies, headers } = await import("next/headers");
24
+ try {
25
+ const c = (await cookies()).get("locale")?.value;
26
+ if (c && locales.includes(c)) return c;
27
+ } catch {
28
+ }
29
+ try {
30
+ const accept = (await headers()).get("accept-language") || "";
31
+ const match = locales.find((l) => new RegExp(`(^|,)\\s*${l}(-|;|,|$)`, "i").test(accept));
32
+ if (match) return match;
33
+ } catch {
34
+ }
35
+ } catch {
36
+ }
37
+ return defaultLocale;
38
+ }
39
+ async function loadDictionary(locale) {
40
+ const baseRaw = await loadAppDictionary(locale);
41
+ const merged = { ...flattenDictionary(baseRaw) };
42
+ const modules = getModules();
43
+ for (const m of modules) {
44
+ const dict = m.translations?.[locale];
45
+ if (dict) Object.assign(merged, flattenDictionary(dict));
46
+ }
47
+ return merged;
48
+ }
49
+ async function resolveTranslations() {
50
+ const locale = await detectLocale();
51
+ const dict = await loadDictionary(locale);
52
+ const t = createTranslator(dict);
53
+ const translate = createFallbackTranslator(dict);
54
+ return { locale, dict, t, translate };
55
+ }
56
+ try {
57
+ require("server-only");
58
+ } catch {
59
+ }
60
+ export {
61
+ detectLocale,
62
+ getModules2 as getModules,
63
+ loadDictionary,
64
+ registerAppDictionaryLoader,
65
+ registerModules,
66
+ resolveTranslations
67
+ };
68
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/i18n/server.ts"],
4
+ "sourcesContent": ["import { defaultLocale, locales, type Locale } from './config'\nimport type { Dict } from './context'\nimport { createFallbackTranslator, createTranslator } from './translate'\nimport { getModules } from '../modules/registry'\nimport { loadAppDictionary } from './app-dictionaries'\n\n// Re-export for backwards compatibility\nexport { registerModules, getModules } from '../modules/registry'\nexport { registerAppDictionaryLoader } from './app-dictionaries'\n\nfunction flattenDictionary(source: unknown, prefix = ''): Dict {\n if (!source || typeof source !== 'object' || Array.isArray(source)) return {}\n const result: Dict = {}\n for (const [key, value] of Object.entries(source as Record<string, unknown>)) {\n if (!key) continue\n const nextKey = prefix ? `${prefix}.${key}` : key\n if (typeof value === 'string') {\n result[nextKey] = value\n } else if (value && typeof value === 'object' && !Array.isArray(value)) {\n Object.assign(result, flattenDictionary(value, nextKey))\n }\n }\n return result\n}\n\nexport async function detectLocale(): Promise<Locale> {\n // Dynamic import to avoid requiring Next.js in non-Next.js contexts (CLI, tests)\n try {\n const { cookies, headers } = await import('next/headers')\n try {\n const c = (await cookies()).get('locale')?.value\n if (c && locales.includes(c as Locale)) return c as Locale\n } catch {\n // cookies() may not be available outside request context (e.g., in tests)\n }\n try {\n const accept = (await headers()).get('accept-language') || ''\n const match = locales.find(l => new RegExp(`(^|,)\\\\s*${l}(-|;|,|$)`, 'i').test(accept))\n if (match) return match\n } catch {\n // headers() may not be available outside request context (e.g., in tests)\n }\n } catch {\n // next/headers not available (CLI context)\n }\n return defaultLocale\n}\n\nexport async function loadDictionary(locale: Locale): Promise<Dict> {\n // Load from registry instead of @/ import (works in standalone packages)\n const baseRaw = await loadAppDictionary(locale)\n const merged: Dict = { ...flattenDictionary(baseRaw) }\n const modules = getModules()\n for (const m of modules) {\n const dict = m.translations?.[locale]\n if (dict) Object.assign(merged, flattenDictionary(dict))\n }\n return merged\n}\n\nexport async function resolveTranslations() {\n const locale = await detectLocale()\n const dict = await loadDictionary(locale)\n const t = createTranslator(dict)\n const translate = createFallbackTranslator(dict)\n return { locale, dict, t, translate }\n}\n// Hint Next.js to keep this server-only; ignore if unavailable when running scripts outside Next.\ntry {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n require('server-only')\n} catch {\n // noop: allows running generator scripts without Next's server-only package\n}\n"],
5
+ "mappings": "AAAA,SAAS,eAAe,eAA4B;AAEpD,SAAS,0BAA0B,wBAAwB;AAC3D,SAAS,kBAAkB;AAC3B,SAAS,yBAAyB;AAGlC,SAAS,iBAAiB,cAAAA,mBAAkB;AAC5C,SAAS,mCAAmC;AAE5C,SAAS,kBAAkB,QAAiB,SAAS,IAAU;AAC7D,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,QAAO,CAAC;AAC5E,QAAM,SAAe,CAAC;AACtB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAiC,GAAG;AAC5E,QAAI,CAAC,IAAK;AACV,UAAM,UAAU,SAAS,GAAG,MAAM,IAAI,GAAG,KAAK;AAC9C,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,OAAO,IAAI;AAAA,IACpB,WAAW,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AACtE,aAAO,OAAO,QAAQ,kBAAkB,OAAO,OAAO,CAAC;AAAA,IACzD;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,eAAgC;AAEpD,MAAI;AACF,UAAM,EAAE,SAAS,QAAQ,IAAI,MAAM,OAAO,cAAc;AACxD,QAAI;AACF,YAAM,KAAK,MAAM,QAAQ,GAAG,IAAI,QAAQ,GAAG;AAC3C,UAAI,KAAK,QAAQ,SAAS,CAAW,EAAG,QAAO;AAAA,IACjD,QAAQ;AAAA,IAER;AACA,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ,GAAG,IAAI,iBAAiB,KAAK;AAC3D,YAAM,QAAQ,QAAQ,KAAK,OAAK,IAAI,OAAO,YAAY,CAAC,aAAa,GAAG,EAAE,KAAK,MAAM,CAAC;AACtF,UAAI,MAAO,QAAO;AAAA,IACpB,QAAQ;AAAA,IAER;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,eAAsB,eAAe,QAA+B;AAElE,QAAM,UAAU,MAAM,kBAAkB,MAAM;AAC9C,QAAM,SAAe,EAAE,GAAG,kBAAkB,OAAO,EAAE;AACrD,QAAM,UAAU,WAAW;AAC3B,aAAW,KAAK,SAAS;AACvB,UAAM,OAAO,EAAE,eAAe,MAAM;AACpC,QAAI,KAAM,QAAO,OAAO,QAAQ,kBAAkB,IAAI,CAAC;AAAA,EACzD;AACA,SAAO;AACT;AAEA,eAAsB,sBAAsB;AAC1C,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,OAAO,MAAM,eAAe,MAAM;AACxC,QAAM,IAAI,iBAAiB,IAAI;AAC/B,QAAM,YAAY,yBAAyB,IAAI;AAC/C,SAAO,EAAE,QAAQ,MAAM,GAAG,UAAU;AACtC;AAEA,IAAI;AAEF,UAAQ,aAAa;AACvB,QAAQ;AAER;",
6
+ "names": ["getModules"]
7
+ }
@@ -0,0 +1,45 @@
1
+ function format(template, params) {
2
+ if (!params) return template;
3
+ return template.replace(/\{\{(\w+)\}\}|\{(\w+)\}/g, (match, doubleKey, singleKey) => {
4
+ const key = doubleKey ?? singleKey;
5
+ if (!key) return match;
6
+ const value = params[key];
7
+ if (value === void 0) return match;
8
+ return String(value);
9
+ });
10
+ }
11
+ function createTranslator(dict) {
12
+ const translator = ((key, fallbackOrParams, params) => {
13
+ let fallback;
14
+ let resolvedParams;
15
+ if (typeof fallbackOrParams === "string") {
16
+ fallback = fallbackOrParams;
17
+ resolvedParams = params;
18
+ } else {
19
+ resolvedParams = fallbackOrParams;
20
+ }
21
+ const template = dict[key] ?? fallback ?? key;
22
+ return format(template, resolvedParams);
23
+ });
24
+ return translator;
25
+ }
26
+ function translateWithFallback(t, key, fallback, params) {
27
+ const value = params ? t(key, params) : t(key);
28
+ if (value !== key) return value;
29
+ if (fallback === void 0) return key;
30
+ return format(fallback, params);
31
+ }
32
+ function createTranslatorWithFallback(translate) {
33
+ return (key, fallback, params) => translateWithFallback(translate, key, fallback, params);
34
+ }
35
+ function createFallbackTranslator(dict) {
36
+ const t = createTranslator(dict);
37
+ return (key, fallback, params) => translateWithFallback(t, key, fallback, params);
38
+ }
39
+ export {
40
+ createFallbackTranslator,
41
+ createTranslator,
42
+ createTranslatorWithFallback,
43
+ translateWithFallback
44
+ };
45
+ //# sourceMappingURL=translate.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/i18n/translate.ts"],
4
+ "sourcesContent": ["import type { Dict, TranslateFn, TranslateParams } from './context'\n\nexport type TranslateWithFallbackFn = (key: string, fallback?: string, params?: TranslateParams) => string\n\nfunction format(template: string, params?: TranslateParams) {\n if (!params) return template\n return template.replace(/\\{\\{(\\w+)\\}\\}|\\{(\\w+)\\}/g, (match, doubleKey, singleKey) => {\n const key = doubleKey ?? singleKey\n if (!key) return match\n const value = params[key]\n if (value === undefined) return match\n return String(value)\n })\n}\n\nexport function createTranslator(dict: Dict): TranslateFn {\n const translator = ((key: string, fallbackOrParams?: string | TranslateParams, params?: TranslateParams) => {\n let fallback: string | undefined\n let resolvedParams: TranslateParams | undefined\n\n if (typeof fallbackOrParams === 'string') {\n fallback = fallbackOrParams\n resolvedParams = params\n } else {\n resolvedParams = fallbackOrParams\n }\n\n const template = dict[key] ?? fallback ?? key\n return format(template, resolvedParams)\n }) as TranslateFn\n\n return translator\n}\n\nexport function translateWithFallback(\n t: TranslateFn,\n key: string,\n fallback?: string,\n params?: TranslateParams,\n): string {\n const value = params ? t(key, params) : t(key)\n if (value !== key) return value\n if (fallback === undefined) return key\n return format(fallback, params)\n}\n\nexport function createTranslatorWithFallback(translate: TranslateFn): TranslateWithFallbackFn {\n return (key, fallback, params) => translateWithFallback(translate, key, fallback, params)\n}\n\nexport function createFallbackTranslator(dict: Dict): TranslateWithFallbackFn {\n const t = createTranslator(dict)\n return (key, fallback, params) => translateWithFallback(t, key, fallback, params)\n}\n"],
5
+ "mappings": "AAIA,SAAS,OAAO,UAAkB,QAA0B;AAC1D,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,SAAS,QAAQ,4BAA4B,CAAC,OAAO,WAAW,cAAc;AACnF,UAAM,MAAM,aAAa;AACzB,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,UAAU,OAAW,QAAO;AAChC,WAAO,OAAO,KAAK;AAAA,EACrB,CAAC;AACH;AAEO,SAAS,iBAAiB,MAAyB;AACxD,QAAM,cAAc,CAAC,KAAa,kBAA6C,WAA6B;AAC1G,QAAI;AACJ,QAAI;AAEJ,QAAI,OAAO,qBAAqB,UAAU;AACxC,iBAAW;AACX,uBAAiB;AAAA,IACnB,OAAO;AACL,uBAAiB;AAAA,IACnB;AAEA,UAAM,WAAW,KAAK,GAAG,KAAK,YAAY;AAC1C,WAAO,OAAO,UAAU,cAAc;AAAA,EACxC;AAEA,SAAO;AACT;AAEO,SAAS,sBACd,GACA,KACA,UACA,QACQ;AACR,QAAM,QAAQ,SAAS,EAAE,KAAK,MAAM,IAAI,EAAE,GAAG;AAC7C,MAAI,UAAU,IAAK,QAAO;AAC1B,MAAI,aAAa,OAAW,QAAO;AACnC,SAAO,OAAO,UAAU,MAAM;AAChC;AAEO,SAAS,6BAA6B,WAAiD;AAC5F,SAAO,CAAC,KAAK,UAAU,WAAW,sBAAsB,WAAW,KAAK,UAAU,MAAM;AAC1F;AAEO,SAAS,yBAAyB,MAAqC;AAC5E,QAAM,IAAI,iBAAiB,IAAI;AAC/B,SAAO,CAAC,KAAK,UAAU,WAAW,sBAAsB,GAAG,KAAK,UAAU,MAAM;AAClF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,82 @@
1
+ const MAX_MESSAGE_LENGTH = 8192;
2
+ const MAX_STACK_LENGTH = 32768;
3
+ function truncate(input, limit) {
4
+ if (!input) return null;
5
+ return input.length > limit ? `${input.slice(0, limit - 3)}...` : input;
6
+ }
7
+ function normalizeError(error) {
8
+ if (error instanceof Error) {
9
+ return {
10
+ message: error.message || error.name || "Unknown error",
11
+ stack: typeof error.stack === "string" ? error.stack : null
12
+ };
13
+ }
14
+ if (typeof error === "string") {
15
+ return { message: error, stack: null };
16
+ }
17
+ try {
18
+ const json = JSON.stringify(error);
19
+ return { message: json, stack: null };
20
+ } catch {
21
+ return { message: String(error ?? "Unknown error"), stack: null };
22
+ }
23
+ }
24
+ function safeJson(value) {
25
+ if (value === void 0) return null;
26
+ try {
27
+ return JSON.parse(JSON.stringify(value));
28
+ } catch {
29
+ if (value == null) return null;
30
+ if (typeof value === "object") {
31
+ return { note: "unserializable", asString: String(value) };
32
+ }
33
+ return value;
34
+ }
35
+ }
36
+ function pickKnex(deps) {
37
+ if (deps.knex) return deps.knex;
38
+ if (deps.em) {
39
+ try {
40
+ const connection = deps.em.getConnection();
41
+ if (connection && typeof connection.getKnex === "function") {
42
+ return connection.getKnex();
43
+ }
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
48
+ return null;
49
+ }
50
+ async function recordIndexerError(deps, input) {
51
+ const knex = pickKnex(deps);
52
+ if (!knex) {
53
+ console.error("[indexers] Unable to record indexer error (missing knex connection)", {
54
+ source: input.source,
55
+ handler: input.handler
56
+ });
57
+ return;
58
+ }
59
+ const { message, stack } = normalizeError(input.error);
60
+ const payload = safeJson(input.payload);
61
+ const now = /* @__PURE__ */ new Date();
62
+ try {
63
+ await knex("indexer_error_logs").insert({
64
+ source: input.source,
65
+ handler: input.handler,
66
+ entity_type: input.entityType ?? null,
67
+ record_id: input.recordId ?? null,
68
+ tenant_id: input.tenantId ?? null,
69
+ organization_id: input.organizationId ?? null,
70
+ payload,
71
+ message: truncate(message, MAX_MESSAGE_LENGTH),
72
+ stack: truncate(stack, MAX_STACK_LENGTH),
73
+ occurred_at: now
74
+ });
75
+ } catch (loggingError) {
76
+ console.error("[indexers] Failed to persist indexer error", loggingError);
77
+ }
78
+ }
79
+ export {
80
+ recordIndexerError
81
+ };
82
+ //# sourceMappingURL=error-log.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/indexers/error-log.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { Knex } from 'knex'\n\nexport type IndexerErrorSource = 'query_index' | 'vector' | 'fulltext'\n\nexport type RecordIndexerErrorInput = {\n source: IndexerErrorSource\n handler: string\n error: unknown\n entityType?: string | null\n recordId?: string | null\n tenantId?: string | null\n organizationId?: string | null\n payload?: unknown\n}\n\ntype RecordIndexerErrorDeps = {\n em?: EntityManager\n knex?: Knex\n}\n\nconst MAX_MESSAGE_LENGTH = 8_192\nconst MAX_STACK_LENGTH = 32_768\n\nfunction truncate(input: string | null | undefined, limit: number): string | null {\n if (!input) return null\n return input.length > limit ? `${input.slice(0, limit - 3)}...` : input\n}\n\nfunction normalizeError(error: unknown): { message: string; stack: string | null } {\n if (error instanceof Error) {\n return {\n message: error.message || error.name || 'Unknown error',\n stack: typeof error.stack === 'string' ? error.stack : null,\n }\n }\n if (typeof error === 'string') {\n return { message: error, stack: null }\n }\n try {\n const json = JSON.stringify(error)\n return { message: json, stack: null }\n } catch {\n return { message: String(error ?? 'Unknown error'), stack: null }\n }\n}\n\nfunction safeJson(value: unknown): unknown {\n if (value === undefined) return null\n try {\n return JSON.parse(JSON.stringify(value))\n } catch {\n if (value == null) return null\n if (typeof value === 'object') {\n return { note: 'unserializable', asString: String(value) }\n }\n return value\n }\n}\n\nfunction pickKnex(deps: RecordIndexerErrorDeps): Knex | null {\n if (deps.knex) return deps.knex\n if (deps.em) {\n try {\n const connection = deps.em.getConnection()\n if (connection && typeof connection.getKnex === 'function') {\n return connection.getKnex()\n }\n } catch {\n return null\n }\n }\n return null\n}\n\nexport async function recordIndexerError(deps: RecordIndexerErrorDeps, input: RecordIndexerErrorInput): Promise<void> {\n const knex = pickKnex(deps)\n if (!knex) {\n console.error('[indexers] Unable to record indexer error (missing knex connection)', {\n source: input.source,\n handler: input.handler,\n })\n return\n }\n\n const { message, stack } = normalizeError(input.error)\n const payload = safeJson(input.payload)\n const now = new Date()\n\n try {\n await knex('indexer_error_logs').insert({\n source: input.source,\n handler: input.handler,\n entity_type: input.entityType ?? null,\n record_id: input.recordId ?? null,\n tenant_id: input.tenantId ?? null,\n organization_id: input.organizationId ?? null,\n payload,\n message: truncate(message, MAX_MESSAGE_LENGTH),\n stack: truncate(stack, MAX_STACK_LENGTH),\n occurred_at: now,\n })\n } catch (loggingError) {\n console.error('[indexers] Failed to persist indexer error', loggingError)\n }\n}\n"],
5
+ "mappings": "AAqBA,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;AAEzB,SAAS,SAAS,OAAkC,OAA8B;AAChF,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,SAAS,QAAQ,GAAG,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,QAAQ;AACpE;AAEA,SAAS,eAAe,OAA2D;AACjF,MAAI,iBAAiB,OAAO;AAC1B,WAAO;AAAA,MACL,SAAS,MAAM,WAAW,MAAM,QAAQ;AAAA,MACxC,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,IACzD;AAAA,EACF;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,EAAE,SAAS,OAAO,OAAO,KAAK;AAAA,EACvC;AACA,MAAI;AACF,UAAM,OAAO,KAAK,UAAU,KAAK;AACjC,WAAO,EAAE,SAAS,MAAM,OAAO,KAAK;AAAA,EACtC,QAAQ;AACN,WAAO,EAAE,SAAS,OAAO,SAAS,eAAe,GAAG,OAAO,KAAK;AAAA,EAClE;AACF;AAEA,SAAS,SAAS,OAAyB;AACzC,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI;AACF,WAAO,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AAAA,EACzC,QAAQ;AACN,QAAI,SAAS,KAAM,QAAO;AAC1B,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,EAAE,MAAM,kBAAkB,UAAU,OAAO,KAAK,EAAE;AAAA,IAC3D;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,SAAS,MAA2C;AAC3D,MAAI,KAAK,KAAM,QAAO,KAAK;AAC3B,MAAI,KAAK,IAAI;AACX,QAAI;AACF,YAAM,aAAa,KAAK,GAAG,cAAc;AACzC,UAAI,cAAc,OAAO,WAAW,YAAY,YAAY;AAC1D,eAAO,WAAW,QAAQ;AAAA,MAC5B;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,mBAAmB,MAA8B,OAA+C;AACpH,QAAM,OAAO,SAAS,IAAI;AAC1B,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,uEAAuE;AAAA,MACnF,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,IACjB,CAAC;AACD;AAAA,EACF;AAEA,QAAM,EAAE,SAAS,MAAM,IAAI,eAAe,MAAM,KAAK;AACrD,QAAM,UAAU,SAAS,MAAM,OAAO;AACtC,QAAM,MAAM,oBAAI,KAAK;AAErB,MAAI;AACF,UAAM,KAAK,oBAAoB,EAAE,OAAO;AAAA,MACtC,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,aAAa,MAAM,cAAc;AAAA,MACjC,WAAW,MAAM,YAAY;AAAA,MAC7B,WAAW,MAAM,YAAY;AAAA,MAC7B,iBAAiB,MAAM,kBAAkB;AAAA,MACzC;AAAA,MACA,SAAS,SAAS,SAAS,kBAAkB;AAAA,MAC7C,OAAO,SAAS,OAAO,gBAAgB;AAAA,MACvC,aAAa;AAAA,IACf,CAAC;AAAA,EACH,SAAS,cAAc;AACrB,YAAQ,MAAM,8CAA8C,YAAY;AAAA,EAC1E;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,80 @@
1
+ const MAX_MESSAGE_LENGTH = 4096;
2
+ const MAX_DELETE_BATCH = 5e3;
3
+ const MAX_LOGS_PER_SOURCE = 1e4;
4
+ function truncate(input, limit) {
5
+ if (!input) return null;
6
+ return input.length > limit ? `${input.slice(0, limit - 3)}...` : input;
7
+ }
8
+ function safeJson(value) {
9
+ if (value === void 0) return null;
10
+ try {
11
+ return JSON.parse(JSON.stringify(value));
12
+ } catch {
13
+ if (value == null) return null;
14
+ if (typeof value === "object") {
15
+ return { note: "unserializable", asString: String(value) };
16
+ }
17
+ return value;
18
+ }
19
+ }
20
+ function pickKnex(deps) {
21
+ if (deps.knex) return deps.knex;
22
+ if (deps.em) {
23
+ try {
24
+ const connection = deps.em.getConnection();
25
+ if (connection && typeof connection.getKnex === "function") {
26
+ return connection.getKnex();
27
+ }
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ return null;
33
+ }
34
+ async function pruneExcessLogs(knex, source) {
35
+ const rows = await knex("indexer_status_logs").select("id").where("source", source).orderBy("occurred_at", "desc").orderBy("id", "desc").offset(MAX_LOGS_PER_SOURCE).limit(MAX_DELETE_BATCH);
36
+ if (!rows.length) return;
37
+ const ids = rows.map((row) => row.id).filter(Boolean);
38
+ if (!ids.length) return;
39
+ await knex("indexer_status_logs").whereIn("id", ids).del();
40
+ }
41
+ async function recordIndexerLog(deps, input) {
42
+ const knex = pickKnex(deps);
43
+ if (!knex) {
44
+ console.warn("[indexers] Unable to record indexer log (missing knex connection)", {
45
+ source: input.source,
46
+ handler: input.handler
47
+ });
48
+ return;
49
+ }
50
+ const level = input.level === "warn" ? "warn" : "info";
51
+ const message = truncate(input.message, MAX_MESSAGE_LENGTH) ?? "\u2014";
52
+ const details = safeJson(input.details);
53
+ const occurredAt = /* @__PURE__ */ new Date();
54
+ try {
55
+ await knex("indexer_status_logs").insert({
56
+ source: input.source,
57
+ handler: input.handler,
58
+ level,
59
+ entity_type: input.entityType ?? null,
60
+ record_id: input.recordId ?? null,
61
+ tenant_id: input.tenantId ?? null,
62
+ organization_id: input.organizationId ?? null,
63
+ message,
64
+ details,
65
+ occurred_at: occurredAt
66
+ });
67
+ } catch (error) {
68
+ console.error("[indexers] Failed to persist indexer log", error);
69
+ return;
70
+ }
71
+ try {
72
+ await pruneExcessLogs(knex, input.source);
73
+ } catch (pruneError) {
74
+ console.warn("[indexers] Failed to prune indexer logs", pruneError);
75
+ }
76
+ }
77
+ export {
78
+ recordIndexerLog
79
+ };
80
+ //# sourceMappingURL=status-log.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/indexers/status-log.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { Knex } from 'knex'\nimport type { IndexerErrorSource } from './error-log'\n\nexport type IndexerLogLevel = 'info' | 'warn'\n\nexport type RecordIndexerLogInput = {\n source: IndexerErrorSource\n handler: string\n message: string\n level?: IndexerLogLevel\n entityType?: string | null\n recordId?: string | null\n tenantId?: string | null\n organizationId?: string | null\n details?: unknown\n}\n\ntype RecordIndexerLogDeps = {\n em?: EntityManager\n knex?: Knex\n}\n\nconst MAX_MESSAGE_LENGTH = 4_096\nconst MAX_DELETE_BATCH = 5_000\nconst MAX_LOGS_PER_SOURCE = 10_000\n\nfunction truncate(input: string | null | undefined, limit: number): string | null {\n if (!input) return null\n return input.length > limit ? `${input.slice(0, limit - 3)}...` : input\n}\n\nfunction safeJson(value: unknown): unknown {\n if (value === undefined) return null\n try {\n return JSON.parse(JSON.stringify(value))\n } catch {\n if (value == null) return null\n if (typeof value === 'object') {\n return { note: 'unserializable', asString: String(value) }\n }\n return value\n }\n}\n\nfunction pickKnex(deps: RecordIndexerLogDeps): Knex | null {\n if (deps.knex) return deps.knex\n if (deps.em) {\n try {\n const connection = deps.em.getConnection()\n if (connection && typeof connection.getKnex === 'function') {\n return connection.getKnex()\n }\n } catch {\n return null\n }\n }\n return null\n}\n\nasync function pruneExcessLogs(knex: Knex, source: IndexerErrorSource): Promise<void> {\n const rows = await knex('indexer_status_logs')\n .select('id')\n .where('source', source)\n .orderBy('occurred_at', 'desc')\n .orderBy('id', 'desc')\n .offset(MAX_LOGS_PER_SOURCE)\n .limit(MAX_DELETE_BATCH)\n\n if (!rows.length) return\n const ids = rows.map((row: any) => row.id).filter(Boolean)\n if (!ids.length) return\n await knex('indexer_status_logs')\n .whereIn('id', ids)\n .del()\n}\n\nexport async function recordIndexerLog(\n deps: RecordIndexerLogDeps,\n input: RecordIndexerLogInput,\n): Promise<void> {\n const knex = pickKnex(deps)\n if (!knex) {\n console.warn('[indexers] Unable to record indexer log (missing knex connection)', {\n source: input.source,\n handler: input.handler,\n })\n return\n }\n\n const level: IndexerLogLevel = input.level === 'warn' ? 'warn' : 'info'\n const message = truncate(input.message, MAX_MESSAGE_LENGTH) ?? '\u2014'\n const details = safeJson(input.details)\n const occurredAt = new Date()\n\n try {\n await knex('indexer_status_logs').insert({\n source: input.source,\n handler: input.handler,\n level,\n entity_type: input.entityType ?? null,\n record_id: input.recordId ?? null,\n tenant_id: input.tenantId ?? null,\n organization_id: input.organizationId ?? null,\n message,\n details,\n occurred_at: occurredAt,\n })\n } catch (error) {\n console.error('[indexers] Failed to persist indexer log', error)\n return\n }\n\n try {\n await pruneExcessLogs(knex, input.source)\n } catch (pruneError) {\n console.warn('[indexers] Failed to prune indexer logs', pruneError)\n }\n}\n"],
5
+ "mappings": "AAuBA,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;AACzB,MAAM,sBAAsB;AAE5B,SAAS,SAAS,OAAkC,OAA8B;AAChF,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,SAAS,QAAQ,GAAG,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,QAAQ;AACpE;AAEA,SAAS,SAAS,OAAyB;AACzC,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI;AACF,WAAO,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AAAA,EACzC,QAAQ;AACN,QAAI,SAAS,KAAM,QAAO;AAC1B,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,EAAE,MAAM,kBAAkB,UAAU,OAAO,KAAK,EAAE;AAAA,IAC3D;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,SAAS,MAAyC;AACzD,MAAI,KAAK,KAAM,QAAO,KAAK;AAC3B,MAAI,KAAK,IAAI;AACX,QAAI;AACF,YAAM,aAAa,KAAK,GAAG,cAAc;AACzC,UAAI,cAAc,OAAO,WAAW,YAAY,YAAY;AAC1D,eAAO,WAAW,QAAQ;AAAA,MAC5B;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,gBAAgB,MAAY,QAA2C;AACpF,QAAM,OAAO,MAAM,KAAK,qBAAqB,EAC1C,OAAO,IAAI,EACX,MAAM,UAAU,MAAM,EACtB,QAAQ,eAAe,MAAM,EAC7B,QAAQ,MAAM,MAAM,EACpB,OAAO,mBAAmB,EAC1B,MAAM,gBAAgB;AAEzB,MAAI,CAAC,KAAK,OAAQ;AAClB,QAAM,MAAM,KAAK,IAAI,CAAC,QAAa,IAAI,EAAE,EAAE,OAAO,OAAO;AACzD,MAAI,CAAC,IAAI,OAAQ;AACjB,QAAM,KAAK,qBAAqB,EAC7B,QAAQ,MAAM,GAAG,EACjB,IAAI;AACT;AAEA,eAAsB,iBACpB,MACA,OACe;AACf,QAAM,OAAO,SAAS,IAAI;AAC1B,MAAI,CAAC,MAAM;AACT,YAAQ,KAAK,qEAAqE;AAAA,MAChF,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,IACjB,CAAC;AACD;AAAA,EACF;AAEA,QAAM,QAAyB,MAAM,UAAU,SAAS,SAAS;AACjE,QAAM,UAAU,SAAS,MAAM,SAAS,kBAAkB,KAAK;AAC/D,QAAM,UAAU,SAAS,MAAM,OAAO;AACtC,QAAM,aAAa,oBAAI,KAAK;AAE5B,MAAI;AACF,UAAM,KAAK,qBAAqB,EAAE,OAAO;AAAA,MACvC,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf;AAAA,MACA,aAAa,MAAM,cAAc;AAAA,MACjC,WAAW,MAAM,YAAY;AAAA,MAC7B,WAAW,MAAM,YAAY;AAAA,MAC7B,iBAAiB,MAAM,kBAAkB;AAAA,MACzC;AAAA,MACA;AAAA,MACA,aAAa;AAAA,IACf,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,MAAM,4CAA4C,KAAK;AAC/D;AAAA,EACF;AAEA,MAAI;AACF,UAAM,gBAAgB,MAAM,MAAM,MAAM;AAAA,EAC1C,SAAS,YAAY;AACnB,YAAQ,KAAK,2CAA2C,UAAU;AAAA,EACpE;AACF;",
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/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
+ }