bunderstack 0.19.1 → 0.20.0

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 (46) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/api/crud-router.d.ts +19 -24
  3. package/dist/api/crud-router.d.ts.map +1 -1
  4. package/dist/api/crud-router.js +39 -18
  5. package/dist/api/crud-router.js.map +1 -1
  6. package/dist/api/live-window.d.ts.map +1 -1
  7. package/dist/api/live-window.js +13 -3
  8. package/dist/api/live-window.js.map +1 -1
  9. package/dist/api/realtime-router.d.ts +2 -0
  10. package/dist/api/realtime-router.d.ts.map +1 -1
  11. package/dist/api/realtime-router.js +1 -0
  12. package/dist/api/realtime-router.js.map +1 -1
  13. package/dist/api/types.d.ts +2 -2
  14. package/dist/api/types.d.ts.map +1 -1
  15. package/dist/api/types.js.map +1 -1
  16. package/dist/blueprint-generator.d.ts.map +1 -1
  17. package/dist/blueprint-generator.js +8 -2
  18. package/dist/blueprint-generator.js.map +1 -1
  19. package/dist/blueprint.d.ts +3 -1
  20. package/dist/blueprint.d.ts.map +1 -1
  21. package/dist/blueprint.js +2 -2
  22. package/dist/blueprint.js.map +1 -1
  23. package/dist/codegen.d.ts +36 -0
  24. package/dist/codegen.d.ts.map +1 -0
  25. package/dist/codegen.js +235 -0
  26. package/dist/codegen.js.map +1 -0
  27. package/dist/crud-operations.d.ts.map +1 -1
  28. package/dist/crud-operations.js +7 -3
  29. package/dist/crud-operations.js.map +1 -1
  30. package/dist/index.d.ts +9 -4
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/live/protocol.d.ts +3 -0
  34. package/dist/live/protocol.d.ts.map +1 -1
  35. package/dist/live/protocol.js.map +1 -1
  36. package/dist/realtime/facade.d.ts +3 -1
  37. package/dist/realtime/facade.d.ts.map +1 -1
  38. package/dist/realtime/facade.js +2 -1
  39. package/dist/realtime/facade.js.map +1 -1
  40. package/dist/realtime/filter.d.ts.map +1 -1
  41. package/dist/realtime/filter.js +1 -0
  42. package/dist/realtime/filter.js.map +1 -1
  43. package/dist/realtime/publisher.d.ts +2 -0
  44. package/dist/realtime/publisher.d.ts.map +1 -1
  45. package/dist/realtime/publisher.js.map +1 -1
  46. package/package.json +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/realtime/filter.ts"],"names":[],"mappings":"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","sourcesContent":["import { getEventMeta, withEventMeta } from '@orpc/server'\n\nimport type {\n AccessUser,\n OperationRule,\n ResolvedAccess,\n ResolvedTableAccess,\n} from '../access'\nimport type { RealtimeChange } from './publisher'\n\nimport { checkAccess, rowMatchesScope, tableEntryForName } from '../access'\n\ntype GetSession = () => Promise<{\n user: AccessUser | null\n activeOrganizationId: string | null\n}>\n\nexport interface FilterRealtimeChangesOptions {\n subscriptions: readonly string[]\n access: ResolvedAccess\n request: Request\n getSession: GetSession\n}\n\nexport interface FilterTableChangesOptions {\n /** Events arrive under this name — the schema key they were published with. */\n tableName: string\n entry: ResolvedTableAccess\n /**\n * The operation right this stream reads under: `get` for a subscription to\n * rows, `list` for a live view of a query.\n */\n rule: OperationRule\n request: Request\n getSession: GetSession\n}\n\n/**\n * Whether one change may reach this subscriber: the given right plus the read\n * scope of the row, evaluated against the caller's session. The session\n * resolves at most once per stream.\n */\nexport function createChangeGuard(\n entry: ResolvedTableAccess,\n options: { rule: OperationRule; request: Request; getSession: GetSession },\n): (change: RealtimeChange) => Promise<boolean> {\n let sessionPromise: ReturnType<GetSession> | undefined\n const getSession = () => (sessionPromise ??= options.getSession())\n\n return async (change) => {\n if (!entry.enabled || options.rule === 'deny') return false\n\n const needsSession =\n options.rule !== 'public' || entry.readScope !== undefined\n const session = needsSession\n ? await getSession()\n : { user: null, activeOrganizationId: null }\n const context = {\n request: options.request,\n user: session.user,\n row: change.record,\n session: { activeOrganizationId: session.activeOrganizationId },\n }\n if (!(await checkAccess(options.rule, context, entry.ownerColumn)).allowed) {\n return false\n }\n if (\n entry.readScope &&\n !rowMatchesScope(change.record, entry.readScope(context))\n ) {\n return false\n }\n return true\n }\n}\n\n/** Preserve publisher event metadata (ids) across the projection. */\nfunction project(change: RealtimeChange): RealtimeChange {\n const projected: RealtimeChange = {\n table: change.table,\n action: change.action,\n record: change.record,\n }\n const meta = getEventMeta(change)\n return meta ? withEventMeta(projected, meta) : projected\n}\n\nexport async function* filterRealtimeChanges(\n source: AsyncIterable<RealtimeChange>,\n options: FilterRealtimeChangesOptions,\n): AsyncGenerator<RealtimeChange, void, void> {\n const subscriptions = new Set(options.subscriptions)\n // One guard — and therefore one cached session — per table entry.\n const guards = new Map<\n ResolvedTableAccess,\n ReturnType<typeof createChangeGuard>\n >()\n\n for await (const change of source) {\n // Events name tables by schema key; the SQL-name lookup stays as a fallback\n // for publishers outside the CRUD path that only know the physical name.\n const entry =\n options.access.get(change.table) ??\n tableEntryForName(options.access, change.table)\n if (!entry?.enabled) continue\n\n const recordId = change.record.id\n if (\n !subscriptions.has(change.table) &&\n (recordId == null ||\n !subscriptions.has(`${change.table}/${String(recordId)}`))\n ) {\n continue\n }\n\n let guard = guards.get(entry)\n if (!guard) {\n guard = createChangeGuard(entry, { ...options, rule: entry.get })\n guards.set(entry, guard)\n }\n if (!(await guard(change))) continue\n yield project(change)\n }\n}\n\n/**\n * The same stream narrowed to one table with its access entry known up front —\n * what a live view (`GET /{table}:live`) consumes.\n */\nexport async function* filterTableChanges(\n source: AsyncIterable<RealtimeChange>,\n options: FilterTableChangesOptions,\n): AsyncGenerator<RealtimeChange, void, void> {\n const guard = createChangeGuard(options.entry, options)\n for await (const change of source) {\n if (change.table !== options.tableName) continue\n if (!(await guard(change))) continue\n yield project(change)\n }\n}\n"]}
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/realtime/filter.ts"],"names":[],"mappings":"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","sourcesContent":["import { getEventMeta, withEventMeta } from '@orpc/server'\n\nimport type {\n AccessUser,\n OperationRule,\n ResolvedAccess,\n ResolvedTableAccess,\n} from '../access'\nimport type { RealtimeChange } from './publisher'\n\nimport { checkAccess, rowMatchesScope, tableEntryForName } from '../access'\n\ntype GetSession = () => Promise<{\n user: AccessUser | null\n activeOrganizationId: string | null\n}>\n\nexport interface FilterRealtimeChangesOptions {\n subscriptions: readonly string[]\n access: ResolvedAccess\n request: Request\n getSession: GetSession\n}\n\nexport interface FilterTableChangesOptions {\n /** Events arrive under this name — the schema key they were published with. */\n tableName: string\n entry: ResolvedTableAccess\n /**\n * The operation right this stream reads under: `get` for a subscription to\n * rows, `list` for a live view of a query.\n */\n rule: OperationRule\n request: Request\n getSession: GetSession\n}\n\n/**\n * Whether one change may reach this subscriber: the given right plus the read\n * scope of the row, evaluated against the caller's session. The session\n * resolves at most once per stream.\n */\nexport function createChangeGuard(\n entry: ResolvedTableAccess,\n options: { rule: OperationRule; request: Request; getSession: GetSession },\n): (change: RealtimeChange) => Promise<boolean> {\n let sessionPromise: ReturnType<GetSession> | undefined\n const getSession = () => (sessionPromise ??= options.getSession())\n\n return async (change) => {\n if (!entry.enabled || options.rule === 'deny') return false\n\n const needsSession =\n options.rule !== 'public' || entry.readScope !== undefined\n const session = needsSession\n ? await getSession()\n : { user: null, activeOrganizationId: null }\n const context = {\n request: options.request,\n user: session.user,\n row: change.record,\n session: { activeOrganizationId: session.activeOrganizationId },\n }\n if (\n !(await checkAccess(options.rule, context, entry.ownerColumn)).allowed\n ) {\n return false\n }\n if (\n entry.readScope &&\n !rowMatchesScope(change.record, entry.readScope(context))\n ) {\n return false\n }\n return true\n }\n}\n\n/** Preserve publisher event metadata (ids) across the projection. */\nfunction project(change: RealtimeChange): RealtimeChange {\n const projected: RealtimeChange = {\n table: change.table,\n action: change.action,\n record: change.record,\n ...(change.operationId ? { operationId: change.operationId } : {}),\n }\n const meta = getEventMeta(change)\n return meta ? withEventMeta(projected, meta) : projected\n}\n\nexport async function* filterRealtimeChanges(\n source: AsyncIterable<RealtimeChange>,\n options: FilterRealtimeChangesOptions,\n): AsyncGenerator<RealtimeChange, void, void> {\n const subscriptions = new Set(options.subscriptions)\n // One guard — and therefore one cached session — per table entry.\n const guards = new Map<\n ResolvedTableAccess,\n ReturnType<typeof createChangeGuard>\n >()\n\n for await (const change of source) {\n // Events name tables by schema key; the SQL-name lookup stays as a fallback\n // for publishers outside the CRUD path that only know the physical name.\n const entry =\n options.access.get(change.table) ??\n tableEntryForName(options.access, change.table)\n if (!entry?.enabled) continue\n\n const recordId = change.record.id\n if (\n !subscriptions.has(change.table) &&\n (recordId == null ||\n !subscriptions.has(`${change.table}/${String(recordId)}`))\n ) {\n continue\n }\n\n let guard = guards.get(entry)\n if (!guard) {\n guard = createChangeGuard(entry, { ...options, rule: entry.get })\n guards.set(entry, guard)\n }\n if (!(await guard(change))) continue\n yield project(change)\n }\n}\n\n/**\n * The same stream narrowed to one table with its access entry known up front —\n * what a live view (`GET /{table}:live`) consumes.\n */\nexport async function* filterTableChanges(\n source: AsyncIterable<RealtimeChange>,\n options: FilterTableChangesOptions,\n): AsyncGenerator<RealtimeChange, void, void> {\n const guard = createChangeGuard(options.entry, options)\n for await (const change of source) {\n if (change.table !== options.tableName) continue\n if (!(await guard(change))) continue\n yield project(change)\n }\n}\n"]}
@@ -5,6 +5,8 @@ export interface RealtimeChange {
5
5
  table: string;
6
6
  action: RealtimeAction;
7
7
  record: Record<string, unknown>;
8
+ /** Correlates this confirmed write with the client operation that caused it. */
9
+ operationId?: string;
8
10
  }
9
11
  export interface RealtimeEvents extends Record<string, object> {
10
12
  change: RealtimeChange;
@@ -1 +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"}
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;IAC/B,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;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"}
@@ -1 +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","sourcesContent":["import type { Publisher } from '@orpc/publisher'\nimport type { RedisClient } from 'bun'\n\nimport { BunRedisPublisher } from '@orpc/bun'\nimport { MemoryPublisher } from '@orpc/publisher/memory'\n\nexport type RealtimeAction = 'create' | 'update' | 'delete'\n\nexport interface RealtimeChange {\n table: string\n action: RealtimeAction\n record: Record<string, unknown>\n}\n\nexport interface RealtimeEvents extends Record<string, object> {\n change: RealtimeChange\n}\n\nexport type RealtimePublisher = Publisher<RealtimeEvents>\n\nexport interface RealtimePublisherOptions {\n maxBufferedEvents?: number\n resumeSeconds?: number\n}\n\nexport function createMemoryRealtimePublisher(\n options: RealtimePublisherOptions = {},\n): RealtimePublisher {\n return new MemoryPublisher<RealtimeEvents>({\n maxBufferedEvents: options.maxBufferedEvents,\n resume: { enabled: true, seconds: options.resumeSeconds ?? 300 },\n })\n}\n\nexport function createRedisRealtimePublisher(\n redis: RedisClient,\n subscriber: RedisClient | Promise<RedisClient>,\n options: RealtimePublisherOptions & { prefix?: string } = {},\n): RealtimePublisher {\n return new BunRedisPublisher<RealtimeEvents>(redis, {\n subscriber,\n prefix: options.prefix ?? 'bunderstack:',\n maxBufferedEvents: options.maxBufferedEvents,\n resume: { enabled: true, seconds: options.resumeSeconds ?? 300 },\n })\n}\n"]}
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;AAuBxD,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","sourcesContent":["import type { Publisher } from '@orpc/publisher'\nimport type { RedisClient } from 'bun'\n\nimport { BunRedisPublisher } from '@orpc/bun'\nimport { MemoryPublisher } from '@orpc/publisher/memory'\n\nexport type RealtimeAction = 'create' | 'update' | 'delete'\n\nexport interface RealtimeChange {\n table: string\n action: RealtimeAction\n record: Record<string, unknown>\n /** Correlates this confirmed write with the client operation that caused it. */\n operationId?: string\n}\n\nexport interface RealtimeEvents extends Record<string, object> {\n change: RealtimeChange\n}\n\nexport type RealtimePublisher = Publisher<RealtimeEvents>\n\nexport interface RealtimePublisherOptions {\n maxBufferedEvents?: number\n resumeSeconds?: number\n}\n\nexport function createMemoryRealtimePublisher(\n options: RealtimePublisherOptions = {},\n): RealtimePublisher {\n return new MemoryPublisher<RealtimeEvents>({\n maxBufferedEvents: options.maxBufferedEvents,\n resume: { enabled: true, seconds: options.resumeSeconds ?? 300 },\n })\n}\n\nexport function createRedisRealtimePublisher(\n redis: RedisClient,\n subscriber: RedisClient | Promise<RedisClient>,\n options: RealtimePublisherOptions & { prefix?: string } = {},\n): RealtimePublisher {\n return new BunRedisPublisher<RealtimeEvents>(redis, {\n subscriber,\n prefix: options.prefix ?? 'bunderstack:',\n maxBufferedEvents: options.maxBufferedEvents,\n resume: { enabled: true, seconds: options.resumeSeconds ?? 300 },\n })\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bunderstack",
3
- "version": "0.19.1",
3
+ "version": "0.20.0",
4
4
  "description": "Batteries-included backend framework for Bun: type-safe oRPC APIs, auth, storage, realtime, jobs, email, and validated env from one config.",
5
5
  "keywords": [
6
6
  "backend",
@@ -44,6 +44,10 @@
44
44
  "types": "./dist/access.d.ts",
45
45
  "default": "./dist/access.js"
46
46
  },
47
+ "./codegen": {
48
+ "types": "./dist/codegen.d.ts",
49
+ "default": "./dist/codegen.js"
50
+ },
47
51
  "./database/bun-sql": {
48
52
  "types": "./dist/database/bun-sql.d.ts",
49
53
  "default": "./dist/database/bun-sql.js"