@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,282 @@
1
+ import crypto from "node:crypto";
2
+ import { generateDek, hashForLookup } from "./aes.js";
3
+ import { isEncryptionDebugEnabled, isTenantDataEncryptionEnabled } from "./toggles.js";
4
+ class FallbackKmsService {
5
+ constructor(primary, fallback, onFallback) {
6
+ this.primary = primary;
7
+ this.fallback = fallback;
8
+ this.onFallback = onFallback;
9
+ this.notified = false;
10
+ }
11
+ isHealthy() {
12
+ return this.primary.isHealthy() || Boolean(this.fallback?.isHealthy?.());
13
+ }
14
+ notifyFallback() {
15
+ if (this.notified) return;
16
+ this.notified = true;
17
+ this.onFallback?.();
18
+ }
19
+ async fromPrimary(op) {
20
+ try {
21
+ return await op();
22
+ } catch (err) {
23
+ console.warn("\u26A0\uFE0F [encryption][kms] Primary KMS failed, will try fallback", {
24
+ error: err?.message || String(err)
25
+ });
26
+ return null;
27
+ }
28
+ }
29
+ async getTenantDek(tenantId) {
30
+ if (this.primary.isHealthy()) {
31
+ const dek = await this.fromPrimary(() => this.primary.getTenantDek(tenantId));
32
+ if (dek) return dek;
33
+ }
34
+ if (this.fallback?.isHealthy()) {
35
+ this.notifyFallback();
36
+ return this.fallback.getTenantDek(tenantId);
37
+ }
38
+ return null;
39
+ }
40
+ async createTenantDek(tenantId) {
41
+ if (this.primary.isHealthy()) {
42
+ const dek = await this.fromPrimary(() => this.primary.createTenantDek(tenantId));
43
+ if (dek) return dek;
44
+ }
45
+ if (this.fallback?.isHealthy()) {
46
+ this.notifyFallback();
47
+ return this.fallback.createTenantDek(tenantId);
48
+ }
49
+ return null;
50
+ }
51
+ }
52
+ function normalizeEnv(value) {
53
+ if (!value) return "";
54
+ return value.trim().replace(/^['"]|['"]$/g, "");
55
+ }
56
+ function resolveDerivedKeySecret() {
57
+ const candidates = [
58
+ { value: process.env.TENANT_DATA_ENCRYPTION_FALLBACK_KEY ?? null, envName: "TENANT_DATA_ENCRYPTION_FALLBACK_KEY" },
59
+ { value: process.env.TENANT_DATA_ENCRYPTION_KEY ?? null, envName: "TENANT_DATA_ENCRYPTION_KEY" },
60
+ { value: process.env.AUTH_SECRET ?? null, envName: "AUTH_SECRET" },
61
+ { value: process.env.NEXTAUTH_SECRET ?? null, envName: "NEXTAUTH_SECRET" }
62
+ ];
63
+ for (const raw of candidates) {
64
+ const normalized = normalizeEnv(raw.value ?? void 0);
65
+ if (normalized) return { secret: normalized, source: "explicit", envName: raw.envName };
66
+ }
67
+ if (process.env.NODE_ENV !== "production") {
68
+ return { secret: "om-dev-tenant-encryption", source: "dev-default", envName: "DEV_DEFAULT" };
69
+ }
70
+ return null;
71
+ }
72
+ class NoopKmsService {
73
+ isHealthy() {
74
+ return !isTenantDataEncryptionEnabled();
75
+ }
76
+ async getTenantDek() {
77
+ return null;
78
+ }
79
+ async createTenantDek() {
80
+ return null;
81
+ }
82
+ }
83
+ class DerivedKmsService {
84
+ constructor(secret) {
85
+ this.root = crypto.createHash("sha256").update(secret).digest();
86
+ }
87
+ isHealthy() {
88
+ return true;
89
+ }
90
+ deriveKey(tenantId) {
91
+ const iterations = 31e4;
92
+ const keyLength = 32;
93
+ const derived = crypto.pbkdf2Sync(this.root, tenantId, iterations, keyLength, "sha512");
94
+ return derived.toString("base64");
95
+ }
96
+ async getTenantDek(tenantId) {
97
+ if (!tenantId) return null;
98
+ return { tenantId, key: this.deriveKey(tenantId), fetchedAt: Date.now() };
99
+ }
100
+ async createTenantDek(tenantId) {
101
+ return this.getTenantDek(tenantId);
102
+ }
103
+ }
104
+ class HashicorpVaultKmsService {
105
+ constructor(opts = {}) {
106
+ this.cache = /* @__PURE__ */ new Map();
107
+ this.healthy = true;
108
+ this.vaultAddr = normalizeEnv(opts.vaultAddr || process.env.VAULT_ADDR || "");
109
+ this.vaultToken = normalizeEnv(opts.vaultToken || process.env.VAULT_TOKEN || "");
110
+ this.mountPath = (opts.mountPath || process.env.VAULT_KV_PATH || "secret/data").replace(/\/+$/, "");
111
+ this.ttlMs = opts.ttlMs ?? 15 * 60 * 1e3;
112
+ this.debugEnabled = isEncryptionDebugEnabled();
113
+ if (!this.vaultAddr || !this.vaultToken) {
114
+ this.healthy = false;
115
+ if (this.debugEnabled) {
116
+ console.warn("\u26A0\uFE0F [encryption][kms] Vault misconfigured (missing VAULT_ADDR or VAULT_TOKEN)");
117
+ }
118
+ }
119
+ if (this.healthy && !HashicorpVaultKmsService.loggedInit && this.debugEnabled) {
120
+ HashicorpVaultKmsService.loggedInit = true;
121
+ if (this.debugEnabled) {
122
+ console.info("\u{1F510} [encryption][kms] Hashicorp Vault KMS enabled");
123
+ }
124
+ }
125
+ }
126
+ static {
127
+ this.loggedInit = false;
128
+ }
129
+ isHealthy() {
130
+ return this.healthy;
131
+ }
132
+ now() {
133
+ return Date.now();
134
+ }
135
+ cacheHit(tenantId) {
136
+ const entry = this.cache.get(tenantId);
137
+ if (!entry) return null;
138
+ if (this.now() - entry.fetchedAt > this.ttlMs) {
139
+ this.cache.delete(tenantId);
140
+ return null;
141
+ }
142
+ return entry;
143
+ }
144
+ async readVault(path) {
145
+ if (!this.vaultAddr || !this.vaultToken) {
146
+ this.healthy = false;
147
+ return null;
148
+ }
149
+ try {
150
+ const res = await fetch(`${this.vaultAddr}/v1/${path}`, {
151
+ method: "GET",
152
+ headers: { "X-Vault-Token": this.vaultToken }
153
+ });
154
+ if (!res.ok) {
155
+ this.healthy = res.status < 500;
156
+ console.warn("\u26A0\uFE0F [encryption][kms] Vault read failed", { path, status: res.status });
157
+ return null;
158
+ }
159
+ if (this.debugEnabled) {
160
+ console.info("\u{1F50D} [encryption][kms] Vault read ok", { path });
161
+ }
162
+ return await res.json();
163
+ } catch (err) {
164
+ this.healthy = false;
165
+ console.warn("\u26A0\uFE0F [encryption][kms] Vault read error", { path, error: err?.message || String(err) });
166
+ return null;
167
+ }
168
+ }
169
+ async writeVault(path, key) {
170
+ if (!this.vaultAddr || !this.vaultToken) {
171
+ this.healthy = false;
172
+ return false;
173
+ }
174
+ try {
175
+ const res = await fetch(`${this.vaultAddr}/v1/${path}`, {
176
+ method: "POST",
177
+ headers: {
178
+ "X-Vault-Token": this.vaultToken,
179
+ "Content-Type": "application/json"
180
+ },
181
+ body: JSON.stringify({ data: { key } })
182
+ });
183
+ this.healthy = res.ok;
184
+ if (!res.ok) {
185
+ console.warn("\u26A0\uFE0F [encryption][kms] Vault write failed", { path, status: res.status });
186
+ }
187
+ return res.ok;
188
+ } catch (err) {
189
+ this.healthy = false;
190
+ console.warn("\u26A0\uFE0F [encryption][kms] Vault write error", { path, error: err?.message || String(err) });
191
+ return false;
192
+ }
193
+ }
194
+ buildKeyPath(tenantId) {
195
+ const suffix = `tenant_key_${tenantId}`;
196
+ const normalizedMount = this.mountPath.replace(/^\/+/, "");
197
+ return `${normalizedMount}/${suffix}`;
198
+ }
199
+ remember(entry) {
200
+ this.cache.set(entry.tenantId, entry);
201
+ return entry;
202
+ }
203
+ async getTenantDek(tenantId) {
204
+ const cached = this.cacheHit(tenantId);
205
+ if (cached) return cached;
206
+ const path = this.buildKeyPath(tenantId);
207
+ const res = await this.readVault(path);
208
+ const key = res?.data?.data?.key;
209
+ if (!key) {
210
+ console.warn("\u26A0\uFE0F [encryption][kms] No tenant DEK found in Vault", { tenantId, path });
211
+ return null;
212
+ }
213
+ const dek = { tenantId, key, fetchedAt: this.now() };
214
+ return this.remember(dek);
215
+ }
216
+ async createTenantDek(tenantId) {
217
+ const key = generateDek();
218
+ const path = this.buildKeyPath(tenantId);
219
+ const ok = await this.writeVault(path, key);
220
+ if (ok) {
221
+ console.info("\u{1F511} [encryption][kms] Stored tenant DEK in Vault", { tenantId, path });
222
+ } else {
223
+ console.warn("\u26A0\uFE0F [encryption][kms] Failed to store tenant DEK in Vault", { tenantId, path });
224
+ }
225
+ if (!ok) return null;
226
+ return this.remember({ tenantId, key, fetchedAt: this.now() });
227
+ }
228
+ }
229
+ let loggedDerivedKeyFallbackBanner = false;
230
+ function logDerivedKeyFallbackBanner(opts) {
231
+ if (process.env.NODE_ENV === "test" || loggedDerivedKeyFallbackBanner) return;
232
+ loggedDerivedKeyFallbackBanner = true;
233
+ const redBg = "\x1B[41m";
234
+ const white = "\x1B[97m";
235
+ const reset = "\x1B[0m";
236
+ const width = 110;
237
+ const border = `${redBg}${white}${"\u2501".repeat(width)}${reset}`;
238
+ const isProduction = process.env.NODE_ENV === "production";
239
+ const sourceLine = opts.source === "explicit" ? `Source: ${opts.envName}` : "Source: dev default secret (do NOT use in production)";
240
+ const body = [
241
+ "\u{1F6A8} Using derived tenant encryption keys (Vault unavailable / no DEK)",
242
+ sourceLine,
243
+ isProduction ? "Secret: [redacted in production]" : `Secret: ${opts.secret}`,
244
+ "Persist this secret securely. Without it, encrypted tenant data cannot be recovered after restart."
245
+ ];
246
+ console.warn(border);
247
+ for (const line of body) {
248
+ const padded = line.padEnd(width - 2, " ");
249
+ console.warn(`${redBg}${white} ${padded} ${reset}`);
250
+ }
251
+ console.warn(border);
252
+ }
253
+ function createKmsService() {
254
+ if (!isTenantDataEncryptionEnabled()) return new NoopKmsService();
255
+ const primary = new HashicorpVaultKmsService();
256
+ const derived = resolveDerivedKeySecret();
257
+ const fallback = derived ? new DerivedKmsService(derived.secret) : null;
258
+ const notifyFallback = derived ? () => {
259
+ logDerivedKeyFallbackBanner(derived);
260
+ } : void 0;
261
+ if (!primary.isHealthy()) {
262
+ if (fallback) {
263
+ notifyFallback?.();
264
+ return fallback;
265
+ }
266
+ console.warn(
267
+ "\u26A0\uFE0F [encryption][kms] Vault not healthy or misconfigured (missing VAULT_ADDR/VAULT_TOKEN) and no fallback secret provided; falling back to noop KMS"
268
+ );
269
+ return new NoopKmsService();
270
+ }
271
+ if (fallback) {
272
+ return new FallbackKmsService(primary, fallback, notifyFallback);
273
+ }
274
+ return primary;
275
+ }
276
+ export {
277
+ HashicorpVaultKmsService,
278
+ NoopKmsService,
279
+ createKmsService,
280
+ hashForLookup
281
+ };
282
+ //# sourceMappingURL=kms.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/encryption/kms.ts"],
4
+ "sourcesContent": ["import crypto from 'node:crypto'\nimport { generateDek, hashForLookup } from './aes'\nimport { isEncryptionDebugEnabled, isTenantDataEncryptionEnabled } from './toggles'\n\nexport type TenantDek = {\n tenantId: string\n key: string // base64\n fetchedAt: number\n}\n\nexport interface KmsService {\n getTenantDek(tenantId: string): Promise<TenantDek | null>\n createTenantDek(tenantId: string): Promise<TenantDek | null>\n isHealthy(): boolean\n}\n\nclass FallbackKmsService implements KmsService {\n private notified = false\n constructor(\n private readonly primary: KmsService,\n private readonly fallback: KmsService | null,\n private readonly onFallback?: () => void,\n ) {}\n\n isHealthy(): boolean {\n return this.primary.isHealthy() || Boolean(this.fallback?.isHealthy?.())\n }\n\n private notifyFallback() {\n if (this.notified) return\n this.notified = true\n this.onFallback?.()\n }\n\n private async fromPrimary<T>(op: () => Promise<T | null>): Promise<T | null> {\n try {\n return await op()\n } catch (err) {\n console.warn('\u26A0\uFE0F [encryption][kms] Primary KMS failed, will try fallback', {\n error: (err as Error)?.message || String(err),\n })\n return null\n }\n }\n\n async getTenantDek(tenantId: string): Promise<TenantDek | null> {\n if (this.primary.isHealthy()) {\n const dek = await this.fromPrimary(() => this.primary.getTenantDek(tenantId))\n if (dek) return dek\n }\n if (this.fallback?.isHealthy()) {\n this.notifyFallback()\n return this.fallback.getTenantDek(tenantId)\n }\n return null\n }\n\n async createTenantDek(tenantId: string): Promise<TenantDek | null> {\n if (this.primary.isHealthy()) {\n const dek = await this.fromPrimary(() => this.primary.createTenantDek(tenantId))\n if (dek) return dek\n }\n if (this.fallback?.isHealthy()) {\n this.notifyFallback()\n return this.fallback.createTenantDek(tenantId)\n }\n return null\n }\n}\n\ntype VaultClientOpts = {\n vaultAddr?: string\n vaultToken?: string\n mountPath?: string\n ttlMs?: number\n}\n\ntype VaultReadResponse = {\n data?: { data?: { key?: string; version?: number }; metadata?: Record<string, unknown> }\n}\n\nfunction normalizeEnv(value: string | undefined): string {\n if (!value) return ''\n return value.trim().replace(/^['\"]|['\"]$/g, '')\n}\n\ntype DerivedSecret = { secret: string; source: 'explicit' | 'dev-default'; envName: string }\n\nfunction resolveDerivedKeySecret(): DerivedSecret | null {\n const candidates: Array<{ value: string | null; envName: string }> = [\n { value: process.env.TENANT_DATA_ENCRYPTION_FALLBACK_KEY ?? null, envName: 'TENANT_DATA_ENCRYPTION_FALLBACK_KEY' },\n { value: process.env.TENANT_DATA_ENCRYPTION_KEY ?? null, envName: 'TENANT_DATA_ENCRYPTION_KEY' },\n { value: process.env.AUTH_SECRET ?? null, envName: 'AUTH_SECRET' },\n { value: process.env.NEXTAUTH_SECRET ?? null, envName: 'NEXTAUTH_SECRET' },\n ]\n for (const raw of candidates) {\n const normalized = normalizeEnv(raw.value ?? undefined)\n if (normalized) return { secret: normalized, source: 'explicit', envName: raw.envName }\n }\n if (process.env.NODE_ENV !== 'production') {\n return { secret: 'om-dev-tenant-encryption', source: 'dev-default', envName: 'DEV_DEFAULT' }\n }\n return null\n}\n\nexport class NoopKmsService implements KmsService {\n isHealthy(): boolean { return !isTenantDataEncryptionEnabled() }\n async getTenantDek(): Promise<TenantDek | null> { return null }\n async createTenantDek(): Promise<TenantDek | null> { return null }\n}\n\nclass DerivedKmsService implements KmsService {\n private root: Buffer\n constructor(secret: string) {\n // Derive a stable root key from the provided secret so derived tenant keys are deterministic\n this.root = crypto.createHash('sha256').update(secret).digest()\n }\n\n isHealthy(): boolean {\n return true\n }\n\n private deriveKey(tenantId: string): string {\n const iterations = 310_000\n const keyLength = 32\n const derived = crypto.pbkdf2Sync(this.root, tenantId, iterations, keyLength, 'sha512')\n return derived.toString('base64')\n }\n\n async getTenantDek(tenantId: string): Promise<TenantDek | null> {\n if (!tenantId) return null\n return { tenantId, key: this.deriveKey(tenantId), fetchedAt: Date.now() }\n }\n\n async createTenantDek(tenantId: string): Promise<TenantDek | null> {\n return this.getTenantDek(tenantId)\n }\n}\n\nexport class HashicorpVaultKmsService implements KmsService {\n private cache = new Map<string, TenantDek>()\n private readonly vaultAddr: string\n private readonly vaultToken: string\n private readonly mountPath: string\n private readonly ttlMs: number\n private healthy = true\n private readonly debugEnabled: boolean\n private static loggedInit = false\n\n constructor(opts: VaultClientOpts = {}) {\n this.vaultAddr = normalizeEnv(opts.vaultAddr || process.env.VAULT_ADDR || '')\n this.vaultToken = normalizeEnv(opts.vaultToken || process.env.VAULT_TOKEN || '')\n this.mountPath = (opts.mountPath || process.env.VAULT_KV_PATH || 'secret/data').replace(/\\/+$/, '')\n this.ttlMs = opts.ttlMs ?? 15 * 60 * 1000\n this.debugEnabled = isEncryptionDebugEnabled()\n if (!this.vaultAddr || !this.vaultToken) {\n this.healthy = false\n if (this.debugEnabled) {\n console.warn('\u26A0\uFE0F [encryption][kms] Vault misconfigured (missing VAULT_ADDR or VAULT_TOKEN)')\n }\n }\n if (this.healthy && !HashicorpVaultKmsService.loggedInit && this.debugEnabled) {\n HashicorpVaultKmsService.loggedInit = true\n if(this.debugEnabled) {\n console.info('\uD83D\uDD10 [encryption][kms] Hashicorp Vault KMS enabled')\n }\n }\n }\n\n isHealthy(): boolean {\n return this.healthy\n }\n\n private now(): number {\n return Date.now()\n }\n\n private cacheHit(tenantId: string): TenantDek | null {\n const entry = this.cache.get(tenantId)\n if (!entry) return null\n if (this.now() - entry.fetchedAt > this.ttlMs) {\n this.cache.delete(tenantId)\n return null\n }\n return entry\n }\n\n private async readVault(path: string): Promise<VaultReadResponse | null> {\n if (!this.vaultAddr || !this.vaultToken) {\n this.healthy = false\n return null\n }\n try {\n const res = await fetch(`${this.vaultAddr}/v1/${path}`, {\n method: 'GET',\n headers: { 'X-Vault-Token': this.vaultToken },\n })\n if (!res.ok) {\n this.healthy = res.status < 500\n console.warn('\u26A0\uFE0F [encryption][kms] Vault read failed', { path, status: res.status })\n return null\n }\n if (this.debugEnabled) {\n console.info('\uD83D\uDD0D [encryption][kms] Vault read ok', { path })\n }\n return (await res.json()) as VaultReadResponse\n } catch (err) {\n this.healthy = false\n console.warn('\u26A0\uFE0F [encryption][kms] Vault read error', { path, error: (err as Error)?.message || String(err) })\n return null\n }\n }\n\n private async writeVault(path: string, key: string): Promise<boolean> {\n if (!this.vaultAddr || !this.vaultToken) {\n this.healthy = false\n return false\n }\n try {\n const res = await fetch(`${this.vaultAddr}/v1/${path}`, {\n\n method: 'POST',\n headers: {\n 'X-Vault-Token': this.vaultToken,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ data: { key } }),\n })\n this.healthy = res.ok\n if (!res.ok) {\n console.warn('\u26A0\uFE0F [encryption][kms] Vault write failed', { path, status: res.status })\n }\n return res.ok\n } catch (err) {\n this.healthy = false\n console.warn('\u26A0\uFE0F [encryption][kms] Vault write error', { path, error: (err as Error)?.message || String(err) })\n return false\n }\n }\n\n private buildKeyPath(tenantId: string): string {\n const suffix = `tenant_key_${tenantId}`\n const normalizedMount = this.mountPath.replace(/^\\/+/, '')\n return `${normalizedMount}/${suffix}`\n }\n\n private remember(entry: TenantDek): TenantDek {\n this.cache.set(entry.tenantId, entry)\n return entry\n }\n\n async getTenantDek(tenantId: string): Promise<TenantDek | null> {\n const cached = this.cacheHit(tenantId)\n if (cached) return cached\n const path = this.buildKeyPath(tenantId)\n const res = await this.readVault(path)\n const key = res?.data?.data?.key\n if (!key) {\n console.warn('\u26A0\uFE0F [encryption][kms] No tenant DEK found in Vault', { tenantId, path })\n return null\n }\n const dek: TenantDek = { tenantId, key, fetchedAt: this.now() }\n return this.remember(dek)\n }\n\n async createTenantDek(tenantId: string): Promise<TenantDek | null> {\n const key = generateDek()\n const path = this.buildKeyPath(tenantId)\n const ok = await this.writeVault(path, key)\n if (ok) {\n console.info('\uD83D\uDD11 [encryption][kms] Stored tenant DEK in Vault', { tenantId, path })\n } else {\n console.warn('\u26A0\uFE0F [encryption][kms] Failed to store tenant DEK in Vault', { tenantId, path })\n }\n if (!ok) return null\n return this.remember({ tenantId, key, fetchedAt: this.now() })\n }\n}\n\nlet loggedDerivedKeyFallbackBanner = false\n\nfunction logDerivedKeyFallbackBanner(opts: DerivedSecret): void {\n if (process.env.NODE_ENV === 'test' || loggedDerivedKeyFallbackBanner) return\n loggedDerivedKeyFallbackBanner = true\n const redBg = '\\x1b[41m'\n const white = '\\x1b[97m'\n const reset = '\\x1b[0m'\n const width = 110\n const border = `${redBg}${white}${'\u2501'.repeat(width)}${reset}`\n const isProduction = process.env.NODE_ENV === 'production'\n const sourceLine =\n opts.source === 'explicit' ? `Source: ${opts.envName}` : 'Source: dev default secret (do NOT use in production)'\n const body = [\n '\uD83D\uDEA8 Using derived tenant encryption keys (Vault unavailable / no DEK)',\n sourceLine,\n isProduction ? 'Secret: [redacted in production]' : `Secret: ${opts.secret}`,\n 'Persist this secret securely. Without it, encrypted tenant data cannot be recovered after restart.',\n ]\n console.warn(border)\n for (const line of body) {\n const padded = line.padEnd(width - 2, ' ')\n console.warn(`${redBg}${white} ${padded} ${reset}`)\n }\n console.warn(border)\n}\n\nexport function createKmsService(): KmsService {\n if (!isTenantDataEncryptionEnabled()) return new NoopKmsService()\n const primary = new HashicorpVaultKmsService()\n\n const derived = resolveDerivedKeySecret()\n const fallback = derived ? new DerivedKmsService(derived.secret) : null\n const notifyFallback = derived\n ? () => {\n logDerivedKeyFallbackBanner(derived)\n }\n : undefined\n\n if (!primary.isHealthy()) {\n if (fallback) {\n notifyFallback?.()\n return fallback\n }\n console.warn(\n '\u26A0\uFE0F [encryption][kms] Vault not healthy or misconfigured (missing VAULT_ADDR/VAULT_TOKEN) and no fallback secret provided; falling back to noop KMS',\n )\n return new NoopKmsService()\n }\n\n if (fallback) {\n return new FallbackKmsService(primary, fallback, notifyFallback)\n }\n\n return primary\n}\n\nexport { hashForLookup }\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,330 @@
1
+ import { ReferenceKind } from "@mikro-orm/core";
2
+ import { resolveEntityIdFromMetadata } from "./entityIds.js";
3
+ import { isTenantDataEncryptionEnabled } from "./toggles.js";
4
+ import { isEncryptionDebugEnabled } from "./toggles.js";
5
+ import { resolveTenantEncryptionService } from "./customFieldValues.js";
6
+ function resolveScope(entity) {
7
+ const tenantId = entity.tenantId ?? entity.tenant_id ?? entity.tenant?.id ?? null;
8
+ const organizationId = entity.organizationId ?? entity.organization_id ?? entity.organization?.id ?? null;
9
+ return {
10
+ tenantId: tenantId ? String(tenantId) : null,
11
+ organizationId: organizationId ? String(organizationId) : null
12
+ };
13
+ }
14
+ function debug(event, payload) {
15
+ if (!isEncryptionDebugEnabled()) return;
16
+ try {
17
+ console.debug(event, payload);
18
+ } catch {
19
+ }
20
+ }
21
+ const registeredEventManagers = /* @__PURE__ */ new WeakSet();
22
+ const toSnakeCase = (value) => value.replace(/([A-Z])/g, "_$1").replace(/__/g, "_").toLowerCase();
23
+ class TenantEncryptionSubscriber {
24
+ constructor(service) {
25
+ this.service = service;
26
+ }
27
+ getSubscribedEntities() {
28
+ return [];
29
+ }
30
+ resolveMeta(meta, entity, em) {
31
+ if (meta) return meta;
32
+ const ctor = entity?.constructor;
33
+ const name = ctor?.name;
34
+ const registry = em?.getMetadata?.();
35
+ if (!registry || !name) return meta;
36
+ try {
37
+ return registry.find?.(name);
38
+ } catch {
39
+ }
40
+ try {
41
+ return registry.find?.(ctor);
42
+ } catch {
43
+ }
44
+ try {
45
+ return registry.get?.(name);
46
+ } catch {
47
+ }
48
+ try {
49
+ return registry.get?.(ctor);
50
+ } catch {
51
+ }
52
+ const all = typeof registry.getAll === "function" && registry.getAll() || (Array.isArray(registry.metadata) ? registry.metadata : void 0) || registry.metadata || {};
53
+ try {
54
+ const entries = Array.isArray(all) ? all : Object.values(all);
55
+ const match = entries.find(
56
+ (m) => m?.className === name || m?.name === name || m?.entityName === name || m?.collection === ctor?.prototype?.__meta?.tableName || m?.tableName === ctor?.prototype?.__meta?.tableName
57
+ );
58
+ if (match) return match;
59
+ } catch {
60
+ }
61
+ return meta;
62
+ }
63
+ resolveEntityId(meta) {
64
+ try {
65
+ return resolveEntityIdFromMetadata(meta);
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+ syncOriginalEntityData(target, meta, em) {
71
+ const helper = target?.__helper;
72
+ if (!helper || typeof helper !== "object") return;
73
+ try {
74
+ const comparator = em?.getComparator?.();
75
+ if (comparator?.prepareEntity) {
76
+ helper.__originalEntityData = comparator.prepareEntity(target);
77
+ helper.__touched = false;
78
+ return;
79
+ }
80
+ } catch (err) {
81
+ debug("\u26AA\uFE0F subscriber.sync_original.comparator_failed", {
82
+ entity: meta?.className || meta?.name,
83
+ message: err?.message ?? String(err)
84
+ });
85
+ }
86
+ const properties = meta?.properties ? Object.values(meta.properties) : [];
87
+ if (properties.length === 0) return;
88
+ const snapshot = { ...helper.__originalEntityData ?? {} };
89
+ for (const prop of properties) {
90
+ if ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind)) continue;
91
+ const name = prop.name;
92
+ if (typeof name !== "string" || !name.length) continue;
93
+ snapshot[name] = target[name];
94
+ }
95
+ helper.__originalEntityData = snapshot;
96
+ helper.__touched = false;
97
+ }
98
+ async encrypt(target, meta, em, changeSet) {
99
+ if (!isTenantDataEncryptionEnabled() || !this.service.isEnabled()) {
100
+ debug("\u26AA\uFE0F subscriber.skip", { reason: "disabled", entity: meta?.className || meta?.name });
101
+ return;
102
+ }
103
+ const resolvedMeta = this.resolveMeta(meta, target, em);
104
+ const entityId = this.resolveEntityId(resolvedMeta);
105
+ if (!entityId) {
106
+ debug("\u26A0\uFE0F subscriber.decrypt.skip.entity_id_missing", {
107
+ metaName: resolvedMeta?.className || resolvedMeta?.name,
108
+ table: resolvedMeta?.tableName
109
+ });
110
+ return;
111
+ }
112
+ const { tenantId, organizationId } = resolveScope(target);
113
+ if (!tenantId) {
114
+ debug("\u26AA\uFE0F subscriber.skip", { reason: "no-tenant", entityId });
115
+ return;
116
+ }
117
+ const encrypted = await this.service.encryptEntityPayload(entityId, target, tenantId, organizationId);
118
+ const metaProps = resolvedMeta?.properties && typeof resolvedMeta.properties === "object" ? resolvedMeta.properties : {};
119
+ const payloadObj = changeSet && typeof changeSet === "object" ? typeof changeSet.payload === "object" && changeSet.payload ? changeSet.payload : changeSet.payload = {} : null;
120
+ const updates = {};
121
+ const columnNameFor = (propKey, prop) => {
122
+ try {
123
+ if (prop && typeof prop === "object") {
124
+ const explicit = prop?.fieldName;
125
+ if (typeof explicit === "string" && explicit.length) return explicit;
126
+ const name = prop?.name;
127
+ if (typeof name === "string" && name.length) return name;
128
+ }
129
+ } catch (err) {
130
+ debug("\u26A0\uFE0F subscriber.column_name.resolve", {
131
+ entityId,
132
+ propKey,
133
+ message: err?.message ?? String(err)
134
+ });
135
+ }
136
+ return toSnakeCase(propKey);
137
+ };
138
+ for (const [key, value] of Object.entries(encrypted)) {
139
+ const prop = metaProps[key];
140
+ if (!prop || typeof prop !== "object") continue;
141
+ if (target[key] === value) continue;
142
+ updates[key] = value;
143
+ }
144
+ if (Object.keys(updates).length === 0) return;
145
+ Object.assign(target, updates);
146
+ if (payloadObj) {
147
+ try {
148
+ const ensureColumnKey = (propKey, value) => {
149
+ const columnName = columnNameFor(propKey, metaProps[propKey]);
150
+ const canonicalKey = columnName || toSnakeCase(propKey);
151
+ const aliases = new Set(
152
+ [propKey, toSnakeCase(propKey), columnName, columnName ? toSnakeCase(columnName) : void 0].filter(
153
+ (v) => typeof v === "string" && v.length > 0
154
+ )
155
+ );
156
+ for (const alias of aliases) {
157
+ if (Object.prototype.hasOwnProperty.call(payloadObj, alias)) delete payloadObj[alias];
158
+ }
159
+ const finalKey = columnName || toSnakeCase(propKey);
160
+ payloadObj[finalKey] = value;
161
+ };
162
+ for (const key of Object.keys(updates)) {
163
+ ensureColumnKey(key, updates[key]);
164
+ }
165
+ } catch (err) {
166
+ debug("\u26A0\uFE0F subscriber.payload.normalize.error", {
167
+ entityId,
168
+ message: err?.message ?? String(err)
169
+ });
170
+ }
171
+ }
172
+ }
173
+ async decryptEntityGraph(target, meta, em, opts = {}) {
174
+ await this.decrypt(target, meta, em, opts);
175
+ }
176
+ async decrypt(target, meta, em, {
177
+ syncOriginal = false,
178
+ seen,
179
+ fallbackScope
180
+ } = {}) {
181
+ const visited = seen ?? /* @__PURE__ */ new WeakSet();
182
+ if (visited.has(target)) return;
183
+ visited.add(target);
184
+ if (!isTenantDataEncryptionEnabled() || !this.service.isEnabled()) {
185
+ debug("\u26AA\uFE0F subscriber.skip", { reason: "disabled", entity: meta?.className || meta?.name });
186
+ return;
187
+ }
188
+ const resolvedMeta = this.resolveMeta(meta, target, em);
189
+ const entityId = this.resolveEntityId(resolvedMeta);
190
+ if (!entityId) return;
191
+ const { tenantId, organizationId } = resolveScope(target);
192
+ const scopedTenantId = tenantId ?? fallbackScope?.tenantId ?? null;
193
+ const scopedOrgId = organizationId ?? fallbackScope?.organizationId ?? null;
194
+ if (!scopedTenantId) {
195
+ debug("\u26AA\uFE0F subscriber.skip", { reason: "no-tenant", entityId });
196
+ return;
197
+ }
198
+ const decrypted = await this.service.decryptEntityPayload(entityId, target, scopedTenantId, scopedOrgId);
199
+ Object.assign(target, decrypted);
200
+ if (syncOriginal) {
201
+ this.syncOriginalEntityData(target, resolvedMeta, em);
202
+ }
203
+ const nextFallback = fallbackScope ?? (tenantId || organizationId ? { tenantId: tenantId ?? null, organizationId: organizationId ?? null } : { tenantId: scopedTenantId, organizationId: scopedOrgId });
204
+ try {
205
+ const extractEntities = (value) => {
206
+ if (!value) return [];
207
+ if (typeof value === "object" && typeof value.isInitialized === "function") {
208
+ try {
209
+ if (value.isInitialized()) {
210
+ const unwrapped = typeof value.unwrap === "function" ? value.unwrap() : value.__entity ?? value;
211
+ if (unwrapped && typeof unwrapped === "object") return [unwrapped];
212
+ }
213
+ } catch {
214
+ }
215
+ return [];
216
+ }
217
+ if (typeof value === "object" && typeof value.isInitialized === "function" && typeof value.getItems === "function") {
218
+ try {
219
+ return value.isInitialized() ? value.getItems() ?? [] : [];
220
+ } catch {
221
+ return [];
222
+ }
223
+ }
224
+ if (Array.isArray(value)) return value;
225
+ if (typeof value === "object") return [value];
226
+ return [];
227
+ };
228
+ const props = resolvedMeta?.properties ? Object.values(resolvedMeta.properties) : [];
229
+ for (const prop of props) {
230
+ const kind = prop?.kind;
231
+ const name = prop?.name;
232
+ if (typeof name !== "string" || !name.length) continue;
233
+ const value = target[name];
234
+ if (!value) continue;
235
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(kind)) {
236
+ const nestedEntities = extractEntities(value);
237
+ for (const nested of nestedEntities) {
238
+ const nestedMeta = this.resolveMeta(nested.__meta ?? nested.__helper?.__meta, nested, em);
239
+ await this.decrypt(nested, nestedMeta, em, {
240
+ syncOriginal: true,
241
+ seen: visited,
242
+ fallbackScope: nextFallback
243
+ });
244
+ }
245
+ continue;
246
+ }
247
+ if ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(kind)) {
248
+ const items = extractEntities(value);
249
+ for (const item of items) {
250
+ if (!item || typeof item !== "object") continue;
251
+ const nestedMeta = this.resolveMeta(item.__meta ?? item.__helper?.__meta, item, em);
252
+ await this.decrypt(item, nestedMeta, em, {
253
+ syncOriginal: true,
254
+ seen: visited,
255
+ fallbackScope: nextFallback
256
+ });
257
+ }
258
+ }
259
+ }
260
+ } catch (err) {
261
+ debug("\u26A0\uFE0F subscriber.deep_decrypt.error", {
262
+ entityId,
263
+ message: err?.message ?? String(err)
264
+ });
265
+ }
266
+ }
267
+ async beforeCreate(args) {
268
+ await this.encrypt(args.entity, args.meta, args.em, args.changeSet);
269
+ }
270
+ async beforeUpdate(args) {
271
+ await this.decrypt(args.entity, args.meta, args.em);
272
+ await this.encrypt(args.entity, args.meta, args.em, args.changeSet);
273
+ }
274
+ async afterCreate(args) {
275
+ await this.decrypt(args.entity, args.meta, args.em, { syncOriginal: true });
276
+ }
277
+ async afterUpdate(args) {
278
+ await this.decrypt(args.entity, args.meta, args.em, { syncOriginal: true });
279
+ }
280
+ async afterUpsert(args) {
281
+ await this.decrypt(args.entity, args.meta, args.em, { syncOriginal: true });
282
+ }
283
+ async onLoad(args) {
284
+ await this.decrypt(args.entity, args.meta, args.em, { syncOriginal: true });
285
+ }
286
+ async afterFind(args) {
287
+ const entities = Array.isArray(args.entities) ? args.entities : [];
288
+ for (const entity of entities) {
289
+ await this.decrypt(entity, args.meta, args.em, { syncOriginal: true });
290
+ }
291
+ }
292
+ }
293
+ function registerTenantEncryptionSubscriber(em, service) {
294
+ const eventManager = em?.getEventManager?.();
295
+ if (!eventManager || typeof eventManager.registerSubscriber !== "function") return;
296
+ if (registeredEventManagers.has(eventManager)) return;
297
+ eventManager.registerSubscriber(new TenantEncryptionSubscriber(service));
298
+ registeredEventManagers.add(eventManager);
299
+ }
300
+ async function decryptEntitiesWithFallbackScope(targets, {
301
+ em,
302
+ tenantId,
303
+ organizationId,
304
+ encryptionService
305
+ }) {
306
+ if (!isTenantDataEncryptionEnabled()) return;
307
+ const list = Array.isArray(targets) ? targets : [targets];
308
+ if (!list.length) return;
309
+ const service = encryptionService ?? resolveTenantEncryptionService(em);
310
+ if (!service || !service.isEnabled()) return;
311
+ const subscriber = new TenantEncryptionSubscriber(service);
312
+ const fallback = tenantId || organizationId ? {
313
+ tenantId: tenantId ?? null,
314
+ organizationId: organizationId ?? null
315
+ } : void 0;
316
+ for (const entity of list) {
317
+ if (!entity || typeof entity !== "object") continue;
318
+ const meta = entity.__meta ?? entity.__helper?.__meta;
319
+ await subscriber.decryptEntityGraph(entity, meta, em, {
320
+ syncOriginal: true,
321
+ fallbackScope: fallback
322
+ });
323
+ }
324
+ }
325
+ export {
326
+ TenantEncryptionSubscriber,
327
+ decryptEntitiesWithFallbackScope,
328
+ registerTenantEncryptionSubscriber
329
+ };
330
+ //# sourceMappingURL=subscriber.js.map