bunderstack 0.17.0-beta.0 → 0.17.0-beta.3

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 (337) hide show
  1. package/CHANGELOG.md +227 -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 +76 -0
  60. package/dist/config.d.ts.map +1 -0
  61. package/dist/config.js +81 -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 +477 -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 +81 -29
  272. package/src/access.ts +0 -552
  273. package/src/api/api-types.types.ts +0 -106
  274. package/src/api/builder.ts +0 -52
  275. package/src/api/context.ts +0 -83
  276. package/src/api/crud-router.ts +0 -321
  277. package/src/api/openapi.ts +0 -184
  278. package/src/api/realtime-router.ts +0 -75
  279. package/src/api/registry.ts +0 -338
  280. package/src/api/router.ts +0 -34
  281. package/src/api/storage-router.ts +0 -224
  282. package/src/api/types.ts +0 -84
  283. package/src/auth.ts +0 -117
  284. package/src/blueprint-generator.ts +0 -203
  285. package/src/blueprint.ts +0 -264
  286. package/src/cli.ts +0 -90
  287. package/src/config.ts +0 -215
  288. package/src/cron.ts +0 -3
  289. package/src/crud-operations.ts +0 -488
  290. package/src/database/adapter.ts +0 -26
  291. package/src/database/bun-sql.ts +0 -23
  292. package/src/database/libsql.ts +0 -28
  293. package/src/database/pglite.ts +0 -33
  294. package/src/database/postgres-js.ts +0 -33
  295. package/src/db.ts +0 -61
  296. package/src/dialect.ts +0 -38
  297. package/src/email/smtp.ts +0 -45
  298. package/src/email.ts +0 -154
  299. package/src/env.ts +0 -180
  300. package/src/errors.ts +0 -118
  301. package/src/handler.ts +0 -30
  302. package/src/idempotency.ts +0 -97
  303. package/src/index.ts +0 -822
  304. package/src/internal-tables.ts +0 -149
  305. package/src/jobs/cron.ts +0 -87
  306. package/src/jobs/define.ts +0 -283
  307. package/src/jobs/index.ts +0 -37
  308. package/src/jobs/queue.ts +0 -67
  309. package/src/jobs/runtime.ts +0 -58
  310. package/src/jobs/slots.ts +0 -52
  311. package/src/jobs/worker.ts +0 -369
  312. package/src/lifecycle.ts +0 -49
  313. package/src/list-query.ts +0 -416
  314. package/src/manifest.ts +0 -297
  315. package/src/provision-internals.ts +0 -29
  316. package/src/provision.ts +0 -128
  317. package/src/rate-limit.ts +0 -71
  318. package/src/realtime/facade.ts +0 -55
  319. package/src/realtime/filter.ts +0 -77
  320. package/src/realtime/heartbeat.ts +0 -80
  321. package/src/realtime/publisher.ts +0 -46
  322. package/src/schema-export-pg.ts +0 -7
  323. package/src/schema-export.ts +0 -5
  324. package/src/scope.ts +0 -17
  325. package/src/standard-schema.ts +0 -59
  326. package/src/storage/buckets.ts +0 -308
  327. package/src/storage/delete.ts +0 -26
  328. package/src/storage/file-meta.ts +0 -222
  329. package/src/storage/index.ts +0 -39
  330. package/src/storage/local.ts +0 -69
  331. package/src/storage/operations.ts +0 -398
  332. package/src/storage/registry.ts +0 -40
  333. package/src/storage/s3.ts +0 -99
  334. package/src/storage/sweep.ts +0 -25
  335. package/src/storage/thumbnails.ts +0 -65
  336. package/src/testing.ts +0 -31
  337. 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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"}