@digimuza/saas-core 0.0.2

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 (474) hide show
  1. package/CLAUDE.md +1165 -0
  2. package/LICENSE +21 -0
  3. package/README.md +234 -0
  4. package/dist/api-keys/index.d.ts +9 -0
  5. package/dist/api-keys/index.d.ts.map +1 -0
  6. package/dist/api-keys/index.js +37 -0
  7. package/dist/api-keys/index.js.map +1 -0
  8. package/dist/api-keys/keys.d.ts +55 -0
  9. package/dist/api-keys/keys.d.ts.map +1 -0
  10. package/dist/api-keys/keys.js +92 -0
  11. package/dist/api-keys/keys.js.map +1 -0
  12. package/dist/api-keys/service.d.ts +111 -0
  13. package/dist/api-keys/service.d.ts.map +1 -0
  14. package/dist/api-keys/service.js +210 -0
  15. package/dist/api-keys/service.js.map +1 -0
  16. package/dist/audit/index.d.ts +5 -0
  17. package/dist/audit/index.d.ts.map +1 -0
  18. package/dist/audit/index.js +44 -0
  19. package/dist/audit/index.js.map +1 -0
  20. package/dist/audit/service.d.ts +88 -0
  21. package/dist/audit/service.d.ts.map +1 -0
  22. package/dist/audit/service.js +128 -0
  23. package/dist/audit/service.js.map +1 -0
  24. package/dist/auth/client.d.ts +5 -0
  25. package/dist/auth/client.d.ts.map +1 -0
  26. package/dist/auth/client.js +26 -0
  27. package/dist/auth/client.js.map +1 -0
  28. package/dist/auth/cookies.d.ts +51 -0
  29. package/dist/auth/cookies.d.ts.map +1 -0
  30. package/dist/auth/cookies.js +58 -0
  31. package/dist/auth/cookies.js.map +1 -0
  32. package/dist/auth/index.d.ts +14 -0
  33. package/dist/auth/index.d.ts.map +1 -0
  34. package/dist/auth/index.js +46 -0
  35. package/dist/auth/index.js.map +1 -0
  36. package/dist/auth/service.d.ts +67 -0
  37. package/dist/auth/service.d.ts.map +1 -0
  38. package/dist/auth/service.js +275 -0
  39. package/dist/auth/service.js.map +1 -0
  40. package/dist/auth/types.d.ts +56 -0
  41. package/dist/auth/types.d.ts.map +1 -0
  42. package/dist/auth/types.js +2 -0
  43. package/dist/auth/types.js.map +1 -0
  44. package/dist/authorization/index.d.ts +4 -0
  45. package/dist/authorization/index.d.ts.map +1 -0
  46. package/dist/authorization/index.js +24 -0
  47. package/dist/authorization/index.js.map +1 -0
  48. package/dist/authorization/service.d.ts +92 -0
  49. package/dist/authorization/service.d.ts.map +1 -0
  50. package/dist/authorization/service.js +254 -0
  51. package/dist/authorization/service.js.map +1 -0
  52. package/dist/billing/index.d.ts +16 -0
  53. package/dist/billing/index.d.ts.map +1 -0
  54. package/dist/billing/index.js +47 -0
  55. package/dist/billing/index.js.map +1 -0
  56. package/dist/billing/provider.d.ts +114 -0
  57. package/dist/billing/provider.d.ts.map +1 -0
  58. package/dist/billing/provider.js +2 -0
  59. package/dist/billing/provider.js.map +1 -0
  60. package/dist/billing/revolut.d.ts +68 -0
  61. package/dist/billing/revolut.d.ts.map +1 -0
  62. package/dist/billing/revolut.js +181 -0
  63. package/dist/billing/revolut.js.map +1 -0
  64. package/dist/billing/service.d.ts +124 -0
  65. package/dist/billing/service.d.ts.map +1 -0
  66. package/dist/billing/service.js +470 -0
  67. package/dist/billing/service.js.map +1 -0
  68. package/dist/cli/commands/dev.d.ts +43 -0
  69. package/dist/cli/commands/dev.d.ts.map +1 -0
  70. package/dist/cli/commands/dev.js +212 -0
  71. package/dist/cli/commands/dev.js.map +1 -0
  72. package/dist/cli/commands/project.d.ts +12 -0
  73. package/dist/cli/commands/project.d.ts.map +1 -0
  74. package/dist/cli/commands/project.js +49 -0
  75. package/dist/cli/commands/project.js.map +1 -0
  76. package/dist/cli/docker.d.ts +50 -0
  77. package/dist/cli/docker.d.ts.map +1 -0
  78. package/dist/cli/docker.js +84 -0
  79. package/dist/cli/docker.js.map +1 -0
  80. package/dist/cli/index.d.ts +6 -0
  81. package/dist/cli/index.d.ts.map +1 -0
  82. package/dist/cli/index.js +198 -0
  83. package/dist/cli/index.js.map +1 -0
  84. package/dist/cli/output.d.ts +30 -0
  85. package/dist/cli/output.d.ts.map +1 -0
  86. package/dist/cli/output.js +66 -0
  87. package/dist/cli/output.js.map +1 -0
  88. package/dist/cli/templates.d.ts +52 -0
  89. package/dist/cli/templates.d.ts.map +1 -0
  90. package/dist/cli/templates.js +225 -0
  91. package/dist/cli/templates.js.map +1 -0
  92. package/dist/config/client.d.ts +60 -0
  93. package/dist/config/client.d.ts.map +1 -0
  94. package/dist/config/client.js +94 -0
  95. package/dist/config/client.js.map +1 -0
  96. package/dist/config/config-loader.d.ts +2 -0
  97. package/dist/config/config-loader.d.ts.map +1 -0
  98. package/dist/config/config-loader.js +2 -0
  99. package/dist/config/config-loader.js.map +1 -0
  100. package/dist/config/env.d.ts +24 -0
  101. package/dist/config/env.d.ts.map +1 -0
  102. package/dist/config/env.js +40 -0
  103. package/dist/config/env.js.map +1 -0
  104. package/dist/config/errors.d.ts +17 -0
  105. package/dist/config/errors.d.ts.map +1 -0
  106. package/dist/config/errors.js +26 -0
  107. package/dist/config/errors.js.map +1 -0
  108. package/dist/config/index.d.ts +72 -0
  109. package/dist/config/index.d.ts.map +1 -0
  110. package/dist/config/index.js +106 -0
  111. package/dist/config/index.js.map +1 -0
  112. package/dist/config/runtime.d.ts +15 -0
  113. package/dist/config/runtime.d.ts.map +1 -0
  114. package/dist/config/runtime.js +22 -0
  115. package/dist/config/runtime.js.map +1 -0
  116. package/dist/config/sections.d.ts +226 -0
  117. package/dist/config/sections.d.ts.map +1 -0
  118. package/dist/config/sections.js +141 -0
  119. package/dist/config/sections.js.map +1 -0
  120. package/dist/db/client.d.ts +43 -0
  121. package/dist/db/client.d.ts.map +1 -0
  122. package/dist/db/client.js +77 -0
  123. package/dist/db/client.js.map +1 -0
  124. package/dist/db/errors.d.ts +39 -0
  125. package/dist/db/errors.d.ts.map +1 -0
  126. package/dist/db/errors.js +67 -0
  127. package/dist/db/errors.js.map +1 -0
  128. package/dist/db/index.d.ts +10 -0
  129. package/dist/db/index.d.ts.map +1 -0
  130. package/dist/db/index.js +10 -0
  131. package/dist/db/index.js.map +1 -0
  132. package/dist/db/migrate.d.ts +21 -0
  133. package/dist/db/migrate.d.ts.map +1 -0
  134. package/dist/db/migrate.js +28 -0
  135. package/dist/db/migrate.js.map +1 -0
  136. package/dist/db/schema/_shared.d.ts +30 -0
  137. package/dist/db/schema/_shared.d.ts.map +1 -0
  138. package/dist/db/schema/_shared.js +36 -0
  139. package/dist/db/schema/_shared.js.map +1 -0
  140. package/dist/db/schema/apikeys.d.ts +263 -0
  141. package/dist/db/schema/apikeys.d.ts.map +1 -0
  142. package/dist/db/schema/apikeys.js +70 -0
  143. package/dist/db/schema/apikeys.js.map +1 -0
  144. package/dist/db/schema/authorization.d.ts +465 -0
  145. package/dist/db/schema/authorization.d.ts.map +1 -0
  146. package/dist/db/schema/authorization.js +134 -0
  147. package/dist/db/schema/authorization.js.map +1 -0
  148. package/dist/db/schema/billing.d.ts +1100 -0
  149. package/dist/db/schema/billing.d.ts.map +1 -0
  150. package/dist/db/schema/billing.js +223 -0
  151. package/dist/db/schema/billing.js.map +1 -0
  152. package/dist/db/schema/events.d.ts +161 -0
  153. package/dist/db/schema/events.d.ts.map +1 -0
  154. package/dist/db/schema/events.js +66 -0
  155. package/dist/db/schema/events.js.map +1 -0
  156. package/dist/db/schema/features.d.ts +243 -0
  157. package/dist/db/schema/features.d.ts.map +1 -0
  158. package/dist/db/schema/features.js +87 -0
  159. package/dist/db/schema/features.js.map +1 -0
  160. package/dist/db/schema/files.d.ts +253 -0
  161. package/dist/db/schema/files.d.ts.map +1 -0
  162. package/dist/db/schema/files.js +74 -0
  163. package/dist/db/schema/files.js.map +1 -0
  164. package/dist/db/schema/index.d.ts +38 -0
  165. package/dist/db/schema/index.d.ts.map +1 -0
  166. package/dist/db/schema/index.js +38 -0
  167. package/dist/db/schema/index.js.map +1 -0
  168. package/dist/db/schema/invitations.d.ts +214 -0
  169. package/dist/db/schema/invitations.d.ts.map +1 -0
  170. package/dist/db/schema/invitations.js +80 -0
  171. package/dist/db/schema/invitations.js.map +1 -0
  172. package/dist/db/schema/messaging.d.ts +442 -0
  173. package/dist/db/schema/messaging.d.ts.map +1 -0
  174. package/dist/db/schema/messaging.js +120 -0
  175. package/dist/db/schema/messaging.js.map +1 -0
  176. package/dist/db/schema/users.d.ts +246 -0
  177. package/dist/db/schema/users.d.ts.map +1 -0
  178. package/dist/db/schema/users.js +60 -0
  179. package/dist/db/schema/users.js.map +1 -0
  180. package/dist/db/schema/webhooks.d.ts +693 -0
  181. package/dist/db/schema/webhooks.d.ts.map +1 -0
  182. package/dist/db/schema/webhooks.js +147 -0
  183. package/dist/db/schema/webhooks.js.map +1 -0
  184. package/dist/db/schema/workspaces.d.ts +196 -0
  185. package/dist/db/schema/workspaces.d.ts.map +1 -0
  186. package/dist/db/schema/workspaces.js +57 -0
  187. package/dist/db/schema/workspaces.js.map +1 -0
  188. package/dist/db/types.d.ts +18 -0
  189. package/dist/db/types.d.ts.map +1 -0
  190. package/dist/db/types.js +2 -0
  191. package/dist/db/types.js.map +1 -0
  192. package/dist/email/adapters.d.ts +29 -0
  193. package/dist/email/adapters.d.ts.map +1 -0
  194. package/dist/email/adapters.js +60 -0
  195. package/dist/email/adapters.js.map +1 -0
  196. package/dist/email/index.d.ts +20 -0
  197. package/dist/email/index.d.ts.map +1 -0
  198. package/dist/email/index.js +79 -0
  199. package/dist/email/index.js.map +1 -0
  200. package/dist/email/provider.d.ts +47 -0
  201. package/dist/email/provider.d.ts.map +1 -0
  202. package/dist/email/provider.js +7 -0
  203. package/dist/email/provider.js.map +1 -0
  204. package/dist/email/resend.d.ts +22 -0
  205. package/dist/email/resend.d.ts.map +1 -0
  206. package/dist/email/resend.js +51 -0
  207. package/dist/email/resend.js.map +1 -0
  208. package/dist/email/service.d.ts +55 -0
  209. package/dist/email/service.d.ts.map +1 -0
  210. package/dist/email/service.js +87 -0
  211. package/dist/email/service.js.map +1 -0
  212. package/dist/email/templates.d.ts +81 -0
  213. package/dist/email/templates.d.ts.map +1 -0
  214. package/dist/email/templates.js +84 -0
  215. package/dist/email/templates.js.map +1 -0
  216. package/dist/entitlements/index.d.ts +10 -0
  217. package/dist/entitlements/index.d.ts.map +1 -0
  218. package/dist/entitlements/index.js +28 -0
  219. package/dist/entitlements/index.js.map +1 -0
  220. package/dist/entitlements/service.d.ts +83 -0
  221. package/dist/entitlements/service.d.ts.map +1 -0
  222. package/dist/entitlements/service.js +158 -0
  223. package/dist/entitlements/service.js.map +1 -0
  224. package/dist/errors.d.ts +85 -0
  225. package/dist/errors.d.ts.map +1 -0
  226. package/dist/errors.js +95 -0
  227. package/dist/errors.js.map +1 -0
  228. package/dist/events/core-events.d.ts +120 -0
  229. package/dist/events/core-events.d.ts.map +1 -0
  230. package/dist/events/core-events.js +109 -0
  231. package/dist/events/core-events.js.map +1 -0
  232. package/dist/events/index.d.ts +15 -0
  233. package/dist/events/index.d.ts.map +1 -0
  234. package/dist/events/index.js +58 -0
  235. package/dist/events/index.js.map +1 -0
  236. package/dist/events/publisher.d.ts +46 -0
  237. package/dist/events/publisher.d.ts.map +1 -0
  238. package/dist/events/publisher.js +54 -0
  239. package/dist/events/publisher.js.map +1 -0
  240. package/dist/events/registry.d.ts +87 -0
  241. package/dist/events/registry.d.ts.map +1 -0
  242. package/dist/events/registry.js +34 -0
  243. package/dist/events/registry.js.map +1 -0
  244. package/dist/events/service.d.ts +78 -0
  245. package/dist/events/service.d.ts.map +1 -0
  246. package/dist/events/service.js +182 -0
  247. package/dist/events/service.js.map +1 -0
  248. package/dist/features/bucket.d.ts +22 -0
  249. package/dist/features/bucket.d.ts.map +1 -0
  250. package/dist/features/bucket.js +42 -0
  251. package/dist/features/bucket.js.map +1 -0
  252. package/dist/features/index.d.ts +15 -0
  253. package/dist/features/index.d.ts.map +1 -0
  254. package/dist/features/index.js +78 -0
  255. package/dist/features/index.js.map +1 -0
  256. package/dist/features/registry.d.ts +51 -0
  257. package/dist/features/registry.d.ts.map +1 -0
  258. package/dist/features/registry.js +52 -0
  259. package/dist/features/registry.js.map +1 -0
  260. package/dist/features/service.d.ts +78 -0
  261. package/dist/features/service.d.ts.map +1 -0
  262. package/dist/features/service.js +207 -0
  263. package/dist/features/service.js.map +1 -0
  264. package/dist/files/index.d.ts +6 -0
  265. package/dist/files/index.d.ts.map +1 -0
  266. package/dist/files/index.js +64 -0
  267. package/dist/files/index.js.map +1 -0
  268. package/dist/files/service.d.ts +92 -0
  269. package/dist/files/service.d.ts.map +1 -0
  270. package/dist/files/service.js +303 -0
  271. package/dist/files/service.js.map +1 -0
  272. package/dist/index.d.ts +33 -0
  273. package/dist/index.d.ts.map +1 -0
  274. package/dist/index.js +33 -0
  275. package/dist/index.js.map +1 -0
  276. package/dist/jobs/backend.d.ts +23 -0
  277. package/dist/jobs/backend.d.ts.map +1 -0
  278. package/dist/jobs/backend.js +23 -0
  279. package/dist/jobs/backend.js.map +1 -0
  280. package/dist/jobs/index.d.ts +29 -0
  281. package/dist/jobs/index.d.ts.map +1 -0
  282. package/dist/jobs/index.js +114 -0
  283. package/dist/jobs/index.js.map +1 -0
  284. package/dist/jobs/service.d.ts +67 -0
  285. package/dist/jobs/service.d.ts.map +1 -0
  286. package/dist/jobs/service.js +139 -0
  287. package/dist/jobs/service.js.map +1 -0
  288. package/dist/jobs/types.d.ts +78 -0
  289. package/dist/jobs/types.d.ts.map +1 -0
  290. package/dist/jobs/types.js +4 -0
  291. package/dist/jobs/types.js.map +1 -0
  292. package/dist/logger/default.d.ts +7 -0
  293. package/dist/logger/default.d.ts.map +1 -0
  294. package/dist/logger/default.js +28 -0
  295. package/dist/logger/default.js.map +1 -0
  296. package/dist/logger/index.d.ts +24 -0
  297. package/dist/logger/index.d.ts.map +1 -0
  298. package/dist/logger/index.js +90 -0
  299. package/dist/logger/index.js.map +1 -0
  300. package/dist/logger/redact.d.ts +40 -0
  301. package/dist/logger/redact.d.ts.map +1 -0
  302. package/dist/logger/redact.js +178 -0
  303. package/dist/logger/redact.js.map +1 -0
  304. package/dist/logger/service.d.ts +14 -0
  305. package/dist/logger/service.d.ts.map +1 -0
  306. package/dist/logger/service.js +56 -0
  307. package/dist/logger/service.js.map +1 -0
  308. package/dist/logger/sinks.d.ts +37 -0
  309. package/dist/logger/sinks.d.ts.map +1 -0
  310. package/dist/logger/sinks.js +135 -0
  311. package/dist/logger/sinks.js.map +1 -0
  312. package/dist/logger/types.d.ts +47 -0
  313. package/dist/logger/types.d.ts.map +1 -0
  314. package/dist/logger/types.js +8 -0
  315. package/dist/logger/types.js.map +1 -0
  316. package/dist/notifications/index.d.ts +8 -0
  317. package/dist/notifications/index.d.ts.map +1 -0
  318. package/dist/notifications/index.js +72 -0
  319. package/dist/notifications/index.js.map +1 -0
  320. package/dist/notifications/service.d.ts +79 -0
  321. package/dist/notifications/service.d.ts.map +1 -0
  322. package/dist/notifications/service.js +164 -0
  323. package/dist/notifications/service.js.map +1 -0
  324. package/dist/realtime/channels.d.ts +37 -0
  325. package/dist/realtime/channels.d.ts.map +1 -0
  326. package/dist/realtime/channels.js +58 -0
  327. package/dist/realtime/channels.js.map +1 -0
  328. package/dist/realtime/index.d.ts +19 -0
  329. package/dist/realtime/index.d.ts.map +1 -0
  330. package/dist/realtime/index.js +118 -0
  331. package/dist/realtime/index.js.map +1 -0
  332. package/dist/realtime/postgres.d.ts +48 -0
  333. package/dist/realtime/postgres.d.ts.map +1 -0
  334. package/dist/realtime/postgres.js +151 -0
  335. package/dist/realtime/postgres.js.map +1 -0
  336. package/dist/realtime/service.d.ts +75 -0
  337. package/dist/realtime/service.d.ts.map +1 -0
  338. package/dist/realtime/service.js +103 -0
  339. package/dist/realtime/service.js.map +1 -0
  340. package/dist/realtime/sse.d.ts +55 -0
  341. package/dist/realtime/sse.d.ts.map +1 -0
  342. package/dist/realtime/sse.js +123 -0
  343. package/dist/realtime/sse.js.map +1 -0
  344. package/dist/realtime/transport.d.ts +52 -0
  345. package/dist/realtime/transport.d.ts.map +1 -0
  346. package/dist/realtime/transport.js +2 -0
  347. package/dist/realtime/transport.js.map +1 -0
  348. package/dist/storage/index.d.ts +18 -0
  349. package/dist/storage/index.d.ts.map +1 -0
  350. package/dist/storage/index.js +89 -0
  351. package/dist/storage/index.js.map +1 -0
  352. package/dist/storage/keys.d.ts +50 -0
  353. package/dist/storage/keys.d.ts.map +1 -0
  354. package/dist/storage/keys.js +120 -0
  355. package/dist/storage/keys.js.map +1 -0
  356. package/dist/storage/memory.d.ts +32 -0
  357. package/dist/storage/memory.d.ts.map +1 -0
  358. package/dist/storage/memory.js +84 -0
  359. package/dist/storage/memory.js.map +1 -0
  360. package/dist/storage/provider.d.ts +93 -0
  361. package/dist/storage/provider.d.ts.map +1 -0
  362. package/dist/storage/provider.js +2 -0
  363. package/dist/storage/provider.js.map +1 -0
  364. package/dist/storage/s3.d.ts +34 -0
  365. package/dist/storage/s3.d.ts.map +1 -0
  366. package/dist/storage/s3.js +175 -0
  367. package/dist/storage/s3.js.map +1 -0
  368. package/dist/storage/service.d.ts +86 -0
  369. package/dist/storage/service.d.ts.map +1 -0
  370. package/dist/storage/service.js +107 -0
  371. package/dist/storage/service.js.map +1 -0
  372. package/dist/storage/sigv4.d.ts +58 -0
  373. package/dist/storage/sigv4.d.ts.map +1 -0
  374. package/dist/storage/sigv4.js +114 -0
  375. package/dist/storage/sigv4.js.map +1 -0
  376. package/dist/streams/client.d.ts +91 -0
  377. package/dist/streams/client.d.ts.map +1 -0
  378. package/dist/streams/client.js +128 -0
  379. package/dist/streams/client.js.map +1 -0
  380. package/dist/streams/events.d.ts +68 -0
  381. package/dist/streams/events.d.ts.map +1 -0
  382. package/dist/streams/events.js +81 -0
  383. package/dist/streams/events.js.map +1 -0
  384. package/dist/streams/index.d.ts +47 -0
  385. package/dist/streams/index.d.ts.map +1 -0
  386. package/dist/streams/index.js +47 -0
  387. package/dist/streams/index.js.map +1 -0
  388. package/dist/streams/realtime.d.ts +27 -0
  389. package/dist/streams/realtime.d.ts.map +1 -0
  390. package/dist/streams/realtime.js +50 -0
  391. package/dist/streams/realtime.js.map +1 -0
  392. package/dist/streams/state.d.ts +26 -0
  393. package/dist/streams/state.d.ts.map +1 -0
  394. package/dist/streams/state.js +34 -0
  395. package/dist/streams/state.js.map +1 -0
  396. package/dist/users/index.d.ts +9 -0
  397. package/dist/users/index.d.ts.map +1 -0
  398. package/dist/users/index.js +23 -0
  399. package/dist/users/index.js.map +1 -0
  400. package/dist/users/service.d.ts +43 -0
  401. package/dist/users/service.d.ts.map +1 -0
  402. package/dist/users/service.js +113 -0
  403. package/dist/users/service.js.map +1 -0
  404. package/dist/webhooks/inbound.d.ts +70 -0
  405. package/dist/webhooks/inbound.d.ts.map +1 -0
  406. package/dist/webhooks/inbound.js +146 -0
  407. package/dist/webhooks/inbound.js.map +1 -0
  408. package/dist/webhooks/index.d.ts +12 -0
  409. package/dist/webhooks/index.d.ts.map +1 -0
  410. package/dist/webhooks/index.js +65 -0
  411. package/dist/webhooks/index.js.map +1 -0
  412. package/dist/webhooks/outgoing.d.ts +89 -0
  413. package/dist/webhooks/outgoing.d.ts.map +1 -0
  414. package/dist/webhooks/outgoing.js +375 -0
  415. package/dist/webhooks/outgoing.js.map +1 -0
  416. package/dist/webhooks/signature.d.ts +40 -0
  417. package/dist/webhooks/signature.d.ts.map +1 -0
  418. package/dist/webhooks/signature.js +77 -0
  419. package/dist/webhooks/signature.js.map +1 -0
  420. package/dist/workspaces/context.d.ts +30 -0
  421. package/dist/workspaces/context.d.ts.map +1 -0
  422. package/dist/workspaces/context.js +12 -0
  423. package/dist/workspaces/context.js.map +1 -0
  424. package/dist/workspaces/index.d.ts +5 -0
  425. package/dist/workspaces/index.d.ts.map +1 -0
  426. package/dist/workspaces/index.js +21 -0
  427. package/dist/workspaces/index.js.map +1 -0
  428. package/dist/workspaces/service.d.ts +126 -0
  429. package/dist/workspaces/service.d.ts.map +1 -0
  430. package/dist/workspaces/service.js +495 -0
  431. package/dist/workspaces/service.js.map +1 -0
  432. package/docs/README.md +71 -0
  433. package/docs/api-keys.md +184 -0
  434. package/docs/audit.md +198 -0
  435. package/docs/auth.md +196 -0
  436. package/docs/authorization.md +225 -0
  437. package/docs/billing.md +293 -0
  438. package/docs/cli.md +238 -0
  439. package/docs/config.md +163 -0
  440. package/docs/db.md +219 -0
  441. package/docs/email.md +222 -0
  442. package/docs/entitlements.md +194 -0
  443. package/docs/errors.md +158 -0
  444. package/docs/events.md +279 -0
  445. package/docs/feature-flags.md +237 -0
  446. package/docs/files.md +229 -0
  447. package/docs/jobs.md +288 -0
  448. package/docs/logger.md +269 -0
  449. package/docs/notifications.md +179 -0
  450. package/docs/publishing.md +128 -0
  451. package/docs/realtime.md +360 -0
  452. package/docs/storage.md +279 -0
  453. package/docs/streams.md +296 -0
  454. package/docs/users.md +117 -0
  455. package/docs/webhooks.md +272 -0
  456. package/docs/workspaces.md +269 -0
  457. package/drizzle/0000_init_users.sql +21 -0
  458. package/drizzle/0001_workspaces_roles_permissions.sql +86 -0
  459. package/drizzle/0002_billing_entitlements.sql +97 -0
  460. package/drizzle/0003_events.sql +17 -0
  461. package/drizzle/0004_notifications_audit.sql +64 -0
  462. package/drizzle/0005_api_keys_webhooks.sql +77 -0
  463. package/drizzle/0006_feature_flags.sql +22 -0
  464. package/drizzle/0007_files.sql +23 -0
  465. package/drizzle/meta/0000_snapshot.json +160 -0
  466. package/drizzle/meta/0001_snapshot.json +837 -0
  467. package/drizzle/meta/0002_snapshot.json +1580 -0
  468. package/drizzle/meta/0003_snapshot.json +1751 -0
  469. package/drizzle/meta/0004_snapshot.json +2109 -0
  470. package/drizzle/meta/0005_snapshot.json +2719 -0
  471. package/drizzle/meta/0006_snapshot.json +2909 -0
  472. package/drizzle/meta/0007_snapshot.json +3113 -0
  473. package/drizzle/meta/_journal.json +62 -0
  474. package/package.json +180 -0
