bunderstack 0.17.0-beta.2 → 0.17.0-beta.4

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 (336) hide show
  1. package/CHANGELOG.md +233 -0
  2. package/README.md +11 -1
  3. package/dist/access.d.ts +116 -0
  4. package/dist/access.d.ts.map +1 -0
  5. package/dist/access.js +325 -0
  6. package/dist/access.js.map +1 -0
  7. package/dist/api/builder.d.ts +145 -0
  8. package/dist/api/builder.d.ts.map +1 -0
  9. package/dist/api/builder.js +28 -0
  10. package/dist/api/builder.js.map +1 -0
  11. package/dist/api/context.d.ts +34 -0
  12. package/dist/api/context.d.ts.map +1 -0
  13. package/dist/api/context.js +32 -0
  14. package/dist/api/context.js.map +1 -0
  15. package/dist/api/crud-router.d.ts +290 -0
  16. package/dist/api/crud-router.d.ts.map +1 -0
  17. package/dist/api/crud-router.js +249 -0
  18. package/dist/api/crud-router.js.map +1 -0
  19. package/dist/api/openapi.d.ts +6 -0
  20. package/dist/api/openapi.d.ts.map +1 -0
  21. package/dist/api/openapi.js +146 -0
  22. package/dist/api/openapi.js.map +1 -0
  23. package/dist/api/realtime-router.d.ts +76 -0
  24. package/dist/api/realtime-router.d.ts.map +1 -0
  25. package/dist/api/realtime-router.js +41 -0
  26. package/dist/api/realtime-router.js.map +1 -0
  27. package/dist/api/registry.d.ts +30 -0
  28. package/dist/api/registry.d.ts.map +1 -0
  29. package/dist/api/registry.js +239 -0
  30. package/dist/api/registry.js.map +1 -0
  31. package/dist/api/router.d.ts +9 -0
  32. package/dist/api/router.d.ts.map +1 -0
  33. package/dist/api/router.js +19 -0
  34. package/dist/api/router.js.map +1 -0
  35. package/dist/api/storage-router.d.ts +279 -0
  36. package/dist/api/storage-router.d.ts.map +1 -0
  37. package/dist/api/storage-router.js +155 -0
  38. package/dist/api/storage-router.js.map +1 -0
  39. package/dist/api/types.d.ts +55 -0
  40. package/dist/api/types.d.ts.map +1 -0
  41. package/dist/api/types.js +2 -0
  42. package/dist/api/types.js.map +1 -0
  43. package/dist/auth.d.ts +31 -0
  44. package/dist/auth.d.ts.map +1 -0
  45. package/dist/auth.js +102 -0
  46. package/dist/auth.js.map +1 -0
  47. package/dist/blueprint-generator.d.ts +18 -0
  48. package/dist/blueprint-generator.d.ts.map +1 -0
  49. package/dist/blueprint-generator.js +125 -0
  50. package/dist/blueprint-generator.js.map +1 -0
  51. package/dist/blueprint.d.ts +46 -0
  52. package/dist/blueprint.d.ts.map +1 -0
  53. package/dist/blueprint.js +162 -0
  54. package/dist/blueprint.js.map +1 -0
  55. package/dist/cli.d.ts +8 -0
  56. package/dist/cli.d.ts.map +1 -0
  57. package/dist/cli.js +68 -0
  58. package/dist/cli.js.map +1 -0
  59. package/dist/config.d.ts +108 -0
  60. package/dist/config.d.ts.map +1 -0
  61. package/dist/config.js +90 -0
  62. package/dist/config.js.map +1 -0
  63. package/dist/cron.d.ts +4 -0
  64. package/dist/cron.d.ts.map +1 -0
  65. package/dist/cron.js +3 -0
  66. package/dist/cron.js.map +1 -0
  67. package/dist/crud-operations.d.ts +43 -0
  68. package/dist/crud-operations.d.ts.map +1 -0
  69. package/dist/crud-operations.js +238 -0
  70. package/dist/crud-operations.js.map +1 -0
  71. package/dist/database/adapter.d.ts +20 -0
  72. package/dist/database/adapter.d.ts.map +1 -0
  73. package/dist/database/adapter.js +2 -0
  74. package/dist/database/adapter.js.map +1 -0
  75. package/dist/database/bun-sql.d.ts +3 -0
  76. package/dist/database/bun-sql.d.ts.map +1 -0
  77. package/dist/database/bun-sql.js +21 -0
  78. package/dist/database/bun-sql.js.map +1 -0
  79. package/dist/database/libsql.d.ts +3 -0
  80. package/dist/database/libsql.d.ts.map +1 -0
  81. package/dist/database/libsql.js +22 -0
  82. package/dist/database/libsql.js.map +1 -0
  83. package/dist/database/pglite.d.ts +3 -0
  84. package/dist/database/pglite.d.ts.map +1 -0
  85. package/dist/database/pglite.js +27 -0
  86. package/dist/database/pglite.js.map +1 -0
  87. package/dist/database/postgres-js.d.ts +3 -0
  88. package/dist/database/postgres-js.d.ts.map +1 -0
  89. package/dist/database/postgres-js.js +21 -0
  90. package/dist/database/postgres-js.js.map +1 -0
  91. package/dist/db.d.ts +18 -0
  92. package/dist/db.d.ts.map +1 -0
  93. package/dist/db.js +26 -0
  94. package/dist/db.js.map +1 -0
  95. package/dist/dialect.d.ts +17 -0
  96. package/dist/dialect.d.ts.map +1 -0
  97. package/dist/dialect.js +22 -0
  98. package/dist/dialect.js.map +1 -0
  99. package/dist/email/smtp.d.ts +14 -0
  100. package/dist/email/smtp.d.ts.map +1 -0
  101. package/dist/email/smtp.js +27 -0
  102. package/dist/email/smtp.js.map +1 -0
  103. package/dist/email.d.ts +39 -0
  104. package/dist/email.d.ts.map +1 -0
  105. package/dist/email.js +97 -0
  106. package/dist/email.js.map +1 -0
  107. package/dist/env.d.ts +47 -0
  108. package/dist/env.d.ts.map +1 -0
  109. package/dist/env.js +99 -0
  110. package/dist/env.js.map +1 -0
  111. package/dist/errors.d.ts +125 -0
  112. package/dist/errors.d.ts.map +1 -0
  113. package/dist/errors.js +92 -0
  114. package/dist/errors.js.map +1 -0
  115. package/dist/handler.d.ts +9 -0
  116. package/dist/handler.d.ts.map +1 -0
  117. package/dist/handler.js +22 -0
  118. package/dist/handler.js.map +1 -0
  119. package/dist/idempotency.d.ts +17 -0
  120. package/dist/idempotency.d.ts.map +1 -0
  121. package/dist/idempotency.js +65 -0
  122. package/dist/idempotency.js.map +1 -0
  123. package/dist/index.d.ts +134 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +480 -0
  126. package/dist/index.js.map +1 -0
  127. package/dist/internal-tables-pg.d.ts +481 -0
  128. package/dist/internal-tables-pg.d.ts.map +1 -0
  129. package/{src/internal-tables-pg.ts → dist/internal-tables-pg.js} +10 -34
  130. package/dist/internal-tables-pg.js.map +1 -0
  131. package/dist/internal-tables.d.ts +2509 -0
  132. package/dist/internal-tables.d.ts.map +1 -0
  133. package/dist/internal-tables.js +108 -0
  134. package/dist/internal-tables.js.map +1 -0
  135. package/dist/jobs/cron.d.ts +15 -0
  136. package/dist/jobs/cron.d.ts.map +1 -0
  137. package/dist/jobs/cron.js +74 -0
  138. package/dist/jobs/cron.js.map +1 -0
  139. package/dist/jobs/define.d.ts +133 -0
  140. package/dist/jobs/define.d.ts.map +1 -0
  141. package/dist/jobs/define.js +74 -0
  142. package/dist/jobs/define.js.map +1 -0
  143. package/dist/jobs/index.d.ts +11 -0
  144. package/dist/jobs/index.d.ts.map +1 -0
  145. package/dist/jobs/index.js +8 -0
  146. package/dist/jobs/index.js.map +1 -0
  147. package/dist/jobs/queue.d.ts +6 -0
  148. package/dist/jobs/queue.d.ts.map +1 -0
  149. package/dist/jobs/queue.js +55 -0
  150. package/dist/jobs/queue.js.map +1 -0
  151. package/dist/jobs/runtime.d.ts +13 -0
  152. package/dist/jobs/runtime.d.ts.map +1 -0
  153. package/dist/jobs/runtime.js +46 -0
  154. package/dist/jobs/runtime.js.map +1 -0
  155. package/dist/jobs/slots.d.ts +25 -0
  156. package/dist/jobs/slots.d.ts.map +1 -0
  157. package/dist/jobs/slots.js +41 -0
  158. package/dist/jobs/slots.js.map +1 -0
  159. package/dist/jobs/worker.d.ts +12 -0
  160. package/dist/jobs/worker.d.ts.map +1 -0
  161. package/dist/jobs/worker.js +311 -0
  162. package/dist/jobs/worker.js.map +1 -0
  163. package/dist/lifecycle.d.ts +10 -0
  164. package/dist/lifecycle.d.ts.map +1 -0
  165. package/dist/lifecycle.js +37 -0
  166. package/dist/lifecycle.js.map +1 -0
  167. package/dist/list-query.d.ts +62 -0
  168. package/dist/list-query.d.ts.map +1 -0
  169. package/dist/list-query.js +194 -0
  170. package/dist/list-query.js.map +1 -0
  171. package/dist/manifest.d.ts +59 -0
  172. package/dist/manifest.d.ts.map +1 -0
  173. package/dist/manifest.js +167 -0
  174. package/dist/manifest.js.map +1 -0
  175. package/dist/provision-internals.d.ts +24 -0
  176. package/dist/provision-internals.d.ts.map +1 -0
  177. package/dist/provision-internals.js +7 -0
  178. package/dist/provision-internals.js.map +1 -0
  179. package/dist/provision.d.ts +23 -0
  180. package/dist/provision.d.ts.map +1 -0
  181. package/dist/provision.js +96 -0
  182. package/dist/provision.js.map +1 -0
  183. package/dist/rate-limit.d.ts +7 -0
  184. package/dist/rate-limit.d.ts.map +1 -0
  185. package/dist/rate-limit.js +49 -0
  186. package/dist/rate-limit.js.map +1 -0
  187. package/dist/realtime/facade.d.ts +18 -0
  188. package/dist/realtime/facade.d.ts.map +1 -0
  189. package/dist/realtime/facade.js +36 -0
  190. package/dist/realtime/facade.js.map +1 -0
  191. package/dist/realtime/filter.d.ts +13 -0
  192. package/dist/realtime/filter.d.ts.map +1 -0
  193. package/dist/realtime/filter.js +48 -0
  194. package/dist/realtime/filter.js.map +1 -0
  195. package/dist/realtime/heartbeat.d.ts +14 -0
  196. package/dist/realtime/heartbeat.d.ts.map +1 -0
  197. package/dist/realtime/heartbeat.js +64 -0
  198. package/dist/realtime/heartbeat.js.map +1 -0
  199. package/dist/realtime/publisher.d.ts +21 -0
  200. package/dist/realtime/publisher.d.ts.map +1 -0
  201. package/dist/realtime/publisher.js +17 -0
  202. package/dist/realtime/publisher.js.map +1 -0
  203. package/dist/schema-export-pg.d.ts +2 -0
  204. package/dist/schema-export-pg.d.ts.map +1 -0
  205. package/dist/schema-export-pg.js +4 -0
  206. package/dist/schema-export-pg.js.map +1 -0
  207. package/dist/schema-export.d.ts +2 -0
  208. package/dist/schema-export.d.ts.map +1 -0
  209. package/dist/schema-export.js +2 -0
  210. package/dist/schema-export.js.map +1 -0
  211. package/dist/scope.d.ts +4 -0
  212. package/dist/scope.d.ts.map +1 -0
  213. package/dist/scope.js +13 -0
  214. package/dist/scope.js.map +1 -0
  215. package/dist/standard-schema.d.ts +13 -0
  216. package/dist/standard-schema.d.ts.map +1 -0
  217. package/dist/standard-schema.js +34 -0
  218. package/dist/standard-schema.js.map +1 -0
  219. package/dist/storage/buckets.d.ts +80 -0
  220. package/dist/storage/buckets.d.ts.map +1 -0
  221. package/dist/storage/buckets.js +178 -0
  222. package/dist/storage/buckets.js.map +1 -0
  223. package/dist/storage/delete.d.ts +11 -0
  224. package/dist/storage/delete.d.ts.map +1 -0
  225. package/dist/storage/delete.js +18 -0
  226. package/dist/storage/delete.js.map +1 -0
  227. package/dist/storage/file-meta.d.ts +37 -0
  228. package/dist/storage/file-meta.d.ts.map +1 -0
  229. package/dist/storage/file-meta.js +166 -0
  230. package/dist/storage/file-meta.js.map +1 -0
  231. package/dist/storage/index.d.ts +28 -0
  232. package/dist/storage/index.d.ts.map +1 -0
  233. package/dist/storage/index.js +5 -0
  234. package/dist/storage/index.js.map +1 -0
  235. package/dist/storage/local.d.ts +15 -0
  236. package/dist/storage/local.d.ts.map +1 -0
  237. package/dist/storage/local.js +56 -0
  238. package/dist/storage/local.js.map +1 -0
  239. package/dist/storage/operations.d.ts +54 -0
  240. package/dist/storage/operations.d.ts.map +1 -0
  241. package/dist/storage/operations.js +250 -0
  242. package/dist/storage/operations.js.map +1 -0
  243. package/dist/storage/registry.d.ts +10 -0
  244. package/dist/storage/registry.d.ts.map +1 -0
  245. package/dist/storage/registry.js +23 -0
  246. package/dist/storage/registry.js.map +1 -0
  247. package/dist/storage/s3.d.ts +28 -0
  248. package/dist/storage/s3.d.ts.map +1 -0
  249. package/dist/storage/s3.js +71 -0
  250. package/dist/storage/s3.js.map +1 -0
  251. package/dist/storage/sweep.d.ts +9 -0
  252. package/dist/storage/sweep.d.ts.map +1 -0
  253. package/dist/storage/sweep.js +17 -0
  254. package/dist/storage/sweep.js.map +1 -0
  255. package/dist/storage/thumbnails.d.ts +11 -0
  256. package/dist/storage/thumbnails.d.ts.map +1 -0
  257. package/dist/storage/thumbnails.js +60 -0
  258. package/dist/storage/thumbnails.js.map +1 -0
  259. package/dist/testing.d.ts +27 -0
  260. package/dist/testing.d.ts.map +1 -0
  261. package/dist/testing.js +11 -0
  262. package/dist/testing.js.map +1 -0
  263. package/dist/typeid-pg.d.ts +19 -0
  264. package/dist/typeid-pg.d.ts.map +1 -0
  265. package/{src/typeid-pg.ts → dist/typeid-pg.js} +10 -13
  266. package/dist/typeid-pg.js.map +1 -0
  267. package/dist/typeid.d.ts +45 -0
  268. package/dist/typeid.d.ts.map +1 -0
  269. package/dist/typeid.js +100 -0
  270. package/dist/typeid.js.map +1 -0
  271. package/package.json +77 -28
  272. package/src/access.ts +0 -532
  273. package/src/api/builder.ts +0 -52
  274. package/src/api/context.ts +0 -83
  275. package/src/api/crud-router.ts +0 -386
  276. package/src/api/openapi.ts +0 -184
  277. package/src/api/realtime-router.ts +0 -75
  278. package/src/api/registry.ts +0 -338
  279. package/src/api/router.ts +0 -34
  280. package/src/api/storage-router.ts +0 -224
  281. package/src/api/types.ts +0 -105
  282. package/src/auth.ts +0 -117
  283. package/src/blueprint-generator.ts +0 -203
  284. package/src/blueprint.ts +0 -264
  285. package/src/cli.ts +0 -90
  286. package/src/config.ts +0 -215
  287. package/src/cron.ts +0 -3
  288. package/src/crud-operations.ts +0 -478
  289. package/src/database/adapter.ts +0 -26
  290. package/src/database/bun-sql.ts +0 -23
  291. package/src/database/libsql.ts +0 -28
  292. package/src/database/pglite.ts +0 -33
  293. package/src/database/postgres-js.ts +0 -33
  294. package/src/db.ts +0 -61
  295. package/src/dialect.ts +0 -38
  296. package/src/email/smtp.ts +0 -45
  297. package/src/email.ts +0 -154
  298. package/src/env.ts +0 -180
  299. package/src/errors.ts +0 -123
  300. package/src/handler.ts +0 -30
  301. package/src/idempotency.ts +0 -97
  302. package/src/index.ts +0 -834
  303. package/src/internal-tables.ts +0 -149
  304. package/src/jobs/cron.ts +0 -87
  305. package/src/jobs/define.ts +0 -283
  306. package/src/jobs/index.ts +0 -37
  307. package/src/jobs/queue.ts +0 -67
  308. package/src/jobs/runtime.ts +0 -58
  309. package/src/jobs/slots.ts +0 -52
  310. package/src/jobs/worker.ts +0 -369
  311. package/src/lifecycle.ts +0 -49
  312. package/src/list-query.ts +0 -333
  313. package/src/manifest.ts +0 -297
  314. package/src/provision-internals.ts +0 -29
  315. package/src/provision.ts +0 -128
  316. package/src/rate-limit.ts +0 -71
  317. package/src/realtime/facade.ts +0 -74
  318. package/src/realtime/filter.ts +0 -81
  319. package/src/realtime/heartbeat.ts +0 -80
  320. package/src/realtime/publisher.ts +0 -46
  321. package/src/schema-export-pg.ts +0 -7
  322. package/src/schema-export.ts +0 -5
  323. package/src/scope.ts +0 -17
  324. package/src/standard-schema.ts +0 -59
  325. package/src/storage/buckets.ts +0 -308
  326. package/src/storage/delete.ts +0 -26
  327. package/src/storage/file-meta.ts +0 -222
  328. package/src/storage/index.ts +0 -39
  329. package/src/storage/local.ts +0 -69
  330. package/src/storage/operations.ts +0 -398
  331. package/src/storage/registry.ts +0 -40
  332. package/src/storage/s3.ts +0 -99
  333. package/src/storage/sweep.ts +0 -25
  334. package/src/storage/thumbnails.ts +0 -65
  335. package/src/testing.ts +0 -31
  336. package/src/typeid.ts +0 -116
