@getstrata/core 1.1.8 → 1.1.9

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.
package/dist/index.js CHANGED
@@ -1,4 +1,338 @@
1
1
  // @bun
2
+ var __esm = (fn, res, err) => () => {
3
+ if (fn)
4
+ try {
5
+ res = fn(fn = 0);
6
+ } catch (e) {
7
+ err = [e];
8
+ }
9
+ if (err)
10
+ throw err[0];
11
+ return res;
12
+ };
13
+
14
+ // ../../src/core/runtime/asyncContextStore.ts
15
+ import { AsyncLocalStorage } from "async_hooks";
16
+ function createAsyncContextStore(key) {
17
+ const symbol = Symbol.for(key);
18
+ const globalRecord = globalThis;
19
+ const existing = globalRecord[symbol];
20
+ if (existing) {
21
+ return existing;
22
+ }
23
+ const store = new AsyncLocalStorage;
24
+ globalRecord[symbol] = store;
25
+ return store;
26
+ }
27
+ var init_asyncContextStore = () => {};
28
+
29
+ // ../../src/core/database/connectionContext.ts
30
+ function runWithDatabaseConnection(connection, callback) {
31
+ return activeConnection.run(connection, callback);
32
+ }
33
+ function getActiveDatabaseConnection(fallback) {
34
+ return activeConnection.getStore() ?? fallback;
35
+ }
36
+ function hasActiveDatabaseConnection() {
37
+ return activeConnection.getStore() !== undefined;
38
+ }
39
+ var activeConnection;
40
+ var init_connectionContext = __esm(() => {
41
+ init_asyncContextStore();
42
+ activeConnection = createAsyncContextStore("@getstrata/databaseConnectionContext");
43
+ });
44
+
45
+ // ../../src/core/database/queryProxy.ts
46
+ function createDatabaseQueryProxy(pool) {
47
+ function resolveDatabase() {
48
+ return getActiveDatabaseConnection(pool);
49
+ }
50
+ function resolveDatabaseForProperty(property) {
51
+ if (typeof property === "string" && POOL_CONNECTION_METHODS.has(property)) {
52
+ return pool;
53
+ }
54
+ return resolveDatabase();
55
+ }
56
+ return new Proxy(function database() {}, {
57
+ apply(_target, _thisArg, args) {
58
+ return resolveDatabase()(...args);
59
+ },
60
+ get(_target, property) {
61
+ const connection = resolveDatabaseForProperty(property);
62
+ const value = connection[property];
63
+ return typeof value === "function" ? value.bind(connection) : value;
64
+ }
65
+ });
66
+ }
67
+ var POOL_CONNECTION_METHODS;
68
+ var init_queryProxy = __esm(() => {
69
+ init_connectionContext();
70
+ POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
71
+ });
72
+
73
+ // ../../src/core/database/defaultConnection.ts
74
+ function defaultConnectionState() {
75
+ const globalRecord = globalThis;
76
+ const existing = globalRecord[DEFAULT_CONNECTION_KEY];
77
+ if (existing) {
78
+ return existing;
79
+ }
80
+ const created = { pool: null, query: null };
81
+ globalRecord[DEFAULT_CONNECTION_KEY] = created;
82
+ return created;
83
+ }
84
+ function registerDefaultDatabasePool(connection) {
85
+ const holder = defaultConnectionState();
86
+ holder.pool = connection;
87
+ holder.query = createDatabaseQueryProxy(connection);
88
+ }
89
+ function getDefaultDatabasePool() {
90
+ const pool = defaultConnectionState().pool;
91
+ if (!pool) {
92
+ throw new Error("Default database pool is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
93
+ }
94
+ return pool;
95
+ }
96
+ function getDefaultDatabaseQuery() {
97
+ const query = defaultConnectionState().query;
98
+ if (!query) {
99
+ throw new Error("Default database query handle is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
100
+ }
101
+ return query;
102
+ }
103
+ function resetDefaultDatabasePoolForTests() {
104
+ const holder = defaultConnectionState();
105
+ holder.pool = null;
106
+ holder.query = null;
107
+ }
108
+ var DEFAULT_CONNECTION_KEY;
109
+ var init_defaultConnection = __esm(() => {
110
+ init_queryProxy();
111
+ DEFAULT_CONNECTION_KEY = Symbol.for("@getstrata/defaultDatabaseConnection");
112
+ });
113
+
114
+ // ../../src/core/tenant/tenantContext.ts
115
+ function runWithTenant(tenant, callback) {
116
+ return tenantContext.run(tenant, callback);
117
+ }
118
+ function currentTenant() {
119
+ return tenantContext.getStore() ?? null;
120
+ }
121
+ function currentTenantId() {
122
+ const tenant = currentTenant();
123
+ if (!tenant) {
124
+ throw new Error("Tenant context is required.");
125
+ }
126
+ return tenant.id;
127
+ }
128
+ function rateLimitMultiplierForPlan(plan) {
129
+ switch (plan) {
130
+ case "enterprise":
131
+ return 4;
132
+ case "pro":
133
+ return 2;
134
+ default:
135
+ return 1;
136
+ }
137
+ }
138
+ var tenantContext;
139
+ var init_tenantContext = __esm(() => {
140
+ init_asyncContextStore();
141
+ tenantContext = createAsyncContextStore("@getstrata/tenantContext");
142
+ });
143
+
144
+ // ../../src/core/tenant/tenancyConfig.ts
145
+ function readTenancyDriver(env = process.env) {
146
+ const raw = env.TENANCY_DRIVER?.trim();
147
+ if (raw === undefined || raw === "") {
148
+ return "rls";
149
+ }
150
+ if (TENANCY_DRIVERS.includes(raw)) {
151
+ return raw;
152
+ }
153
+ throw new Error(`TENANCY_DRIVER must be one of ${TENANCY_DRIVERS.join(", ")}; received "${raw}".`);
154
+ }
155
+ function isTenancyEnabled(env = process.env) {
156
+ return readTenancyDriver(env) !== "none";
157
+ }
158
+ function isRlsTenancy(env = process.env) {
159
+ return readTenancyDriver(env) === "rls";
160
+ }
161
+ var TENANCY_DRIVERS;
162
+ var init_tenancyConfig = __esm(() => {
163
+ TENANCY_DRIVERS = ["rls", "column", "none"];
164
+ });
165
+
166
+ // ../../src/core/events/eventBus.ts
167
+ class EventBus {
168
+ constructor() {}
169
+ listeners = new Map;
170
+ on(event, listener) {
171
+ return this.listen(event, listener);
172
+ }
173
+ listen(event, listener) {
174
+ const handlers = this.listeners.get(event) ?? new Set;
175
+ handlers.add(listener);
176
+ this.listeners.set(event, handlers);
177
+ return () => {
178
+ handlers.delete(listener);
179
+ if (handlers.size === 0) {
180
+ this.listeners.delete(event);
181
+ }
182
+ };
183
+ }
184
+ async emit(event, payload) {
185
+ await this.dispatch(event, payload);
186
+ }
187
+ async dispatch(event, payload) {
188
+ const handlers = this.listeners.get(event);
189
+ if (!handlers || handlers.size === 0) {
190
+ return;
191
+ }
192
+ for (const handler of handlers) {
193
+ await handler(payload);
194
+ }
195
+ }
196
+ }
197
+ function readSharedEventBus() {
198
+ const globalBus = globalThis[EVENT_BUS_KEY];
199
+ if (globalBus) {
200
+ return globalBus;
201
+ }
202
+ const bus = new EventBus;
203
+ globalThis[EVENT_BUS_KEY] = bus;
204
+ return bus;
205
+ }
206
+ var EVENT_BUS_KEY, eventBus;
207
+ var init_eventBus = __esm(() => {
208
+ EVENT_BUS_KEY = Symbol.for("@getstrata/eventBus");
209
+ eventBus = readSharedEventBus();
210
+ });
211
+
212
+ // ../../src/core/events/deferredModelEvents.ts
213
+ function sameTenant(left, right) {
214
+ if (left === null && right === null) {
215
+ return true;
216
+ }
217
+ if (left === null || right === null) {
218
+ return false;
219
+ }
220
+ return left.id === right.id;
221
+ }
222
+ function groupQueuedModelEvents(queued) {
223
+ const groups = [];
224
+ for (const item of queued) {
225
+ const lastGroup = groups[groups.length - 1];
226
+ const last = lastGroup?.[lastGroup.length - 1];
227
+ if (!lastGroup || !last || !sameTenant(last.tenant, item.tenant)) {
228
+ groups.push([item]);
229
+ } else {
230
+ lastGroup.push(item);
231
+ }
232
+ }
233
+ return groups;
234
+ }
235
+ async function dispatchEventBatch(batch) {
236
+ for (const item of batch) {
237
+ await eventBus.dispatch(item.event, item.payload);
238
+ }
239
+ }
240
+ async function dispatchQueuedModelEvents(queued) {
241
+ if (queued.length === 0) {
242
+ return;
243
+ }
244
+ await Promise.resolve().then(() => init_tenantDatabaseScope());
245
+ for (const batch of groupQueuedModelEvents(queued)) {
246
+ const tenant = batch[0]?.tenant ?? null;
247
+ if (tenant) {
248
+ await runWithTenantDatabase(tenant, () => dispatchEventBatch(batch));
249
+ } else {
250
+ await dispatchEventBatch(batch);
251
+ }
252
+ }
253
+ }
254
+ async function dispatchModelEvent(event, payload) {
255
+ const state = deferredModelEvents.getStore();
256
+ const frame = state?.frames[state.frames.length - 1];
257
+ if (frame) {
258
+ frame.push({
259
+ event,
260
+ payload,
261
+ tenant: currentTenant()
262
+ });
263
+ return;
264
+ }
265
+ await eventBus.dispatch(event, payload);
266
+ }
267
+ async function runWithDeferredModelEvents(callback) {
268
+ const existing = deferredModelEvents.getStore();
269
+ if (existing) {
270
+ existing.frames.push([]);
271
+ try {
272
+ const result = await callback();
273
+ const nested = existing.frames.pop() ?? [];
274
+ const parent = existing.frames[existing.frames.length - 1];
275
+ if (parent) {
276
+ parent.push(...nested);
277
+ }
278
+ return result;
279
+ } catch (error) {
280
+ existing.frames.pop();
281
+ throw error;
282
+ }
283
+ }
284
+ const state = { frames: [[]] };
285
+ const result = await deferredModelEvents.run(state, callback);
286
+ await dispatchQueuedModelEvents(state.frames[0] ?? []);
287
+ return result;
288
+ }
289
+ var deferredModelEvents;
290
+ var init_deferredModelEvents = __esm(() => {
291
+ init_asyncContextStore();
292
+ init_tenantContext();
293
+ init_eventBus();
294
+ deferredModelEvents = createAsyncContextStore("@getstrata/deferredModelEvents");
295
+ });
296
+
297
+ // ../../src/core/tenant/tenantDatabaseScope.ts
298
+ async function applyTenantContextToTransaction(transaction, tenantId) {
299
+ await transaction.unsafe(`SELECT set_config('app.tenant_id', $1, true)`, [String(tenantId)]);
300
+ await transaction.unsafe(`SELECT set_config('app.bypass_rls', $1, true)`, ["false"]);
301
+ }
302
+ async function runWithTenantDatabase(tenant, callback) {
303
+ if (!isTenancyEnabled() || !isRlsTenancy()) {
304
+ return await runWithTenant(tenant, callback);
305
+ }
306
+ if (hasActiveDatabaseConnection()) {
307
+ const activeConnection = getActiveDatabaseConnection(getDefaultDatabasePool());
308
+ await applyTenantContextToTransaction(activeConnection, tenant.id);
309
+ return await runWithTenant(tenant, callback);
310
+ }
311
+ const pool = getDefaultDatabasePool();
312
+ const begin = pool.begin;
313
+ if (typeof begin !== "function") {
314
+ throw new Error("RLS tenant scope requires a pool that supports begin(). Session-scoped set_config is not used on pooled connections.");
315
+ }
316
+ return await runWithDeferredModelEvents(async () => {
317
+ return await begin(async (transaction) => {
318
+ await applyTenantContextToTransaction(transaction, tenant.id);
319
+ return await runWithDatabaseConnection(transaction, async () => {
320
+ return await runWithTenant(tenant, callback);
321
+ });
322
+ });
323
+ });
324
+ }
325
+ function isInsideTenantDatabaseScope(tenantId = currentTenant()?.id) {
326
+ return hasActiveDatabaseConnection() && currentTenant()?.id === tenantId;
327
+ }
328
+ var init_tenantDatabaseScope = __esm(() => {
329
+ init_defaultConnection();
330
+ init_connectionContext();
331
+ init_deferredModelEvents();
332
+ init_tenancyConfig();
333
+ init_tenantContext();
334
+ });
335
+
2
336
  // ../../src/core/admin/formatValue.ts
3
337
  function formatAdminValue(value, type = "text") {
4
338
  if (value === null || value === undefined) {
@@ -143,21 +477,8 @@ function toHttpError(error) {
143
477
  return new HttpError(error.status, error.message, error.details);
144
478
  }
145
479
 
146
- // ../../src/core/runtime/asyncContextStore.ts
147
- import { AsyncLocalStorage } from "async_hooks";
148
- function createAsyncContextStore(key) {
149
- const symbol = Symbol.for(key);
150
- const globalRecord = globalThis;
151
- const existing = globalRecord[symbol];
152
- if (existing) {
153
- return existing;
154
- }
155
- const store = new AsyncLocalStorage;
156
- globalRecord[symbol] = store;
157
- return store;
158
- }
159
-
160
480
  // ../../src/core/auth/authContext.ts
481
+ init_asyncContextStore();
161
482
  var authContext = createAsyncContextStore("@getstrata/authContext");
162
483
  var credentialSourceContext = createAsyncContextStore("@getstrata/credentialSource");
163
484
  function runWithAuthUser(user, callback) {
@@ -246,78 +567,8 @@ function resetBoundDatabaseConnection() {
246
567
  boundConnectionState().connection = null;
247
568
  }
248
569
 
249
- // ../../src/core/database/connectionContext.ts
250
- var activeConnection = createAsyncContextStore("@getstrata/databaseConnectionContext");
251
- function runWithDatabaseConnection(connection, callback) {
252
- return activeConnection.run(connection, callback);
253
- }
254
- function getActiveDatabaseConnection(fallback) {
255
- return activeConnection.getStore() ?? fallback;
256
- }
257
- function hasActiveDatabaseConnection() {
258
- return activeConnection.getStore() !== undefined;
259
- }
260
-
261
- // ../../src/core/database/queryProxy.ts
262
- var POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
263
- function createDatabaseQueryProxy(pool) {
264
- function resolveDatabase() {
265
- return getActiveDatabaseConnection(pool);
266
- }
267
- function resolveDatabaseForProperty(property) {
268
- if (typeof property === "string" && POOL_CONNECTION_METHODS.has(property)) {
269
- return pool;
270
- }
271
- return resolveDatabase();
272
- }
273
- return new Proxy(function database() {}, {
274
- apply(_target, _thisArg, args) {
275
- return resolveDatabase()(...args);
276
- },
277
- get(_target, property) {
278
- const connection = resolveDatabaseForProperty(property);
279
- const value = connection[property];
280
- return typeof value === "function" ? value.bind(connection) : value;
281
- }
282
- });
283
- }
284
-
285
- // ../../src/core/database/defaultConnection.ts
286
- var DEFAULT_CONNECTION_KEY = Symbol.for("@getstrata/defaultDatabaseConnection");
287
- function defaultConnectionState() {
288
- const globalRecord = globalThis;
289
- const existing = globalRecord[DEFAULT_CONNECTION_KEY];
290
- if (existing) {
291
- return existing;
292
- }
293
- const created = { pool: null, query: null };
294
- globalRecord[DEFAULT_CONNECTION_KEY] = created;
295
- return created;
296
- }
297
- function registerDefaultDatabasePool(connection) {
298
- const holder = defaultConnectionState();
299
- holder.pool = connection;
300
- holder.query = createDatabaseQueryProxy(connection);
301
- }
302
- function getDefaultDatabasePool() {
303
- const pool = defaultConnectionState().pool;
304
- if (!pool) {
305
- throw new Error("Default database pool is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
306
- }
307
- return pool;
308
- }
309
- function getDefaultDatabaseQuery() {
310
- const query = defaultConnectionState().query;
311
- if (!query) {
312
- throw new Error("Default database query handle is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
313
- }
314
- return query;
315
- }
316
- function resetDefaultDatabasePoolForTests() {
317
- const holder = defaultConnectionState();
318
- holder.pool = null;
319
- holder.query = null;
320
- }
570
+ // ../../src/core/auth/basicAuthGuard.ts
571
+ init_defaultConnection();
321
572
 
322
573
  // ../../src/core/http/statelessAuth.ts
323
574
  function authorizationScheme(request) {
@@ -432,6 +683,9 @@ function revealMfaSecret(stored) {
432
683
  return decryptField(stored, key);
433
684
  }
434
685
 
686
+ // ../../src/core/database/dialect.ts
687
+ init_asyncContextStore();
688
+
435
689
  // ../../src/core/database/schema/driver.ts
436
690
  function normalizeConnectionName(connection) {
437
691
  const normalized = connection.trim().toLowerCase();
@@ -1240,6 +1494,7 @@ function isBearerCapableGuard(guard) {
1240
1494
  return guard instanceof ApiTokenGuard || guard instanceof DatabaseTokenGuard || guard instanceof JwtGuard;
1241
1495
  }
1242
1496
  // ../../src/core/auth/membershipContext.ts
1497
+ init_asyncContextStore();
1243
1498
  var membershipContext = createAsyncContextStore("@getstrata/membershipContext");
1244
1499
  var uninitializedMembershipLookup = {
1245
1500
  async listForUser() {
@@ -1315,33 +1570,8 @@ function createMembershipContextMiddleware() {
1315
1570
  function createMembershipMiddleware() {
1316
1571
  return createMembershipContextMiddleware();
1317
1572
  }
1318
- // ../../src/core/tenant/tenantContext.ts
1319
- var tenantContext = createAsyncContextStore("@getstrata/tenantContext");
1320
- function runWithTenant(tenant, callback) {
1321
- return tenantContext.run(tenant, callback);
1322
- }
1323
- function currentTenant() {
1324
- return tenantContext.getStore() ?? null;
1325
- }
1326
- function currentTenantId() {
1327
- const tenant = currentTenant();
1328
- if (!tenant) {
1329
- throw new Error("Tenant context is required.");
1330
- }
1331
- return tenant.id;
1332
- }
1333
- function rateLimitMultiplierForPlan(plan) {
1334
- switch (plan) {
1335
- case "enterprise":
1336
- return 4;
1337
- case "pro":
1338
- return 2;
1339
- default:
1340
- return 1;
1341
- }
1342
- }
1343
-
1344
1573
  // ../../src/core/auth/membershipScope.ts
1574
+ init_tenantContext();
1345
1575
  function resolveOrganizationScope() {
1346
1576
  const user = currentAuthUser();
1347
1577
  if (!user) {
@@ -2162,6 +2392,9 @@ function missingOptionalPeer(packageName, reason, error) {
2162
2392
  });
2163
2393
  }
2164
2394
 
2395
+ // ../../src/core/auth/saml/samlAssertionReplay.ts
2396
+ init_defaultConnection();
2397
+
2165
2398
  // ../../src/core/database/errors.ts
2166
2399
  function isPostgresError(error) {
2167
2400
  return typeof error === "object" && error !== null && (("errno" in error) || ("code" in error));
@@ -2543,6 +2776,10 @@ class PolicyGate {
2543
2776
  }
2544
2777
  }
2545
2778
  }
2779
+ // ../../src/core/auth/scimAuthMiddleware.ts
2780
+ init_defaultConnection();
2781
+ init_connectionContext();
2782
+
2546
2783
  // ../../src/core/security/scimTenantTokens.ts
2547
2784
  function parseScimTenantTokens(raw) {
2548
2785
  const tokens = new Map;
@@ -2584,6 +2821,7 @@ function resolveScimTenantFromToken(token) {
2584
2821
  }
2585
2822
 
2586
2823
  // ../../src/core/database/repositoryConnection.ts
2824
+ init_defaultConnection();
2587
2825
  function resolveRepositoryConnection() {
2588
2826
  return getBoundDatabaseConnection() ?? getDefaultDatabaseQuery();
2589
2827
  }
@@ -2628,26 +2866,8 @@ var repositoryConnection = new Proxy(function repositoryConnection() {}, {
2628
2866
  }
2629
2867
  });
2630
2868
 
2631
- // ../../src/core/tenant/tenancyConfig.ts
2632
- var TENANCY_DRIVERS = ["rls", "column", "none"];
2633
- function readTenancyDriver(env = process.env) {
2634
- const raw = env.TENANCY_DRIVER?.trim();
2635
- if (raw === undefined || raw === "") {
2636
- return "rls";
2637
- }
2638
- if (TENANCY_DRIVERS.includes(raw)) {
2639
- return raw;
2640
- }
2641
- throw new Error(`TENANCY_DRIVER must be one of ${TENANCY_DRIVERS.join(", ")}; received "${raw}".`);
2642
- }
2643
- function isTenancyEnabled(env = process.env) {
2644
- return readTenancyDriver(env) !== "none";
2645
- }
2646
- function isRlsTenancy(env = process.env) {
2647
- return readTenancyDriver(env) === "rls";
2648
- }
2649
-
2650
2869
  // ../../src/core/tenant/resolveTenant.ts
2870
+ init_tenancyConfig();
2651
2871
  async function resolveTenant(tenantId) {
2652
2872
  if (!isTenancyEnabled()) {
2653
2873
  return {
@@ -2667,32 +2887,8 @@ async function resolveTenant(tenantId) {
2667
2887
  return row ? { id: row.id, slug: row.slug, plan: row.plan, region: row.region ?? "eu" } : null;
2668
2888
  }
2669
2889
 
2670
- // ../../src/core/tenant/tenantDatabaseScope.ts
2671
- async function applyTenantContextToTransaction(transaction, tenantId) {
2672
- await transaction.unsafe(`SELECT set_config('app.tenant_id', $1, true)`, [String(tenantId)]);
2673
- await transaction.unsafe(`SELECT set_config('app.bypass_rls', $1, true)`, ["false"]);
2674
- }
2675
- async function runWithTenantDatabase(tenant, callback) {
2676
- if (!isTenancyEnabled() || !isRlsTenancy()) {
2677
- return await runWithTenant(tenant, callback);
2678
- }
2679
- if (hasActiveDatabaseConnection()) {
2680
- const activeConnection = getActiveDatabaseConnection(getDefaultDatabasePool());
2681
- await applyTenantContextToTransaction(activeConnection, tenant.id);
2682
- return await runWithTenant(tenant, callback);
2683
- }
2684
- return await getDefaultDatabasePool().begin(async (transaction) => {
2685
- await applyTenantContextToTransaction(transaction, tenant.id);
2686
- return await runWithDatabaseConnection(transaction, async () => {
2687
- return await runWithTenant(tenant, callback);
2688
- });
2689
- });
2690
- }
2691
- function isInsideTenantDatabaseScope(tenantId = currentTenant()?.id) {
2692
- return hasActiveDatabaseConnection() && currentTenant()?.id === tenantId;
2693
- }
2694
-
2695
2890
  // ../../src/core/auth/scimAuthMiddleware.ts
2891
+ init_tenantDatabaseScope();
2696
2892
  function createScimAuthMiddleware() {
2697
2893
  return async (request, next) => {
2698
2894
  const authorization = request.headers.get("authorization");
@@ -3264,50 +3460,9 @@ class ConfigStore {
3264
3460
  return this.values.has(key);
3265
3461
  }
3266
3462
  }
3267
- // ../../src/core/events/eventBus.ts
3268
- class EventBus {
3269
- constructor() {}
3270
- listeners = new Map;
3271
- on(event, listener) {
3272
- return this.listen(event, listener);
3273
- }
3274
- listen(event, listener) {
3275
- const handlers = this.listeners.get(event) ?? new Set;
3276
- handlers.add(listener);
3277
- this.listeners.set(event, handlers);
3278
- return () => {
3279
- handlers.delete(listener);
3280
- if (handlers.size === 0) {
3281
- this.listeners.delete(event);
3282
- }
3283
- };
3284
- }
3285
- async emit(event, payload) {
3286
- await this.dispatch(event, payload);
3287
- }
3288
- async dispatch(event, payload) {
3289
- const handlers = this.listeners.get(event);
3290
- if (!handlers || handlers.size === 0) {
3291
- return;
3292
- }
3293
- for (const handler of handlers) {
3294
- await handler(payload);
3295
- }
3296
- }
3297
- }
3298
- var EVENT_BUS_KEY = Symbol.for("@getstrata/eventBus");
3299
- function readSharedEventBus() {
3300
- const globalBus = globalThis[EVENT_BUS_KEY];
3301
- if (globalBus) {
3302
- return globalBus;
3303
- }
3304
- const bus = new EventBus;
3305
- globalThis[EVENT_BUS_KEY] = bus;
3306
- return bus;
3307
- }
3308
- var eventBus = readSharedEventBus();
3309
-
3310
3463
  // ../../src/core/events/index.ts
3464
+ init_deferredModelEvents();
3465
+ init_eventBus();
3311
3466
  function modelEventName(tableName, action) {
3312
3467
  return `${tableName}.${action}`;
3313
3468
  }
@@ -4614,7 +4769,7 @@ class BaseRepository {
4614
4769
  throw new Error(`Insert into ${this.table.name} did not return a record.`);
4615
4770
  }
4616
4771
  const entity = record;
4617
- await eventBus.dispatch(modelEventName(this.table.name, "created"), entity);
4772
+ await dispatchModelEvent(modelEventName(this.table.name, "created"), entity);
4618
4773
  return entity;
4619
4774
  });
4620
4775
  }
@@ -4624,7 +4779,7 @@ class BaseRepository {
4624
4779
  const [record] = await this.connection.unsafe(text, params);
4625
4780
  const entity = record ?? null;
4626
4781
  if (entity) {
4627
- await eventBus.dispatch(modelEventName(this.table.name, "updated"), entity);
4782
+ await dispatchModelEvent(modelEventName(this.table.name, "updated"), entity);
4628
4783
  }
4629
4784
  return entity;
4630
4785
  });
@@ -4649,7 +4804,7 @@ class BaseRepository {
4649
4804
  if (!record) {
4650
4805
  return false;
4651
4806
  }
4652
- await eventBus.dispatch(modelEventName(this.table.name, "deleted"), record);
4807
+ await dispatchModelEvent(modelEventName(this.table.name, "deleted"), record);
4653
4808
  return true;
4654
4809
  });
4655
4810
  }
@@ -4660,7 +4815,7 @@ class BaseRepository {
4660
4815
  if (!row) {
4661
4816
  return false;
4662
4817
  }
4663
- await eventBus.dispatch(modelEventName(this.table.name, "force-deleted"), {
4818
+ await dispatchModelEvent(modelEventName(this.table.name, "force-deleted"), {
4664
4819
  id
4665
4820
  });
4666
4821
  return true;
@@ -4674,7 +4829,7 @@ class BaseRepository {
4674
4829
  return null;
4675
4830
  }
4676
4831
  const entity = record;
4677
- await eventBus.dispatch(modelEventName(this.table.name, "restored"), entity);
4832
+ await dispatchModelEvent(modelEventName(this.table.name, "restored"), entity);
4678
4833
  return entity;
4679
4834
  });
4680
4835
  }
@@ -4888,6 +5043,7 @@ class BaseRepository {
4888
5043
  var baseRepository_default = BaseRepository;
4889
5044
  // ../../src/core/database/bunSql.ts
4890
5045
  var {SQL } = globalThis.Bun;
5046
+ init_defaultConnection();
4891
5047
  function createBunSqlPool(options) {
4892
5048
  if (!options.url) {
4893
5049
  throw new Error("DATABASE_URL is not configured. Set url before creating a Bun SQL pool.");
@@ -4913,6 +5069,11 @@ function createDatabaseConnection(source) {
4913
5069
  }
4914
5070
  };
4915
5071
  }
5072
+
5073
+ // ../../src/framework/public-api.ts
5074
+ init_connectionContext();
5075
+ init_defaultConnection();
5076
+
4916
5077
  // ../../src/core/database/inflection.ts
4917
5078
  function singularize(word) {
4918
5079
  if (word.endsWith("ies") && word.length > 3) {
@@ -6989,6 +7150,7 @@ function createMysqlConnection(url) {
6989
7150
  };
6990
7151
  }
6991
7152
  // ../../src/core/database/namedConnections.ts
7153
+ init_connectionContext();
6992
7154
  var REGISTRY_KEY = Symbol.for("@getstrata/namedConnections");
6993
7155
  function registry() {
6994
7156
  const globalRecord = globalThis;
@@ -7026,6 +7188,10 @@ function runOnNamedConnection(name, callback) {
7026
7188
  const entry = getNamedConnection(name);
7027
7189
  return runWithSqlDialect(entry.driver, () => runWithDatabaseConnection(entry.connection, callback));
7028
7190
  }
7191
+
7192
+ // ../../src/framework/public-api.ts
7193
+ init_queryProxy();
7194
+
7029
7195
  // ../../src/core/database/schema/columnDefinition.ts
7030
7196
  class ColumnDefinition {
7031
7197
  name;
@@ -7675,6 +7841,7 @@ function defineTable(definition) {
7675
7841
  return definition;
7676
7842
  }
7677
7843
  // ../../src/core/database/transaction.ts
7844
+ init_deferredModelEvents();
7678
7845
  function supportsTransactions(connection) {
7679
7846
  return typeof connection.begin === "function";
7680
7847
  }
@@ -7683,10 +7850,17 @@ async function runInTransaction(operation) {
7683
7850
  if (!supportsTransactions(pool)) {
7684
7851
  throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
7685
7852
  }
7686
- return await pool.begin(async (transaction) => {
7687
- return await operation(createDatabaseConnection(transaction));
7853
+ const begin = pool.begin;
7854
+ return await runWithDeferredModelEvents(async () => {
7855
+ return await begin(async (transaction) => {
7856
+ return await operation(createDatabaseConnection(transaction));
7857
+ });
7688
7858
  });
7689
7859
  }
7860
+
7861
+ // ../../src/framework/public-api.ts
7862
+ init_eventBus();
7863
+
7690
7864
  // ../../src/core/mail/mailer.ts
7691
7865
  function resolveSmtpConfig() {
7692
7866
  const host = process.env.MAIL_HOST?.trim();
@@ -8131,6 +8305,7 @@ function createBodySizeLimitMiddleware(maxBytes = resolveMaxBodyBytes()) {
8131
8305
  };
8132
8306
  }
8133
8307
  // ../../src/core/http/requestMetaContext.ts
8308
+ init_asyncContextStore();
8134
8309
  var requestMetaContext = createAsyncContextStore("@getstrata/requestMetaContext");
8135
8310
  function runWithRequestMeta(meta, callback) {
8136
8311
  return requestMetaContext.run(meta, callback);
@@ -8806,6 +8981,7 @@ function createFlashMiddleware() {
8806
8981
  };
8807
8982
  }
8808
8983
  // ../../src/core/http/validation.ts
8984
+ init_tenantContext();
8809
8985
  function buildRequestCacheKey(fallbackPath, request) {
8810
8986
  if (!request) {
8811
8987
  return fallbackPath;
@@ -10128,6 +10304,7 @@ function createValidateSignatureMiddleware() {
10128
10304
  };
10129
10305
  }
10130
10306
  // ../../src/core/http/throttleMiddleware.ts
10307
+ init_tenantContext();
10131
10308
  var {RedisClient: RedisClient4 } = globalThis.Bun;
10132
10309
  function resolveThrottleIdentity(request) {
10133
10310
  const user = currentAuthUser();
@@ -11041,10 +11218,20 @@ function generatedRlsBootstrapSql(tables, userOwnedTables = []) {
11041
11218
  ].join(`
11042
11219
  `);
11043
11220
  }
11221
+
11222
+ // ../../src/framework/public-api.ts
11223
+ init_tenancyConfig();
11224
+ init_tenantContext();
11225
+ init_tenantDatabaseScope();
11226
+
11044
11227
  // ../../src/core/tenant/tenantMiddleware.ts
11045
11228
  import { createHash as createHash4 } from "crypto";
11046
11229
 
11047
11230
  // ../../src/core/tenant/databaseTenantContext.ts
11231
+ init_defaultConnection();
11232
+ init_connectionContext();
11233
+ init_deferredModelEvents();
11234
+ init_tenancyConfig();
11048
11235
  function stringifyBypassIdentifier(identifier) {
11049
11236
  if (typeof identifier === "number") {
11050
11237
  return String(identifier);
@@ -11073,12 +11260,15 @@ async function runWithScopedTenantTransaction(apply, callback) {
11073
11260
  return await callback();
11074
11261
  }
11075
11262
  const pool = getDefaultDatabasePool();
11076
- if (typeof pool.begin !== "function") {
11263
+ const begin = pool.begin;
11264
+ if (typeof begin !== "function") {
11077
11265
  throw new Error("RLS migration bypass requires a pool that supports begin(). Session-scoped set_config is not used on pooled connections.");
11078
11266
  }
11079
- return await pool.begin(async (transaction) => {
11080
- await apply(transaction);
11081
- return await runWithDatabaseConnection(transaction, callback);
11267
+ return await runWithDeferredModelEvents(async () => {
11268
+ return await begin(async (transaction) => {
11269
+ await apply(transaction);
11270
+ return await runWithDatabaseConnection(transaction, callback);
11271
+ });
11082
11272
  });
11083
11273
  }
11084
11274
  async function runWithMigrationBypassForIdentifier(identifier, callback) {
@@ -11087,6 +11277,9 @@ async function runWithMigrationBypassForIdentifier(identifier, callback) {
11087
11277
  }
11088
11278
 
11089
11279
  // ../../src/core/tenant/tenantMiddleware.ts
11280
+ init_tenancyConfig();
11281
+ init_tenantContext();
11282
+ init_tenantDatabaseScope();
11090
11283
  var DEFAULT_TENANT = {
11091
11284
  id: 1,
11092
11285
  slug: "default",
@@ -11174,6 +11367,7 @@ function createTenantMiddleware() {
11174
11367
  };
11175
11368
  }
11176
11369
  // ../../src/core/tracing/traceContext.ts
11370
+ init_asyncContextStore();
11177
11371
  var traceContextStorage = createAsyncContextStore("@getstrata/traceContext");
11178
11372
  function runWithTraceContext(context, callback) {
11179
11373
  return traceContextStorage.run(context, callback);
@@ -11845,6 +12039,7 @@ export {
11845
12039
  defineTable,
11846
12040
  dehydrateValue,
11847
12041
  dialectFor,
12042
+ dispatchModelEvent,
11848
12043
  emailRule,
11849
12044
  emptyPaginateResult,
11850
12045
  enableTenantRlsSql,
@@ -12034,6 +12229,7 @@ export {
12034
12229
  runWithAuthContext,
12035
12230
  runWithAuthUser,
12036
12231
  runWithDatabaseConnection,
12232
+ runWithDeferredModelEvents,
12037
12233
  runWithMembershipContext,
12038
12234
  runWithRequestMeta,
12039
12235
  runWithSqlDialect,