@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,151 @@
1
+ /**
2
+ * The single PostgreSQL notification channel every message travels on.
3
+ *
4
+ * One PG channel rather than one per application channel, because `LISTEN` is
5
+ * per-connection and per-name: a workspace-per-channel design would mean
6
+ * thousands of `LISTEN` statements and constant `LISTEN`/`UNLISTEN` churn as
7
+ * clients come and go. Instead every server sees every message and filters to the
8
+ * channels it has authorized subscribers for.
9
+ *
10
+ * The trade-off is real: fan-out is O(servers), so at large scale every node
11
+ * decodes traffic it discards. That is the point at which to swap in a broker —
12
+ * which is why {@link RealtimeTransport} exists.
13
+ */
14
+ export const PG_NOTIFY_CHANNEL = "saas_core_realtime";
15
+ /**
16
+ * `pg_notify` rejects payloads over 8000 bytes. Staying under it with headroom
17
+ * for the envelope means a large event's `data` is dropped rather than the whole
18
+ * notification failing — the client re-reads the event by id.
19
+ */
20
+ const MAX_PAYLOAD_BYTES = 7000;
21
+ /** Shrink an over-large message rather than failing the notification. */
22
+ export function encodeMessage(message, maxBytes = MAX_PAYLOAD_BYTES) {
23
+ const full = JSON.stringify(message);
24
+ if (Buffer.byteLength(full, "utf8") <= maxBytes) {
25
+ return full;
26
+ }
27
+ const { data: _dropped, ...rest } = message;
28
+ return JSON.stringify({ ...rest, truncated: true });
29
+ }
30
+ export function decodeMessage(payload) {
31
+ try {
32
+ const parsed = JSON.parse(payload);
33
+ /**
34
+ * Validated rather than cast. This payload arrived through the database, so
35
+ * anything with `NOTIFY` privileges could have written it — a shape check
36
+ * keeps a malformed or hostile notification from reaching subscribers as if
37
+ * it were a real event.
38
+ */
39
+ if (typeof parsed.channel !== "string" ||
40
+ typeof parsed.eventId !== "string" ||
41
+ typeof parsed.type !== "string" ||
42
+ typeof parsed.occurredAt !== "string") {
43
+ return undefined;
44
+ }
45
+ return parsed;
46
+ }
47
+ catch {
48
+ return undefined;
49
+ }
50
+ }
51
+ /**
52
+ * Realtime over PostgreSQL `LISTEN`/`NOTIFY`.
53
+ *
54
+ * The default transport because it adds no infrastructure: the database is
55
+ * already there. Browsers never touch `LISTEN`/`NOTIFY` — the server holds the
56
+ * listening connection and re-emits only what a given subscriber is authorized
57
+ * for, over SSE.
58
+ */
59
+ export function createPostgresTransport(options) {
60
+ const notifyChannel = options.notifyChannel ?? PG_NOTIFY_CHANNEL;
61
+ const client = options.client;
62
+ /**
63
+ * Every local subscriber, each with the channel set it was authorized for.
64
+ *
65
+ * One database listener is shared across them all: a `LISTEN` per HTTP
66
+ * connection would exhaust the pool at a few hundred concurrent clients.
67
+ */
68
+ const subscribers = new Set();
69
+ let listening;
70
+ function handleNotification(payload) {
71
+ const message = decodeMessage(payload);
72
+ if (message === undefined) {
73
+ options.onError?.(new Error("Discarded a malformed realtime notification."));
74
+ return;
75
+ }
76
+ for (const subscriber of subscribers) {
77
+ // The authorization boundary: a subscriber only ever sees its own channels.
78
+ if (!subscriber.channels.has(message.channel)) {
79
+ continue;
80
+ }
81
+ try {
82
+ subscriber.onMessage(message);
83
+ }
84
+ catch (error) {
85
+ // One broken consumer must not stop delivery to the others.
86
+ options.onError?.(error);
87
+ }
88
+ }
89
+ }
90
+ async function ensureListening() {
91
+ listening ??= (async () => {
92
+ await client.listen(notifyChannel, handleNotification);
93
+ })();
94
+ try {
95
+ await listening;
96
+ }
97
+ catch (error) {
98
+ // Allow a later subscribe to retry rather than caching the failure.
99
+ listening = undefined;
100
+ throw error;
101
+ }
102
+ }
103
+ return {
104
+ name: "postgres",
105
+ async publish(messages) {
106
+ for (const message of messages) {
107
+ try {
108
+ await client.notify(notifyChannel, encodeMessage(message));
109
+ }
110
+ catch (error) {
111
+ /**
112
+ * Realtime is best-effort by design. The event is already committed, so
113
+ * a failed notification costs a client its live update, not the record
114
+ * — and must not fail the operation that published it.
115
+ */
116
+ options.onError?.(error);
117
+ }
118
+ }
119
+ },
120
+ async subscribe(channels, onMessage) {
121
+ await ensureListening();
122
+ const subscriber = { channels: new Set(channels), onMessage };
123
+ subscribers.add(subscriber);
124
+ return {
125
+ close: async () => {
126
+ subscribers.delete(subscriber);
127
+ },
128
+ };
129
+ },
130
+ async close() {
131
+ subscribers.clear();
132
+ if (listening !== undefined) {
133
+ listening = undefined;
134
+ await client.unlisten?.(notifyChannel);
135
+ }
136
+ },
137
+ };
138
+ }
139
+ /** Adapt a postgres.js `Sql` instance to {@link NotifyCapableClient}. */
140
+ export function postgresJsNotifyClient(sql) {
141
+ return {
142
+ listen: async (channel, onNotify) => sql.listen(channel, onNotify),
143
+ notify: async (channel, payload) => {
144
+ if (typeof sql.notify !== "function") {
145
+ throw new Error("This postgres client does not support notify().");
146
+ }
147
+ return sql.notify(channel, payload);
148
+ },
149
+ };
150
+ }
151
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/realtime/postgres.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import type { SaasEvent } from "../events/registry.ts";
2
+ import type { EventsService } from "../events/service.ts";
3
+ import type { EventSchemaMap, Unsubscribe } from "../events/registry.ts";
4
+ import type { WorkspacesService } from "../workspaces/service.ts";
5
+ import type { RealtimeMessage, RealtimeSubscription, RealtimeTransport } from "./transport.ts";
6
+ export interface AuthorizedChannels {
7
+ /** Channels the caller may receive. Safe to hand to a transport. */
8
+ readonly granted: readonly string[];
9
+ /**
10
+ * Channels refused, for the client's own diagnostics.
11
+ *
12
+ * Deliberately does not say *why*: "not a member" and "no such workspace" are
13
+ * the same answer, or a client could enumerate tenants by probing channels.
14
+ */
15
+ readonly denied: readonly string[];
16
+ }
17
+ export interface PublishOptions {
18
+ /**
19
+ * Extra channels beyond the event's own workspace — a user channel for
20
+ * something addressed to one person, for instance.
21
+ */
22
+ readonly channels?: readonly string[];
23
+ }
24
+ export interface SubscribeInput {
25
+ /** Resolved from the session. Never from a request body. */
26
+ readonly userId: string;
27
+ /** Requested by the client, therefore untrusted. */
28
+ readonly channels: readonly string[];
29
+ readonly onMessage: (message: RealtimeMessage) => void;
30
+ }
31
+ export interface RealtimeService {
32
+ /**
33
+ * Decide which of `channels` this user may receive.
34
+ *
35
+ * The one place channel access is decided. Transports do not filter, so a bug
36
+ * here is not caught downstream — and equally, there is only one rule to audit.
37
+ */
38
+ authorizeChannels(input: {
39
+ userId: string;
40
+ channels: readonly string[];
41
+ }): Promise<AuthorizedChannels>;
42
+ /** Project an event onto its channels and hand it to the transport. */
43
+ publish(event: SaasEvent, options?: PublishOptions): Promise<void>;
44
+ /**
45
+ * Authorize, then subscribe. Returns a subscription even when nothing was
46
+ * granted, so a caller has one code path.
47
+ */
48
+ subscribe(input: SubscribeInput): Promise<RealtimeSubscription & {
49
+ granted: readonly string[];
50
+ }>;
51
+ /**
52
+ * Mirror an events service onto the transport.
53
+ *
54
+ * Uses the existing `onAny` hook rather than reaching into the events service,
55
+ * so realtime stays an optional consumer of events and not a dependency of
56
+ * publishing.
57
+ */
58
+ attach<S extends EventSchemaMap>(events: EventsService<S>): Unsubscribe;
59
+ }
60
+ export interface RealtimeServiceDeps {
61
+ readonly transport: RealtimeTransport;
62
+ /** Used to verify workspace membership before granting a channel. */
63
+ readonly workspaces: Pick<WorkspacesService, "resolveContext">;
64
+ /**
65
+ * Which events reach clients at all.
66
+ *
67
+ * Defaults to workspace-scoped events only. Platform-wide events — a user
68
+ * being provisioned, say — have no tenant channel to go to, and broadcasting
69
+ * them would mean choosing an audience the event does not describe.
70
+ */
71
+ readonly broadcast?: (event: SaasEvent) => boolean;
72
+ readonly onError?: (error: unknown) => void;
73
+ }
74
+ export declare function createRealtimeService(deps: RealtimeServiceDeps): RealtimeService;
75
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/realtime/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAOlE,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAE/F,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,iBAAiB,CAAC,KAAK,EAAE;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;KAC7B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAEhC,uEAAuE;IACvE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnE;;;OAGG;IACH,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,oBAAoB,GAAG;QAAE,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAEjG;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,SAAS,cAAc,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC;CACzE;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,qEAAqE;IACrE,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;IAC/D;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;IACnD,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC7C;AAMD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,eAAe,CAkHhF"}
@@ -0,0 +1,103 @@
1
+ import { MAX_CHANNELS_PER_SUBSCRIPTION, parseChannel, userChannel, workspaceChannel, } from "./channels.js";
2
+ function defaultBroadcast(event) {
3
+ return event.workspaceId !== null;
4
+ }
5
+ export function createRealtimeService(deps) {
6
+ const shouldBroadcast = deps.broadcast ?? defaultBroadcast;
7
+ function toMessage(event, channel) {
8
+ return {
9
+ channel,
10
+ eventId: event.id,
11
+ type: event.type,
12
+ occurredAt: event.occurredAt.toISOString(),
13
+ data: event.data,
14
+ };
15
+ }
16
+ const service = {
17
+ async authorizeChannels({ userId, channels }) {
18
+ const granted = [];
19
+ const denied = [];
20
+ // Bound the work a single unauthenticated-ish request can cause.
21
+ const requested = channels.slice(0, MAX_CHANNELS_PER_SUBSCRIPTION);
22
+ for (const extra of channels.slice(MAX_CHANNELS_PER_SUBSCRIPTION)) {
23
+ denied.push(extra);
24
+ }
25
+ // De-duplicated so a client repeating a channel cannot multiply the
26
+ // membership lookups it triggers.
27
+ for (const value of new Set(requested)) {
28
+ const channel = parseChannel(value);
29
+ if (channel === undefined) {
30
+ denied.push(value);
31
+ continue;
32
+ }
33
+ if (channel.kind === "user") {
34
+ /**
35
+ * A user channel is only ever your own. Comparing to the session's
36
+ * user id is the whole check — there is no membership involved.
37
+ */
38
+ if (channel.userId === userId) {
39
+ granted.push(value);
40
+ }
41
+ else {
42
+ denied.push(value);
43
+ }
44
+ continue;
45
+ }
46
+ const context = await deps.workspaces.resolveContext({
47
+ userId,
48
+ workspaceId: channel.workspaceId,
49
+ });
50
+ if (context === undefined) {
51
+ denied.push(value);
52
+ }
53
+ else {
54
+ granted.push(value);
55
+ }
56
+ }
57
+ return { granted, denied };
58
+ },
59
+ async publish(event, options = {}) {
60
+ if (!shouldBroadcast(event)) {
61
+ return;
62
+ }
63
+ const channels = new Set(options.channels ?? []);
64
+ if (event.workspaceId !== null) {
65
+ channels.add(workspaceChannel(event.workspaceId));
66
+ }
67
+ if (channels.size === 0) {
68
+ return;
69
+ }
70
+ await deps.transport.publish([...channels].map((channel) => toMessage(event, channel)));
71
+ },
72
+ async subscribe({ userId, channels, onMessage }) {
73
+ const { granted } = await service.authorizeChannels({ userId, channels });
74
+ if (granted.length === 0) {
75
+ /**
76
+ * Nothing authorized, so nothing is opened against the transport. The
77
+ * caller still gets a subscription to close, which keeps its cleanup path
78
+ * unconditional.
79
+ */
80
+ return { granted, close: async () => undefined };
81
+ }
82
+ const subscription = await deps.transport.subscribe(granted, onMessage);
83
+ return { granted, close: () => subscription.close() };
84
+ },
85
+ attach(events) {
86
+ return events.onAny(async (event) => {
87
+ try {
88
+ await service.publish(event);
89
+ }
90
+ catch (error) {
91
+ /**
92
+ * Realtime delivery must never fail a publish: the event is already
93
+ * committed and durable, and a dropped live update is recoverable by
94
+ * re-reading it.
95
+ */
96
+ deps.onError?.(error);
97
+ }
98
+ });
99
+ },
100
+ };
101
+ return service;
102
+ }
103
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/realtime/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { RealtimeService } from "./service.ts";
2
+ /**
3
+ * A server-sent-event stream, as bytes plus the headers it needs.
4
+ *
5
+ * Deliberately not a `Response`. Returning one would tie this module to the fetch
6
+ * types and to a single framework; a stream and a header map compose with
7
+ * anything, including plain `node:http`.
8
+ */
9
+ export interface EventStream {
10
+ readonly body: ReadableStream<Uint8Array>;
11
+ readonly headers: Record<string, string>;
12
+ /** Channels actually granted. Fewer than requested means some were refused. */
13
+ readonly granted: readonly string[];
14
+ close(): Promise<void>;
15
+ }
16
+ export interface EventStreamOptions {
17
+ readonly userId: string;
18
+ readonly channels: readonly string[];
19
+ /**
20
+ * Aborts the stream when the client disconnects.
21
+ *
22
+ * Without it a dropped connection leaks a subscription and a database listener
23
+ * slot for the lifetime of the process.
24
+ */
25
+ readonly signal?: AbortSignal;
26
+ /**
27
+ * Comment-only keep-alive interval. Defaults to 25 seconds — under the 30-second
28
+ * idle timeout most proxies and load balancers impose.
29
+ */
30
+ readonly heartbeatMs?: number;
31
+ /** Client reconnect delay hint, in milliseconds. */
32
+ readonly retryMs?: number;
33
+ }
34
+ /**
35
+ * Open an authorized SSE stream.
36
+ *
37
+ * ```ts
38
+ * // app/api/realtime/route.ts
39
+ * export async function GET(request: Request) {
40
+ * const user = await auth.requireUser();
41
+ * const stream = await createEventStream(realtime, {
42
+ * userId: user.id,
43
+ * channels: new URL(request.url).searchParams.getAll("channel"),
44
+ * signal: request.signal,
45
+ * });
46
+ * return new Response(stream.body, { headers: stream.headers });
47
+ * }
48
+ * ```
49
+ *
50
+ * Channels are authorized before the stream opens, and unauthorized ones are
51
+ * silently dropped rather than failing the request — a client asking for a
52
+ * workspace it just left should keep receiving the rest.
53
+ */
54
+ export declare function createEventStream(realtime: RealtimeService, options: EventStreamOptions): Promise<EventStream>;
55
+ //# sourceMappingURL=sse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/realtime/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,oDAAoD;IACpD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAUD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,WAAW,CAAC,CA0GtB"}
@@ -0,0 +1,123 @@
1
+ const DEFAULT_HEARTBEAT_MS = 25_000;
2
+ const DEFAULT_RETRY_MS = 3_000;
3
+ /** SSE frame. `id` lets a client resume with `Last-Event-ID`. */
4
+ function frame(message) {
5
+ return `id: ${message.eventId}\nevent: ${message.type}\ndata: ${JSON.stringify(message)}\n\n`;
6
+ }
7
+ /**
8
+ * Open an authorized SSE stream.
9
+ *
10
+ * ```ts
11
+ * // app/api/realtime/route.ts
12
+ * export async function GET(request: Request) {
13
+ * const user = await auth.requireUser();
14
+ * const stream = await createEventStream(realtime, {
15
+ * userId: user.id,
16
+ * channels: new URL(request.url).searchParams.getAll("channel"),
17
+ * signal: request.signal,
18
+ * });
19
+ * return new Response(stream.body, { headers: stream.headers });
20
+ * }
21
+ * ```
22
+ *
23
+ * Channels are authorized before the stream opens, and unauthorized ones are
24
+ * silently dropped rather than failing the request — a client asking for a
25
+ * workspace it just left should keep receiving the rest.
26
+ */
27
+ export async function createEventStream(realtime, options) {
28
+ const encoder = new TextEncoder();
29
+ const heartbeatMs = options.heartbeatMs ?? DEFAULT_HEARTBEAT_MS;
30
+ let heartbeat;
31
+ let closed = false;
32
+ let close = async () => undefined;
33
+ /**
34
+ * Frames that arrived before the stream was constructed.
35
+ *
36
+ * `subscribe` has to happen first — `granted` is part of the returned value —
37
+ * but `ReadableStream.start` does not run until the stream is built. Anything
38
+ * delivered in that window would otherwise be silently dropped.
39
+ */
40
+ const pending = [];
41
+ let enqueue = (chunk) => {
42
+ pending.push(chunk);
43
+ };
44
+ const subscription = await realtime.subscribe({
45
+ userId: options.userId,
46
+ channels: options.channels,
47
+ onMessage: (message) => {
48
+ enqueue(frame(message));
49
+ },
50
+ });
51
+ const body = new ReadableStream({
52
+ start(controller) {
53
+ const write = (chunk) => {
54
+ if (closed) {
55
+ return;
56
+ }
57
+ try {
58
+ controller.enqueue(encoder.encode(chunk));
59
+ }
60
+ catch {
61
+ /**
62
+ * The client went away between the readiness check and the write. Not
63
+ * an error worth surfacing — tear down instead.
64
+ */
65
+ void close();
66
+ }
67
+ };
68
+ // Tells the browser how long to wait before reconnecting.
69
+ write(`retry: ${options.retryMs ?? DEFAULT_RETRY_MS}\n\n`);
70
+ // An immediate comment flushes headers, so the client's connection opens
71
+ // now rather than on the first real event.
72
+ write(`: connected\n\n`);
73
+ // Anything buffered during setup, in arrival order, then switch to direct
74
+ // writes for everything after.
75
+ for (const buffered of pending.splice(0, pending.length)) {
76
+ write(buffered);
77
+ }
78
+ enqueue = write;
79
+ heartbeat = setInterval(() => {
80
+ write(`: heartbeat\n\n`);
81
+ }, heartbeatMs);
82
+ // Do not hold the process open just for a keep-alive timer.
83
+ heartbeat.unref?.();
84
+ close = async () => {
85
+ if (closed) {
86
+ return;
87
+ }
88
+ closed = true;
89
+ if (heartbeat !== undefined) {
90
+ clearInterval(heartbeat);
91
+ }
92
+ await subscription.close();
93
+ try {
94
+ controller.close();
95
+ }
96
+ catch {
97
+ // Already closed by the runtime; nothing to do.
98
+ }
99
+ };
100
+ options.signal?.addEventListener("abort", () => void close(), { once: true });
101
+ if (options.signal?.aborted === true) {
102
+ void close();
103
+ }
104
+ },
105
+ cancel() {
106
+ return close();
107
+ },
108
+ });
109
+ return {
110
+ body,
111
+ granted: subscription.granted,
112
+ headers: {
113
+ "Content-Type": "text/event-stream",
114
+ // Proxies and CDNs must not buffer or cache a stream.
115
+ "Cache-Control": "no-cache, no-transform",
116
+ Connection: "keep-alive",
117
+ // Disables response buffering in nginx, which would defeat SSE entirely.
118
+ "X-Accel-Buffering": "no",
119
+ },
120
+ close: () => close(),
121
+ };
122
+ }
123
+ //# sourceMappingURL=sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/realtime/sse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * One realtime delivery.
3
+ *
4
+ * A projection of a persisted event, not the event itself. Realtime is a
5
+ * delivery mechanism, never the source of truth: a client that missed a message
6
+ * re-reads from the `events` table.
7
+ */
8
+ export interface RealtimeMessage {
9
+ /** Target channel, already authorized when it reaches a subscriber. */
10
+ readonly channel: string;
11
+ /** The `events.id` this projects, so a client can reconcile or re-fetch. */
12
+ readonly eventId: string;
13
+ readonly type: string;
14
+ /** ISO 8601. A string because this crosses a serialization boundary. */
15
+ readonly occurredAt: string;
16
+ /** Absent when the payload was too large to carry — see `truncated`. */
17
+ readonly data?: unknown;
18
+ /**
19
+ * True when `data` was dropped to fit the transport's size limit. The client
20
+ * should re-read the event by id rather than assume an empty payload.
21
+ */
22
+ readonly truncated?: boolean;
23
+ }
24
+ export interface RealtimeSubscription {
25
+ close(): Promise<void>;
26
+ }
27
+ /**
28
+ * The seam between the core and a realtime transport.
29
+ *
30
+ * Everything above this interface is transport-independent, so replacing the
31
+ * default PostgreSQL transport with Centrifugo, Soketi or a hosted service means
32
+ * writing an adapter rather than touching the service or its authorization.
33
+ *
34
+ * Implementations must not perform authorization. Channel access is decided once,
35
+ * server-side, before `subscribe` is called — a transport that also filtered
36
+ * would create two places for the rule to live and one of them would drift.
37
+ */
38
+ export interface RealtimeTransport {
39
+ readonly name: string;
40
+ /** Fan out messages. Must not throw for an unknown channel. */
41
+ publish(messages: readonly RealtimeMessage[]): Promise<void>;
42
+ /**
43
+ * Deliver messages for exactly these channels.
44
+ *
45
+ * `channels` is already authorized. A transport must deliver to no channel
46
+ * outside the set.
47
+ */
48
+ subscribe(channels: readonly string[], onMessage: (message: RealtimeMessage) => void): Promise<RealtimeSubscription>;
49
+ /** Release transport-wide resources. */
50
+ close?(): Promise<void>;
51
+ }
52
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/realtime/transport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,+DAA+D;IAC/D,OAAO,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7D;;;;;OAKG;IACH,SAAS,CACP,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAC5C,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEjC,wCAAwC;IACxC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/realtime/transport.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import { type StorageService } from "./service.ts";
2
+ import type { StorageProvider } from "./provider.ts";
3
+ export { assertKeyBelongsTo, assertObjectPath, isValidObjectPath, MAX_OBJECT_KEY_LENGTH, parseWorkspaceObjectKey, WORKSPACE_PREFIX, workspaceObjectKey, } from "./keys.ts";
4
+ export { bodyBytes, createMemoryStorageProvider, type MemoryObject, type MemoryStorageOptions, type MemoryStorageProvider, } from "./memory.ts";
5
+ export type { ObjectBody, ObjectStat, PutObjectInput, SignedDownloadInput, SignedUploadInput, SignedUrlInput, StorageProvider, StoredObject, } from "./provider.ts";
6
+ export { createS3Provider, objectDigest, type S3ProviderOptions } from "./s3.ts";
7
+ export { assertObjectExists, createStorageService, MAX_SIGNED_URL_SECONDS, type ScopedStorage, type StorageService, type StorageServiceDeps, type UploadInput, type UploadUrlOptions, type UrlOptions, } from "./service.ts";
8
+ export { encodeObjectPath, presign, signingKey, uriEncode, type PresignInput, type PresignResult, type SigV4Credentials, } from "./sigv4.ts";
9
+ /** An S3-compatible provider built from the `storage` configuration section. */
10
+ export declare function createConfiguredStorageProvider(): StorageProvider;
11
+ /**
12
+ * Default service, bound to configuration.
13
+ *
14
+ * The provider is a getter, so the `storage` configuration section resolves on
15
+ * first use — importing this module does not require credentials.
16
+ */
17
+ export declare const storage: StorageService;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAuDA,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,SAAS,EACT,2BAA2B,EAC3B,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,YAAY,GACb,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjF,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,UAAU,GAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,gBAAgB,EAChB,OAAO,EACP,UAAU,EACV,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,YAAY,CAAC;AAEpB,gFAAgF;AAChF,wBAAgB,+BAA+B,IAAI,eAAe,CAajE;AAID;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE,cAKpB,CAAC"}