@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,225 @@
1
+ # Roles, permissions & authorization
2
+
3
+ ```ts
4
+ import { authorization, definePermissions } from "@digimuza/saas-core/authorization";
5
+ ```
6
+
7
+ > Orientation and recipes: [`src/authorization/README.md`](../src/authorization/README.md).
8
+
9
+
10
+ Authorization always requires workspace context. A user's effective permissions are
11
+ the **union** of the permissions carried by every role they hold in that workspace.
12
+
13
+ Permissions are application-defined; the core stores the vocabulary you register
14
+ rather than shipping its own.
15
+
16
+ ---
17
+
18
+ ## Setup
19
+
20
+ ```ts
21
+ // lib/permissions.ts
22
+ import { definePermissions } from "@digimuza/saas-core/authorization";
23
+
24
+ export const PERMISSIONS = definePermissions([
25
+ "projects.read",
26
+ "projects.create",
27
+ "projects.delete",
28
+ "members.invite",
29
+ "billing.read",
30
+ ] as const);
31
+
32
+ export type AppPermission = (typeof PERMISSIONS)[number];
33
+ ```
34
+
35
+ ```ts
36
+ // once at startup, or from a migration step
37
+ await authorization.registerPermissions(PERMISSIONS.map((key) => ({ key })));
38
+ ```
39
+
40
+ ### `definePermissions(keys)`
41
+
42
+ ```ts
43
+ function definePermissions<const T extends readonly string[]>(keys: T): T
44
+ ```
45
+
46
+ Purely a typing helper — no I/O. The `const` type parameter preserves the literal
47
+ keys so you get a union type and autocompletion.
48
+
49
+ ### `registerPermissions(definitions)`
50
+
51
+ ```ts
52
+ function registerPermissions(definitions: readonly { key: string; description?: string }[]): Promise<void>
53
+ ```
54
+
55
+ Idempotent, so it is safe on every boot. Permissions must exist before a role can
56
+ be granted them.
57
+
58
+ ---
59
+
60
+ ## Checking
61
+
62
+ ### `authorization.can(context, permission)`
63
+
64
+ ```ts
65
+ function can(context: WorkspaceContext, permission: string): Promise<boolean>
66
+ ```
67
+
68
+ ```ts
69
+ if (await authorization.can(context, "projects.delete")) {
70
+ // show the delete button
71
+ }
72
+ ```
73
+
74
+ ### `authorization.require(context, permission)`
75
+
76
+ ```ts
77
+ function require(context: WorkspaceContext, permission: string): Promise<void>
78
+ ```
79
+
80
+ Throws `ForbiddenError` with `.permission` set to the missing key.
81
+
82
+ ### `canAll` / `canAny`
83
+
84
+ ```ts
85
+ function canAll(context: WorkspaceContext, required: readonly string[]): Promise<boolean>
86
+ function canAny(context: WorkspaceContext, required: readonly string[]): Promise<boolean>
87
+ ```
88
+
89
+ Empty lists are handled explicitly and differently: `canAll([])` is `true`
90
+ (vacuously satisfied), `canAny([])` is `false` (nothing to satisfy). Both are
91
+ tested so neither is accidental.
92
+
93
+ ### `authorization.getEffectivePermissions(context)`
94
+
95
+ ```ts
96
+ function getEffectivePermissions(context: WorkspaceContext): Promise<Set<string>>
97
+ ```
98
+
99
+ The union across all the user's roles, resolved in **one** query — a `SELECT
100
+ DISTINCT` over member grants joined through roles to permissions. Holding more
101
+ roles simply widens the set.
102
+
103
+ Both halves of the join to `roles` are constrained by workspace, so a stale grant
104
+ could not contribute another tenant's permissions.
105
+
106
+ ### `authorization.hasRole(context, roleKey)`
107
+
108
+ ```ts
109
+ function hasRole(context: WorkspaceContext, roleKey: string): Promise<boolean>
110
+ ```
111
+
112
+ **Prefer permissions.** Role checks couple application logic to the role structure,
113
+ so restructuring roles silently changes behaviour. This exists for the rare check
114
+ that genuinely is about role identity.
115
+
116
+ Matches on `key`, the stable machine identifier, never on `name`, which is
117
+ user-editable and localisable — renaming a role must not change who can do what.
118
+
119
+ ### `authorization.getRoles(context)`
120
+
121
+ ```ts
122
+ function getRoles(context: WorkspaceContext): Promise<Role[]>
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Role administration
128
+
129
+ ```ts
130
+ authorization.roles.list(context): Promise<Role[]>
131
+
132
+ authorization.roles.create(context, {
133
+ key: string;
134
+ name: string;
135
+ description?: string;
136
+ isDefault?: boolean;
137
+ permissions?: readonly string[];
138
+ }): Promise<Role>
139
+
140
+ authorization.roles.setPermissions(context, roleId, keys): Promise<void>
141
+ authorization.roles.delete(context, roleId): Promise<void>
142
+ authorization.roles.assign(context, { userId, roleId }): Promise<void>
143
+ authorization.roles.unassign(context, { userId, roleId }): Promise<void>
144
+ ```
145
+
146
+ - `setPermissions` **replaces** the set; pass `[]` to clear it.
147
+ - `delete` throws `ForbiddenError` for system roles. Deleting `admin` would leave
148
+ nobody able to administer the workspace.
149
+ - `assign` is idempotent and emits nothing when the role was already held —
150
+ re-announcing an unchanged grant would make event consumers act twice.
151
+ - `unassign` throws `NotFoundError` if the user does not hold the role.
152
+ - Every one of these verifies the role belongs to the caller's workspace first, so
153
+ a role id from another tenant cannot be probed or modified.
154
+
155
+ ---
156
+
157
+ ## Cross-workspace isolation is a database constraint
158
+
159
+ `workspace_member_roles` stores `workspace_id` beside `user_id` and `role_id` so
160
+ that two composite foreign keys can share it:
161
+
162
+ ```
163
+ (workspace_id, user_id) → workspace_members(workspace_id, user_id)
164
+ (role_id, workspace_id) → roles(id, workspace_id)
165
+ ```
166
+
167
+ Both read the **same** `workspace_id` column, so granting a member of workspace A
168
+ a role belonging to workspace B is rejected by PostgreSQL — not by application code
169
+ that could be forgotten or bypassed. Switching `workspace_id` to satisfy one key
170
+ breaks the other. There are tests for both directions, plus the bypass attempt.
171
+
172
+ `workspace_invitations` carries the same guard on its optional `role_id`.
173
+
174
+ When the constraint fires, `roles.assign` translates it to `NotFoundError` — a
175
+ foreign-key violation is the database enforcing tenancy, not an unexpected fault.
176
+
177
+ ---
178
+
179
+ ## Roles table
180
+
181
+ | Column | Notes |
182
+ | --- | --- |
183
+ | `key` | Stable machine identifier. Unique per workspace. |
184
+ | `name` | Human label. Editable; never used in authorization logic. |
185
+ | `is_system` | Created with the workspace; protected from deletion. |
186
+ | `is_default` | Granted to new members. At most one per workspace. |
187
+
188
+ `key` and the two flags are additions beyond the original spec's column list.
189
+ `key` exists so authorization never depends on a renameable string; the flags
190
+ implement the spec's "system roles, default roles, custom roles" requirement.
191
+
192
+ ---
193
+
194
+ ## `findRolesWithPermission(db, workspaceId, permission)`
195
+
196
+ ```ts
197
+ function findRolesWithPermission(
198
+ db: CoreDatabase, workspaceId: string, permission: string,
199
+ ): Promise<Role[]>
200
+ ```
201
+
202
+ "Which roles here can do X?" — for building a permissions matrix UI.
203
+
204
+ ---
205
+
206
+ ## Authorization vs entitlements
207
+
208
+ They answer different questions and **both** must pass:
209
+
210
+ ```ts
211
+ await authorization.require(context, "projects.create"); // may this user?
212
+ await entitlements.require(context, "ai_generation"); // has this workspace paid?
213
+ ```
214
+
215
+ See [entitlements.md](./entitlements.md).
216
+
217
+ ---
218
+
219
+ ## Custom construction
220
+
221
+ ```ts
222
+ import { createAuthorizationService } from "@digimuza/saas-core/authorization";
223
+
224
+ const authorization = createAuthorizationService({ db, events }); // events optional
225
+ ```
@@ -0,0 +1,293 @@
1
+ # Billing
2
+
3
+ ```ts
4
+ import { billing, InvalidWebhookSignatureError } from "@digimuza/saas-core/billing";
5
+ ```
6
+
7
+ > Orientation and recipes: [`src/billing/README.md`](../src/billing/README.md).
8
+
9
+
10
+ Everything above the `BillingProvider` interface is provider-independent, so
11
+ adopting a second payment provider means writing an adapter — a test enforces that
12
+ nothing outside the adapter mentions Revolut.
13
+
14
+ The core does not implement payment processing.
15
+
16
+ ---
17
+
18
+ ## Plans
19
+
20
+ ### `billing.plans.upsert(input)`
21
+
22
+ ```ts
23
+ function upsert(input: {
24
+ key: string; // stable internal identifier
25
+ name: string;
26
+ description?: string;
27
+ providerPriceId?: string; // for providers with a price catalogue
28
+ amountCents?: number; // minor units, to avoid floating-point money
29
+ currency?: string; // ISO 4217, uppercased for you
30
+ interval?: "month" | "year" | "one_time";
31
+ isActive?: boolean;
32
+ sortOrder?: number;
33
+ entitlements?: readonly EntitlementDefinition[];
34
+ }): Promise<Plan>
35
+ ```
36
+
37
+ Idempotent — run it on every boot to sync the catalogue from code.
38
+
39
+ ```ts
40
+ await billing.plans.upsert({
41
+ key: "pro",
42
+ name: "Pro",
43
+ amountCents: 2900,
44
+ entitlements: [
45
+ { key: "ai_generation", kind: "feature" },
46
+ { key: "ai_generations", kind: "limit", limitValue: 100 },
47
+ { key: "team_members", kind: "limit", limitValue: null }, // unlimited
48
+ ],
49
+ });
50
+ ```
51
+
52
+ Omit `entitlements` and the existing set is left alone; pass it and the set is
53
+ **replaced**. A `limitValue` on a `feature` is discarded — storing one would make
54
+ `getLimit()` on a feature look meaningful.
55
+
56
+ Throws `InvalidInputError` for duplicate keys or a negative limit.
57
+
58
+ ### `billing.plans.list` / `getByKey` / `setEntitlements`
59
+
60
+ ```ts
61
+ function list(options?: { includeInactive?: boolean }): Promise<Plan[]>
62
+ function getByKey(key: string): Promise<Plan | undefined>
63
+ function setEntitlements(planKey: string, definitions: readonly EntitlementDefinition[]): Promise<void>
64
+ ```
65
+
66
+ `list()` hides inactive plans by default: `isActive: false` retires a plan from the
67
+ pricing page while still honouring it for existing customers.
68
+
69
+ Plans use `ON DELETE RESTRICT` from `subscriptions`. Deleting a plan customers are
70
+ paying for would silently strip their entitlements — retire it instead. There is a
71
+ test asserting the delete fails.
72
+
73
+ ---
74
+
75
+ ## Customers
76
+
77
+ ```ts
78
+ function getCustomer(context: WorkspaceContext): Promise<BillingCustomer | undefined>
79
+ function ensureCustomer(context: WorkspaceContext, options?: { email?: string }): Promise<BillingCustomer>
80
+ ```
81
+
82
+ Billing is workspace-scoped: the tenant pays, and members come and go.
83
+
84
+ `ensureCustomer` is safe to call concurrently — a race on the workspace constraint
85
+ adopts the winner's row. It matches on
86
+ `billing_customers_workspace_id_unique` specifically; a violation of
87
+ `billing_customers_provider_customer_unique` means the provider handed back an id
88
+ already bound to a *different* workspace, which is a genuine fault that must
89
+ surface.
90
+
91
+ ---
92
+
93
+ ## Checkout
94
+
95
+ ```ts
96
+ function createCheckout(context: WorkspaceContext, options: {
97
+ planKey: string;
98
+ successUrl: string;
99
+ cancelUrl: string;
100
+ quantity?: number;
101
+ metadata?: Record<string, string>;
102
+ }): Promise<{ url: string; providerCheckoutId?: string }>
103
+ ```
104
+
105
+ ```ts
106
+ const { url } = await billing.createCheckout(context, {
107
+ planKey: "pro",
108
+ successUrl: "https://app.example.com/billing/done",
109
+ cancelUrl: "https://app.example.com/billing",
110
+ });
111
+ redirect(url);
112
+ ```
113
+
114
+ Creates the provider customer lazily if needed. Throws `NotFoundError` for an
115
+ unknown plan, `ConflictError` for a retired one.
116
+
117
+ **Do not grant access when the user returns to `successUrl`.** That redirect is
118
+ attacker-controllable and proves nothing about payment. Access follows from the
119
+ webhook.
120
+
121
+ ---
122
+
123
+ ## Webhooks are the only source of truth
124
+
125
+ ### `billing.webhooks.handle(request)`
126
+
127
+ ```ts
128
+ function handle(request: {
129
+ rawBody: string; // exactly as received, before any parsing
130
+ signature: string;
131
+ timestamp?: string;
132
+ }): Promise<WebhookOutcome>
133
+
134
+ type WebhookOutcome =
135
+ | { status: "processed"; eventId: string; type: string }
136
+ | { status: "duplicate"; type: string }
137
+ | { status: "ignored"; eventId: string; type: string };
138
+ ```
139
+
140
+ ```ts
141
+ // app/api/billing/webhook/route.ts
142
+ export async function POST(request: Request) {
143
+ const rawBody = await request.text(); // text, not json
144
+
145
+ try {
146
+ const outcome = await billing.webhooks.handle({
147
+ rawBody,
148
+ signature: request.headers.get("revolut-signature") ?? "",
149
+ timestamp: request.headers.get("revolut-request-timestamp") ?? undefined,
150
+ });
151
+ return Response.json(outcome);
152
+ } catch (error) {
153
+ if (error instanceof InvalidWebhookSignatureError) {
154
+ return new Response("invalid signature", { status: 401 });
155
+ }
156
+ throw error; // 5xx makes the provider retry
157
+ }
158
+ }
159
+ ```
160
+
161
+ **Read the body as text.** Parsing and re-serialising JSON changes key order and
162
+ whitespace, which invalidates the signature.
163
+
164
+ Verification happens before the parser, and before anything touches the database.
165
+ `InvalidWebhookSignatureError`'s message is deliberately uninformative — a caller
166
+ who cannot produce a valid signature gets no hint about which part failed.
167
+
168
+ ### Idempotency is a database constraint
169
+
170
+ `(provider, provider_event_id)` is unique and **the insert is the claim**. So
171
+ at-least-once delivery and concurrent redeliveries are handled by PostgreSQL, not
172
+ by a check-then-act two requests could pass together. There is a test firing three
173
+ identical deliveries concurrently: one processes, two dedupe, one subscription row
174
+ results.
175
+
176
+ The claim is a conditional upsert with `setWhere: status = 'failed'`, so a retry
177
+ re-claims an event whose previous attempt **failed** but never one already
178
+ `processed` or currently `pending`. Genuine failures are replayable without
179
+ risking a double application. The raw payload is retained so replay needs no help
180
+ from the provider.
181
+
182
+ ### `processed` vs `ignored` vs `duplicate`
183
+
184
+ `ignored` means verified and stored but not actionable — an unknown customer or an
185
+ unresolvable plan. Routine when several environments share one provider account;
186
+ conflating it with `failed` would bury real failures.
187
+
188
+ ### Tenancy comes from our own records
189
+
190
+ The workspace is resolved from our `billing_customers` row, matched on the provider
191
+ customer id — **never** from the webhook payload. So even a leaked signing secret
192
+ could not redirect a subscription to another tenant.
193
+
194
+ ### Upgrades retire the previous subscription
195
+
196
+ `subscriptions_one_live_per_workspace_idx` allows exactly one live subscription per
197
+ workspace, which keeps "what plan is this workspace on?" unambiguous rather than
198
+ row-order dependent. An upgrade arrives as a *new* subscription, so applying it
199
+ cancels the old one.
200
+
201
+ ---
202
+
203
+ ## Subscription lifecycle
204
+
205
+ ```ts
206
+ function getSubscription(context: WorkspaceContext): Promise<{ subscription: Subscription; plan: Plan } | undefined>
207
+ function cancelSubscription(context: WorkspaceContext, options?: { atPeriodEnd?: boolean }): Promise<Subscription>
208
+ function getPortal(context: WorkspaceContext, options: { returnUrl: string }): Promise<{ url: string | undefined }>
209
+ ```
210
+
211
+ `cancelSubscription` defaults to `atPeriodEnd: true`, which keeps the subscription
212
+ live — and therefore entitling — until the paid period expires. `false` ends
213
+ entitlements immediately.
214
+
215
+ **`getPortal` can return `undefined`.** Handle it; do not assume a URL.
216
+
217
+ ---
218
+
219
+ ## Revolut's capability boundaries
220
+
221
+ Revolut Merchant is an order-and-payment API, not a subscription platform. It has
222
+ no hosted customer portal and no server-side subscription object. So
223
+ `cancelSubscription` and `getPortalUrl` are **optional** on `BillingProvider` and
224
+ absent from the Revolut adapter rather than stubbed to silently do nothing:
225
+
226
+ - `getPortal()` returns `{ url: undefined }` — build your own billing screen.
227
+ - `cancelSubscription()` records the local state change, and calls the provider
228
+ only when the adapter supports it.
229
+
230
+ Recurring charges on Revolut are merchant-initiated: the core owns subscription
231
+ state and drives the charges.
232
+
233
+ ### Verification status
234
+
235
+ Signature verification implements Revolut's documented scheme and is unit-tested:
236
+ HMAC-SHA256 over `v1.{timestamp}.{body}`, a freshness window for replay protection
237
+ (rejecting both stale timestamps and clocks skewed forward), constant-time
238
+ comparison, and the comma-separated signatures sent during secret rotation.
239
+
240
+ **The HTTP calls — `createCustomer` and `createCheckout` — have not been run
241
+ against live Revolut credentials.** Treat them as unverified.
242
+
243
+ ```ts
244
+ import { verifyRevolutSignature } from "@digimuza/saas-core/billing";
245
+
246
+ // Exported separately, so a route handler can verify without constructing
247
+ // API credentials it does not need.
248
+ verifyRevolutSignature({ rawBody, signature, timestamp, secret });
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Writing another provider
254
+
255
+ ```ts
256
+ interface BillingProvider {
257
+ readonly name: string;
258
+ createCustomer(input): Promise<{ providerCustomerId: string }>;
259
+ createCheckout(input): Promise<{ url: string; providerCheckoutId?: string }>;
260
+ cancelSubscription?(input): Promise<void>; // optional
261
+ getPortalUrl?(input): Promise<string>; // optional
262
+ verifyWebhook(input): boolean;
263
+ parseWebhookEvent(rawBody: string): ProviderWebhookEvent;
264
+ }
265
+ ```
266
+
267
+ Two obligations the types cannot express:
268
+
269
+ 1. **Map the provider's statuses onto `SubscriptionStatus`.** Fail closed — an
270
+ unrecognised state must not become `active`, or you grant entitlements the
271
+ customer may not have.
272
+ 2. **Convert dates to `Date` instances.** Providers send ISO strings; passing one
273
+ through fails deep inside the database driver with an error naming neither the
274
+ field nor the adapter.
275
+
276
+ Resolve the plan by `providerPriceId` if the provider has a price catalogue, or by
277
+ `planKey` if the plan travels in a reference you set at checkout.
278
+
279
+ ```ts
280
+ import { createBillingService } from "@digimuza/saas-core/billing";
281
+
282
+ const billing = createBillingService({ db, provider: myProvider, events });
283
+ ```
284
+
285
+ ---
286
+
287
+ ## Diagnostics
288
+
289
+ ```ts
290
+ import { countFailedBillingEvents } from "@digimuza/saas-core/billing";
291
+
292
+ const backlog = await countFailedBillingEvents(db); // awaiting replay
293
+ ```