@@ -0,0 +1,49 @@
1
+ const buckets = new Map();
2
+ function resolveConfig(config) {
3
+ if (!config)
4
+ return null;
5
+ if (config === true)
6
+ return {};
7
+ return config;
8
+ }
9
+ function clientKey(req) {
10
+ const forwarded = req.headers.get('x-forwarded-for');
11
+ if (forwarded)
12
+ return forwarded.split(',')[0].trim();
13
+ return req.headers.get('x-real-ip') ?? 'local';
14
+ }
15
+ export function createRateLimiter(config) {
16
+ const resolved = resolveConfig(config);
17
+ if (!resolved) {
18
+ return async (_req) => null;
19
+ }
20
+ const windowMs = resolved.windowMs ?? 60_000;
21
+ const max = resolved.max ?? 100;
22
+ return async (req) => {
23
+ if (resolved.skip?.(req))
24
+ return null;
25
+ const key = `${clientKey(req)}:${new URL(req.url).pathname}`;
26
+ const now = Date.now();
27
+ let bucket = buckets.get(key);
28
+ if (!bucket || bucket.resetAt <= now) {
29
+ bucket = { count: 0, resetAt: now + windowMs };
30
+ buckets.set(key, bucket);
31
+ }
32
+ bucket.count += 1;
33
+ if (bucket.count > max) {
34
+ const retryAfter = Math.ceil((bucket.resetAt - now) / 1000);
35
+ return new Response(JSON.stringify({
36
+ error: 'Too many requests',
37
+ code: 'TOO_MANY_REQUESTS',
38
+ }), {
39
+ status: 429,
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ 'Retry-After': String(retryAfter),
43
+ },
44
+ });
45
+ }
46
+ return null;
47
+ };
48
+ }
49
+ //# sourceMappingURL=rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAA;AAEzC,SAAS,aAAa,CACpB,MAA6C;IAE7C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACxB,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,EAAE,CAAA;IAC9B,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,SAAS,CAAC,GAAY;IAC7B,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;IACpD,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAA;IACrD,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,OAAO,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAA6C;IAE7C,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;IACtC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,KAAK,EAAE,IAAa,EAAE,EAAE,CAAC,IAAI,CAAA;IACtC,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,MAAM,CAAA;IAC5C,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,IAAI,GAAG,CAAA;IAE/B,OAAO,KAAK,EAAE,GAAY,EAA4B,EAAE;QACtD,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAA;QAErC,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAE7B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,GAAG,EAAE,CAAC;YACrC,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,GAAG,QAAQ,EAAE,CAAA;YAC9C,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QAC1B,CAAC;QAED,MAAM,CAAC,KAAK,IAAI,CAAC,CAAA;QACjB,IAAI,MAAM,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC;YACvB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA;YAC3D,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC;gBACb,KAAK,EAAE,mBAAmB;gBAC1B,IAAI,EAAE,mBAAmB;aAC1B,CAAC,EACF;gBACE,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC;iBAClC;aACF,CACF,CAAA;QACH,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type InferSelectModel, type Table } from 'drizzle-orm';
2
+ import type { RealtimeAction, RealtimePublisher } from './publisher.js';
3
+ export type RealtimeTransport = 'disabled' | 'memory' | 'redis';
4
+ export type SchemaTable<TSchema extends Record<string, unknown>> = Extract<TSchema[keyof TSchema], Table>;
5
+ export interface RealtimeFacade<TSchema extends Record<string, unknown> = Record<string, unknown>> {
6
+ readonly enabled: boolean;
7
+ readonly transport: RealtimeTransport;
8
+ publish<TTable extends SchemaTable<TSchema>>(table: TTable, action: RealtimeAction, record: InferSelectModel<TTable>): Promise<void>;
9
+ }
10
+ /**
11
+ * One name for a table everywhere: events, subscriptions, and the CRUD router
12
+ * all use the schema key. Pass the schema so a key like `creditBalances` is not
13
+ * published as its SQL name `credit_balances` — clients subscribe with the key
14
+ * they call procedures with. Without a schema, the SQL name is the only name
15
+ * available and is used as-is.
16
+ */
17
+ export declare function createRealtimeFacade<TSchema extends Record<string, unknown>>(publisher?: RealtimePublisher, transport?: RealtimeTransport, schema?: TSchema): RealtimeFacade<TSchema>;
18
+ //# sourceMappingURL=facade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facade.d.ts","sourceRoot":"","sources":["../../src/realtime/facade.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,KAAK,EACX,MAAM,aAAa,CAAA;AAEpB,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EAClB,MAAM,aAAa,CAAA;AAEpB,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE/D,MAAM,MAAM,WAAW,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,OAAO,CACxE,OAAO,CAAC,MAAM,OAAO,CAAC,EACtB,KAAK,CACN,CAAA;AAED,MAAM,WAAW,cAAc,CAC7B,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEjE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAA;IAErC,OAAO,CAAC,MAAM,SAAS,WAAW,CAAC,OAAO,CAAC,EACzC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAAA;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1E,SAAS,CAAC,EAAE,iBAAiB,EAC7B,SAAS,GAAE,iBAAqD,EAChE,MAAM,CAAC,EAAE,OAAO,GACf,cAAc,CAAC,OAAO,CAAC,CA8BzB"}
@@ -0,0 +1,36 @@
1
+ import { getTableName, isTable, } from 'drizzle-orm';
2
+ /**
3
+ * One name for a table everywhere: events, subscriptions, and the CRUD router
4
+ * all use the schema key. Pass the schema so a key like `creditBalances` is not
5
+ * published as its SQL name `credit_balances` — clients subscribe with the key
6
+ * they call procedures with. Without a schema, the SQL name is the only name
7
+ * available and is used as-is.
8
+ */
9
+ export function createRealtimeFacade(publisher, transport = publisher ? 'memory' : 'disabled', schema) {
10
+ if (!publisher && transport !== 'disabled') {
11
+ throw new Error('[bunderstack] an enabled realtime transport requires a publisher');
12
+ }
13
+ if (publisher && transport === 'disabled') {
14
+ throw new Error('[bunderstack] a realtime publisher cannot use the disabled transport');
15
+ }
16
+ const keyByTableName = new Map();
17
+ for (const [key, value] of Object.entries(schema ?? {})) {
18
+ if (isTable(value))
19
+ keyByTableName.set(getTableName(value), key);
20
+ }
21
+ return {
22
+ enabled: publisher !== undefined,
23
+ transport,
24
+ async publish(table, action, record) {
25
+ if (!publisher)
26
+ return;
27
+ const tableName = getTableName(table);
28
+ await publisher.publish('change', {
29
+ table: keyByTableName.get(tableName) ?? tableName,
30
+ action,
31
+ record: record,
32
+ });
33
+ },
34
+ };
35
+ }
36
+ //# sourceMappingURL=facade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facade.js","sourceRoot":"","sources":["../../src/realtime/facade.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,OAAO,GAGR,MAAM,aAAa,CAAA;AA2BpB;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAA6B,EAC7B,YAA+B,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,EAChE,MAAgB;IAEhB,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAA;IACH,CAAC;IACD,IAAI,SAAS,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,sEAAsE,CACvE,CAAA;IACH,CAAC;IAED,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAA;IAChD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,IAAI,OAAO,CAAC,KAAK,CAAC;YAAE,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAA;IAClE,CAAC;IAED,OAAO;QACL,OAAO,EAAE,SAAS,KAAK,SAAS;QAChC,SAAS;QACT,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM;YACjC,IAAI,CAAC,SAAS;gBAAE,OAAM;YACtB,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;YACrC,MAAM,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE;gBAChC,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS;gBACjD,MAAM;gBACN,MAAM,EAAE,MAA4C;aACrD,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { AccessUser, ResolvedAccess } from '../access.js';
2
+ import type { RealtimeChange } from './publisher.js';
3
+ export interface FilterRealtimeChangesOptions {
4
+ subscriptions: readonly string[];
5
+ access: ResolvedAccess;
6
+ request: Request;
7
+ getSession: () => Promise<{
8
+ user: AccessUser | null;
9
+ activeOrganizationId: string | null;
10
+ }>;
11
+ }
12
+ export declare function filterRealtimeChanges(source: AsyncIterable<RealtimeChange>, options: FilterRealtimeChangesOptions): AsyncGenerator<RealtimeChange, void, void>;
13
+ //# sourceMappingURL=filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/realtime/filter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACf,MAAM,WAAW,CAAA;AAClB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAQjD,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE,SAAS,MAAM,EAAE,CAAA;IAChC,MAAM,EAAE,cAAc,CAAA;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,OAAO,CAAC;QACxB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;QACvB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;KACpC,CAAC,CAAA;CACH;AAED,wBAAuB,qBAAqB,CAC1C,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,EACrC,OAAO,EAAE,4BAA4B,GACpC,cAAc,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,CAqD5C"}
@@ -0,0 +1,48 @@
1
+ import { getEventMeta, withEventMeta } from '@orpc/server';
2
+ import { checkAccess, rowMatchesScope, tableEntryForName, } from '../access.js';
3
+ export async function* filterRealtimeChanges(source, options) {
4
+ const subscriptions = new Set(options.subscriptions);
5
+ let sessionPromise;
6
+ const getSession = () => (sessionPromise ??= options.getSession());
7
+ for await (const change of source) {
8
+ // Events name tables by schema key; the SQL-name lookup stays as a fallback
9
+ // for publishers outside the CRUD path that only know the physical name.
10
+ const entry = options.access.get(change.table) ??
11
+ tableEntryForName(options.access, change.table);
12
+ if (!entry?.enabled)
13
+ continue;
14
+ const recordId = change.record.id;
15
+ if (!subscriptions.has(change.table) &&
16
+ (recordId == null ||
17
+ !subscriptions.has(`${change.table}/${String(recordId)}`))) {
18
+ continue;
19
+ }
20
+ if (entry.get === 'deny')
21
+ continue;
22
+ const needsSession = entry.get !== 'public' || entry.readScope !== undefined;
23
+ const session = needsSession
24
+ ? await getSession()
25
+ : { user: null, activeOrganizationId: null };
26
+ const context = {
27
+ request: options.request,
28
+ user: session.user,
29
+ row: change.record,
30
+ session: { activeOrganizationId: session.activeOrganizationId },
31
+ };
32
+ if (!(await checkAccess(entry.get, context, entry.ownerColumn)).allowed) {
33
+ continue;
34
+ }
35
+ if (entry.readScope &&
36
+ !rowMatchesScope(change.record, entry.readScope(context))) {
37
+ continue;
38
+ }
39
+ const projected = {
40
+ table: change.table,
41
+ action: change.action,
42
+ record: change.record,
43
+ };
44
+ const meta = getEventMeta(change);
45
+ yield meta ? withEventMeta(projected, meta) : projected;
46
+ }
47
+ }
48
+ //# sourceMappingURL=filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/realtime/filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAQ1D,OAAO,EACL,WAAW,EACX,eAAe,EACf,iBAAiB,GAClB,MAAM,WAAW,CAAA;AAYlB,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,qBAAqB,CAC1C,MAAqC,EACrC,OAAqC;IAErC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;IACpD,IAAI,cAES,CAAA;IACb,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,CAAC,cAAc,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;IAElE,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;QAClC,4EAA4E;QAC5E,yEAAyE;QACzE,MAAM,KAAK,GACT,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;YAChC,iBAAiB,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;QACjD,IAAI,CAAC,KAAK,EAAE,OAAO;YAAE,SAAQ;QAE7B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAA;QACjC,IACE,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;YAChC,CAAC,QAAQ,IAAI,IAAI;gBACf,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAC5D,CAAC;YACD,SAAQ;QACV,CAAC;QACD,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM;YAAE,SAAQ;QAElC,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAA;QAC5E,MAAM,OAAO,GAAG,YAAY;YAC1B,CAAC,CAAC,MAAM,UAAU,EAAE;YACpB,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAA;QAC9C,MAAM,OAAO,GAAG;YACd,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,GAAG,EAAE,MAAM,CAAC,MAAM;YAClB,OAAO,EAAE,EAAE,oBAAoB,EAAE,OAAO,CAAC,oBAAoB,EAAE;SAChE,CAAA;QACD,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACxE,SAAQ;QACV,CAAC;QACD,IACE,KAAK,CAAC,SAAS;YACf,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EACzD,CAAC;YACD,SAAQ;QACV,CAAC;QAED,MAAM,SAAS,GAAmB;YAChC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAA;QACD,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;QACjC,MAAM,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACzD,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ export declare const REALTIME_HEARTBEAT_INTERVAL_MS = 5000;
2
+ export type RealtimeHeartbeat = {
3
+ type: 'heartbeat';
4
+ };
5
+ /**
6
+ * Emits a transport-only event whenever the source has been idle for an
7
+ * interval. Heartbeats are deliberately not published, persisted, or assigned
8
+ * event IDs, so they do not affect replay and resume semantics.
9
+ */
10
+ export declare function withRealtimeHeartbeat<T>(source: AsyncIterable<T>, options: {
11
+ intervalMs?: number;
12
+ signal?: AbortSignal;
13
+ }): AsyncGenerator<T | RealtimeHeartbeat, void, void>;
14
+ //# sourceMappingURL=heartbeat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../src/realtime/heartbeat.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,8BAA8B,OAAQ,CAAA;AAEnD,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAA;AAOrD;;;;GAIG;AACH,wBAAuB,qBAAqB,CAAC,CAAC,EAC5C,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EACxB,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GACrD,cAAc,CAAC,CAAC,GAAG,iBAAiB,EAAE,IAAI,EAAE,IAAI,CAAC,CA8DnD"}
@@ -0,0 +1,64 @@
1
+ export const REALTIME_HEARTBEAT_INTERVAL_MS = 5_000;
2
+ /**
3
+ * Emits a transport-only event whenever the source has been idle for an
4
+ * interval. Heartbeats are deliberately not published, persisted, or assigned
5
+ * event IDs, so they do not affect replay and resume semantics.
6
+ */
7
+ export async function* withRealtimeHeartbeat(source, options) {
8
+ const intervalMs = Math.max(1, options.intervalMs ?? REALTIME_HEARTBEAT_INTERVAL_MS);
9
+ const iterator = source[Symbol.asyncIterator]();
10
+ let state = { status: 'pending' };
11
+ let wake;
12
+ const getState = () => state;
13
+ const requestNext = () => {
14
+ state = { status: 'pending' };
15
+ void iterator.next().then((result) => {
16
+ state = { status: 'ready', result };
17
+ wake?.();
18
+ }, (error) => {
19
+ state = { status: 'error', error };
20
+ wake?.();
21
+ });
22
+ };
23
+ requestNext();
24
+ try {
25
+ while (!options.signal?.aborted) {
26
+ let current = getState();
27
+ if (current.status === 'pending') {
28
+ await new Promise((resolve) => {
29
+ let settled = false;
30
+ const finish = () => {
31
+ if (settled)
32
+ return;
33
+ settled = true;
34
+ clearTimeout(timer);
35
+ options.signal?.removeEventListener('abort', finish);
36
+ resolve();
37
+ };
38
+ const timer = setTimeout(finish, intervalMs);
39
+ options.signal?.addEventListener('abort', finish, { once: true });
40
+ wake = finish;
41
+ });
42
+ wake = undefined;
43
+ if (options.signal?.aborted)
44
+ break;
45
+ current = getState();
46
+ if (current.status === 'pending') {
47
+ yield { type: 'heartbeat' };
48
+ continue;
49
+ }
50
+ }
51
+ if (current.status === 'error')
52
+ throw current.error;
53
+ if (current.result.done)
54
+ break;
55
+ yield current.result.value;
56
+ requestNext();
57
+ }
58
+ }
59
+ finally {
60
+ wake = undefined;
61
+ await iterator.return?.();
62
+ }
63
+ }
64
+ //# sourceMappingURL=heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../../src/realtime/heartbeat.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,8BAA8B,GAAG,KAAK,CAAA;AASnD;;;;GAIG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,qBAAqB,CAC1C,MAAwB,EACxB,OAAsD;IAEtD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CACzB,CAAC,EACD,OAAO,CAAC,UAAU,IAAI,8BAA8B,CACrD,CAAA;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAA;IAC/C,IAAI,KAAK,GAAmB,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;IACjD,IAAI,IAA8B,CAAA;IAClC,MAAM,QAAQ,GAAG,GAAmB,EAAE,CAAC,KAAK,CAAA;IAE5C,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,KAAK,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;QAC7B,KAAK,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,CACvB,CAAC,MAAM,EAAE,EAAE;YACT,KAAK,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;YACnC,IAAI,EAAE,EAAE,CAAA;QACV,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;YACjB,KAAK,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;YAClC,IAAI,EAAE,EAAE,CAAA;QACV,CAAC,CACF,CAAA;IACH,CAAC,CAAA;IAED,WAAW,EAAE,CAAA;IACb,IAAI,CAAC;QACH,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;YAChC,IAAI,OAAO,GAAG,QAAQ,EAAE,CAAA;YACxB,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACjC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;oBAClC,IAAI,OAAO,GAAG,KAAK,CAAA;oBACnB,MAAM,MAAM,GAAG,GAAG,EAAE;wBAClB,IAAI,OAAO;4BAAE,OAAM;wBACnB,OAAO,GAAG,IAAI,CAAA;wBACd,YAAY,CAAC,KAAK,CAAC,CAAA;wBACnB,OAAO,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;wBACpD,OAAO,EAAE,CAAA;oBACX,CAAC,CAAA;oBACD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;oBAC5C,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;oBACjE,IAAI,GAAG,MAAM,CAAA;gBACf,CAAC,CAAC,CAAA;gBACF,IAAI,GAAG,SAAS,CAAA;gBAEhB,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;oBAAE,MAAK;gBAClC,OAAO,GAAG,QAAQ,EAAE,CAAA;gBACpB,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;oBACjC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;oBAC3B,SAAQ;gBACV,CAAC;YACH,CAAC;YAED,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO;gBAAE,MAAM,OAAO,CAAC,KAAK,CAAA;YACnD,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI;gBAAE,MAAK;YAE9B,MAAM,OAAO,CAAC,MAAM,CAAC,KAAK,CAAA;YAC1B,WAAW,EAAE,CAAA;QACf,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,GAAG,SAAS,CAAA;QAChB,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAA;IAC3B,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { Publisher } from '@orpc/publisher';
2
+ import type { RedisClient } from 'bun';
3
+ export type RealtimeAction = 'create' | 'update' | 'delete';
4
+ export interface RealtimeChange {
5
+ table: string;
6
+ action: RealtimeAction;
7
+ record: Record<string, unknown>;
8
+ }
9
+ export interface RealtimeEvents extends Record<string, object> {
10
+ change: RealtimeChange;
11
+ }
12
+ export type RealtimePublisher = Publisher<RealtimeEvents>;
13
+ export interface RealtimePublisherOptions {
14
+ maxBufferedEvents?: number;
15
+ resumeSeconds?: number;
16
+ }
17
+ export declare function createMemoryRealtimePublisher(options?: RealtimePublisherOptions): RealtimePublisher;
18
+ export declare function createRedisRealtimePublisher(redis: RedisClient, subscriber: RedisClient | Promise<RedisClient>, options?: RealtimePublisherOptions & {
19
+ prefix?: string;
20
+ }): RealtimePublisher;
21
+ //# sourceMappingURL=publisher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher.d.ts","sourceRoot":"","sources":["../../src/realtime/publisher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAA;AAKtC,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAE3D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,cAAc,CAAA;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC;AAED,MAAM,WAAW,cAAe,SAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAC5D,MAAM,EAAE,cAAc,CAAA;CACvB;AAED,MAAM,MAAM,iBAAiB,GAAG,SAAS,CAAC,cAAc,CAAC,CAAA;AAEzD,MAAM,WAAW,wBAAwB;IACvC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,wBAA6B,GACrC,iBAAiB,CAKnB;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,EAC9C,OAAO,GAAE,wBAAwB,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3D,iBAAiB,CAOnB"}
@@ -0,0 +1,17 @@
1
+ import { BunRedisPublisher } from '@orpc/bun';
2
+ import { MemoryPublisher } from '@orpc/publisher/memory';
3
+ export function createMemoryRealtimePublisher(options = {}) {
4
+ return new MemoryPublisher({
5
+ maxBufferedEvents: options.maxBufferedEvents,
6
+ resume: { enabled: true, seconds: options.resumeSeconds ?? 300 },
7
+ });
8
+ }
9
+ export function createRedisRealtimePublisher(redis, subscriber, options = {}) {
10
+ return new BunRedisPublisher(redis, {
11
+ subscriber,
12
+ prefix: options.prefix ?? 'bunderstack:',
13
+ maxBufferedEvents: options.maxBufferedEvents,
14
+ resume: { enabled: true, seconds: options.resumeSeconds ?? 300 },
15
+ });
16
+ }
17
+ //# sourceMappingURL=publisher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher.js","sourceRoot":"","sources":["../../src/realtime/publisher.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAqBxD,MAAM,UAAU,6BAA6B,CAC3C,UAAoC,EAAE;IAEtC,OAAO,IAAI,eAAe,CAAiB;QACzC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,IAAI,GAAG,EAAE;KACjE,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,KAAkB,EAClB,UAA8C,EAC9C,UAA0D,EAAE;IAE5D,OAAO,IAAI,iBAAiB,CAAiB,KAAK,EAAE;QAClD,UAAU;QACV,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,cAAc;QACxC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,IAAI,GAAG,EAAE;KACjE,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { bunderstackFilesPg as bunderstackFiles, bunderstackIdempotencyPg as bunderstackIdempotency, bunderstackJobsPg as bunderstackJobs, } from './internal-tables-pg.js';
2
+ //# sourceMappingURL=schema-export-pg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-export-pg.d.ts","sourceRoot":"","sources":["../src/schema-export-pg.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,IAAI,gBAAgB,EACtC,wBAAwB,IAAI,sBAAsB,EAClD,iBAAiB,IAAI,eAAe,GACrC,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,4 @@
1
+ // src/schema-export-pg.ts — pg twins under the same names bunderstack/schema
2
+ // uses, so `export * from 'bunderstack/schema/pg'` mirrors the sqlite setup.
3
+ export { bunderstackFilesPg as bunderstackFiles, bunderstackIdempotencyPg as bunderstackIdempotency, bunderstackJobsPg as bunderstackJobs, } from './internal-tables-pg.js';
4
+ //# sourceMappingURL=schema-export-pg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-export-pg.js","sourceRoot":"","sources":["../src/schema-export-pg.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,OAAO,EACL,kBAAkB,IAAI,gBAAgB,EACtC,wBAAwB,IAAI,sBAAsB,EAClD,iBAAiB,IAAI,eAAe,GACrC,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { bunderstackFiles, bunderstackIdempotency, bunderstackJobs, } from './internal-tables.js';
2
+ //# sourceMappingURL=schema-export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-export.d.ts","sourceRoot":"","sources":["../src/schema-export.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,GAChB,MAAM,mBAAmB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { bunderstackFiles, bunderstackIdempotency, bunderstackJobs, } from './internal-tables.js';
2
+ //# sourceMappingURL=schema-export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-export.js","sourceRoot":"","sources":["../src/schema-export.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,GAChB,MAAM,mBAAmB,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { getTableColumns, type SQL } from 'drizzle-orm';
2
+ import type { ScopeMap } from './access.js';
3
+ export declare function buildScopeWhere(table: Parameters<typeof getTableColumns>[0], scope: ScopeMap): SQL | undefined;
4
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,eAAe,EAAW,KAAK,GAAG,EAAE,MAAM,aAAa,CAAA;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,wBAAgB,eAAe,CAC7B,KAAK,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,EAC5C,KAAK,EAAE,QAAQ,GACd,GAAG,GAAG,SAAS,CASjB"}
package/dist/scope.js ADDED
@@ -0,0 +1,13 @@
1
+ import { and, eq, getTableColumns, inArray } from 'drizzle-orm';
2
+ export function buildScopeWhere(table, scope) {
3
+ const columns = getTableColumns(table);
4
+ const conditions = [];
5
+ for (const [name, value] of Object.entries(scope)) {
6
+ const col = columns[name];
7
+ if (!col)
8
+ continue;
9
+ conditions.push(Array.isArray(value) ? inArray(col, value) : eq(col, value));
10
+ }
11
+ return conditions.length ? and(...conditions) : undefined;
12
+ }
13
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,eAAe,EAAE,OAAO,EAAY,MAAM,aAAa,CAAA;AAIzE,MAAM,UAAU,eAAe,CAC7B,KAA4C,EAC5C,KAAe;IAEf,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;IACtC,MAAM,UAAU,GAAU,EAAE,CAAA;IAC5B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QACzB,IAAI,CAAC,GAAG;YAAE,SAAQ;QAClB,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;IAC9E,CAAC;IACD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAC3D,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
2
+ export type StandardSchema = StandardSchemaV1;
3
+ export type InferStandardOutput<TSchema extends StandardSchemaV1> = StandardSchemaV1.InferOutput<TSchema>;
4
+ export type StandardSchemaIssue = {
5
+ path: PropertyKey[];
6
+ message: string;
7
+ };
8
+ export declare class StandardSchemaValidationError extends Error {
9
+ readonly issues: StandardSchemaIssue[];
10
+ constructor(label: string, issues: readonly StandardSchemaV1.Issue[]);
11
+ }
12
+ export declare function validateStandardSchema<TSchema extends StandardSchemaV1>(schema: TSchema, value: unknown, label: string): StandardSchemaV1.InferOutput<TSchema>;
13
+ //# sourceMappingURL=standard-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard-schema.d.ts","sourceRoot":"","sources":["../src/standard-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAE7D,MAAM,MAAM,cAAc,GAAG,gBAAgB,CAAA;AAC7C,MAAM,MAAM,mBAAmB,CAAC,OAAO,SAAS,gBAAgB,IAC9D,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;AAEvC,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,WAAW,EAAE,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,QAAQ,CAAC,MAAM,EAAE,mBAAmB,EAAE,CAAA;gBAE1B,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,gBAAgB,CAAC,KAAK,EAAE;CAkBrE;AAWD,wBAAgB,sBAAsB,CAAC,OAAO,SAAS,gBAAgB,EACrE,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,GACZ,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,CAWvC"}
@@ -0,0 +1,34 @@
1
+ export class StandardSchemaValidationError extends Error {
2
+ issues;
3
+ constructor(label, issues) {
4
+ const normalized = issues.map((issue) => ({
5
+ path: [...(issue.path ?? [])].map((segment) => typeof segment === 'object' ? segment.key : segment),
6
+ message: issue.message,
7
+ }));
8
+ super(normalized
9
+ .map((issue) => {
10
+ const path = issue.path.map(String).join('.');
11
+ return `${label}${path ? `.${path}` : ''}: ${issue.message}`;
12
+ })
13
+ .join('\n'));
14
+ this.name = 'StandardSchemaValidationError';
15
+ this.issues = normalized;
16
+ }
17
+ }
18
+ function isPromiseLike(value) {
19
+ return (typeof value === 'object' &&
20
+ value !== null &&
21
+ 'then' in value &&
22
+ typeof value.then === 'function');
23
+ }
24
+ export function validateStandardSchema(schema, value, label) {
25
+ const result = schema['~standard'].validate(value);
26
+ if (isPromiseLike(result)) {
27
+ throw new Error(`[bunderstack] ${label} schema validation must be synchronous`);
28
+ }
29
+ if (result.issues) {
30
+ throw new StandardSchemaValidationError(label, result.issues);
31
+ }
32
+ return result.value;
33
+ }
34
+ //# sourceMappingURL=standard-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard-schema.js","sourceRoot":"","sources":["../src/standard-schema.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAC7C,MAAM,CAAuB;IAEtC,YAAY,KAAa,EAAE,MAAyC;QAClE,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACxC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAC5C,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CACpD;YACD,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC,CAAA;QACH,KAAK,CACH,UAAU;aACP,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC7C,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,OAAO,EAAE,CAAA;QAC9D,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CACd,CAAA;QACD,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAA;QAC3C,IAAI,CAAC,MAAM,GAAG,UAAU,CAAA;IAC1B,CAAC;CACF;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CACjC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,MAAe,EACf,KAAc,EACd,KAAa;IAEb,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAClD,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,iBAAiB,KAAK,wCAAwC,CAC/D,CAAA;IACH,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,IAAI,6BAA6B,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAA;AACrB,CAAC"}
@@ -0,0 +1,80 @@
1
+ import type { OperationRule, ScopeResolver } from '../access.js';
2
+ export type BucketBackendInput = {
3
+ s3: {
4
+ bucket: string;
5
+ region?: string;
6
+ endpoint?: string;
7
+ publicUrl?: string;
8
+ };
9
+ } | {
10
+ local: string;
11
+ };
12
+ export type BucketConfigInput = {
13
+ visibility?: 'public' | 'private';
14
+ access?: {
15
+ create?: OperationRule;
16
+ get?: OperationRule;
17
+ delete?: OperationRule;
18
+ };
19
+ upload?: {
20
+ maxSize?: string | number;
21
+ accept?: string[];
22
+ };
23
+ transforms?: boolean;
24
+ scope?: {
25
+ read?: ScopeResolver;
26
+ write?: ScopeResolver;
27
+ };
28
+ quota?: {
29
+ perUser?: string | number;
30
+ perScope?: string | number;
31
+ };
32
+ } & Partial<BucketBackendInput>;
33
+ export type StorageConfigInput = {
34
+ s3?: true | {
35
+ endpoint?: string;
36
+ };
37
+ local?: true | string;
38
+ defaultBucket?: string;
39
+ buckets?: Record<string, BucketConfigInput>;
40
+ };
41
+ export type ResolvedBackend = {
42
+ type: 'local';
43
+ path: string;
44
+ } | {
45
+ type: 's3';
46
+ bucket: string;
47
+ region: string;
48
+ endpoint?: string;
49
+ accessKeyId: string;
50
+ secretAccessKey: string;
51
+ publicUrl?: string;
52
+ };
53
+ export type ResolvedBucket = {
54
+ name: string;
55
+ backend: ResolvedBackend;
56
+ visibility: 'public' | 'private';
57
+ access: {
58
+ create: OperationRule;
59
+ get: OperationRule;
60
+ delete: OperationRule;
61
+ };
62
+ upload?: {
63
+ maxSizeBytes?: number;
64
+ accept?: string[];
65
+ };
66
+ transforms: boolean;
67
+ readScope?: ScopeResolver;
68
+ writeScope?: ScopeResolver;
69
+ quota?: {
70
+ perUserBytes?: number;
71
+ perScopeBytes?: number;
72
+ };
73
+ };
74
+ export type ResolvedStorageBuckets = {
75
+ defaultBucket: string;
76
+ buckets: Map<string, ResolvedBucket>;
77
+ };
78
+ export declare function parseSize(value: string | number): number;
79
+ export declare function resolveBuckets(input: StorageConfigInput | undefined, env?: Record<string, string | undefined>): ResolvedStorageBuckets;
80
+ //# sourceMappingURL=buckets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buckets.d.ts","sourceRoot":"","sources":["../../src/storage/buckets.ts"],"names":[],"mappings":"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"}