@pattern-stack/codegen 0.10.1 → 0.12.0

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 (279) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/README.md +5 -5
  3. package/consumer-skills/codegen/SKILL.md +2 -2
  4. package/consumer-skills/{sync → integration}/SKILL.md +29 -29
  5. package/consumer-skills/{sync → integration}/audit-and-detection.md +22 -22
  6. package/consumer-skills/{sync → integration}/change-sources-and-sinks.md +60 -60
  7. package/consumer-skills/subsystems/SKILL.md +8 -8
  8. package/consumer-skills/subsystems/wiring-and-order.md +7 -7
  9. package/dist/runtime/base-classes/index.d.ts +4 -4
  10. package/dist/runtime/base-classes/index.js +35 -35
  11. package/dist/runtime/base-classes/index.js.map +1 -1
  12. package/dist/runtime/base-classes/{synced-entity-repository.d.ts → integrated-entity-repository.d.ts} +15 -15
  13. package/dist/runtime/base-classes/{synced-entity-repository.js → integrated-entity-repository.js} +21 -21
  14. package/dist/runtime/base-classes/integrated-entity-repository.js.map +1 -0
  15. package/dist/runtime/base-classes/{synced-entity-service.d.ts → integrated-entity-service.d.ts} +6 -6
  16. package/dist/runtime/base-classes/{synced-entity-service.js → integrated-entity-service.js} +4 -4
  17. package/dist/runtime/base-classes/integrated-entity-service.js.map +1 -0
  18. package/dist/runtime/base-classes/{sync-upsert-config.d.ts → integration-upsert-config.d.ts} +13 -13
  19. package/dist/runtime/base-classes/integration-upsert-config.js +1 -0
  20. package/dist/runtime/base-classes/{junction-sync-repository.d.ts → junction-integration-repository.d.ts} +11 -11
  21. package/dist/runtime/base-classes/{junction-sync-repository.js → junction-integration-repository.js} +15 -15
  22. package/dist/runtime/base-classes/junction-integration-repository.js.map +1 -0
  23. package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js.map +1 -1
  24. package/dist/runtime/subsystems/auth/auth.module.d.ts +4 -4
  25. package/dist/runtime/subsystems/auth/auth.module.js +3 -3
  26. package/dist/runtime/subsystems/auth/auth.module.js.map +1 -1
  27. package/dist/runtime/subsystems/auth/auth.tokens.d.ts +8 -8
  28. package/dist/runtime/subsystems/auth/auth.tokens.js +6 -6
  29. package/dist/runtime/subsystems/auth/auth.tokens.js.map +1 -1
  30. package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js.map +1 -1
  31. package/dist/runtime/subsystems/auth/controllers/auth.controller.d.ts +2 -2
  32. package/dist/runtime/subsystems/auth/controllers/auth.controller.js +3 -3
  33. package/dist/runtime/subsystems/auth/controllers/auth.controller.js.map +1 -1
  34. package/dist/runtime/subsystems/auth/index.d.ts +3 -3
  35. package/dist/runtime/subsystems/auth/index.js +40 -40
  36. package/dist/runtime/subsystems/auth/index.js.map +1 -1
  37. package/dist/runtime/subsystems/auth/middleware/requester-context.js.map +1 -1
  38. package/dist/runtime/subsystems/auth/protocols/auth-strategy.d.ts +3 -3
  39. package/dist/runtime/subsystems/auth/protocols/{integration-store.d.ts → connection-store.d.ts} +20 -20
  40. package/dist/runtime/subsystems/auth/protocols/connection-store.js +1 -0
  41. package/dist/runtime/subsystems/auth/protocols/provider-strategy.d.ts +3 -3
  42. package/dist/runtime/subsystems/auth/runtime/{integration-broken.error.d.ts → connection-broken.error.d.ts} +5 -5
  43. package/dist/runtime/subsystems/auth/runtime/connection-broken.error.js +19 -0
  44. package/dist/runtime/subsystems/auth/runtime/connection-broken.error.js.map +1 -0
  45. package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.d.ts +10 -10
  46. package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.js +28 -28
  47. package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.js.map +1 -1
  48. package/dist/runtime/subsystems/auth/runtime/with-auth-retry.d.ts +1 -1
  49. package/dist/runtime/subsystems/auth/runtime/with-auth-retry.js +3 -3
  50. package/dist/runtime/subsystems/auth/runtime/with-auth-retry.js.map +1 -1
  51. package/dist/runtime/subsystems/index.d.ts +11 -7
  52. package/dist/runtime/subsystems/index.js +1041 -67
  53. package/dist/runtime/subsystems/index.js.map +1 -1
  54. package/dist/runtime/subsystems/{sync → integration}/build-change-source.d.ts +3 -3
  55. package/dist/runtime/subsystems/{sync → integration}/build-change-source.js +3 -3
  56. package/dist/runtime/subsystems/integration/build-change-source.js.map +1 -0
  57. package/dist/runtime/subsystems/{sync → integration}/deep-equal.differ.d.ts +2 -2
  58. package/dist/runtime/subsystems/{sync → integration}/deep-equal.differ.js +1 -1
  59. package/dist/runtime/subsystems/integration/deep-equal.differ.js.map +1 -0
  60. package/dist/runtime/subsystems/{sync → integration}/detection-config.schema.d.ts +3 -3
  61. package/dist/runtime/subsystems/{sync → integration}/detection-config.schema.js +1 -1
  62. package/dist/runtime/subsystems/integration/detection-config.schema.js.map +1 -0
  63. package/dist/runtime/subsystems/integration/entity-change-source-registry.memory.d.ts +25 -0
  64. package/dist/runtime/subsystems/integration/entity-change-source-registry.memory.js +34 -0
  65. package/dist/runtime/subsystems/integration/entity-change-source-registry.memory.js.map +1 -0
  66. package/dist/runtime/subsystems/integration/entity-change-source-registry.protocol.d.ts +53 -0
  67. package/dist/runtime/subsystems/integration/entity-change-source-registry.protocol.js +13 -0
  68. package/dist/runtime/subsystems/integration/entity-change-source-registry.protocol.js.map +1 -0
  69. package/dist/runtime/subsystems/{sync/execute-sync.use-case.d.ts → integration/execute-integration.use-case.d.ts} +13 -13
  70. package/dist/runtime/subsystems/{sync/execute-sync.use-case.js → integration/execute-integration.use-case.js} +30 -30
  71. package/dist/runtime/subsystems/integration/execute-integration.use-case.js.map +1 -0
  72. package/dist/runtime/subsystems/integration/index.d.ts +30 -0
  73. package/dist/runtime/subsystems/{sync → integration}/index.js +206 -171
  74. package/dist/runtime/subsystems/integration/index.js.map +1 -0
  75. package/dist/runtime/subsystems/{sync/sync-audit.schema.d.ts → integration/integration-audit.schema.d.ts} +64 -64
  76. package/dist/runtime/subsystems/{sync/sync-audit.schema.js → integration/integration-audit.schema.js} +47 -47
  77. package/dist/runtime/subsystems/integration/integration-audit.schema.js.map +1 -0
  78. package/dist/runtime/subsystems/{sync/sync-change-source.protocol.d.ts → integration/integration-change-source.protocol.d.ts} +10 -10
  79. package/dist/runtime/subsystems/integration/integration-change-source.protocol.js +1 -0
  80. package/dist/runtime/subsystems/{sync/sync-cursor-store.drizzle-backend.d.ts → integration/integration-cursor-store.drizzle-backend.d.ts} +1 -1
  81. package/dist/runtime/subsystems/{sync/sync-cursor-store.drizzle-backend.js → integration/integration-cursor-store.drizzle-backend.js} +65 -65
  82. package/dist/runtime/subsystems/integration/integration-cursor-store.drizzle-backend.js.map +1 -0
  83. package/dist/runtime/subsystems/{sync/sync-cursor-store.memory-backend.d.ts → integration/integration-cursor-store.memory-backend.d.ts} +6 -6
  84. package/dist/runtime/subsystems/{sync/sync-cursor-store.memory-backend.js → integration/integration-cursor-store.memory-backend.js} +5 -5
  85. package/dist/runtime/subsystems/integration/integration-cursor-store.memory-backend.js.map +1 -0
  86. package/dist/runtime/subsystems/{sync/sync-cursor-store.protocol.d.ts → integration/integration-cursor-store.protocol.d.ts} +13 -13
  87. package/dist/runtime/subsystems/integration/integration-cursor-store.protocol.js +1 -0
  88. package/dist/runtime/subsystems/{sync/sync-errors.d.ts → integration/integration-errors.d.ts} +2 -2
  89. package/dist/runtime/subsystems/{sync/sync-errors.js → integration/integration-errors.js} +3 -3
  90. package/dist/runtime/subsystems/integration/integration-errors.js.map +1 -0
  91. package/dist/runtime/subsystems/{sync/sync-field-diff.protocol.d.ts → integration/integration-field-diff.protocol.d.ts} +2 -2
  92. package/dist/runtime/subsystems/{sync/sync-field-diff.protocol.js → integration/integration-field-diff.protocol.js} +2 -2
  93. package/dist/runtime/subsystems/integration/integration-field-diff.protocol.js.map +1 -0
  94. package/dist/runtime/subsystems/{sync/sync-loopback.protocol.d.ts → integration/integration-loopback.protocol.d.ts} +2 -2
  95. package/dist/runtime/subsystems/integration/integration-loopback.protocol.js +1 -0
  96. package/dist/runtime/subsystems/{sync/sync-middleware.protocol.d.ts → integration/integration-middleware.protocol.d.ts} +5 -5
  97. package/dist/runtime/subsystems/integration/integration-middleware.protocol.js +1 -0
  98. package/dist/runtime/subsystems/{sync/sync-run-recorder.drizzle-backend.d.ts → integration/integration-run-recorder.drizzle-backend.d.ts} +5 -5
  99. package/dist/runtime/subsystems/{sync/sync-run-recorder.drizzle-backend.js → integration/integration-run-recorder.drizzle-backend.js} +73 -73
  100. package/dist/runtime/subsystems/integration/integration-run-recorder.drizzle-backend.js.map +1 -0
  101. package/dist/runtime/subsystems/{sync/sync-run-recorder.memory-backend.d.ts → integration/integration-run-recorder.memory-backend.d.ts} +15 -15
  102. package/dist/runtime/subsystems/{sync/sync-run-recorder.memory-backend.js → integration/integration-run-recorder.memory-backend.js} +11 -11
  103. package/dist/runtime/subsystems/integration/integration-run-recorder.memory-backend.js.map +1 -0
  104. package/dist/runtime/subsystems/{sync/sync-run-recorder.protocol.d.ts → integration/integration-run-recorder.protocol.d.ts} +25 -25
  105. package/dist/runtime/subsystems/integration/integration-run-recorder.protocol.js +1 -0
  106. package/dist/runtime/subsystems/{sync/sync-sink.protocol.d.ts → integration/integration-sink.protocol.d.ts} +5 -5
  107. package/dist/runtime/subsystems/integration/integration-sink.protocol.js +1 -0
  108. package/dist/runtime/subsystems/{sync/sync.module.d.ts → integration/integration.module.d.ts} +24 -24
  109. package/dist/runtime/subsystems/{sync/sync.module.js → integration/integration.module.js} +132 -132
  110. package/dist/runtime/subsystems/integration/integration.module.js.map +1 -0
  111. package/dist/runtime/subsystems/integration/integration.tokens.d.ts +60 -0
  112. package/dist/runtime/subsystems/integration/integration.tokens.js +20 -0
  113. package/dist/runtime/subsystems/integration/integration.tokens.js.map +1 -0
  114. package/dist/runtime/subsystems/{sync → integration}/loopback.middleware.d.ts +5 -5
  115. package/dist/runtime/subsystems/{sync → integration}/loopback.middleware.js +1 -1
  116. package/dist/runtime/subsystems/integration/loopback.middleware.js.map +1 -0
  117. package/dist/runtime/subsystems/{sync → integration}/poll-change-source.d.ts +5 -5
  118. package/dist/runtime/subsystems/{sync → integration}/poll-change-source.js +1 -1
  119. package/dist/runtime/subsystems/integration/poll-change-source.js.map +1 -0
  120. package/dist/runtime/subsystems/{sync → integration}/webhook-change-source.d.ts +5 -5
  121. package/dist/runtime/subsystems/{sync → integration}/webhook-change-source.js +1 -1
  122. package/dist/runtime/subsystems/integration/webhook-change-source.js.map +1 -0
  123. package/dist/runtime/subsystems/jobs/job-worker.module.d.ts +1 -1
  124. package/dist/runtime/subsystems/observability/index.d.ts +4 -4
  125. package/dist/runtime/subsystems/observability/index.js +11 -11
  126. package/dist/runtime/subsystems/observability/index.js.map +1 -1
  127. package/dist/runtime/subsystems/observability/observability.module.d.ts +2 -2
  128. package/dist/runtime/subsystems/observability/observability.module.js +11 -11
  129. package/dist/runtime/subsystems/observability/observability.module.js.map +1 -1
  130. package/dist/runtime/subsystems/observability/observability.protocol.d.ts +11 -11
  131. package/dist/runtime/subsystems/observability/observability.service.d.ts +6 -6
  132. package/dist/runtime/subsystems/observability/observability.service.js +11 -11
  133. package/dist/runtime/subsystems/observability/observability.service.js.map +1 -1
  134. package/dist/runtime/subsystems/observability/observability.tokens.d.ts +1 -1
  135. package/dist/runtime/subsystems/observability/observability.tokens.js.map +1 -1
  136. package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.d.ts +3 -3
  137. package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.js.map +1 -1
  138. package/dist/runtime/subsystems/observability/reporters/index.d.ts +3 -3
  139. package/dist/runtime/subsystems/observability/reporters/index.js.map +1 -1
  140. package/dist/src/cli/index.js +1336 -376
  141. package/dist/src/cli/index.js.map +1 -1
  142. package/dist/src/index.d.ts +70 -22
  143. package/dist/src/index.js +290 -194
  144. package/dist/src/index.js.map +1 -1
  145. package/examples/auth-integrations/README.md +32 -32
  146. package/examples/auth-integrations/definitions/entities/{integration.yaml → connection.yaml} +10 -10
  147. package/examples/auth-integrations/runtime/{integrations/adapters/integration-grant-sink.adapter.ts → connections/adapters/connection-grant-sink.adapter.ts} +7 -7
  148. package/examples/auth-integrations/runtime/{integrations/adapters/integration-reader.adapter.ts → connections/adapters/connection-reader.adapter.ts} +10 -10
  149. package/examples/auth-integrations/runtime/{integrations/adapters/integration-token-writer.adapter.ts → connections/adapters/connection-token-writer.adapter.ts} +11 -11
  150. package/examples/auth-integrations/runtime/connections/connections-auth.module.ts +81 -0
  151. package/examples/auth-integrations/runtime/{integrations/facade/integrations.service.ts → connections/facade/connections.service.ts} +35 -35
  152. package/examples/auth-integrations/runtime/{integrations → connections}/oauth/use-cases/create-or-update-from-oauth-grant.use-case.ts +11 -11
  153. package/examples/auth-integrations/runtime/{integrations/oauth/use-cases/disconnect-integration.use-case.ts → connections/oauth/use-cases/disconnect-connection.use-case.ts} +6 -6
  154. package/examples/auth-integrations/runtime/connections/oauth/use-cases/list-user-connections.use-case.ts +21 -0
  155. package/examples/auth-integrations/runtime/connections/oauth/use-cases/mark-connection-requires-reauth.use-case.ts +21 -0
  156. package/package.json +9 -1
  157. package/runtime/base-classes/index.ts +8 -8
  158. package/runtime/base-classes/{synced-entity-repository.ts → integrated-entity-repository.ts} +36 -36
  159. package/runtime/base-classes/{synced-entity-service.ts → integrated-entity-service.ts} +6 -6
  160. package/runtime/base-classes/{sync-upsert-config.ts → integration-upsert-config.ts} +12 -12
  161. package/runtime/base-classes/{junction-sync-repository.ts → junction-integration-repository.ts} +28 -28
  162. package/runtime/subsystems/auth/auth-oauth-state.schema.ts +1 -1
  163. package/runtime/subsystems/auth/auth.module.ts +4 -4
  164. package/runtime/subsystems/auth/auth.tokens.ts +7 -7
  165. package/runtime/subsystems/auth/controllers/auth.controller.ts +7 -7
  166. package/runtime/subsystems/auth/index.ts +19 -19
  167. package/runtime/subsystems/auth/protocols/auth-strategy.ts +3 -3
  168. package/runtime/subsystems/auth/protocols/{integration-store.ts → connection-store.ts} +19 -19
  169. package/runtime/subsystems/auth/protocols/provider-strategy.ts +2 -2
  170. package/runtime/subsystems/auth/runtime/{integration-broken.error.ts → connection-broken.error.ts} +5 -5
  171. package/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.ts +35 -35
  172. package/runtime/subsystems/auth/runtime/with-auth-retry.ts +3 -3
  173. package/runtime/subsystems/index.ts +26 -11
  174. package/runtime/subsystems/{sync → integration}/build-change-source.ts +3 -3
  175. package/runtime/subsystems/{sync → integration}/deep-equal.differ.ts +7 -7
  176. package/runtime/subsystems/{sync → integration}/detection-config.schema.ts +3 -3
  177. package/runtime/subsystems/integration/entity-change-source-registry.memory.ts +40 -0
  178. package/runtime/subsystems/integration/entity-change-source-registry.protocol.ts +59 -0
  179. package/runtime/subsystems/{sync/execute-sync.use-case.ts → integration/execute-integration.use-case.ts} +40 -40
  180. package/runtime/subsystems/{sync → integration}/index.ts +56 -47
  181. package/runtime/subsystems/{sync/sync-audit.schema.ts → integration/integration-audit.schema.ts} +61 -61
  182. package/runtime/subsystems/{sync/sync-change-source.protocol.ts → integration/integration-change-source.protocol.ts} +9 -9
  183. package/runtime/subsystems/{sync/sync-cursor-store.drizzle-backend.ts → integration/integration-cursor-store.drizzle-backend.ts} +30 -30
  184. package/runtime/subsystems/{sync/sync-cursor-store.memory-backend.ts → integration/integration-cursor-store.memory-backend.ts} +9 -9
  185. package/runtime/subsystems/{sync/sync-cursor-store.protocol.ts → integration/integration-cursor-store.protocol.ts} +13 -13
  186. package/runtime/subsystems/{sync/sync-errors.ts → integration/integration-errors.ts} +3 -3
  187. package/runtime/subsystems/{sync/sync-field-diff.protocol.ts → integration/integration-field-diff.protocol.ts} +2 -2
  188. package/runtime/subsystems/{sync/sync-loopback.protocol.ts → integration/integration-loopback.protocol.ts} +2 -2
  189. package/runtime/subsystems/{sync/sync-middleware.protocol.ts → integration/integration-middleware.protocol.ts} +6 -6
  190. package/runtime/subsystems/{sync/sync-run-recorder.drizzle-backend.ts → integration/integration-run-recorder.drizzle-backend.ts} +39 -39
  191. package/runtime/subsystems/{sync/sync-run-recorder.memory-backend.ts → integration/integration-run-recorder.memory-backend.ts} +23 -23
  192. package/runtime/subsystems/{sync/sync-run-recorder.protocol.ts → integration/integration-run-recorder.protocol.ts} +25 -25
  193. package/runtime/subsystems/{sync/sync-sink.protocol.ts → integration/integration-sink.protocol.ts} +4 -4
  194. package/runtime/subsystems/{sync/sync.module.ts → integration/integration.module.ts} +48 -48
  195. package/runtime/subsystems/integration/integration.tokens.ts +63 -0
  196. package/runtime/subsystems/{sync → integration}/loopback.middleware.ts +5 -5
  197. package/runtime/subsystems/{sync → integration}/poll-change-source.ts +7 -7
  198. package/runtime/subsystems/{sync → integration}/webhook-change-source.ts +7 -7
  199. package/runtime/subsystems/observability/index.ts +1 -1
  200. package/runtime/subsystems/observability/observability.module.ts +2 -2
  201. package/runtime/subsystems/observability/observability.protocol.ts +11 -11
  202. package/runtime/subsystems/observability/observability.service.ts +13 -13
  203. package/runtime/subsystems/observability/observability.tokens.ts +1 -1
  204. package/src/patterns/library/index.ts +4 -4
  205. package/src/patterns/library/{synced.pattern.ts → integrated.pattern.ts} +12 -12
  206. package/src/patterns/library/junction.pattern.ts +1 -1
  207. package/src/patterns/pattern-definition.ts +3 -3
  208. package/templates/entity/new/backend/modules/core/{sync-source.ejs.t → integration-source.ejs.t} +6 -6
  209. package/templates/entity/new/clean-lite-ps/entity.ejs.t +12 -3
  210. package/templates/entity/new/clean-lite-ps/module.ejs.t +1 -1
  211. package/templates/entity/new/clean-lite-ps/prompt-extension.js +243 -60
  212. package/templates/entity/new/clean-lite-ps/repository.ejs.t +27 -27
  213. package/templates/entity/new/frontend/collections/collection.ejs.t +26 -1
  214. package/templates/entity/new/frontend/collections/collections-base.ejs.t +11 -0
  215. package/templates/entity/new/frontend/entity/combined.ejs.t +31 -1
  216. package/templates/entity/new/prompt.js +27 -15
  217. package/templates/junction/new/entity.ejs.t +1 -1
  218. package/templates/junction/new/prompt.js +24 -24
  219. package/templates/junction/new/repository.ejs.t +19 -19
  220. package/templates/subsystem/auth/auth-oauth-state.schema.ejs.t +2 -2
  221. package/templates/subsystem/auth-config/prompt.js +1 -1
  222. package/templates/subsystem/auth-integrations/app-module-hook.ejs.t +5 -5
  223. package/templates/subsystem/bridge/prompt.js +1 -1
  224. package/templates/subsystem/integration/integration-audit.schema.ejs.t +192 -0
  225. package/templates/subsystem/{sync → integration}/prompt.js +12 -12
  226. package/templates/subsystem/{sync-config/codegen-config-sync-block.ejs.t → integration-config/codegen-config-integration-block.ejs.t} +7 -7
  227. package/templates/subsystem/integration-config/prompt.js +22 -0
  228. package/templates/subsystem/jobs/worker.ejs.t +2 -2
  229. package/templates/subsystem/observability/main-hook.ejs.t +1 -1
  230. package/templates/subsystem/observability/prompt.js +1 -1
  231. package/templates/subsystem/openapi-config/prompt.js +1 -1
  232. package/dist/runtime/base-classes/junction-sync-repository.js.map +0 -1
  233. package/dist/runtime/base-classes/sync-upsert-config.js +0 -1
  234. package/dist/runtime/base-classes/synced-entity-repository.js.map +0 -1
  235. package/dist/runtime/base-classes/synced-entity-service.js.map +0 -1
  236. package/dist/runtime/subsystems/auth/protocols/integration-store.js +0 -1
  237. package/dist/runtime/subsystems/auth/runtime/integration-broken.error.js +0 -19
  238. package/dist/runtime/subsystems/auth/runtime/integration-broken.error.js.map +0 -1
  239. package/dist/runtime/subsystems/sync/build-change-source.js.map +0 -1
  240. package/dist/runtime/subsystems/sync/deep-equal.differ.js.map +0 -1
  241. package/dist/runtime/subsystems/sync/detection-config.schema.js.map +0 -1
  242. package/dist/runtime/subsystems/sync/execute-sync.use-case.js.map +0 -1
  243. package/dist/runtime/subsystems/sync/index.d.ts +0 -28
  244. package/dist/runtime/subsystems/sync/index.js.map +0 -1
  245. package/dist/runtime/subsystems/sync/loopback.middleware.js.map +0 -1
  246. package/dist/runtime/subsystems/sync/poll-change-source.js.map +0 -1
  247. package/dist/runtime/subsystems/sync/sync-audit.schema.js.map +0 -1
  248. package/dist/runtime/subsystems/sync/sync-change-source.protocol.js +0 -1
  249. package/dist/runtime/subsystems/sync/sync-cursor-store.drizzle-backend.js.map +0 -1
  250. package/dist/runtime/subsystems/sync/sync-cursor-store.memory-backend.js.map +0 -1
  251. package/dist/runtime/subsystems/sync/sync-cursor-store.protocol.js +0 -1
  252. package/dist/runtime/subsystems/sync/sync-errors.js.map +0 -1
  253. package/dist/runtime/subsystems/sync/sync-field-diff.protocol.js.map +0 -1
  254. package/dist/runtime/subsystems/sync/sync-loopback.protocol.js +0 -1
  255. package/dist/runtime/subsystems/sync/sync-middleware.protocol.js +0 -1
  256. package/dist/runtime/subsystems/sync/sync-run-recorder.drizzle-backend.js.map +0 -1
  257. package/dist/runtime/subsystems/sync/sync-run-recorder.memory-backend.js.map +0 -1
  258. package/dist/runtime/subsystems/sync/sync-run-recorder.protocol.js +0 -1
  259. package/dist/runtime/subsystems/sync/sync-sink.protocol.js +0 -1
  260. package/dist/runtime/subsystems/sync/sync.module.js.map +0 -1
  261. package/dist/runtime/subsystems/sync/sync.tokens.d.ts +0 -47
  262. package/dist/runtime/subsystems/sync/sync.tokens.js +0 -18
  263. package/dist/runtime/subsystems/sync/sync.tokens.js.map +0 -1
  264. package/dist/runtime/subsystems/sync/webhook-change-source.js.map +0 -1
  265. package/examples/auth-integrations/runtime/integrations/integrations-auth.module.ts +0 -81
  266. package/examples/auth-integrations/runtime/integrations/oauth/use-cases/list-user-integrations.use-case.ts +0 -21
  267. package/examples/auth-integrations/runtime/integrations/oauth/use-cases/mark-integration-requires-reauth.use-case.ts +0 -21
  268. package/runtime/subsystems/sync/sync.tokens.ts +0 -49
  269. package/templates/entity/new/backend/modules/core/sync-source.providers.ejs.t +0 -18
  270. package/templates/subsystem/sync/sync-audit.schema.ejs.t +0 -192
  271. package/templates/subsystem/sync-config/prompt.js +0 -22
  272. /package/dist/runtime/base-classes/{sync-upsert-config.js.map → integration-upsert-config.js.map} +0 -0
  273. /package/dist/runtime/subsystems/auth/protocols/{integration-store.js.map → connection-store.js.map} +0 -0
  274. /package/dist/runtime/subsystems/{sync/sync-change-source.protocol.js.map → integration/integration-change-source.protocol.js.map} +0 -0
  275. /package/dist/runtime/subsystems/{sync/sync-cursor-store.protocol.js.map → integration/integration-cursor-store.protocol.js.map} +0 -0
  276. /package/dist/runtime/subsystems/{sync/sync-loopback.protocol.js.map → integration/integration-loopback.protocol.js.map} +0 -0
  277. /package/dist/runtime/subsystems/{sync/sync-middleware.protocol.js.map → integration/integration-middleware.protocol.js.map} +0 -0
  278. /package/dist/runtime/subsystems/{sync/sync-run-recorder.protocol.js.map → integration/integration-run-recorder.protocol.js.map} +0 -0
  279. /package/dist/runtime/subsystems/{sync/sync-sink.protocol.js.map → integration/integration-sink.protocol.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- // runtime/base-classes/synced-entity-repository.ts
1
+ // runtime/base-classes/integrated-entity-repository.ts
2
2
  import { and as and2, eq as eq2, inArray as inArray2 } from "drizzle-orm";
3
3
 
4
4
  // runtime/base-classes/base-repository.ts
@@ -279,8 +279,8 @@ var BaseRepository = class {
279
279
  }
280
280
  };
