@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
package/docs/events.md ADDED
@@ -0,0 +1,279 @@
1
+ # Events
2
+
3
+ ```ts
4
+ import {
5
+ coreEvents, createEventsService, defineEvents, mergeEventRegistries,
6
+ } from "@digimuza/saas-core/events";
7
+ ```
8
+
9
+ > Orientation and recipes: [`src/events/README.md`](../src/events/README.md).
10
+
11
+
12
+ One durable record of everything that happens, typed at compile time and validated
13
+ at runtime. Realtime delivery, RxJS streams, notifications, audit logs, outgoing
14
+ webhooks and durable jobs all read from here rather than inventing their own
15
+ channel.
16
+
17
+ ---
18
+
19
+ ## The registry
20
+
21
+ Each event type is paired with a Zod schema, which does double duty: `z.infer`
22
+ gives the compile-time payload type, and the same schema validates before anything
23
+ is written.
24
+
25
+ A `Record<string, unknown>` payload would give neither. A hand-written TypeScript
26
+ interface would give only the first, leaving the database to accept whatever a
27
+ caller happened to pass.
28
+
29
+ ### `defineEvents(schemas)`
30
+
31
+ ```ts
32
+ function defineEvents<const S extends Record<string, z.ZodType>>(schemas: S): EventRegistry<S>
33
+ ```
34
+
35
+ ```ts
36
+ import { z } from "zod";
37
+
38
+ export const appEvents = defineEvents({
39
+ "project.created": z.object({ projectId: z.uuid(), name: z.string().min(1) }),
40
+ "project.deleted": z.object({ projectId: z.uuid() }),
41
+ });
42
+ ```
43
+
44
+ The `const` type parameter preserves the literal keys — that is what makes
45
+ `publish({ type: "project.created", ... })` autocomplete and narrow `data`.
46
+
47
+ ### `mergeEventRegistries(first, second)`
48
+
49
+ ```ts
50
+ function mergeEventRegistries<A, B>(first: EventRegistry<A>, second: EventRegistry<B>): EventRegistry<A & B>
51
+ ```
52
+
53
+ ```ts
54
+ // lib/events.ts
55
+ import { getDatabase } from "@digimuza/saas-core/db";
56
+
57
+ const registry = mergeEventRegistries(coreEvents, appEvents);
58
+ export const events = createEventsService({ db: getDatabase(), registry });
59
+ ```
60
+
61
+ Duplicate keys **throw**. An application that redefined
62
+ `workspace.member.created` with a different payload would make every core consumer
63
+ of that event wrong, and the failure would surface far from the cause.
64
+
65
+ ---
66
+
67
+ ## `events.publish(input)`
68
+
69
+ ```ts
70
+ function publish(input: {
71
+ type: K; // a key of the registry
72
+ data: z.input<S[K]>; // narrowed to that key's schema
73
+ workspaceId?: string | null;
74
+ actorId?: string | null;
75
+ idempotencyKey?: string;
76
+ occurredAt?: Date;
77
+ }): Promise<SaasEvent>
78
+ ```
79
+
80
+ ```ts
81
+ await events.publish({
82
+ type: "project.created",
83
+ workspaceId: context.workspaceId,
84
+ actorId: user.id,
85
+ data: { projectId, name },
86
+ });
87
+ ```
88
+
89
+ Validates, persists, then fans out. The row is committed **before** handlers run,
90
+ so an event is never lost because a subscriber failed.
91
+
92
+ Passing a payload that does not match its type is a **compile error**. There is a
93
+ test asserting that with `@ts-expect-error`, so the guarantee cannot silently
94
+ regress.
95
+
96
+ `workspaceId` may be `null` for platform-wide events that precede any workspace,
97
+ such as a user being provisioned. `occurredAt` lets you record when something
98
+ actually happened, which is not always when it was recorded — a webhook may report
99
+ an event minutes after the fact.
100
+
101
+ Throws `InvalidInputError` for a payload that fails its schema, or an unknown type
102
+ (reachable only from untyped JavaScript).
103
+
104
+ ## `events.scoped(context)`
105
+
106
+ ```ts
107
+ function scoped(context: WorkspaceContext): ScopedPublisher
108
+ ```
109
+
110
+ Binds the verified workspace so callers cannot pass a different one:
111
+
112
+ ```ts
113
+ const scoped = events.scoped(context);
114
+ await scoped.publish({ type: "project.created", actorId: user.id, data });
115
+ ```
116
+
117
+ ## `events.record(input, tx?)` and `events.dispatch(event)`
118
+
119
+ ```ts
120
+ function record(input: PublishInput, tx?: CoreDatabase): Promise<{ event: SaasEvent; created: boolean }>
121
+ function dispatch(event: SaasEvent): Promise<void>
122
+ ```
123
+
124
+ The transactional outbox. Write the event in the **same transaction** as the state
125
+ change it describes, then dispatch after the commit:
126
+
127
+ ```ts
128
+ const { event, created } = await db.transaction(async (tx) => {
129
+ await createProject(tx, input);
130
+ return events.record({ type: "project.created", data }, tx);
131
+ });
132
+
133
+ if (created) {
134
+ await events.dispatch(event);
135
+ }
136
+ ```
137
+
138
+ So there is no state change without its event, and no event for a change that
139
+ rolled back. Both directions are tested.
140
+
141
+ **Dispatch only when `created` is true.** A deduplicated event was already fanned
142
+ out when first recorded, and firing again would make every handler run twice for
143
+ one real occurrence. This was a real bug: the outbox originally queued deduplicated
144
+ events, which would have re-fired `user.created` handlers on every sign-in.
145
+
146
+ ## `events.on(type, handler)` / `events.onAny(handler)`
147
+
148
+ ```ts
149
+ function on<K>(type: K, handler: (event: SaasEventOf<S, K>) => void | Promise<void>): Unsubscribe
150
+ function onAny(handler: (event: SaasEvent<S>) => void | Promise<void>): Unsubscribe
151
+ ```
152
+
153
+ ```ts
154
+ const unsubscribe = events.on("project.created", async (event) => {
155
+ event.data.name; // narrowed to this event's schema
156
+ });
157
+ ```
158
+
159
+ ### Subscribers are in-process and not durable
160
+
161
+ A crash between the commit and the handler loses the **reaction**, not the event.
162
+ That is deliberate: durable reactions belong in Trigger.dev (see
163
+ [jobs.md](./jobs.md)), reading the persisted row. Never keep state in a handler
164
+ that must survive a restart.
165
+
166
+ ### Handlers cannot fail a publish
167
+
168
+ They run concurrently via `Promise.allSettled`; each failure goes to the service's
169
+ error sink and the others still run. The event has happened and is committed, so a
170
+ broken subscriber is a separate operational problem.
171
+
172
+ ```ts
173
+ createEventsService({
174
+ db, registry,
175
+ onHandlerError: (error, event) => logger.error({ error, type: event.type }),
176
+ });
177
+ ```
178
+
179
+ Without a sink, failures are logged with `console.error`. Provide one in production
180
+ so they reach your error tracker.
181
+
182
+ ## `events.list(context, options?)`
183
+
184
+ ```ts
185
+ function list(context: WorkspaceContext, options?: {
186
+ types?: readonly string[];
187
+ limit?: number; // default 50, capped at 500
188
+ before?: Date; // keyset pagination
189
+ actorId?: string;
190
+ }): Promise<SaasEvent[]>
191
+ ```
192
+
193
+ Always workspace-scoped: an event feed is tenant data. Newest first, tie-broken on
194
+ id so keyset pagination cannot loop on equal timestamps.
195
+
196
+ ```ts
197
+ const page = await events.list(context, { types: ["project.created"], limit: 20 });
198
+ const next = await events.list(context, { before: page.at(-1)!.occurredAt });
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Idempotency
204
+
205
+ `(type, idempotency_key)` is a **partial** unique index, so a retried operation
206
+ records its event once. Keys are scoped per type — two event types may legitimately
207
+ derive a key from the same request.
208
+
209
+ `user.created` uses the WorkOS id as its key, which is how a re-login provisions no
210
+ second event without a racy select-then-decide.
211
+
212
+ > Because the index is partial (`WHERE idempotency_key IS NOT NULL`), the
213
+ > `ON CONFLICT` clause must carry a matching `where` predicate. PostgreSQL refuses
214
+ > to infer a partial index as a conflict arbiter otherwise, and every insert fails
215
+ > with `42P10`. Worth knowing if you add a similar index of your own.
216
+
217
+ ---
218
+
219
+ ## What the core emits
220
+
221
+ | Event | Payload |
222
+ | --- | --- |
223
+ | `user.created` | `userId`, `workosUserId` |
224
+ | `workspace.created` | `workspaceId`, `slug` |
225
+ | `workspace.updated` | `workspaceId`, `changed: ("name"\|"slug")[]` |
226
+ | `workspace.deleted` | `workspaceId`, `slug` |
227
+ | `workspace.member.created` | `userId`, `roleIds` |
228
+ | `workspace.member.removed` | `userId` |
229
+ | `workspace.member.role.updated` | `userId`, `roleId`, `action` |
230
+ | `workspace.invitation.created` | `invitationId`, `email`, `roleId` |
231
+ | `workspace.invitation.accepted` | `invitationId`, `userId` |
232
+ | `workspace.invitation.revoked` | `invitationId` |
233
+ | `billing.subscription.updated` | `subscriptionId`, `planKey`, `status`, `previousStatus?` |
234
+ | `billing.subscription.canceled` | `subscriptionId`, `planKey`, `atPeriodEnd` |
235
+ | `job.started` | `runId`, `taskId` |
236
+ | `job.progress` | `runId`, `taskId`, `percent?`, `message?`, `step?`, `totalSteps?` |
237
+ | `job.completed` | `runId`, `taskId`, `durationMs?` |
238
+ | `job.failed` | `runId`, `taskId`, `error`, `attempt?` |
239
+
240
+ Notification and realtime events arrive with the phases that introduce them.
241
+ Declaring them now would ship types nothing publishes — worse than no type, since
242
+ consumers would write handlers that never fire.
243
+
244
+ ### Payload conventions
245
+
246
+ **Identifiers, not snapshots.** An embedded copy goes stale between publication and
247
+ delivery, and would put mutable user data in an append-only table. A consumer that
248
+ needs current state should read it.
249
+
250
+ **No credentials.** Invitation events deliberately omit the token: events are
251
+ durable and readable, and the token is a bearer credential. There is a test
252
+ asserting it never appears.
253
+
254
+ **`workspace.deleted` carries `workspaceId: null`** on the row itself. It is
255
+ recorded before the delete, in the same transaction, because `events.workspace_id`
256
+ cascades — a scoped row would vanish along with the tenant it was recording.
257
+
258
+ ---
259
+
260
+ ## Emission is opt-in
261
+
262
+ `createWorkspacesService({ db })` emits nothing.
263
+ `createWorkspacesService({ db, events })` does.
264
+
265
+ The default exports are wired together, so
266
+ `import { workspaces } from "@digimuza/saas-core/workspaces"` already emits to the
267
+ core registry. If you build your own services from a merged registry, pass it in —
268
+ `CoreEventPublisher` is a supertype-friendly slice, so a merged-registry service is
269
+ accepted without the core knowing about your extra event types.
270
+
271
+ ---
272
+
273
+ ## The events table
274
+
275
+ Append-only. There is no `updated_at`: an event is a statement about the past, and
276
+ revising one would make every derived record untrustworthy.
277
+
278
+ Indexed for `(workspace_id, occurred_at DESC)` — the activity-feed query — and
279
+ `(type, occurred_at DESC)` for backfills and diagnostics.
@@ -0,0 +1,237 @@
1
+ # Feature flags
2
+
3
+ ```ts
4
+ import {
5
+ defineFeatureFlags, createFeaturesService, createConfiguredFeaturesService,
6
+ } from "@digimuza/saas-core/feature-flags";
7
+ ```
8
+
9
+ > Orientation and recipes: [`src/features/README.md`](../src/features/README.md).
10
+
11
+ Simple flags with four scopes, resolved most-specific-first. **Not** a feature
12
+ management platform — no segments, no rule engines, no audience builders.
13
+
14
+ ---
15
+
16
+ ## Declaring flags
17
+
18
+ ```ts
19
+ export const flags = defineFeatureFlags({
20
+ "new-editor": { default: false, description: "Rebuilt document editor" },
21
+ ranking: { default: true, variants: ["control", "v2"], defaultVariant: "control" },
22
+ });
23
+ ```
24
+
25
+ ```ts
26
+ interface FeatureFlagDefinition {
27
+ default: boolean;
28
+ description?: string;
29
+ variants?: readonly string[];
30
+ defaultVariant?: string;
31
+ }
32
+ ```
33
+
34
+ Definitions live in **code**, not the database. So a fresh database behaves the
35
+ same as a configured one, a misspelled key is a compile error, and deleting the
36
+ flag from the code deletes it from the product. Database rows are only *overrides*.
37
+
38
+ Keys must be lowercase alphanumerics with dots, dashes or underscores — they reach
39
+ URLs, log lines and client payloads, and constraining them here avoids escaping
40
+ them everywhere downstream.
41
+
42
+ `mergeFeatureFlags(a, b)` combines registries and **throws** on a duplicate: two
43
+ modules defining the same flag would make its behaviour depend on import order.
44
+
45
+ ### Constructing the service
46
+
47
+ ```ts
48
+ createConfiguredFeaturesService(flags); // application = APP_NAME
49
+ createFeaturesService({ db, registry: flags, application }); // explicit
50
+ ```
51
+
52
+ There is deliberately **no default `features` export** — flags are
53
+ application-defined, so a service with an empty registry could not answer
54
+ anything.
55
+
56
+ ---
57
+
58
+ ## Scopes
59
+
60
+ ```
61
+ global < application < workspace < user
62
+ ```
63
+
64
+ The most specific matching override wins. `FLAG_SCOPE_PRECEDENCE` is exported, so
65
+ a debug view can show the order.
66
+
67
+ `global` is every application sharing this database; `application` narrows to one
68
+ product built on the core. That distinction exists because this package is
69
+ explicitly meant to back several SaaS products — without it, turning a flag on for
70
+ one would turn it on for all of them.
71
+
72
+ An `application`-scoped override only matches when the service was given an
73
+ `application`. Otherwise it is ignored rather than guessed at.
74
+
75
+ ---
76
+
77
+ ## Reading
78
+
79
+ ### `features.all(subject?)`
80
+
81
+ ```ts
82
+ function all(subject?: FlagSubject): Promise<Map<Key, ResolvedFlag>>
83
+ ```
84
+
85
+ Every declared flag, resolved in **one** query. The recommended path: resolve once
86
+ per request and pass the result to the client, rather than querying per
87
+ conditional.
88
+
89
+ ```ts
90
+ const resolved = await features.all({ workspaceId: context.workspaceId, userId: user.id });
91
+ ```
92
+
93
+ ### `features.isEnabled(key, subject?)` / `getVariant(key, subject?)`
94
+
95
+ ```ts
96
+ function isEnabled(key: Key, subject?: FlagSubject): Promise<boolean>
97
+ function getVariant<K>(key: K, subject?: FlagSubject): Promise<Variant<K> | undefined>
98
+ ```
99
+
100
+ `getVariant` is typed to the flag's declared variants, so a `switch` is
101
+ exhaustively checkable.
102
+
103
+ **A disabled flag has no variant** — `undefined`. Returning one would invite code
104
+ that reads the variant without checking `isEnabled` first.
105
+
106
+ ### `features.resolve(key, subject?)`
107
+
108
+ ```ts
109
+ interface ResolvedFlag {
110
+ key: string;
111
+ enabled: boolean;
112
+ variant: string | undefined;
113
+ source: "global" | "application" | "workspace" | "user" | "default";
114
+ }
115
+ ```
116
+
117
+ `source` answers "why is this on for me", which is the question every flag system
118
+ eventually has to answer.
119
+
120
+ ### `FlagSubject`
121
+
122
+ ```ts
123
+ interface FlagSubject {
124
+ workspaceId?: string;
125
+ userId?: string;
126
+ }
127
+ ```
128
+
129
+ Plain ids, **not** a `WorkspaceContext` — the one deliberate exception in the core.
130
+ Flags are read many times per request, and a membership check per read would make
131
+ them expensive enough that people would cache them badly. A flag state is
132
+ configuration, not tenant data.
133
+
134
+ Pass ids that came from a verified context. The service will not check for you.
135
+
136
+ ### Unknown keys throw
137
+
138
+ `InvalidInputError`, not `false`. Reachable only from untyped JavaScript, but a
139
+ flag that silently never turns on is far harder to diagnose than one that fails at
140
+ the call site.
141
+
142
+ ---
143
+
144
+ ## Writing
145
+
146
+ ### `features.set(input)`
147
+
148
+ ```ts
149
+ function set(input: {
150
+ key: Key;
151
+ scope: FeatureFlagScope;
152
+ application?: string; // required for scope: "application"
153
+ workspaceId?: string; // required for scope: "workspace"
154
+ userId?: string; // required for scope: "user"
155
+ enabled: boolean;
156
+ variant?: string | null;
157
+ rolloutPercentage?: number | null; // 0-100
158
+ description?: string;
159
+ }): Promise<FeatureFlagRow>
160
+ ```
161
+
162
+ Idempotent per target — setting the same override twice updates it, which is what
163
+ both an admin UI and a seeding script want.
164
+
165
+ Two things are rejected rather than tolerated:
166
+
167
+ - **A variant not declared on the flag.** Better than discovering it when a
168
+ `switch` silently matches nothing.
169
+ - **A target that contradicts the scope.** `{ scope: "global", workspaceId }` is
170
+ always a mistake, and ignoring it would look like it had worked.
171
+
172
+ ### `features.unset(input)` / `overrides(key)`
173
+
174
+ `unset` removes one override, falling back to the next-broadest scope. Throws
175
+ `NotFoundError` if there was none. `overrides` lists every stored override for a
176
+ key, broadest first.
177
+
178
+ ---
179
+
180
+ ## Percentage rollout
181
+
182
+ ```ts
183
+ await features.set({ key: "new-editor", scope: "global", enabled: true, rolloutPercentage: 10 });
184
+ ```
185
+
186
+ **Rollout narrows an override; it never turns one on.** A `rolloutPercentage` on a
187
+ *disabled* override leaves it disabled. On an enabled one it means "on for this
188
+ percentage of the subjects this override covers".
189
+
190
+ Bucketing is `sha256(key + subjectId) % 100`, so:
191
+
192
+ - **Stable.** A subject stays on the same side across requests, processes and
193
+ deploys. A flag that flickered would be worse than no flag — a user would see
194
+ the new editor, reload, and lose their work.
195
+ - **Salted by flag key.** Otherwise the same unlucky cohort would receive every
196
+ experiment.
197
+ - **Stateless.** Nothing to store, nothing to keep in sync.
198
+
199
+ The subject is the **most specific available**: `userId` if present, else
200
+ `workspaceId`. So a per-user rollout is stable per user and a per-workspace one per
201
+ workspace.
202
+
203
+ With **no subject**, anything below 100 is off. There is nothing stable to hash,
204
+ and guessing would reintroduce the flickering this design exists to prevent.
205
+
206
+ `bucketOf(key, subjectId)` and `isInRollout(key, percentage, subjectId)` are
207
+ exported, if you need the same bucketing for something the service does not cover.
208
+
209
+ ---
210
+
211
+ ## Storage
212
+
213
+ One table, `feature_flags`, one row per override per target.
214
+
215
+ ```
216
+ unique nulls not distinct (key, scope, application, workspace_id, user_id)
217
+ ```
218
+
219
+ `NULLS NOT DISTINCT` is load-bearing. PostgreSQL treats NULLs as distinct in a
220
+ unique index by default, so without it every global override — where all three
221
+ target columns are null — would count as unique and you could insert the same one
222
+ endlessly. There is a test for exactly that.
223
+
224
+ `workspace_id` and `user_id` are real foreign keys with `ON DELETE CASCADE`, so an
225
+ override for a deleted tenant does not accumulate as dead configuration. Contrast
226
+ [audit](./audit.md), where the identifiers are deliberately *not* foreign keys
227
+ because an entry must outlive its subject.
228
+
229
+ ---
230
+
231
+ ## No caching
232
+
233
+ Every call is a query. `all()` exists so you make one per request rather than one
234
+ per conditional; wrap it in your own cache if you need more.
235
+
236
+ Deliberate: a library that cached by default would give you stale flags at a moment
237
+ you did not choose, and the right TTL depends on how you deploy.