@getstrata/core 1.1.7 → 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.
@@ -1,6 +1,15 @@
1
1
  // @bun
2
- // ../../src/core/tenant/tenantDatabaseScope.ts
3
- import { getDefaultDatabasePool } from "@getstrata/core/database/defaultConnection";
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
+ };
4
13
 
5
14
  // ../../src/core/runtime/asyncContextStore.ts
6
15
  import { AsyncLocalStorage } from "async_hooks";
@@ -15,9 +24,9 @@ function createAsyncContextStore(key) {
15
24
  globalRecord[symbol] = store;
16
25
  return store;
17
26
  }
27
+ var init_asyncContextStore = () => {};
18
28
 
19
29
  // ../../src/core/database/connectionContext.ts
20
- var activeConnection = createAsyncContextStore("@getstrata/databaseConnectionContext");
21
30
  function runWithDatabaseConnection(connection, callback) {
22
31
  return activeConnection.run(connection, callback);
23
32
  }
@@ -27,9 +36,144 @@ function getActiveDatabaseConnection(fallback) {
27
36
  function hasActiveDatabaseConnection() {
28
37
  return activeConnection.getStore() !== undefined;
29
38
  }
39
+ var activeConnection;
40
+ var init_connectionContext = __esm(() => {
41
+ init_asyncContextStore();
42
+ activeConnection = createAsyncContextStore("@getstrata/databaseConnectionContext");
43
+ });
44
+
45
+ // ../../src/core/tenant/tenantContext.ts
46
+ function runWithTenant(tenant, callback) {
47
+ return tenantContext.run(tenant, callback);
48
+ }
49
+ function currentTenant() {
50
+ return tenantContext.getStore() ?? null;
51
+ }
52
+ var tenantContext;
53
+ var init_tenantContext = __esm(() => {
54
+ init_asyncContextStore();
55
+ tenantContext = createAsyncContextStore("@getstrata/tenantContext");
56
+ });
57
+
58
+ // ../../src/core/events/eventBus.ts
59
+ class EventBus {
60
+ constructor() {}
61
+ listeners = new Map;
62
+ on(event, listener) {
63
+ return this.listen(event, listener);
64
+ }
65
+ listen(event, listener) {
66
+ const handlers = this.listeners.get(event) ?? new Set;
67
+ handlers.add(listener);
68
+ this.listeners.set(event, handlers);
69
+ return () => {
70
+ handlers.delete(listener);
71
+ if (handlers.size === 0) {
72
+ this.listeners.delete(event);
73
+ }
74
+ };
75
+ }
76
+ async emit(event, payload) {
77
+ await this.dispatch(event, payload);
78
+ }
79
+ async dispatch(event, payload) {
80
+ const handlers = this.listeners.get(event);
81
+ if (!handlers || handlers.size === 0) {
82
+ return;
83
+ }
84
+ for (const handler of handlers) {
85
+ await handler(payload);
86
+ }
87
+ }
88
+ }
89
+ function readSharedEventBus() {
90
+ const globalBus = globalThis[EVENT_BUS_KEY];
91
+ if (globalBus) {
92
+ return globalBus;
93
+ }
94
+ const bus = new EventBus;
95
+ globalThis[EVENT_BUS_KEY] = bus;
96
+ return bus;
97
+ }
98
+ var EVENT_BUS_KEY, eventBus;
99
+ var init_eventBus = __esm(() => {
100
+ EVENT_BUS_KEY = Symbol.for("@getstrata/eventBus");
101
+ eventBus = readSharedEventBus();
102
+ });
103
+
104
+ // ../../src/core/events/deferredModelEvents.ts
105
+ function sameTenant(left, right) {
106
+ if (left === null && right === null) {
107
+ return true;
108
+ }
109
+ if (left === null || right === null) {
110
+ return false;
111
+ }
112
+ return left.id === right.id;
113
+ }
114
+ function groupQueuedModelEvents(queued) {
115
+ const groups = [];
116
+ for (const item of queued) {
117
+ const lastGroup = groups[groups.length - 1];
118
+ const last = lastGroup?.[lastGroup.length - 1];
119
+ if (!lastGroup || !last || !sameTenant(last.tenant, item.tenant)) {
120
+ groups.push([item]);
121
+ } else {
122
+ lastGroup.push(item);
123
+ }
124
+ }
125
+ return groups;
126
+ }
127
+ async function dispatchEventBatch(batch) {
128
+ for (const item of batch) {
129
+ await eventBus.dispatch(item.event, item.payload);
130
+ }
131
+ }
132
+ async function dispatchQueuedModelEvents(queued) {
133
+ if (queued.length === 0) {
134
+ return;
135
+ }
136
+ await Promise.resolve().then(() => init_tenantDatabaseScope());
137
+ for (const batch of groupQueuedModelEvents(queued)) {
138
+ const tenant = batch[0]?.tenant ?? null;
139
+ if (tenant) {
140
+ await runWithTenantDatabase(tenant, () => dispatchEventBatch(batch));
141
+ } else {
142
+ await dispatchEventBatch(batch);
143
+ }
144
+ }
145
+ }
146
+ async function runWithDeferredModelEvents(callback) {
147
+ const existing = deferredModelEvents.getStore();
148
+ if (existing) {
149
+ existing.frames.push([]);
150
+ try {
151
+ const result = await callback();
152
+ const nested = existing.frames.pop() ?? [];
153
+ const parent = existing.frames[existing.frames.length - 1];
154
+ if (parent) {
155
+ parent.push(...nested);
156
+ }
157
+ return result;
158
+ } catch (error) {
159
+ existing.frames.pop();
160
+ throw error;
161
+ }
162
+ }
163
+ const state = { frames: [[]] };
164
+ const result = await deferredModelEvents.run(state, callback);
165
+ await dispatchQueuedModelEvents(state.frames[0] ?? []);
166
+ return result;
167
+ }
168
+ var deferredModelEvents;
169
+ var init_deferredModelEvents = __esm(() => {
170
+ init_asyncContextStore();
171
+ init_tenantContext();
172
+ init_eventBus();
173
+ deferredModelEvents = createAsyncContextStore("@getstrata/deferredModelEvents");
174
+ });
30
175
 
31
176
  // ../../src/core/tenant/tenancyConfig.ts
32
- var TENANCY_DRIVERS = ["rls", "column", "none"];
33
177
  function readTenancyDriver(env = process.env) {
34
178
  const raw = env.TENANCY_DRIVER?.trim();
35
179
  if (raw === undefined || raw === "") {
@@ -46,17 +190,13 @@ function isTenancyEnabled(env = process.env) {
46
190
  function isRlsTenancy(env = process.env) {
47
191
  return readTenancyDriver(env) === "rls";
48
192
  }
49
-
50
- // ../../src/core/tenant/tenantContext.ts
51
- var tenantContext = createAsyncContextStore("@getstrata/tenantContext");
52
- function runWithTenant(tenant, callback) {
53
- return tenantContext.run(tenant, callback);
54
- }
55
- function currentTenant() {
56
- return tenantContext.getStore() ?? null;
57
- }
193
+ var TENANCY_DRIVERS;
194
+ var init_tenancyConfig = __esm(() => {
195
+ TENANCY_DRIVERS = ["rls", "column", "none"];
196
+ });
58
197
 
59
198
  // ../../src/core/tenant/tenantDatabaseScope.ts
199
+ import { getDefaultDatabasePool } from "@getstrata/core/database/defaultConnection";
60
200
  async function applyTenantContextToTransaction(transaction, tenantId) {
61
201
  await transaction.unsafe(`SELECT set_config('app.tenant_id', $1, true)`, [String(tenantId)]);
62
202
  await transaction.unsafe(`SELECT set_config('app.bypass_rls', $1, true)`, ["false"]);
@@ -70,16 +210,32 @@ async function runWithTenantDatabase(tenant, callback) {
70
210
  await applyTenantContextToTransaction(activeConnection, tenant.id);
71
211
  return await runWithTenant(tenant, callback);
72
212
  }
73
- return await getDefaultDatabasePool().begin(async (transaction) => {
74
- await applyTenantContextToTransaction(transaction, tenant.id);
75
- return await runWithDatabaseConnection(transaction, async () => {
76
- return await runWithTenant(tenant, callback);
213
+ const pool = getDefaultDatabasePool();
214
+ const begin = pool.begin;
215
+ if (typeof begin !== "function") {
216
+ throw new Error("RLS tenant scope requires a pool that supports begin(). Session-scoped set_config is not used on pooled connections.");
217
+ }
218
+ return await runWithDeferredModelEvents(async () => {
219
+ return await begin(async (transaction) => {
220
+ await applyTenantContextToTransaction(transaction, tenant.id);
221
+ return await runWithDatabaseConnection(transaction, async () => {
222
+ return await runWithTenant(tenant, callback);
223
+ });
77
224
  });
78
225
  });
79
226
  }
80
227
  function isInsideTenantDatabaseScope(tenantId = currentTenant()?.id) {
81
228
  return hasActiveDatabaseConnection() && currentTenant()?.id === tenantId;
82
229
  }
230
+ var init_tenantDatabaseScope = __esm(() => {
231
+ init_connectionContext();
232
+ init_deferredModelEvents();
233
+ init_tenancyConfig();
234
+ init_tenantContext();
235
+ });
236
+
237
+ // entries/tenant/tenantDatabaseScope.ts
238
+ init_tenantDatabaseScope();
83
239
  export {
84
240
  applyTenantContextToTransaction,
85
241
  isInsideTenantDatabaseScope,
@@ -1,4 +1,31 @@
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
+
2
29
  // ../../src/core/runtime/appEnv.ts
3
30
  var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
4
31
  function normalizeEnvValue(value) {
@@ -422,21 +449,8 @@ async function exportOtelSpan(span) {
422
449
  });
423
450
  }
424
451
 
425
- // ../../src/core/runtime/asyncContextStore.ts
426
- import { AsyncLocalStorage } from "async_hooks";
427
- function createAsyncContextStore(key) {
428
- const symbol = Symbol.for(key);
429
- const globalRecord = globalThis;
430
- const existing = globalRecord[symbol];
431
- if (existing) {
432
- return existing;
433
- }
434
- const store = new AsyncLocalStorage;
435
- globalRecord[symbol] = store;
436
- return store;
437
- }
438
-
439
452
  // ../../src/core/tracing/traceContext.ts
453
+ init_asyncContextStore();
440
454
  var traceContextStorage = createAsyncContextStore("@getstrata/traceContext");
441
455
  function runWithTraceContext(context, callback) {
442
456
  return traceContextStorage.run(context, callback);
@@ -71,7 +71,7 @@ export { WhereBuilder } from "../core/database/whereBuilder.ts";
71
71
  export { BadRequestError, ConflictError, ForbiddenError, HttpError, InternalServerError, isHttpErrorLike, NotFoundError, PayloadTooLargeError, PreconditionFailedError, toHttpError, UnauthorizedError, UnprocessableEntityError, ValidationError, } from "../core/errors/http.ts";
72
72
  export type { EventListener } from "../core/events/eventBus.ts";
73
73
  export { EventBus, eventBus, readSharedEventBus } from "../core/events/eventBus.ts";
74
- export { modelEventName } from "../core/events/index.ts";
74
+ export { dispatchModelEvent, modelEventName, runWithDeferredModelEvents, } from "../core/events/index.ts";
75
75
  export { auth, cache, config, events, log, mail, policyGate, queue, storage, } from "../core/facades/index.ts";
76
76
  export { createBodySizeLimitMiddleware } from "../core/http/bodySizeLimitMiddleware.ts";
77
77
  export { readClientIp, trustForwardedFor } from "../core/http/clientIp.ts";