@@ -0,0 +1,91 @@
1
+ import { Observable } from "rxjs";
2
+ /**
3
+ * Client-side realtime, as an Observable over the SSE endpoint.
4
+ *
5
+ * Deliberately standalone: this module imports nothing from the server half of
6
+ * the package — no config, no database, no transport. It runs in a browser, and a
7
+ * shared import would drag server code into the bundle.
8
+ *
9
+ * It is also the *shared* abstraction the architecture calls for. Every component
10
+ * piping this one stream beats each of them opening its own `EventSource`: one
11
+ * connection, one reconnect policy, one place to reason about ordering.
12
+ */
13
+ /** The subset of `EventSource` this module uses. */
14
+ export interface EventSourceLike {
15
+ addEventListener(type: string, listener: (event: MessageEventLike) => void): void;
16
+ close(): void;
17
+ readonly readyState?: number;
18
+ }
19
+ export interface MessageEventLike {
20
+ readonly data?: unknown;
21
+ readonly lastEventId?: string;
22
+ }
23
+ /** A realtime message as it arrives in the browser. */
24
+ export interface ClientRealtimeMessage {
25
+ readonly channel: string;
26
+ readonly eventId: string;
27
+ readonly type: string;
28
+ readonly occurredAt: string;
29
+ readonly data?: unknown;
30
+ /** True when the payload was too large to carry; re-read the event by id. */
31
+ readonly truncated?: boolean;
32
+ }
33
+ export interface EventStreamSourceOptions {
34
+ /** Endpoint serving the stream, e.g. `/api/realtime`. */
35
+ readonly url: string;
36
+ /** Channels to request. Appended as repeated `channel` query parameters. */
37
+ readonly channels: readonly string[];
38
+ /**
39
+ * Event types to listen for.
40
+ *
41
+ * Required because SSE dispatches by event name, and the server names each
42
+ * frame after the event type. Listening for `message` alone would receive
43
+ * nothing.
44
+ */
45
+ readonly types: readonly string[];
46
+ /**
47
+ * Construct the underlying source. Defaults to the global `EventSource`.
48
+ * Injectable so reconnect behaviour is testable without a browser.
49
+ */
50
+ readonly createSource?: (url: string) => EventSourceLike;
51
+ /** First reconnect delay, doubling up to {@link maxRetryDelayMs}. */
52
+ readonly initialRetryDelayMs?: number;
53
+ readonly maxRetryDelayMs?: number;
54
+ /** Called on every transport error, before the reconnect is scheduled. */
55
+ readonly onError?: (error: unknown) => void;
56
+ /** Injectable clock, so tests need no real waiting. */
57
+ readonly setTimeoutImpl?: (handler: () => void, ms: number) => unknown;
58
+ readonly clearTimeoutImpl?: (handle: unknown) => void;
59
+ }
60
+ export declare function buildStreamUrl(url: string, channels: readonly string[]): string;
61
+ /**
62
+ * Subscribe to the server's SSE endpoint, reconnecting with exponential backoff.
63
+ *
64
+ * ```ts
65
+ * const events$ = fromEventStream({
66
+ * url: "/api/realtime",
67
+ * channels: [`workspace:${workspaceId}`],
68
+ * types: ["project.created", "job.progress"],
69
+ * });
70
+ *
71
+ * const sub = events$.pipe(
72
+ * filter((message) => message.type === "job.progress"),
73
+ * map((message) => message.data as { percent?: number }),
74
+ * distinctUntilChanged((a, b) => a.percent === b.percent),
75
+ * ).subscribe(render);
76
+ *
77
+ * // Every subscription needs a lifecycle. In React, this is the effect cleanup.
78
+ * return () => sub.unsubscribe();
79
+ * ```
80
+ *
81
+ * The Observable never completes on its own — a realtime stream has no natural
82
+ * end. It stays open until unsubscribed, so bound it with `takeUntil` if
83
+ * something else should end it.
84
+ *
85
+ * Errors do **not** terminate the stream. A dropped connection is expected, not
86
+ * exceptional: it is reported through `onError` and then retried, because
87
+ * surfacing it as an RxJS error would tear down every downstream operator and
88
+ * lose the subscriber's accumulated state on a transient blip.
89
+ */
90
+ export declare function fromEventStream(options: EventStreamSourceOptions): Observable<ClientRealtimeMessage>;
91
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/streams/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiB,MAAM,MAAM,CAAC;AAEjD;;;;;;;;;;GAUG;AAEH,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,IAAI,CAAC;IAClF,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,uDAAuD;AACvD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,yDAAyD;IACzD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,eAAe,CAAC;IACzD,qEAAqE;IACrE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,uDAAuD;IACvD,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACvE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CACvD;AAKD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAQ/E;AAyBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,wBAAwB,GAChC,UAAU,CAAC,qBAAqB,CAAC,CAgFnC"}
@@ -0,0 +1,128 @@
1
+ import { Observable } from "rxjs";
2
+ const DEFAULT_INITIAL_RETRY_MS = 1_000;
3
+ const DEFAULT_MAX_RETRY_MS = 30_000;
4
+ export function buildStreamUrl(url, channels) {
5
+ // Relative endpoints are normal in a browser, so a base is supplied and then
6
+ // discarded rather than requiring an absolute URL.
7
+ const parsed = new URL(url, "http://local");
8
+ for (const channel of channels) {
9
+ parsed.searchParams.append("channel", channel);
10
+ }
11
+ return url.startsWith("http") ? parsed.toString() : `${parsed.pathname}${parsed.search}`;
12
+ }
13
+ function parseMessage(raw) {
14
+ if (typeof raw !== "string") {
15
+ return undefined;
16
+ }
17
+ try {
18
+ const parsed = JSON.parse(raw);
19
+ // Validated, not cast: this crossed the network.
20
+ if (typeof parsed.channel !== "string" ||
21
+ typeof parsed.eventId !== "string" ||
22
+ typeof parsed.type !== "string" ||
23
+ typeof parsed.occurredAt !== "string") {
24
+ return undefined;
25
+ }
26
+ return parsed;
27
+ }
28
+ catch {
29
+ return undefined;
30
+ }
31
+ }
32
+ /**
33
+ * Subscribe to the server's SSE endpoint, reconnecting with exponential backoff.
34
+ *
35
+ * ```ts
36
+ * const events$ = fromEventStream({
37
+ * url: "/api/realtime",
38
+ * channels: [`workspace:${workspaceId}`],
39
+ * types: ["project.created", "job.progress"],
40
+ * });
41
+ *
42
+ * const sub = events$.pipe(
43
+ * filter((message) => message.type === "job.progress"),
44
+ * map((message) => message.data as { percent?: number }),
45
+ * distinctUntilChanged((a, b) => a.percent === b.percent),
46
+ * ).subscribe(render);
47
+ *
48
+ * // Every subscription needs a lifecycle. In React, this is the effect cleanup.
49
+ * return () => sub.unsubscribe();
50
+ * ```
51
+ *
52
+ * The Observable never completes on its own — a realtime stream has no natural
53
+ * end. It stays open until unsubscribed, so bound it with `takeUntil` if
54
+ * something else should end it.
55
+ *
56
+ * Errors do **not** terminate the stream. A dropped connection is expected, not
57
+ * exceptional: it is reported through `onError` and then retried, because
58
+ * surfacing it as an RxJS error would tear down every downstream operator and
59
+ * lose the subscriber's accumulated state on a transient blip.
60
+ */
61
+ export function fromEventStream(options) {
62
+ const initialDelay = options.initialRetryDelayMs ?? DEFAULT_INITIAL_RETRY_MS;
63
+ const maxDelay = options.maxRetryDelayMs ?? DEFAULT_MAX_RETRY_MS;
64
+ const schedule = options.setTimeoutImpl ?? ((handler, ms) => setTimeout(handler, ms));
65
+ const cancel = options.clearTimeoutImpl ?? ((handle) => clearTimeout(handle));
66
+ const createSource = options.createSource ??
67
+ ((url) => {
68
+ const Ctor = globalThis
69
+ .EventSource;
70
+ if (Ctor === undefined) {
71
+ throw new Error("No EventSource available. Pass `createSource` when running outside a browser.");
72
+ }
73
+ return new Ctor(url);
74
+ });
75
+ const url = buildStreamUrl(options.url, options.channels);
76
+ return new Observable((subscriber) => {
77
+ let source;
78
+ let retryHandle;
79
+ let delay = initialDelay;
80
+ let stopped = false;
81
+ const connect = () => {
82
+ if (stopped) {
83
+ return;
84
+ }
85
+ try {
86
+ source = createSource(url);
87
+ }
88
+ catch (error) {
89
+ // Cannot construct a source at all — a configuration fault, not a blip.
90
+ subscriber.error(error);
91
+ return;
92
+ }
93
+ for (const type of options.types) {
94
+ source.addEventListener(type, (event) => {
95
+ const message = parseMessage(event.data);
96
+ if (message === undefined) {
97
+ options.onError?.(new Error(`Discarded a malformed "${type}" frame.`));
98
+ return;
99
+ }
100
+ // A frame arrived, so the connection is healthy; reset the backoff.
101
+ delay = initialDelay;
102
+ subscriber.next(message);
103
+ });
104
+ }
105
+ source.addEventListener("error", (event) => {
106
+ options.onError?.(event);
107
+ if (stopped) {
108
+ return;
109
+ }
110
+ source?.close();
111
+ source = undefined;
112
+ retryHandle = schedule(connect, delay);
113
+ // Doubling, capped. Unbounded retries would hammer a recovering server.
114
+ delay = Math.min(delay * 2, maxDelay);
115
+ });
116
+ };
117
+ connect();
118
+ return () => {
119
+ stopped = true;
120
+ if (retryHandle !== undefined) {
121
+ cancel(retryHandle);
122
+ }
123
+ source?.close();
124
+ source = undefined;
125
+ };
126
+ });
127
+ }
128
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/streams/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { Observable, type MonoTypeOperatorFunction, type OperatorFunction } from "rxjs";
2
+ import type { EventSchemaMap, EventTypeOf, SaasEvent, SaasEventOf } from "../events/registry.ts";
3
+ import type { EventsService } from "../events/service.ts";
4
+ /**
5
+ * An Observable of application events, from the in-process dispatcher.
6
+ *
7
+ * Streams, not promises: a sequence of events over time is exactly what an
8
+ * Observable is for. Nothing else in the core returns one — a one-shot database
9
+ * read stays a promise, because wrapping it would add a lifecycle to manage for
10
+ * no benefit.
11
+ *
12
+ * ## Lifecycle
13
+ *
14
+ * The events subscription is created when the Observable is subscribed and torn
15
+ * down when it is unsubscribed. Nothing is registered before the first
16
+ * subscriber, and nothing lingers after the last one — so a caller that forgets
17
+ * `takeUntil` leaks one handler, not a growing set.
18
+ *
19
+ * ## What this is not
20
+ *
21
+ * Not durable. A crash loses the reaction, not the event, because the event is
22
+ * already committed. Anything that must survive a restart belongs in
23
+ * `@digimuza/saas-core/jobs`, reading the persisted row — never in an operator's
24
+ * accumulated state.
25
+ */
26
+ export declare function fromEvents<S extends EventSchemaMap>(events: EventsService<S>): Observable<SaasEvent<S>>;
27
+ /**
28
+ * Narrow a stream to one or more event types, in the type system as well as at
29
+ * runtime.
30
+ *
31
+ * ```ts
32
+ * fromEvents(events).pipe(
33
+ * ofType("project.created", "project.deleted"),
34
+ * map((event) => event.data.projectId), // narrowed to those two payloads
35
+ * );
36
+ * ```
37
+ *
38
+ * A plain `filter((e) => e.type === "project.created")` would filter correctly
39
+ * but leave `data` as the union of every payload in the registry, so every
40
+ * downstream operator would need a cast.
41
+ */
42
+ export declare function ofType<S extends EventSchemaMap, const K extends readonly EventTypeOf<S>[]>(...types: K): OperatorFunction<SaasEvent<S>, SaasEventOf<S, K[number]>>;
43
+ /**
44
+ * Keep only events belonging to one workspace.
45
+ *
46
+ * A server-side stream sees every workspace's events, because the in-process
47
+ * dispatcher is process-wide. This is the filter that makes a per-tenant stream
48
+ * out of it — and it is *not* an authorization boundary. The caller must already
49
+ * hold a verified `WorkspaceContext`; see `workspaces.requireContext`.
50
+ */
51
+ export declare function inWorkspace<T extends {
52
+ readonly workspaceId: string | null;
53
+ }>(workspaceId: string): MonoTypeOperatorFunction<T>;
54
+ /** Keep only events caused by one actor. */
55
+ export declare function byActor<T extends {
56
+ readonly actorId: string | null;
57
+ }>(actorId: string): MonoTypeOperatorFunction<T>;
58
+ /**
59
+ * Project each event down to its payload.
60
+ *
61
+ * The type parameter is inferred from the *source*, not supplied by the caller —
62
+ * declaring it over the registry and the event key would leave both unbound at
63
+ * the call site and collapse `data` to `unknown`.
64
+ */
65
+ export declare function toData<E extends {
66
+ readonly data: unknown;
67
+ }>(): OperatorFunction<E, E["data"]>;
68
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/streams/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,wBAAwB,EAAE,KAAK,gBAAgB,EAAE,MAAM,MAAM,CAAC;AAGxF,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACjG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,cAAc,EACjD,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GACvB,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAW1B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,cAAc,EAAE,KAAK,CAAC,CAAC,SAAS,SAAS,WAAW,CAAC,CAAC,CAAC,EAAE,EACxF,GAAG,KAAK,EAAE,CAAC,GACV,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAM3D;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC3E,WAAW,EAAE,MAAM,GAClB,wBAAwB,CAAC,CAAC,CAAC,CAE7B;AAED,4CAA4C;AAC5C,wBAAgB,OAAO,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACnE,OAAO,EAAE,MAAM,GACd,wBAAwB,CAAC,CAAC,CAAC,CAE7B;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,KAAK,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAE7F"}
@@ -0,0 +1,81 @@
1
+ import { Observable } from "rxjs";
2
+ import { filter, map } from "rxjs/operators";
3
+ /**
4
+ * An Observable of application events, from the in-process dispatcher.
5
+ *
6
+ * Streams, not promises: a sequence of events over time is exactly what an
7
+ * Observable is for. Nothing else in the core returns one — a one-shot database
8
+ * read stays a promise, because wrapping it would add a lifecycle to manage for
9
+ * no benefit.
10
+ *
11
+ * ## Lifecycle
12
+ *
13
+ * The events subscription is created when the Observable is subscribed and torn
14
+ * down when it is unsubscribed. Nothing is registered before the first
15
+ * subscriber, and nothing lingers after the last one — so a caller that forgets
16
+ * `takeUntil` leaks one handler, not a growing set.
17
+ *
18
+ * ## What this is not
19
+ *
20
+ * Not durable. A crash loses the reaction, not the event, because the event is
21
+ * already committed. Anything that must survive a restart belongs in
22
+ * `@digimuza/saas-core/jobs`, reading the persisted row — never in an operator's
23
+ * accumulated state.
24
+ */
25
+ export function fromEvents(events) {
26
+ return new Observable((subscriber) => {
27
+ /**
28
+ * `onAny` returns its own unsubscribe, which is returned as the teardown —
29
+ * so RxJS's own lifecycle drives the handler's, and there is one place where
30
+ * it is removed.
31
+ */
32
+ return events.onAny((event) => {
33
+ subscriber.next(event);
34
+ });
35
+ });
36
+ }
37
+ /**
38
+ * Narrow a stream to one or more event types, in the type system as well as at
39
+ * runtime.
40
+ *
41
+ * ```ts
42
+ * fromEvents(events).pipe(
43
+ * ofType("project.created", "project.deleted"),
44
+ * map((event) => event.data.projectId), // narrowed to those two payloads
45
+ * );
46
+ * ```
47
+ *
48
+ * A plain `filter((e) => e.type === "project.created")` would filter correctly
49
+ * but leave `data` as the union of every payload in the registry, so every
50
+ * downstream operator would need a cast.
51
+ */
52
+ export function ofType(...types) {
53
+ const wanted = new Set(types);
54
+ return (source) => source.pipe(filter((event) => wanted.has(event.type)));
55
+ }
56
+ /**
57
+ * Keep only events belonging to one workspace.
58
+ *
59
+ * A server-side stream sees every workspace's events, because the in-process
60
+ * dispatcher is process-wide. This is the filter that makes a per-tenant stream
61
+ * out of it — and it is *not* an authorization boundary. The caller must already
62
+ * hold a verified `WorkspaceContext`; see `workspaces.requireContext`.
63
+ */
64
+ export function inWorkspace(workspaceId) {
65
+ return filter((value) => value.workspaceId === workspaceId);
66
+ }
67
+ /** Keep only events caused by one actor. */
68
+ export function byActor(actorId) {
69
+ return filter((value) => value.actorId === actorId);
70
+ }
71
+ /**
72
+ * Project each event down to its payload.
73
+ *
74
+ * The type parameter is inferred from the *source*, not supplied by the caller —
75
+ * declaring it over the registry and the event key would leave both unbound at
76
+ * the call site and collapse `data` to `unknown`.
77
+ */
78
+ export function toData() {
79
+ return map((event) => event.data);
80
+ }
81
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/streams/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAwD,MAAM,MAAM,CAAC;AACxF,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAK7C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,UAAU,CACxB,MAAwB;IAExB,OAAO,IAAI,UAAU,CAAe,CAAC,UAAU,EAAE,EAAE;QACjD;;;;WAIG;QACH,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAC5B,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,MAAM,CACpB,GAAG,KAAQ;IAEX,MAAM,MAAM,GAAG,IAAI,GAAG,CAAS,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,MAAM,EAAE,EAAE,CAChB,MAAM,CAAC,IAAI,CACT,MAAM,CAAC,CAAC,KAAK,EAAsC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAC9E,CAAC;AACN,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,WAAmB;IAEnB,OAAO,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,KAAK,WAAW,CAAC,CAAC;AAC9D,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,OAAO,CACrB,OAAe;IAEf,OAAO,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,MAAM;IACpB,OAAO,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Public streams surface: `@digimuza/saas-core/streams`. Server-only.
3
+ *
4
+ * RxJS is where *reactive behaviour* lives — filtering, combining, debouncing,
5
+ * aggregating, coordinating. It is deliberately none of the other things:
6
+ *
7
+ * - not the database (a one-shot read stays a promise);
8
+ * - not the durable job system (a crash loses a reaction, not an event);
9
+ * - not the realtime transport (that is `@digimuza/saas-core/realtime`).
10
+ *
11
+ * ```
12
+ * event sources → application events → Observable → reactor → application/client
13
+ * ```
14
+ *
15
+ * ## Server-side
16
+ *
17
+ * ```ts
18
+ * import { fromEvents, ofType, inWorkspace } from "@digimuza/saas-core/streams";
19
+ * import { events } from "@digimuza/saas-core/events";
20
+ * import { debounceTime, takeUntil } from "rxjs/operators";
21
+ *
22
+ * const subscription = fromEvents(events)
23
+ * .pipe(
24
+ * inWorkspace(context.workspaceId),
25
+ * ofType("project.updated"),
26
+ * debounceTime(500),
27
+ * takeUntil(shutdown$), // every subscription needs a lifecycle
28
+ * )
29
+ * .subscribe(reindexProject);
30
+ * ```
31
+ *
32
+ * ## Browser
33
+ *
34
+ * `@digimuza/saas-core/streams/client` reads the SSE endpoint instead, and imports
35
+ * nothing from the server half of this package.
36
+ *
37
+ * ## The rule this module exists to respect
38
+ *
39
+ * Promises for one-time work, Observables for sequences over time. Nothing here
40
+ * converts a synchronous or single-shot API into a stream — `getDatabase()` is not
41
+ * an Observable, and `workspaces.get()` never will be.
42
+ */
43
+ export { byActor, fromEvents, inWorkspace, ofType, toData, } from "./events.ts";
44
+ export { fromRealtime, type RealtimeStreamOptions } from "./realtime.ts";
45
+ export { latestByKey } from "./state.ts";
46
+ export { buildStreamUrl, fromEventStream, type ClientRealtimeMessage, type EventSourceLike, type EventStreamSourceOptions, type MessageEventLike, } from "./client.ts";
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/streams/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,OAAO,EACL,OAAO,EACP,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,GACP,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Public streams surface: `@digimuza/saas-core/streams`. Server-only.
3
+ *
4
+ * RxJS is where *reactive behaviour* lives — filtering, combining, debouncing,
5
+ * aggregating, coordinating. It is deliberately none of the other things:
6
+ *
7
+ * - not the database (a one-shot read stays a promise);
8
+ * - not the durable job system (a crash loses a reaction, not an event);
9
+ * - not the realtime transport (that is `@digimuza/saas-core/realtime`).
10
+ *
11
+ * ```
12
+ * event sources → application events → Observable → reactor → application/client
13
+ * ```
14
+ *
15
+ * ## Server-side
16
+ *
17
+ * ```ts
18
+ * import { fromEvents, ofType, inWorkspace } from "@digimuza/saas-core/streams";
19
+ * import { events } from "@digimuza/saas-core/events";
20
+ * import { debounceTime, takeUntil } from "rxjs/operators";
21
+ *
22
+ * const subscription = fromEvents(events)
23
+ * .pipe(
24
+ * inWorkspace(context.workspaceId),
25
+ * ofType("project.updated"),
26
+ * debounceTime(500),
27
+ * takeUntil(shutdown$), // every subscription needs a lifecycle
28
+ * )
29
+ * .subscribe(reindexProject);
30
+ * ```
31
+ *
32
+ * ## Browser
33
+ *
34
+ * `@digimuza/saas-core/streams/client` reads the SSE endpoint instead, and imports
35
+ * nothing from the server half of this package.
36
+ *
37
+ * ## The rule this module exists to respect
38
+ *
39
+ * Promises for one-time work, Observables for sequences over time. Nothing here
40
+ * converts a synchronous or single-shot API into a stream — `getDatabase()` is not
41
+ * an Observable, and `workspaces.get()` never will be.
42
+ */
43
+ export { byActor, fromEvents, inWorkspace, ofType, toData, } from "./events.js";
44
+ export { fromRealtime } from "./realtime.js";
45
+ export { latestByKey } from "./state.js";
46
+ export { buildStreamUrl, fromEventStream, } from "./client.js";
47
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/streams/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,OAAO,EACL,OAAO,EACP,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,GACP,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAA8B,MAAM,eAAe,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EACL,cAAc,EACd,eAAe,GAKhB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { Observable } from "rxjs";
2
+ import type { RealtimeService } from "../realtime/service.ts";
3
+ import type { RealtimeMessage } from "../realtime/transport.ts";
4
+ export interface RealtimeStreamOptions {
5
+ /** Resolved from the session. Never from a request body. */
6
+ readonly userId: string;
7
+ /** Requested channels. Unauthorized ones are dropped, not thrown on. */
8
+ readonly channels: readonly string[];
9
+ }
10
+ /**
11
+ * An Observable of authorized realtime messages.
12
+ *
13
+ * The stream a *server* uses to react to delivery — a reactor coordinating
14
+ * behaviour across tenants, say. A browser should use
15
+ * `@digimuza/saas-core/streams/client` instead, which reads the SSE endpoint
16
+ * rather than subscribing to the transport directly.
17
+ *
18
+ * ## Authorization happens once, on subscribe
19
+ *
20
+ * `realtime.subscribe` verifies channel access before opening anything, so a
21
+ * subscriber never receives a channel it was not granted. Because that check is
22
+ * asynchronous and this is a synchronous Observable constructor, a subscriber
23
+ * that unsubscribes during the check is honoured: the subscription is closed
24
+ * immediately rather than left open until the next message.
25
+ */
26
+ export declare function fromRealtime(realtime: RealtimeService, options: RealtimeStreamOptions): Observable<RealtimeMessage>;
27
+ //# sourceMappingURL=realtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../src/streams/realtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,MAAM,WAAW,qBAAqB;IACpC,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,qBAAqB,GAC7B,UAAU,CAAC,eAAe,CAAC,CAkC7B"}
@@ -0,0 +1,50 @@
1
+ import { Observable } from "rxjs";
2
+ /**
3
+ * An Observable of authorized realtime messages.
4
+ *
5
+ * The stream a *server* uses to react to delivery — a reactor coordinating
6
+ * behaviour across tenants, say. A browser should use
7
+ * `@digimuza/saas-core/streams/client` instead, which reads the SSE endpoint
8
+ * rather than subscribing to the transport directly.
9
+ *
10
+ * ## Authorization happens once, on subscribe
11
+ *
12
+ * `realtime.subscribe` verifies channel access before opening anything, so a
13
+ * subscriber never receives a channel it was not granted. Because that check is
14
+ * asynchronous and this is a synchronous Observable constructor, a subscriber
15
+ * that unsubscribes during the check is honoured: the subscription is closed
16
+ * immediately rather than left open until the next message.
17
+ */
18
+ export function fromRealtime(realtime, options) {
19
+ return new Observable((subscriber) => {
20
+ let closed = false;
21
+ let close;
22
+ void realtime
23
+ .subscribe({
24
+ userId: options.userId,
25
+ channels: options.channels,
26
+ onMessage: (message) => {
27
+ subscriber.next(message);
28
+ },
29
+ })
30
+ .then((subscription) => {
31
+ close = () => subscription.close();
32
+ /**
33
+ * Unsubscribed while authorization was in flight. Without this the
34
+ * transport subscription would stay open with nobody listening, holding a
35
+ * listener slot for the lifetime of the process.
36
+ */
37
+ if (closed) {
38
+ void subscription.close();
39
+ }
40
+ })
41
+ .catch((error) => {
42
+ subscriber.error(error);
43
+ });
44
+ return () => {
45
+ closed = true;
46
+ void close?.();
47
+ };
48
+ });
49
+ }
50
+ //# sourceMappingURL=realtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.js","sourceRoot":"","sources":["../../src/streams/realtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAYlC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,YAAY,CAC1B,QAAyB,EACzB,OAA8B;IAE9B,OAAO,IAAI,UAAU,CAAkB,CAAC,UAAU,EAAE,EAAE;QACpD,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,KAAwC,CAAC;QAE7C,KAAK,QAAQ;aACV,SAAS,CAAC;YACT,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;gBACrB,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,CAAC;SACF,CAAC;aACD,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE;YACrB,KAAK,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YAEnC;;;;eAIG;YACH,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,YAAY,CAAC,KAAK,EAAE,CAAC;YAC5B,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACxB,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,MAAM,GAAG,IAAI,CAAC;YACd,KAAK,KAAK,EAAE,EAAE,CAAC;QACjB,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { Observable } from "rxjs";
2
+ /**
3
+ * Accumulate a stream into "the latest value per key".
4
+ *
5
+ * The one reactive-state shape worth wrapping, because the sharing is easy to get
6
+ * wrong: without `shareReplay`, every new subscriber re-runs the scan from an
7
+ * empty map and sees nothing until the next event arrives.
8
+ *
9
+ * ```ts
10
+ * const progress$ = latestByKey(jobEvents$, (event) => event.data.runId);
11
+ * // Observable<ReadonlyMap<string, JobEvent>> — every run's most recent update.
12
+ * ```
13
+ *
14
+ * `refCount: true` discards the accumulated map when the last subscriber leaves.
15
+ * Deliberate: a cache outliving its subscribers is a leak, and this is a *view* of
16
+ * durable data — the `events` table is where state lives if it must survive
17
+ * anything.
18
+ *
19
+ * Everything else is plain RxJS, on purpose. `debounceTime`, `throttleTime`,
20
+ * `bufferTime`, `scan`, `distinctUntilChanged` — including its
21
+ * `(comparator, keySelector)` form for comparing a projection — already exist, and
22
+ * re-exporting them under new names would add vocabulary without adding
23
+ * behaviour.
24
+ */
25
+ export declare function latestByKey<T>(source: Observable<T>, keyOf: (value: T) => string): Observable<ReadonlyMap<string, T>>;
26
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/streams/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAGvC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,EACrB,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,GAC1B,UAAU,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAWpC"}
@@ -0,0 +1,34 @@
1
+ import { scan, shareReplay } from "rxjs/operators";
2
+ /**
3
+ * Accumulate a stream into "the latest value per key".
4
+ *
5
+ * The one reactive-state shape worth wrapping, because the sharing is easy to get
6
+ * wrong: without `shareReplay`, every new subscriber re-runs the scan from an
7
+ * empty map and sees nothing until the next event arrives.
8
+ *
9
+ * ```ts
10
+ * const progress$ = latestByKey(jobEvents$, (event) => event.data.runId);
11
+ * // Observable<ReadonlyMap<string, JobEvent>> — every run's most recent update.
12
+ * ```
13
+ *
14
+ * `refCount: true` discards the accumulated map when the last subscriber leaves.
15
+ * Deliberate: a cache outliving its subscribers is a leak, and this is a *view* of
16
+ * durable data — the `events` table is where state lives if it must survive
17
+ * anything.
18
+ *
19
+ * Everything else is plain RxJS, on purpose. `debounceTime`, `throttleTime`,
20
+ * `bufferTime`, `scan`, `distinctUntilChanged` — including its
21
+ * `(comparator, keySelector)` form for comparing a projection — already exist, and
22
+ * re-exporting them under new names would add vocabulary without adding
23
+ * behaviour.
24
+ */
25
+ export function latestByKey(source, keyOf) {
26
+ return source.pipe(scan((state, value) => {
27
+ // A fresh Map per emission, so a subscriber holding an earlier value is not
28
+ // mutated underneath it — the usual expectation for a stream of states.
29
+ const next = new Map(state);
30
+ next.set(keyOf(value), value);
31
+ return next;
32
+ }, new Map()), shareReplay({ bufferSize: 1, refCount: true }));
33
+ }
34
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/streams/state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,WAAW,CACzB,MAAqB,EACrB,KAA2B;IAE3B,OAAO,MAAM,CAAC,IAAI,CAChB,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACpB,4EAA4E;QAC5E,wEAAwE;QACxE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC,EAAE,IAAI,GAAG,EAAa,CAAC,EACxB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAC/C,CAAC;AACJ,CAAC"}