281
281
 
282
- // runtime/base-classes/synced-entity-repository.ts
283
- var SyncedEntityRepository = class extends BaseRepository {
282
+ // runtime/base-classes/integrated-entity-repository.ts
283
+ var IntegratedEntityRepository = class extends BaseRepository {
284
284
  /**
285
285
  * Find a single entity by its external CRM identifier.
286
286
  */
@@ -304,20 +304,20 @@ var SyncedEntityRepository = class extends BaseRepository {
304
304
  return rows;
305
305
  }
306
306
  // ==========================================================================
307
- // Inbound sync (#374) — canonical→Drizzle write + provider-scoped FK
307
+ // Inbound integration (#374) — canonical→Drizzle write + provider-scoped FK
308
308
  // resolution + EAV dual-write seam, all inside a SINGLE transaction.
309
- // Driven entirely by `this.syncConfig`; the per-entity shape lives there.
309
+ // Driven entirely by `this.integrationConfig`; the per-entity shape lives there.
310
310
  // ==========================================================================
311
311
  /**
312
312
  * Upsert ONE entity by its `(provider, externalId)` identity, in a single
313
313
  * transaction:
314
- * 1. resolve each `syncConfig.fkResolvers` FK (provider-scoped). Strict
314
+ * 1. resolve each `integrationConfig.fkResolvers` FK (provider-scoped). Strict
315
315
  * resolvers throw on unresolved; non-strict leave the column null.
316
316
  * 2. insert-or-update the canonical columns via `onConflictDoUpdate` on the
317
317
  * `conflictTarget`. Resolved FKs are only written into `set` when
318
318
  * non-null this run (no-clobber).
319
319
  * 3. EAV dual-write of `write.fields` via `writeCustomFields` when
320
- * `syncConfig.eav` and the bag is non-empty (same tx).
320
+ * `integrationConfig.eav` and the bag is non-empty (same tx).
321
321
  *
322
322
  * Idempotent: a second call with the same identity updates in place. Returns
323
323
  * the canonical projection (so the orchestrator records `local_id`).
@@ -326,8 +326,8 @@ var SyncedEntityRepository = class extends BaseRepository {
326
326
  * @param provider adapter/provider label persisted + used to scope lookups
327
327
  * @param tx optional outer transaction; when omitted we open our own
328
328
  */
329
- async syncUpsertOne(write, provider, tx) {
330
- const cfg = this.syncConfig;
329
+ async integrationUpsertOne(write, provider, tx) {
330
+ const cfg = this.integrationConfig;
331
331
  const w = write;
332
332
  const run = async (db) => {
333
333
  const resolvedFks = {};
@@ -385,14 +385,14 @@ var SyncedEntityRepository = class extends BaseRepository {
385
385
  return row ? this.toProjection(row) : null;
386
386
  }
387
387
  /**
388
- * Sync "delete" by external id, provider-scoped. When `softDelete: true`,
388
+ * Integration "delete" by external id, provider-scoped. When `softDelete: true`,
389
389
  * sets `deletedAt`. When `softDelete: false`, tombstone-by-clearing: null out
390
390
  * `external_id`/`provider` so the row no longer matches future inbound
391
391
  * changes while preserving local-id references. Returns `{ id }` or `null`.
392
392
  */
393
393
  async softDeleteByExternalId(externalId, provider, tx) {
394
394
  const db = this.runner(tx);
395
- const set = this.syncConfig.softDelete ? { deletedAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() } : { externalId: null, provider: null, updatedAt: /* @__PURE__ */ new Date() };
395
+ const set = this.integrationConfig.softDelete ? { deletedAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() } : { externalId: null, provider: null, updatedAt: /* @__PURE__ */ new Date() };
396
396
  const rows = await db.update(this.table).set(set).where(
397
397
  and2(
398
398
  eq2(this.table["provider"], provider),
@@ -402,19 +402,19 @@ var SyncedEntityRepository = class extends BaseRepository {
402
402
  return rows[0] ? { id: rows[0].id } : null;
403
403
  }
404
404
  /**
405
- * Batch sync upsert — concretizes the former abstract stub. Delegates to
406
- * `syncUpsertOne` per input inside one transaction. Inputs are raw partial
405
+ * Batch integration upsert — concretizes the former abstract stub. Delegates to
406
+ * `integrationUpsertOne` per input inside one transaction. Inputs are raw partial
407
407
  * rows: provider is read from each input's own `provider` column; rows
408
408
  * missing `externalId`/`provider` are skipped.
409
409
  */
410
- async syncUpsert(inputs) {
410
+ async integrationUpsert(inputs) {
411
411
  if (inputs.length === 0) return [];
412
412
  return this.db.transaction(async (tx) => {
413
413
  const out = [];
414
414
  for (const input of inputs) {
415
415
  const rec = input;
416
416
  if (!rec["externalId"] || !rec["provider"]) continue;
417
- const proj = await this.syncUpsertOne(
417
+ const proj = await this.integrationUpsertOne(
418
418
  input,
419
419
  rec["provider"],
420
420
  tx
@@ -428,13 +428,13 @@ var SyncedEntityRepository = class extends BaseRepository {
428
428
  }
429
429
  /**
430
430
  * Project a raw row to the canonical differ shape — a generic pick over
431
- * `syncConfig.projectionColumns`. Override only for synthesized projections
431
+ * `integrationConfig.projectionColumns`. Override only for synthesized projections
432
432
  * (e.g. junctions); entities use this verbatim.
433
433
  */
434
434
  toProjection(row) {
435
435
  const r = row;
436
436
  const out = {};
437
- for (const col of this.syncConfig.projectionColumns) out[col] = r[col];
437
+ for (const col of this.integrationConfig.projectionColumns) out[col] = r[col];
438
438
  return out;
439
439
  }
440
440
  /**
@@ -456,7 +456,7 @@ var SyncedEntityRepository = class extends BaseRepository {
456
456
  if (!parentExternalId) {
457
457
  if (fk.strict) {
458
458
  throw new Error(
459
- `${this.constructor.name}.syncUpsertOne: missing required parent external id for '${fk.column}' (writeKey '${fk.writeKey}')`
459
+ `${this.constructor.name}.integrationUpsertOne: missing required parent external id for '${fk.column}' (writeKey '${fk.writeKey}')`
460
460
  );
461
461
  }
462
462
  return null;
@@ -471,7 +471,7 @@ var SyncedEntityRepository = class extends BaseRepository {
471
471
  const id = rows[0]?.id ?? null;
472
472
  if (id === null && fk.strict) {
473
473
  throw new Error(
474
- `${this.constructor.name}.syncUpsertOne: unresolved parent '${parentExternalId}' (provider '${provider}') for '${fk.column}' \u2014 parent not synced yet`
474
+ `${this.constructor.name}.integrationUpsertOne: unresolved parent '${parentExternalId}' (provider '${provider}') for '${fk.column}' \u2014 parent not integrated yet`
475
475
  );
476
476
  }
477
477
  return id;
@@ -485,6 +485,6 @@ var SyncedEntityRepository = class extends BaseRepository {
485
485
  }
486
486
  };
487
487
  export {
488
- SyncedEntityRepository
488
+ IntegratedEntityRepository
489
489
  };
490
- //# sourceMappingURL=synced-entity-repository.js.map
490
+ //# sourceMappingURL=integrated-entity-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../runtime/base-classes/integrated-entity-repository.ts","../../../runtime/base-classes/base-repository.ts","../../../runtime/base-classes/tenant-context.ts"],"sourcesContent":["/**\n * IntegratedEntityRepository<TEntity, TIntegrationWrite, TIntegrationProjection>\n *\n * Family-specific base for Integrated entities (contacts, accounts, opportunities).\n * Adds external ID lookups, user-scoped queries, and the generic inbound-integration\n * write surface (canonical→Drizzle upsert + provider-scoped FK resolution +\n * EAV dual-write seam), driven by the concrete repo's `integrationConfig`.\n *\n * The type params default so pre-existing single-param subclasses keep\n * compiling; `pattern: Integrated` repos declare all three plus `integrationConfig`.\n */\nimport { and, eq, inArray } from 'drizzle-orm';\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nimport type { PgTableWithColumns } from 'drizzle-orm/pg-core';\nimport type { DrizzleTx } from '../types/drizzle';\nimport { BaseRepository } from './base-repository';\nimport type { IntegrationUpsertConfig, IntegrationFkResolver } from './integration-upsert-config';\n\nexport abstract class IntegratedEntityRepository<\n TEntity,\n TIntegrationWrite = Partial<TEntity>,\n TIntegrationProjection = TEntity,\n> extends BaseRepository<TEntity> {\n /**\n * Declarative integration write surface. Concrete (`pattern: Integrated`) repositories\n * declare this — the template emits it from the entity's fields + FKs.\n */\n protected abstract readonly integrationConfig: IntegrationUpsertConfig;\n\n /**\n * Find a single entity by its external CRM identifier.\n */\n async findByExternalId(externalId: string): Promise<TEntity | null> {\n const rows = await this.baseQuery()\n .where(eq(this.table['externalId'], externalId))\n .limit(1);\n return (rows[0] as TEntity) ?? null;\n }\n\n /**\n * Find multiple entities by external CRM identifiers.\n */\n async findManyByExternalIds(externalIds: string[]): Promise<TEntity[]> {\n if (externalIds.length === 0) return [];\n const rows = await this.baseQuery()\n .where(inArray(this.table['externalId'], externalIds));\n return rows as TEntity[];\n }\n\n /**\n * Find all entities owned by a specific user.\n */\n async findAllByUserId(userId: string): Promise<TEntity[]> {\n const rows = await this.baseQuery()\n .where(eq(this.table['userId'], userId));\n return rows as TEntity[];\n }\n\n // ==========================================================================\n // Inbound integration (#374) — canonical→Drizzle write + provider-scoped FK\n // resolution + EAV dual-write seam, all inside a SINGLE transaction.\n // Driven entirely by `this.integrationConfig`; the per-entity shape lives there.\n // ==========================================================================\n\n /**\n * Upsert ONE entity by its `(provider, externalId)` identity, in a single\n * transaction:\n * 1. resolve each `integrationConfig.fkResolvers` FK (provider-scoped). Strict\n * resolvers throw on unresolved; non-strict leave the column null.\n * 2. insert-or-update the canonical columns via `onConflictDoUpdate` on the\n * `conflictTarget`. Resolved FKs are only written into `set` when\n * non-null this run (no-clobber).\n * 3. EAV dual-write of `write.fields` via `writeCustomFields` when\n * `integrationConfig.eav` and the bag is non-empty (same tx).\n *\n * Idempotent: a second call with the same identity updates in place. Returns\n * the canonical projection (so the orchestrator records `local_id`).\n *\n * @param write canonical fields + parent external ids + custom-field bag\n * @param provider adapter/provider label persisted + used to scope lookups\n * @param tx optional outer transaction; when omitted we open our own\n */\n async integrationUpsertOne(\n write: TIntegrationWrite,\n provider: string,\n tx?: DrizzleTx,\n ): Promise<TIntegrationProjection> {\n const cfg = this.integrationConfig;\n const w = write as Record<string, unknown>;\n\n const run = async (db: DrizzleTx): Promise<TIntegrationProjection> => {\n // 1. FK resolution (provider-scoped). Strict → throw; else opportunistic null.\n const resolvedFks: Record<string, string | null> = {};\n for (const fk of cfg.fkResolvers) {\n resolvedFks[fk.column] = await this.resolveFk(db, fk, w[fk.writeKey], provider);\n }\n\n // 2. Canonical → Drizzle insert-or-update by the conflict target.\n const now = new Date();\n const copyThrough: Record<string, unknown> = {};\n for (const col of cfg.writeColumns) copyThrough[col] = w[col];\n\n const values: Record<string, unknown> = {\n externalId: w['externalId'],\n provider,\n ...copyThrough,\n ...resolvedFks,\n ...(this.behaviors.timestamps ? { updatedAt: now } : {}),\n };\n\n // `set` excludes the identity (externalId/provider). Resolved FKs are\n // only written when non-null this run — never clobber a previously\n // resolved parent with null on a later run that dropped the ref.\n const set: Record<string, unknown> = {\n ...copyThrough,\n ...(this.behaviors.timestamps ? { updatedAt: now } : {}),\n };\n for (const fk of cfg.fkResolvers) {\n if (resolvedFks[fk.column] !== null) set[fk.column] = resolvedFks[fk.column];\n }\n\n const rows = await db\n .insert(this.table)\n .values(values as never)\n .onConflictDoUpdate({\n target: cfg.conflictTarget.map((c: string) => this.table[c]),\n set: set as never,\n })\n .returning();\n\n const saved = rows[0] as Record<string, unknown>;\n\n // 3. EAV dual-write seam — same tx. No-op unless the entity opts in.\n const fields = w['fields'] as Record<string, unknown> | undefined;\n if (cfg.eav && fields && Object.keys(fields).length > 0) {\n await this.writeCustomFields(\n db,\n saved['id'] as string,\n w['userId'] as string,\n fields,\n );\n }\n\n return this.toProjection(saved as TEntity);\n };\n\n return tx ? run(tx) : this.db.transaction((t) => run(t));\n }\n\n /**\n * Canonical-projected lookup by external id (differ-ready). Returns `null`\n * when no local row exists. Provider-scoped so a HubSpot id can't match a\n * Salesforce row.\n */\n async findByExternalIdProjected(\n externalId: string,\n provider: string,\n ): Promise<TIntegrationProjection | null> {\n const rows = await this.db\n .select()\n .from(this.table)\n .where(\n and(\n eq(this.table['provider'], provider),\n eq(this.table['externalId'], externalId),\n ),\n )\n .limit(1);\n const row = rows[0] as TEntity | undefined;\n return row ? this.toProjection(row) : null;\n }\n\n /**\n * Integration \"delete\" by external id, provider-scoped. When `softDelete: true`,\n * sets `deletedAt`. When `softDelete: false`, tombstone-by-clearing: null out\n * `external_id`/`provider` so the row no longer matches future inbound\n * changes while preserving local-id references. Returns `{ id }` or `null`.\n */\n async softDeleteByExternalId(\n externalId: string,\n provider: string,\n tx?: DrizzleTx,\n ): Promise<{ id: string } | null> {\n const db = this.runner(tx);\n const set = this.integrationConfig.softDelete\n ? { deletedAt: new Date(), updatedAt: new Date() }\n : { externalId: null, provider: null, updatedAt: new Date() };\n const rows = await db\n .update(this.table)\n .set(set as never)\n .where(\n and(\n eq(this.table['provider'], provider),\n eq(this.table['externalId'], externalId),\n ),\n )\n .returning({ id: this.table['id'] });\n return rows[0] ? { id: rows[0].id as string } : null;\n }\n\n /**\n * Batch integration upsert — concretizes the former abstract stub. Delegates to\n * `integrationUpsertOne` per input inside one transaction. Inputs are raw partial\n * rows: provider is read from each input's own `provider` column; rows\n * missing `externalId`/`provider` are skipped.\n */\n async integrationUpsert(inputs: Array<Partial<TEntity>>): Promise<TEntity[]> {\n if (inputs.length === 0) return [];\n return this.db.transaction(async (tx) => {\n const out: TEntity[] = [];\n for (const input of inputs) {\n const rec = input as Record<string, unknown>;\n if (!rec['externalId'] || !rec['provider']) continue;\n const proj = await this.integrationUpsertOne(\n input as unknown as TIntegrationWrite,\n rec['provider'] as string,\n tx,\n );\n const id = (proj as Record<string, unknown>)['id'] as string;\n const row = await tx\n .select()\n .from(this.table)\n .where(eq(this.table['id'], id))\n .limit(1);\n out.push(row[0] as TEntity);\n }\n return out;\n });\n }\n\n /**\n * Project a raw row to the canonical differ shape — a generic pick over\n * `integrationConfig.projectionColumns`. Override only for synthesized projections\n * (e.g. junctions); entities use this verbatim.\n */\n protected toProjection(row: TEntity): TIntegrationProjection {\n const r = row as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const col of this.integrationConfig.projectionColumns) out[col] = r[col];\n return out as TIntegrationProjection;\n }\n\n /**\n * EAV dual-write seam (#374, live path lands in #124). No-op by default;\n * `eav: true` entities emit a concrete override that injects\n * `FieldValueService` and delegates to `upsertFieldsTransactional` so the\n * dual-write joins the same tx (`db`). Kept as an explicit hook so the base\n * stays portable (the FieldValueService dependency is eav-only).\n */\n protected async writeCustomFields(\n _db: DrizzleTx,\n _entityId: string,\n _userId: string,\n _fields: Record<string, unknown>,\n ): Promise<void> {\n // Intentionally empty until the entity opts into EAV.\n }\n\n /**\n * Resolve one FK from a parent external id (provider-scoped). `self` resolves\n * against `this.table`. Strict resolvers throw when unresolved; non-strict\n * return null. A null/absent write value short-circuits to null.\n */\n private async resolveFk(\n db: DrizzleTx,\n fk: IntegrationFkResolver,\n rawExternalId: unknown,\n provider: string,\n ): Promise<string | null> {\n const parentExternalId = rawExternalId as string | null | undefined;\n if (!parentExternalId) {\n if (fk.strict) {\n throw new Error(\n `${this.constructor.name}.integrationUpsertOne: missing required parent ` +\n `external id for '${fk.column}' (writeKey '${fk.writeKey}')`,\n );\n }\n return null;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const refTable: PgTableWithColumns<any> =\n fk.refTable === 'self' ? this.table : fk.refTable;\n const rows = await db\n .select({ id: refTable['id'] })\n .from(refTable)\n .where(\n and(\n eq(refTable['provider'], provider),\n eq(refTable['externalId'], parentExternalId),\n ),\n )\n .limit(1);\n const id = (rows[0]?.id as string | undefined) ?? null;\n if (id === null && fk.strict) {\n throw new Error(\n `${this.constructor.name}.integrationUpsertOne: unresolved parent ` +\n `'${parentExternalId}' (provider '${provider}') for '${fk.column}' — ` +\n `parent not integrated yet`,\n );\n }\n return id;\n }\n\n /**\n * Find entities visible to a user (ownership + sharing rules).\n * Concrete repositories must implement with visibility logic.\n */\n async findVisibleByUserId(_userId: string): Promise<TEntity[]> {\n throw new Error('findVisibleByUserId not implemented — override in concrete repository');\n }\n}\n","/**\n * BaseRepository<TEntity>\n *\n * Abstract base class providing standard CRUD operations via Drizzle ORM.\n * Every generated repository extends this class.\n *\n * Family-specific bases (CrmEntityRepository, etc.) extend this in v0.1\n * without any changes to BaseRepository.\n *\n * NOT @Injectable — concrete repositories are @Injectable and inject DRIZZLE.\n */\nimport { and, eq, inArray, isNull, sql } from 'drizzle-orm';\nimport type { PgTableWithColumns, PgColumn } from 'drizzle-orm/pg-core';\nimport type { SQL } from 'drizzle-orm';\nimport type { DrizzleClient, DrizzleTx } from '../types/drizzle';\nimport {\n requireRequester,\n tryGetRequester,\n type RequesterScope,\n} from './tenant-context';\n\n// ============================================================================\n// Interfaces\n// ============================================================================\n\n/**\n * Behavior flags for the repository. Controls automatic timestamp injection\n * and soft-delete filtering.\n */\nexport interface BehaviorConfig {\n timestamps: boolean;\n softDelete: boolean;\n userTracking: boolean;\n}\n\n/**\n * Options for the list() method.\n */\nexport interface ListOptions {\n where?: SQL;\n limit?: number;\n offset?: number;\n orderBy?: PgColumn | SQL;\n}\n\n// ============================================================================\n// BaseRepository\n// ============================================================================\n\nexport abstract class BaseRepository<TEntity> {\n /**\n * The Drizzle table schema for this entity.\n * Concrete repositories declare this as a class property.\n */\n protected abstract readonly table: PgTableWithColumns<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n /**\n * Behavior flags controlling automatic behavior injection.\n * Override in concrete repositories to enable behaviors.\n */\n protected readonly behaviors: BehaviorConfig = {\n timestamps: false,\n softDelete: false,\n userTracking: false,\n };\n\n /**\n * Ambient tenant-scope enforcement for `userTracking` repos (see\n * `scopePredicate`). Only has effect when `behaviors.userTracking === true`.\n *\n * - `'lenient'` (default): when no ambient requester context is active,\n * reads/writes are NOT scoped — preserves pre-scoping behavior, so adopting\n * ambient scoping is additive. Scoping kicks in automatically once a\n * boundary installs `withRequester(...)`.\n * - `'strict'`: a missing ambient context throws (`requireRequester`),\n * making a forgotten boundary fail loud instead of silently returning\n * cross-tenant rows. Recommended for new multi-tenant consumers — override\n * in a concrete repo or a family base class.\n */\n protected readonly scopeEnforcement: 'lenient' | 'strict' = 'lenient';\n\n protected readonly db: DrizzleClient;\n\n constructor(db: DrizzleClient) {\n this.db = db;\n }\n\n /**\n * Pick the runner for a write: the caller-supplied transaction handle\n * if present, otherwise the repository's own client. Keeps the `tx`\n * parameter purely additive — callers without a transaction call as\n * before. Used by the write methods below + consumer overrides (e.g.\n * the generated `upsertCurrentValues` on EAV value tables).\n */\n protected runner(tx?: DrizzleTx): DrizzleClient {\n return tx ?? this.db;\n }\n\n // ============================================================================\n // Read Operations\n // ============================================================================\n\n /**\n * Find a single entity by its primary key.\n * Returns null if not found (or soft-deleted when softDelete=true).\n */\n async findById(id: string): Promise<TEntity | null> {\n const rows = await this.baseQuery(eq(this.table['id'], id)).limit(1);\n return (rows[0] as TEntity) ?? null;\n }\n\n /**\n * Find multiple entities by their primary keys.\n * Returns empty array immediately for empty input (avoids DB errors).\n */\n async findByIds(ids: string[]): Promise<TEntity[]> {\n if (ids.length === 0) return [];\n const rows = await this.baseQuery(inArray(this.table['id'], ids));\n return rows as TEntity[];\n }\n\n /**\n * List entities with optional filtering, pagination, and ordering.\n */\n async list(options?: ListOptions): Promise<TEntity[]> {\n let query = this.baseQuery(options?.where);\n\n if (options?.orderBy) {\n query = query.orderBy(options.orderBy as SQL) as typeof query;\n }\n if (options?.limit !== undefined) {\n query = query.limit(options.limit) as typeof query;\n }\n if (options?.offset !== undefined) {\n query = query.offset(options.offset) as typeof query;\n }\n\n const rows = await query;\n return rows as TEntity[];\n }\n\n /**\n * Count entities matching an optional WHERE clause.\n * Soft-deleted rows are always excluded when softDelete=true.\n */\n async count(where?: SQL): Promise<number> {\n let query = this.db\n .select({ count: sql<number>`cast(count(*) as integer)` })\n .from(this.table);\n\n const conditions: SQL[] = [];\n if (this.behaviors.softDelete) {\n conditions.push(isNull(this.table['deletedAt']));\n }\n const scope = this.scopePredicate();\n if (scope) {\n conditions.push(scope);\n }\n if (where) {\n conditions.push(where);\n }\n\n if (conditions.length === 1) {\n query = query.where(conditions[0]) as typeof query;\n } else if (conditions.length > 1) {\n query = query.where(and(...conditions)) as typeof query;\n }\n\n const rows = await query;\n return rows[0]?.count ?? 0;\n }\n\n /**\n * Check whether an entity with the given id exists.\n */\n async exists(id: string): Promise<boolean> {\n const result = await this.findById(id);\n return result !== null;\n }\n\n // ============================================================================\n // Write Operations\n // ============================================================================\n\n /**\n * Insert a new entity. Timestamps are auto-injected when timestamps=true.\n */\n async create(input: Partial<TEntity>, tx?: DrizzleTx): Promise<TEntity> {\n const data = this.withTimestamps(input as Record<string, unknown>, 'create');\n const rows = await this.runner(tx)\n .insert(this.table)\n .values(data as any) // eslint-disable-line @typescript-eslint/no-explicit-any\n .returning();\n return rows[0] as TEntity;\n }\n\n /**\n * Update an existing entity by id. updatedAt is auto-injected when timestamps=true.\n * Returns the updated entity.\n */\n async update(id: string, input: Partial<TEntity>, tx?: DrizzleTx): Promise<TEntity> {\n const data = this.withTimestamps(input as Record<string, unknown>, 'update');\n const rows = await this.runner(tx)\n .update(this.table)\n .set(data as any) // eslint-disable-line @typescript-eslint/no-explicit-any\n .where(this.scopeAnd(eq(this.table['id'], id)))\n .returning();\n return rows[0] as TEntity;\n }\n\n /**\n * Delete an entity by id.\n * - softDelete=true: sets deletedAt to current timestamp\n * - softDelete=false: hard-deletes the row\n */\n async delete(id: string, tx?: DrizzleTx): Promise<void> {\n const runner = this.runner(tx);\n if (this.behaviors.softDelete) {\n await runner\n .update(this.table)\n .set({ deletedAt: new Date() } as any) // eslint-disable-line @typescript-eslint/no-explicit-any\n .where(this.scopeAnd(eq(this.table['id'], id)));\n } else {\n await runner\n .delete(this.table)\n .where(this.scopeAnd(eq(this.table['id'], id)));\n }\n }\n\n /**\n * Insert or update multiple entities.\n * Default naive implementation — family repositories override with\n * proper conflict-target upsert (e.g., CrmEntityRepository).\n */\n async upsertMany(inputs: Array<Partial<TEntity>>, tx?: DrizzleTx): Promise<TEntity[]> {\n return Promise.all(inputs.map((input) => this.create(input, tx)));\n }\n\n // ============================================================================\n // Protected Helpers\n // ============================================================================\n\n /**\n * Base SELECT query that automatically applies the ambient guards —\n * soft-delete exclusion (when `softDelete`) and tenant scope (when\n * `userTracking` + an active requester context) — combined with an optional\n * caller `extra` predicate into a SINGLE `WHERE`.\n *\n * Pass the leaf predicate as `extra` rather than chaining a second\n * `.where(...)`: Drizzle's `.where()` OVERRIDES (does not AND) a prior\n * `.where()` on a `$dynamic()` query, so a chained call would silently drop\n * the soft-delete and scope guards. `baseQuery(extra)` is the safe form.\n */\n protected baseQuery(extra?: SQL) {\n const query = this.db.select().from(this.table).$dynamic();\n const where = this.scopeAnd(extra, { softDelete: this.behaviors.softDelete });\n return where ? query.where(where) : query;\n }\n\n /**\n * Build the ambient tenant-scope predicate for this repo's table.\n *\n * Returns `undefined` (no scoping) when:\n * - `behaviors.userTracking` is false (repo is not user-owned), or\n * - no ambient requester context is active AND `scopeEnforcement` is\n * `'lenient'` (the default — preserves pre-scoping behavior).\n *\n * When a requester context is active, scopes by `user_id` per the ambient\n * scope: `'user'` → `user_id = ctx.userId`; `'org'` → `user_id IN\n * ctx.orgUserIds` (empty list matches nothing — fail-closed); `'superuser'`\n * → no filter. See `tenant-context.ts` for the boundary-install contract.\n */\n protected scopePredicate(): SQL | undefined {\n if (!this.behaviors.userTracking) return undefined;\n const ctx =\n this.scopeEnforcement === 'strict'\n ? requireRequester()\n : tryGetRequester();\n if (!ctx) return undefined;\n const scope: RequesterScope = ctx.scope ?? 'user';\n switch (scope) {\n case 'superuser':\n return undefined;\n case 'org':\n return ctx.orgUserIds && ctx.orgUserIds.length > 0\n ? inArray(this.table['userId'], ctx.orgUserIds as string[])\n : sql`false`;\n case 'user':\n default:\n return eq(this.table['userId'], ctx.userId);\n }\n }\n\n /**\n * Combine the ambient scope predicate (and, optionally, the soft-delete\n * guard) with a caller `extra` predicate into one `SQL`. Returns `undefined`\n * when nothing applies. Used by read + by-id write paths so a single\n * `.where(...)` carries every guard.\n */\n protected scopeAnd(\n extra?: SQL,\n opts?: { softDelete?: boolean },\n ): SQL | undefined {\n const conditions: SQL[] = [];\n if (opts?.softDelete) conditions.push(isNull(this.table['deletedAt']));\n const scope = this.scopePredicate();\n if (scope) conditions.push(scope);\n if (extra) conditions.push(extra);\n if (conditions.length === 0) return undefined;\n if (conditions.length === 1) return conditions[0];\n return and(...conditions);\n }\n\n /**\n * Merge timestamp fields into an input object.\n * - mode='create': adds createdAt and updatedAt\n * - mode='update': adds updatedAt only\n *\n * No-op when timestamps behavior is disabled.\n */\n protected withTimestamps(\n input: Record<string, unknown>,\n mode: 'create' | 'update',\n ): Record<string, unknown> {\n if (!this.behaviors.timestamps) return input;\n const now = new Date();\n if (mode === 'create') {\n return { ...input, createdAt: now, updatedAt: now };\n }\n return { ...input, updatedAt: now };\n }\n\n /**\n * Build a WHERE clause fragment that restricts results to rows whose\n * parent (identified by a belongs_to FK) is not soft-deleted.\n *\n * Use this in custom repository methods when you need \"rows reachable\n * from an active parent\". The default findAll / findById behavior is\n * NOT changed by this helper — opt in explicitly where needed.\n *\n * ADR-021 — Soft-delete cascade: Option A (filter at query time).\n * `on_delete` FK rules do not fire for soft-deletes; use this helper\n * instead of expecting cascade semantics on the DB level.\n *\n * Example:\n * async listActiveMessages(): Promise<Message[]> {\n * return this.list({\n * where: this.activeParentFilter(conversations, this.table['conversationId']),\n * });\n * }\n *\n * @param parentTable The Drizzle table object for the parent entity.\n * @param parentFkColumn The FK column on this (child) table that references parent.id.\n */\n protected activeParentFilter(\n parentTable: PgTableWithColumns<any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n parentFkColumn: PgColumn,\n ): SQL {\n return sql`EXISTS (\n SELECT 1 FROM ${parentTable} p\n WHERE p.id = ${parentFkColumn}\n AND p.deleted_at IS NULL\n )`;\n }\n}\n","/**\n * Ambient requester context — AsyncLocalStorage-backed tenant scope.\n *\n * The alternative to threading `userId`/`organizationId` through every\n * repository/service signature. Set ONCE at each boundary the generated app\n * owns, read implicitly inside `BaseRepository` (see `scopePredicate`).\n *\n * ## Where to set it (boundaries)\n *\n * - HTTP / tRPC handlers — from the authenticated `ctx.user`\n * - OAuth callback controllers — from the authenticated session\n * - Queue/worker `process()` — from the job's owning user after the\n * job's record is loaded\n *\n * Each boundary wraps the rest of the request in `withRequester({ userId,\n * organizationId }, () => ...)`. The context propagates through every `await`\n * to all downstream repo/service calls without being passed explicitly.\n *\n * ## Where to read it\n *\n * - `BaseRepository.scopePredicate()` reads it (via `tryGetRequester` in\n * lenient mode, `requireRequester` in strict mode) and filters every read\n * by the ambient scope when the repo declares `userTracking: true`.\n *\n * ## Why AsyncLocalStorage over an explicit parameter\n *\n * Threading `userId` (and later `organizationId`) through dozens of method\n * signatures is pure parameter pollution. Ambient context also lets a repo\n * make the \"I forgot to scope\" mistake impossible at runtime: in strict mode\n * `requireRequester()` throws when no context is active, surfacing a missing\n * boundary call loudly rather than silently leaking cross-tenant data.\n *\n * ## Not-found semantics\n *\n * When a row exists but belongs to a different requester, scoped reads return\n * `null`/`[]` — identical to \"truly doesn't exist\". No existence oracle;\n * callers throw NotFound uniformly. Standard security practice.\n *\n * ## Testing\n *\n * Tests that exercise scoped repos must wrap the call in `withRequester(...)`.\n * In strict mode an unwrapped call hitting `requireRequester()` throws — by\n * design. In lenient mode (the default) an unwrapped call is simply unscoped.\n */\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\n/**\n * Data-visibility scope. The auth layer decides which scope a request is\n * allowed to claim; the repo trusts whatever the ambient context says.\n *\n * - `'user'`: filter every read by `user_id = ctx.userId`. Default.\n * - `'org'`: filter every read by membership in the requester's org, resolved\n * via `user_id IN (ctx.orgUserIds)` rather than via a per-entity\n * `organization_id` column. Works for every user-owned table and keeps repos\n * single-table — the org member list is pre-resolved at the boundary.\n * - `'superuser'`: no scope filter. Engineering / internal-tools only.\n *\n * AUTHORIZATION (who is allowed to claim each scope) lives in boundary\n * middleware, not in the repo. The repo trusts the ambient context — same\n * trust model as a threaded `userId`.\n */\nexport type RequesterScope = 'user' | 'org' | 'superuser';\n\nexport interface RequesterContext {\n /**\n * The user making the request. Always present — even in `'org'` and\n * `'superuser'` scopes it is the audit-trail \"who actually did this\".\n */\n readonly userId: string;\n /**\n * The organization the requester belongs to. Required when\n * `scope === 'org'`; may be null for `'user'` (users with no org) and for\n * `'superuser'` (cross-org reads).\n */\n readonly organizationId: string | null;\n /**\n * Data-visibility scope. Defaults to `'user'` when omitted.\n */\n readonly scope?: RequesterScope;\n /**\n * For `scope === 'org'`: the list of user IDs in the requester's org,\n * pre-resolved by the boundary middleware that established the `'org'`\n * scope (one `SELECT users.id WHERE organization_id = X` at the trust\n * boundary). Repos use this as a literal `IN (...)` filter — they never\n * JOIN to `users` themselves. Required when `scope === 'org'`.\n */\n readonly orgUserIds?: readonly string[];\n}\n\nconst als = new AsyncLocalStorage<RequesterContext>();\n\n/**\n * Set the ambient requester context for the duration of `fn`. The context\n * propagates through `await` boundaries to all downstream calls. Nesting is\n * fine — an inner `withRequester` overrides the outer for its callback.\n */\nexport function withRequester<T>(\n ctx: RequesterContext,\n fn: () => Promise<T>,\n): Promise<T> {\n return als.run(ctx, fn);\n}\n\n/**\n * Read the ambient requester context. Throws if no context is active — by\n * design. Used by repos in strict scope-enforcement mode; an unwrapped call\n * site is a missing boundary.\n */\nexport function requireRequester(): RequesterContext {\n const ctx = als.getStore();\n if (!ctx) {\n throw new Error(\n 'No requester context active. Wrap the entry point in ' +\n 'withRequester({ userId, organizationId }, fn). See tenant-context.ts.',\n );\n }\n return ctx;\n}\n\n/**\n * Read the ambient requester context without throwing. Returns `undefined`\n * when no context is active. Used by repos in lenient scope-enforcement mode\n * (the default) and by code paths that legitimately run outside a request.\n */\nexport function tryGetRequester(): RequesterContext | undefined {\n return als.getStore();\n}\n\n/**\n * Resolve the effective scope for the ambient context, defaulting to `'user'`.\n */\nexport function requireRequesterScope(): RequesterScope {\n return requireRequester().scope ?? 'user';\n}\n\n/**\n * Convenience helpers for setting scope explicitly. All three preserve\n * `userId` in the context (audit trail) regardless of scope.\n *\n * - `withUserScope`: regular end-user requests. Most call sites.\n * - `withOrgScope`: admin / org-shared resource access. The caller MUST verify\n * the requester's role permits `'org'` before calling — the helper does not\n * enforce authorization. `orgUserIds` is pre-resolved at the boundary.\n * - `withSuperuserScope`: engineering scripts / internal tools. `organizationId`\n * is null (cross-org is the point). Same authorization caveat applies.\n */\nexport function withUserScope<T>(\n userId: string,\n organizationId: string | null,\n fn: () => Promise<T>,\n): Promise<T> {\n return withRequester({ userId, organizationId, scope: 'user' }, fn);\n}\n\nexport function withOrgScope<T>(\n userId: string,\n organizationId: string,\n orgUserIds: readonly string[],\n fn: () => Promise<T>,\n): Promise<T> {\n return withRequester(\n { userId, organizationId, scope: 'org', orgUserIds },\n fn,\n );\n}\n\nexport function withSuperuserScope<T>(\n userId: string,\n fn: () => Promise<T>,\n): Promise<T> {\n return withRequester(\n { userId, organizationId: null, scope: 'superuser' },\n fn,\n );\n}\n"],"mappings":"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","names":["and","eq","inArray","eq","inArray","and"]}
@@ -4,21 +4,21 @@ import '../types/drizzle.js';
4
4
  import 'drizzle-orm/node-postgres';
5
5
 
6
6
  /**
7
- * SyncedEntityService<TRepo, TEntity>
7
+ * IntegratedEntityService<TRepo, TEntity>
8
8
  *
9
- * Family-specific base service for Synced entities.
9
+ * Family-specific base service for Integrated entities.
10
10
  * Delegates to a CRM repository that provides external ID lookups
11
11
  * and user-scoped queries.
12
12
  */
13
13
 
14
- interface ISyncedEntityRepository<TEntity> extends IBaseRepository<TEntity> {
14
+ interface IIntegratedEntityRepository<TEntity> extends IBaseRepository<TEntity> {
15
15
  findByExternalId(externalId: string): Promise<TEntity | null>;
16
16
  findManyByExternalIds(externalIds: string[]): Promise<TEntity[]>;
17
17
  findAllByUserId(userId: string): Promise<TEntity[]>;
18
18
  findVisibleByUserId(userId: string): Promise<TEntity[]>;
19
- syncUpsert(inputs: Array<Partial<TEntity>>): Promise<TEntity[]>;
19
+ integrationUpsert(inputs: Array<Partial<TEntity>>): Promise<TEntity[]>;
20
20
  }
21
- declare abstract class SyncedEntityService<TRepo extends ISyncedEntityRepository<TEntity>, TEntity> extends BaseService<TRepo, TEntity> {
21
+ declare abstract class IntegratedEntityService<TRepo extends IIntegratedEntityRepository<TEntity>, TEntity> extends BaseService<TRepo, TEntity> {
22
22
  /**
23
23
  * Find a single entity by its external CRM identifier.
24
24
  */
@@ -38,4 +38,4 @@ declare abstract class SyncedEntityService<TRepo extends ISyncedEntityRepository
38
38
  findVisibleByUser(userId: string): Promise<TEntity[]>;
39
39
  }
40
40
 
41
- export { type ISyncedEntityRepository, SyncedEntityService };
41
+ export { type IIntegratedEntityRepository, IntegratedEntityService };
@@ -183,8 +183,8 @@ var BaseService = class {
183
183
  }
184
184
  };
185
185
 
186
- // runtime/base-classes/synced-entity-service.ts
187
- var SyncedEntityService = class extends BaseService {
186
+ // runtime/base-classes/integrated-entity-service.ts
187
+ var IntegratedEntityService = class extends BaseService {
188
188
  /**
189
189
  * Find a single entity by its external CRM identifier.
190
190
  */
@@ -212,6 +212,6 @@ var SyncedEntityService = class extends BaseService {
212
212
  }
213
213
  };
214
214
  export {
215
- SyncedEntityService
215
+ IntegratedEntityService
216
216
  };
217
- //# sourceMappingURL=synced-entity-service.js.map
217
+ //# sourceMappingURL=integrated-entity-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../runtime/base-classes/lifecycle-events.ts","../../../runtime/base-classes/base-service.ts","../../../runtime/base-classes/integrated-entity-service.ts"],"sourcesContent":["/**\n * Lifecycle event emission for BaseService.\n *\n * Ported from pattern-stack/atoms/patterns/services/base.py — the Python\n * BaseService emits LIFECYCLE and CHANGE events on every CRUD operation.\n * This module provides the same capability for the TypeScript codegen stack.\n *\n * Design:\n * - Fire-and-forget: event emission never fails the CRUD operation.\n * - IEventBus is optional: if no EVENT_BUS is injected, emission is silently\n * skipped. This means base classes work in projects that haven't installed\n * the events subsystem.\n * - LIFECYCLE events carry an entity snapshot in payload.\n * - CHANGE events carry per-field old/new diffs.\n * - Controlled per-entity via `emitLifecycleEvents` flag (default: true).\n *\n * @deprecated EVT-7 — Lifecycle events are untyped and emit outside of the\n * CRUD transaction. New work should declare an `emits:` block on the entity\n * and publish typed domain events from use-cases via TYPED_EVENT_BUS inside\n * the same Drizzle transaction. See `docs/specs/EVT-7.md`. This helper is\n * retained for BaseService backward compatibility until all entities have\n * migrated to typed emits.\n */\n\nimport { randomUUID } from 'crypto';\nimport type { IEventBus, DomainEvent } from '../subsystems/events/event-bus.protocol';\n\n// ============================================================================\n// Event categories (subset of pattern-stack's EventCategory)\n// ============================================================================\n\nexport type EventCategory = 'lifecycle' | 'change';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** System fields excluded from entity snapshots and change diffs. */\nconst SYSTEM_FIELDS = new Set([\n\t'id',\n\t'createdAt',\n\t'updatedAt',\n\t'deletedAt',\n]);\n\n/**\n * Snapshot an entity's field values, excluding system fields.\n * Mirrors pattern-stack's `_get_entity_snapshot()`.\n */\nexport function entitySnapshot(entity: Record<string, unknown>): Record<string, unknown> {\n\tconst snap: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(entity)) {\n\t\tif (!SYSTEM_FIELDS.has(key)) {\n\t\t\tsnap[key] = value;\n\t\t}\n\t}\n\treturn snap;\n}\n\n/**\n * Diff two entity snapshots, returning per-field old/new pairs.\n * Only includes fields that actually changed.\n */\nexport function diffSnapshots(\n\tbefore: Record<string, unknown>,\n\tafter: Record<string, unknown>,\n): Array<{ field: string; oldValue: unknown; newValue: unknown }> {\n\tconst changes: Array<{ field: string; oldValue: unknown; newValue: unknown }> = [];\n\tconst allKeys = new Set([...Object.keys(before), ...Object.keys(after)]);\n\n\tfor (const key of allKeys) {\n\t\tif (SYSTEM_FIELDS.has(key)) continue;\n\t\tconst oldVal = before[key];\n\t\tconst newVal = after[key];\n\t\t// Simple equality — good enough for primitives and nulls.\n\t\t// For deep objects, JSON.stringify comparison.\n\t\tif (oldVal !== newVal && JSON.stringify(oldVal) !== JSON.stringify(newVal)) {\n\t\t\tchanges.push({ field: key, oldValue: oldVal, newValue: newVal });\n\t\t}\n\t}\n\n\treturn changes;\n}\n\n// ============================================================================\n// Event builders\n// ============================================================================\n\nexport function buildLifecycleEvent(\n\tentityName: string,\n\taction: 'created' | 'updated' | 'deleted',\n\tentityId: string,\n\tsnapshot?: Record<string, unknown>,\n): DomainEvent {\n\treturn {\n\t\tid: randomUUID(),\n\t\ttype: `${entityName}.${action}`,\n\t\taggregateId: entityId,\n\t\taggregateType: entityName,\n\t\tpayload: snapshot ? { snapshot } : {},\n\t\toccurredAt: new Date(),\n\t\tmetadata: { category: 'lifecycle' as EventCategory },\n\t};\n}\n\nexport function buildChangeEvents(\n\tentityName: string,\n\tentityId: string,\n\tchanges: Array<{ field: string; oldValue: unknown; newValue: unknown }>,\n): DomainEvent[] {\n\treturn changes.map((c) => ({\n\t\tid: randomUUID(),\n\t\ttype: `${entityName}.field_changed`,\n\t\taggregateId: entityId,\n\t\taggregateType: entityName,\n\t\tpayload: {\n\t\t\tfieldName: c.field,\n\t\t\toldValue: c.oldValue,\n\t\t\tnewValue: c.newValue,\n\t\t},\n\t\toccurredAt: new Date(),\n\t\tmetadata: { category: 'change' as EventCategory },\n\t}));\n}\n\n// ============================================================================\n// Emission helper (fire-and-forget)\n// ============================================================================\n\n/**\n * Emit events to the bus, swallowing errors.\n * Mirrors pattern-stack's `_emit_lifecycle_event()` try/except.\n */\nexport async function emitSafely(\n\teventBus: IEventBus | undefined,\n\tevents: DomainEvent[],\n): Promise<void> {\n\tif (!eventBus || events.length === 0) return;\n\ttry {\n\t\tif (events.length === 1) {\n\t\t\tconst only = events[0];\n\t\t\tif (!only) return;\n\t\t\tawait eventBus.publish(only);\n\t\t} else {\n\t\t\tawait eventBus.publishMany(events);\n\t\t}\n\t} catch {\n\t\t// Log but never fail the CRUD operation.\n\t\t// In production, this would use a structured logger.\n\t\tconsole.warn(`[lifecycle-events] failed to emit ${events.length} event(s)`);\n\t}\n}\n","/**\n * BaseService<TRepo, TEntity>\n *\n * Abstract base class providing 8 CRUD pass-through methods delegating to\n * an injected repository. Every generated service extends this class.\n *\n * Lifecycle event emission (LIFECYCLE + CHANGE categories) is built into\n * create/update/delete — matching pattern-stack's BaseService. Events are\n * fire-and-forget: emission never fails the CRUD operation. If no IEventBus\n * is injected (eventBus is undefined), emission is silently skipped.\n *\n * Generated services set `entityName` and optionally inject `eventBus` via\n * NestJS property injection (@Inject(EVENT_BUS) @Optional()).\n *\n * Note: @Injectable() is applied on concrete services (not here) so that\n * NestJS DI metadata is emitted at the concrete class level. This matches\n * the pattern established by BaseRepository.\n */\n\nimport type { IEventBus } from '../subsystems/events/event-bus.protocol';\nimport {\n entitySnapshot,\n diffSnapshots,\n buildLifecycleEvent,\n buildChangeEvents,\n emitSafely,\n} from './lifecycle-events';\n\n// ============================================================================\n// IBaseRepository interface\n// ============================================================================\n\n/**\n * Structural interface that BaseRepository satisfies.\n * Use this as the TRepo constraint so BaseService is not coupled to the\n * concrete Drizzle-backed BaseRepository.\n */\nexport interface IBaseRepository<TEntity> {\n findById(id: string): Promise<TEntity | null>;\n findByIds(ids: string[]): Promise<TEntity[]>;\n list(options?: unknown): Promise<TEntity[]>;\n count(where?: unknown): Promise<number>;\n exists(id: string): Promise<boolean>;\n create(input: Partial<TEntity>, tx?: unknown): Promise<TEntity>;\n update(id: string, input: Partial<TEntity>, tx?: unknown): Promise<TEntity>;\n delete(id: string, tx?: unknown): Promise<void>;\n}\n\n// ============================================================================\n// BaseService\n// ============================================================================\n\nexport abstract class BaseService<TRepo extends IBaseRepository<TEntity>, TEntity> {\n /**\n * Entity name for event types (e.g., 'account' → 'account.created').\n * Set by generated services. If empty, lifecycle events are skipped.\n */\n protected entityName?: string;\n\n /**\n * Event bus for lifecycle/change event emission.\n * Injected via @Inject(EVENT_BUS) @Optional() on generated services.\n * If undefined (no events subsystem installed), emission is silently skipped.\n */\n protected eventBus?: IEventBus;\n\n /**\n * Whether to emit lifecycle events. Default: true.\n * Override to false in entity YAML via behaviors or in the service class.\n */\n protected emitLifecycleEvents = true;\n\n constructor(protected readonly repository: TRepo) {}\n\n /**\n * Find a single entity by its primary key.\n * Returns null if not found.\n */\n findById(id: string): Promise<TEntity | null> {\n return this.repository.findById(id);\n }\n\n /**\n * Find multiple entities by their primary keys.\n */\n findByIds(ids: string[]): Promise<TEntity[]> {\n return this.repository.findByIds(ids);\n }\n\n /**\n * List entities with optional filtering/pagination options.\n */\n list(options?: unknown): Promise<TEntity[]> {\n return this.repository.list(options);\n }\n\n /**\n * Count entities matching an optional filter.\n */\n count(where?: unknown): Promise<number> {\n return this.repository.count(where);\n }\n\n /**\n * Check whether an entity with the given id exists.\n */\n exists(id: string): Promise<boolean> {\n return this.repository.exists(id);\n }\n\n /**\n * Insert a new entity.\n * Emits a LIFECYCLE 'created' event with entity snapshot.\n */\n async create(input: Partial<TEntity>, tx?: unknown): Promise<TEntity> {\n const result = await this.repository.create(input, tx);\n\n if (this._shouldEmit()) {\n const snap = entitySnapshot(result as Record<string, unknown>);\n const id = (result as Record<string, unknown>).id as string;\n const event = buildLifecycleEvent(this.entityName!, 'created', id, snap);\n void emitSafely(this.eventBus, [event]);\n }\n\n return result;\n }\n\n /**\n * Update an existing entity by id.\n * Emits a LIFECYCLE 'updated' event + CHANGE events for each modified field.\n */\n async update(id: string, input: Partial<TEntity>, tx?: unknown): Promise<TEntity> {\n // Snapshot before for change diffing\n let before: Record<string, unknown> | undefined;\n if (this._shouldEmit()) {\n const existing = await this.repository.findById(id);\n if (existing) {\n before = entitySnapshot(existing as Record<string, unknown>);\n }\n }\n\n const result = await this.repository.update(id, input, tx);\n\n if (this._shouldEmit()) {\n const after = entitySnapshot(result as Record<string, unknown>);\n const events = [\n buildLifecycleEvent(this.entityName!, 'updated', id, after),\n ];\n // Append per-field CHANGE events\n if (before) {\n const changes = diffSnapshots(before, after);\n if (changes.length > 0) {\n events.push(...buildChangeEvents(this.entityName!, id, changes));\n }\n }\n void emitSafely(this.eventBus, events);\n }\n\n return result;\n }\n\n /**\n * Delete an entity by id.\n * Emits a LIFECYCLE 'deleted' event.\n */\n async delete(id: string, tx?: unknown): Promise<void> {\n await this.repository.delete(id, tx);\n\n if (this._shouldEmit()) {\n const event = buildLifecycleEvent(this.entityName!, 'deleted', id);\n void emitSafely(this.eventBus, [event]);\n }\n }\n\n /** Check whether lifecycle event emission is active. */\n private _shouldEmit(): boolean {\n return Boolean(\n this.emitLifecycleEvents &&\n this.entityName &&\n this.eventBus,\n );\n }\n}\n","/**\n * IntegratedEntityService<TRepo, TEntity>\n *\n * Family-specific base service for Integrated entities.\n * Delegates to a CRM repository that provides external ID lookups\n * and user-scoped queries.\n */\nimport { BaseService, type IBaseRepository } from './base-service';\n\nexport interface IIntegratedEntityRepository<TEntity> extends IBaseRepository<TEntity> {\n findByExternalId(externalId: string): Promise<TEntity | null>;\n findManyByExternalIds(externalIds: string[]): Promise<TEntity[]>;\n findAllByUserId(userId: string): Promise<TEntity[]>;\n findVisibleByUserId(userId: string): Promise<TEntity[]>;\n integrationUpsert(inputs: Array<Partial<TEntity>>): Promise<TEntity[]>;\n}\n\nexport abstract class IntegratedEntityService<\n TRepo extends IIntegratedEntityRepository<TEntity>,\n TEntity,\n> extends BaseService<TRepo, TEntity> {\n /**\n * Find a single entity by its external CRM identifier.\n */\n findByExternalId(externalId: string): Promise<TEntity | null> {\n return this.repository.findByExternalId(externalId);\n }\n\n /**\n * Find multiple entities by external CRM identifiers.\n */\n findManyByExternalIds(externalIds: string[]): Promise<TEntity[]> {\n return this.repository.findManyByExternalIds(externalIds);\n }\n\n /**\n * Find all entities owned by a specific user.\n */\n findAllByUser(userId: string): Promise<TEntity[]> {\n return this.repository.findAllByUserId(userId);\n }\n\n /**\n * Find entities visible to a user (ownership + sharing rules).\n * Concrete services may override with domain-specific visibility logic.\n */\n findVisibleByUser(userId: string): Promise<TEntity[]> {\n return this.repository.findVisibleByUserId(userId);\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,16 +1,16 @@
1
1
  import { PgTableWithColumns } from 'drizzle-orm/pg-core';
2
2
 
3
3
  /**
4
- * SyncUpsertConfig + SyncFkResolver
4
+ * IntegrationUpsertConfig + IntegrationFkResolver
5
5
  *
6
- * Declarative description of an entity's inbound-sync write surface, consumed
7
- * by `SyncedEntityRepository.syncUpsertOne` / `findByExternalIdProjected` /
8
- * `softDeleteByExternalId` / `toProjection`. Each `pattern: Synced` repository
9
- * declares a concrete `syncConfig: SyncUpsertConfig` (emitted by the template),
6
+ * Declarative description of an entity's inbound-integration write surface, consumed
7
+ * by `IntegratedEntityRepository.integrationUpsertOne` / `findByExternalIdProjected` /
8
+ * `softDeleteByExternalId` / `toProjection`. Each `pattern: Integrated` repository
9
+ * declares a concrete `integrationConfig: IntegrationUpsertConfig` (emitted by the template),
10
10
  * the same idiom as `behaviors: BehaviorConfig`.
11
11
  *
12
- * Named `SyncUpsertConfig` (not `SyncConfig`) to avoid colliding with the sync
13
- * subsystem's `DetectionConfig`/`SyncConfig` surface.
12
+ * Named `IntegrationUpsertConfig` (not `IntegrationConfig`) to avoid colliding with the integration
13
+ * subsystem's `DetectionConfig`/`IntegrationConfig` surface.
14
14
  *
15
15
  * The generic upsert separates three column roles:
16
16
  * - identity (`conflictTarget`) — only in `values`, never in `set`
@@ -27,17 +27,17 @@ import { PgTableWithColumns } from 'drizzle-orm/pg-core';
27
27
  * posture); falsy leaves the column null this run (opportunistic, entity
28
28
  * posture).
29
29
  */
30
- interface SyncFkResolver {
30
+ interface IntegrationFkResolver {
31
31
  /** Local FK column — camel key into `this.table`, e.g. `'parentAccountId'`. */
32
32
  column: string;
33
- /** Key on `TSyncWrite` carrying the parent external id (see Decision 4). */
33
+ /** Key on `TIntegrationWrite` carrying the parent external id (see Decision 4). */
34
34
  writeKey: string;
35
35
  /** Parent table to resolve against; `'self'` → `this.table`. */
36
36
  refTable: PgTableWithColumns<any> | 'self';
37
37
  /** true = throw on unresolved (junction); falsy = opportunistic null (entity). */
38
38
  strict?: boolean;
39
39
  }
40
- interface SyncUpsertConfig {
40
+ interface IntegrationUpsertConfig {
41
41
  /** Camel keys into `this.table` forming the conflict target, e.g. `['provider', 'externalId']`. */
42
42
  conflictTarget: string[];
43
43
  /**
@@ -46,13 +46,13 @@ interface SyncUpsertConfig {
46
46
  */
47
47
  writeColumns: string[];
48
48
  /** Conditional, provider-scoped FK resolvers. */
49
- fkResolvers: SyncFkResolver[];
49
+ fkResolvers: IntegrationFkResolver[];
50
50
  /** Columns picked into the projection (camel), incl. id/externalId/timestamps. */
51
51
  projectionColumns: string[];
52
- /** When true, `syncUpsertOne` calls `writeCustomFields` for a non-empty `fields` bag. */
52
+ /** When true, `integrationUpsertOne` calls `writeCustomFields` for a non-empty `fields` bag. */
53
53
  eav: boolean;
54
54
  /** When true, deletes set `deletedAt`; when false, tombstone-by-clearing external_id/provider. */
55
55
  softDelete: boolean;
56
56
  }
57
57
 
58
- export type { SyncFkResolver, SyncUpsertConfig };
58
+ export type { IntegrationFkResolver, IntegrationUpsertConfig };
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=integration-upsert-config.js.map
@@ -4,7 +4,7 @@ import { BaseRepository } from './base-repository.js';
4
4
  import 'drizzle-orm/node-postgres';
5
5
  import 'drizzle-orm';
6
6
 
7
- interface JunctionSyncConfig {
7
+ interface JunctionIntegrationConfig {
8
8
  /** Left endpoint: local FK column (camel) + strict parent table. */
9
9
  left: {
10
10
  column: string;
@@ -18,12 +18,12 @@ interface JunctionSyncConfig {
18
18
  /** Role column (camel), or null for a role-less (2-part composite) junction. */
19
19
  roleColumn: string | null;
20
20
  }
21
- declare abstract class JunctionSyncRepository<TEntity, TSyncWrite, TSyncProjection> extends BaseRepository<TEntity> {
21
+ declare abstract class JunctionIntegrationRepository<TEntity, TIntegrationWrite, TIntegrationProjection> extends BaseRepository<TEntity> {
22
22
  /**
23
- * Declarative junction sync surface. Concrete repos declare this — the
23
+ * Declarative junction integration surface. Concrete repos declare this — the
24
24
  * template emits it with live parent-table handles.
25
25
  */
26
- protected abstract readonly syncConfig: JunctionSyncConfig;
26
+ protected abstract readonly integrationConfig: JunctionIntegrationConfig;
27
27
  /**
28
28
  * Upsert ONE junction row by its composite identity, in a single transaction:
29
29
  * 1. resolve the REQUIRED left FK (provider-scoped) — STRICT: missing → throws;
@@ -37,17 +37,17 @@ declare abstract class JunctionSyncRepository<TEntity, TSyncWrite, TSyncProjecti
37
37
  * @param provider adapter/provider label used to scope the parent lookups
38
38
  * @param tx optional outer transaction; when omitted we open our own
39
39
  */
40
- syncUpsertOne(write: TSyncWrite, provider: string, tx?: DrizzleTx): Promise<TSyncProjection>;
40
+ integrationUpsertOne(write: TIntegrationWrite, provider: string, tx?: DrizzleTx): Promise<TIntegrationProjection>;
41
41
  /**
42
42
  * Canonical-projected lookup by the COMPOSITE externalId, differ-ready. Parses
43
43
  * the composite, resolves BOTH parents NON-throwing (→ null), then selects by
44
44
  * the identity tuple. Returns `null` on malformed composite / unresolved
45
45
  * parent / no row (a missing "before" side is a create from the differ's view).
46
46
  */
47
- findByExternalIdProjected(externalId: string, provider: string): Promise<TSyncProjection | null>;
47
+ findByExternalIdProjected(externalId: string, provider: string): Promise<TIntegrationProjection | null>;
48
48
  /**
49
49
  * Hard-delete the junction by composite externalId. Junctions have no
50
- * `deleted_at` and no external-linkage columns to clear, so a sync "delete"
50
+ * `deleted_at` and no external-linkage columns to clear, so a integration "delete"
51
51
  * removes the row. Resolves both parents NON-throwing, then deletes by the
52
52
  * identity tuple. Returns the composite id, or `null` when nothing matched.
53
53
  */
@@ -58,11 +58,11 @@ declare abstract class JunctionSyncRepository<TEntity, TSyncWrite, TSyncProjecti
58
58
  * Project a raw junction row to the differ shape: the COMPOSITE externalId
59
59
  * `id` (junctions have no surrogate id) plus the local FK columns, role (when
60
60
  * role-bearing) and timestamps — matching the emitted
61
- * `<Junction>SyncProjection` interface (id + leftId + rightId + role? +
61
+ * `<Junction>IntegrationProjection` interface (id + leftId + rightId + role? +
62
62
  * createdAt + updatedAt). Junction projections are purely structural, so this
63
- * is fully generic over `syncConfig` — no per-junction override is emitted.
63
+ * is fully generic over `integrationConfig` — no per-junction override is emitted.
64
64
  */
65
- protected toProjection(row: TEntity, write: Record<string, unknown>, _provider: string): TSyncProjection;
65
+ protected toProjection(row: TEntity, write: Record<string, unknown>, _provider: string): TIntegrationProjection;
66
66
  /** Build the identity WHERE clause `(left, right[, role])`. */
67
67
  private identityWhere;
68
68
  /** Resolve a parent id (provider-scoped), throwing when unresolved. */
@@ -86,4 +86,4 @@ declare function parseCompositeExternalId(externalId: string, withRole: boolean)
86
86
  role: string | undefined;
87
87
  } | null;
88
88
 
89
- export { type JunctionSyncConfig, JunctionSyncRepository, buildCompositeExternalId, parseCompositeExternalId };
89
+ export { type JunctionIntegrationConfig, JunctionIntegrationRepository, buildCompositeExternalId, parseCompositeExternalId };
@@ -1,4 +1,4 @@
1
- // runtime/base-classes/junction-sync-repository.ts
1
+ // runtime/base-classes/junction-integration-repository.ts
2
2
  import { and as and2, eq as eq2 } from "drizzle-orm";
3
3
 
4
4
  // runtime/base-classes/base-repository.ts
@@ -279,8 +279,8 @@ var BaseRepository = class {
279
279
  }
280
280
  };
281
281
 
282
- // runtime/base-classes/junction-sync-repository.ts
283
- var JunctionSyncRepository = class extends BaseRepository {
282
+ // runtime/base-classes/junction-integration-repository.ts
283
+ var JunctionIntegrationRepository = class extends BaseRepository {
284
284
  /**
285
285
  * Upsert ONE junction row by its composite identity, in a single transaction:
286
286
  * 1. resolve the REQUIRED left FK (provider-scoped) — STRICT: missing → throws;
@@ -294,8 +294,8 @@ var JunctionSyncRepository = class extends BaseRepository {
294
294
  * @param provider adapter/provider label used to scope the parent lookups
295
295
  * @param tx optional outer transaction; when omitted we open our own
296
296
  */
297
- async syncUpsertOne(write, provider, tx) {
298
- const cfg = this.syncConfig;
297
+ async integrationUpsertOne(write, provider, tx) {
298
+ const cfg = this.integrationConfig;
299
299
  const w = write;
300
300
  const leftWriteKey = `${cfg.left.column.replace(/Id$/, "")}ExternalId`;
301
301
  const rightWriteKey = `${cfg.right.column.replace(/Id$/, "")}ExternalId`;
@@ -339,7 +339,7 @@ var JunctionSyncRepository = class extends BaseRepository {
339
339
  * parent / no row (a missing "before" side is a create from the differ's view).
340
340
  */
341
341
  async findByExternalIdProjected(externalId, provider) {
342
- const cfg = this.syncConfig;
342
+ const cfg = this.integrationConfig;
343
343
  const parsed = parseCompositeExternalId(externalId, cfg.roleColumn !== null);
344
344
  if (!parsed) return null;
345
345
  const leftId = await this.resolveLoose(this.db, cfg.left.refTable, parsed.left, provider);
@@ -359,12 +359,12 @@ var JunctionSyncRepository = class extends BaseRepository {
359
359
  }
360
360
  /**
361
361
  * Hard-delete the junction by composite externalId. Junctions have no
362
- * `deleted_at` and no external-linkage columns to clear, so a sync "delete"
362
+ * `deleted_at` and no external-linkage columns to clear, so a integration "delete"
363
363
  * removes the row. Resolves both parents NON-throwing, then deletes by the
364
364
  * identity tuple. Returns the composite id, or `null` when nothing matched.
365
365
  */
366
366
  async softDeleteByExternalId(externalId, provider, tx) {
367
- const cfg = this.syncConfig;
367
+ const cfg = this.integrationConfig;
368
368
  const parsed = parseCompositeExternalId(externalId, cfg.roleColumn !== null);
369
369
  if (!parsed) return null;
370
370
  const db = this.runner(tx);
@@ -379,12 +379,12 @@ var JunctionSyncRepository = class extends BaseRepository {
379
379
  * Project a raw junction row to the differ shape: the COMPOSITE externalId
380
380
  * `id` (junctions have no surrogate id) plus the local FK columns, role (when
381
381
  * role-bearing) and timestamps — matching the emitted
382
- * `<Junction>SyncProjection` interface (id + leftId + rightId + role? +
382
+ * `<Junction>IntegrationProjection` interface (id + leftId + rightId + role? +
383
383
  * createdAt + updatedAt). Junction projections are purely structural, so this
384
- * is fully generic over `syncConfig` — no per-junction override is emitted.
384
+ * is fully generic over `integrationConfig` — no per-junction override is emitted.
385
385
  */
386
386
  toProjection(row, write, _provider) {
387
- const cfg = this.syncConfig;
387
+ const cfg = this.integrationConfig;
388
388
  const r = row;
389
389
  const leftExt = write[`${cfg.left.column.replace(/Id$/, "")}ExternalId`];
390
390
  const rightExt = write[`${cfg.right.column.replace(/Id$/, "")}ExternalId`];
@@ -401,7 +401,7 @@ var JunctionSyncRepository = class extends BaseRepository {
401
401
  }
402
402
  /** Build the identity WHERE clause `(left, right[, role])`. */
403
403
  identityWhere(leftId, rightId, role) {
404
- const cfg = this.syncConfig;
404
+ const cfg = this.integrationConfig;
405
405
  const conds = [
406
406
  eq2(this.table[cfg.left.column], leftId),
407
407
  eq2(this.table[cfg.right.column], rightId)
@@ -416,7 +416,7 @@ var JunctionSyncRepository = class extends BaseRepository {
416
416
  const id = await this.resolveLoose(db, refTable, parentExternalId, provider);
417
417
  if (!id) {
418
418
  throw new Error(
419
- `${this.constructor.name}.syncUpsertOne: unresolved parent '${parentExternalId}' (provider '${provider}') for '${column}' \u2014 parent not synced yet`
419
+ `${this.constructor.name}.integrationUpsertOne: unresolved parent '${parentExternalId}' (provider '${provider}') for '${column}' \u2014 parent not integrated yet`
420
420
  );
421
421
  }
422
422
  return id;
@@ -447,8 +447,8 @@ function parseCompositeExternalId(externalId, withRole) {
447
447
  };
448
448
  }
449
449
  export {
450
- JunctionSyncRepository,
450
+ JunctionIntegrationRepository,
451
451
  buildCompositeExternalId,
452
452
  parseCompositeExternalId
453
453
  };
454
- //# sourceMappingURL=junction-sync-repository.js.map
454
+ //# sourceMappingURL=junction-integration-repository.js.map