@getstrata/core 2.2.32 → 2.2.34
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/CHANGELOG.md +10 -0
- package/dist/core/auth/accountState.d.ts +9 -0
- package/dist/core/auth/accountStateMigration.d.ts +7 -0
- package/dist/core/auth/authContext.d.ts +3 -0
- package/dist/core/auth/guard.d.ts +1 -0
- package/dist/core/auth/jwt.d.ts +1 -0
- package/dist/core/auth/oneTimeToken.d.ts +2 -0
- package/dist/core/auth/passwordConfirmCookie.d.ts +2 -2
- package/dist/core/auth/passwordLogin.d.ts +2 -2
- package/dist/core/auth/pendingMfaCookie.d.ts +9 -0
- package/dist/core/auth/sessionCookie.d.ts +3 -0
- package/dist/core/contracts/authUserDirectory.d.ts +5 -0
- package/dist/entries/audit/exportAuditLogs.js +14 -0
- package/dist/entries/auth/accountState.js +18 -0
- package/dist/entries/auth/accountStateMigration.js +923 -0
- package/dist/entries/auth/basicAuthGuard.js +33 -1
- package/dist/entries/auth/jwtGuard.js +71 -23
- package/dist/entries/auth/oneTimeToken.js +16 -12
- package/dist/entries/auth/passwordConfirmCookie.js +63 -22
- package/dist/entries/auth/passwordLogin.js +15 -0
- package/dist/entries/auth/pendingMfaCookie.js +100 -0
- package/dist/entries/auth/scimAuthMiddleware.js +2330 -194
- package/dist/entries/auth/sessionCookie.js +49 -21
- package/dist/entries/auth/sessionGuard.js +66 -22
- package/dist/entries/http/cookies.js +5 -1
- package/dist/entries/http/csrfMiddleware.js +5 -1
- package/dist/entries/http/csrfToken.js +5 -1
- package/dist/entries/http/requirePasswordConfirmMiddleware.js +1 -1
- package/dist/entries/jobs/exportAuditLogsJob.js +14 -0
- package/dist/entries/queue/queueMetrics.js +14 -0
- package/dist/entries/tenant/databaseTenantContext.js +14 -0
- package/dist/entries/tenant/tenantDatabaseScope.js +14 -0
- package/dist/index.js +2564 -2535
- package/package.json +17 -2
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
// ../../src/core/auth/sessionCookie.ts
|
|
3
3
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
4
4
|
|
|
5
|
+
// ../../src/core/http/cookies.ts
|
|
6
|
+
function readRequestCookie(request, name) {
|
|
7
|
+
const cookies = request.cookies;
|
|
8
|
+
if (cookies && typeof cookies.get === "function") {
|
|
9
|
+
const value = cookies.get(name);
|
|
10
|
+
if (value) {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const header = request.headers.get("cookie");
|
|
15
|
+
if (!header) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
for (const part of header.split(";")) {
|
|
19
|
+
const idx = part.indexOf("=");
|
|
20
|
+
if (idx === -1)
|
|
21
|
+
continue;
|
|
22
|
+
const cookieName = part.slice(0, idx).trim();
|
|
23
|
+
if (cookieName !== name)
|
|
24
|
+
continue;
|
|
25
|
+
try {
|
|
26
|
+
return decodeURIComponent(part.slice(idx + 1).trim());
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
function readBunRequestCookie(request, name) {
|
|
34
|
+
return request.cookies.get(name) ?? readRequestCookie(request, name);
|
|
35
|
+
}
|
|
36
|
+
|
|
5
37
|
// ../../src/core/runtime/appEnv.ts
|
|
6
38
|
var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
|
|
7
39
|
function normalizeEnvValue(value) {
|
|
@@ -108,25 +140,12 @@ function sessionRememberTtlSeconds() {
|
|
|
108
140
|
function resolveSessionSecret() {
|
|
109
141
|
return requireConfiguredSecret(["SESSION_SECRET"], "session-secret");
|
|
110
142
|
}
|
|
111
|
-
function signSession(userId, issuedAt, ttlSeconds) {
|
|
112
|
-
const payload = ttlSeconds === undefined ? `${userId}.${issuedAt}` : `${userId}.${issuedAt}.${ttlSeconds}`;
|
|
143
|
+
function signSession(userId, issuedAt, ttlSeconds, authVersion) {
|
|
144
|
+
const payload = authVersion !== undefined ? `v2.${userId}.${issuedAt}.${ttlSeconds}.${authVersion}` : ttlSeconds === undefined ? `${userId}.${issuedAt}` : `${userId}.${issuedAt}.${ttlSeconds}`;
|
|
113
145
|
const signature = createHmac("sha256", resolveSessionSecret()).update(payload).digest("hex");
|
|
114
146
|
return `${payload}.${signature}`;
|
|
115
147
|
}
|
|
116
|
-
function
|
|
117
|
-
const cookieHeader = request.headers.get("cookie");
|
|
118
|
-
if (!cookieHeader) {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
for (const part of cookieHeader.split(";")) {
|
|
122
|
-
const [name, ...rest] = part.trim().split("=");
|
|
123
|
-
if (name === cookieName) {
|
|
124
|
-
return decodeURIComponent(rest.join("="));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
function readSignedSession(userIdRaw, issuedAtRaw, cookieSignature, ttlSeconds, remember) {
|
|
148
|
+
function readSignedSession(userIdRaw, issuedAtRaw, cookieSignature, ttlSeconds, remember, authVersion) {
|
|
130
149
|
const userId = Number.parseInt(userIdRaw, 10);
|
|
131
150
|
const issuedAt = Number.parseInt(issuedAtRaw, 10);
|
|
132
151
|
if (!Number.isInteger(userId) || userId <= 0 || !Number.isFinite(issuedAt)) {
|
|
@@ -138,7 +157,7 @@ function readSignedSession(userIdRaw, issuedAtRaw, cookieSignature, ttlSeconds,
|
|
|
138
157
|
if (Date.now() - issuedAt > ttlSeconds * 1000) {
|
|
139
158
|
return null;
|
|
140
159
|
}
|
|
141
|
-
const expectedSignature = (remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt)).split(".").pop();
|
|
160
|
+
const expectedSignature = (authVersion !== undefined ? signSession(userId, issuedAt, ttlSeconds, authVersion) : remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt)).split(".").pop();
|
|
142
161
|
if (!expectedSignature || !cookieSignature) {
|
|
143
162
|
return null;
|
|
144
163
|
}
|
|
@@ -150,14 +169,20 @@ function readSignedSession(userIdRaw, issuedAtRaw, cookieSignature, ttlSeconds,
|
|
|
150
169
|
if (!timingSafeEqual(expectedBuffer, actualBuffer)) {
|
|
151
170
|
return null;
|
|
152
171
|
}
|
|
153
|
-
return { userId, issuedAt };
|
|
172
|
+
return { userId, issuedAt, ...authVersion !== undefined ? { authVersion } : {} };
|
|
154
173
|
}
|
|
155
174
|
function readSession(request) {
|
|
156
|
-
const cookieValue =
|
|
175
|
+
const cookieValue = readRequestCookie(request, sessionCookieName());
|
|
157
176
|
if (!cookieValue) {
|
|
158
177
|
return null;
|
|
159
178
|
}
|
|
160
179
|
const parts = cookieValue.split(".");
|
|
180
|
+
if (parts.length === 6 && parts[0] === "v2") {
|
|
181
|
+
const fields = parts.slice(1, 5);
|
|
182
|
+
if (fields.some((value) => !/^(0|[1-9][0-9]*)$/.test(value) || !Number.isSafeInteger(Number(value))))
|
|
183
|
+
return null;
|
|
184
|
+
return readSignedSession(String(parts[1]), String(parts[2]), parts[5], Number(parts[3]), true, Number(parts[4]));
|
|
185
|
+
}
|
|
161
186
|
if (parts.length === 4) {
|
|
162
187
|
const [userIdRaw, issuedAtRaw, ttlRaw, cookieSignature] = parts;
|
|
163
188
|
return readSignedSession(String(userIdRaw), String(issuedAtRaw), cookieSignature, Number.parseInt(String(ttlRaw), 10), true);
|
|
@@ -182,15 +207,18 @@ function isSessionInvalidated(issuedAt, validAfter) {
|
|
|
182
207
|
return issuedAt < timestamp;
|
|
183
208
|
}
|
|
184
209
|
function createSessionCookieDetails(userId, options = {}) {
|
|
210
|
+
if (options.authVersion !== undefined && (!Number.isSafeInteger(options.authVersion) || options.authVersion < 0))
|
|
211
|
+
throw new RangeError("authVersion must be a non-negative safe integer.");
|
|
185
212
|
const issuedAt = Date.now();
|
|
186
213
|
const ttlSeconds = options.remember ? sessionRememberTtlSeconds() : sessionTtlSeconds();
|
|
187
|
-
const value = options.remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt);
|
|
214
|
+
const value = options.authVersion !== undefined ? signSession(userId, issuedAt, ttlSeconds, options.authVersion) : options.remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt);
|
|
188
215
|
const secure = isProductionEnv() ? "; Secure" : "";
|
|
189
216
|
return {
|
|
190
217
|
header: `${sessionCookieName()}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${ttlSeconds}${secure}`,
|
|
191
218
|
userId,
|
|
192
219
|
issuedAt,
|
|
193
|
-
ttlSeconds
|
|
220
|
+
ttlSeconds,
|
|
221
|
+
...options.authVersion !== undefined ? { authVersion: options.authVersion } : {}
|
|
194
222
|
};
|
|
195
223
|
}
|
|
196
224
|
function createSessionCookie(userId, options = {}) {
|
|
@@ -147,9 +147,54 @@ function resolveAbilitiesForRole(role) {
|
|
|
147
147
|
return [...MEMBER_ABILITIES];
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// ../../src/core/auth/accountState.ts
|
|
151
|
+
function isAccountActive(record) {
|
|
152
|
+
return record.is_active === undefined || record.is_active === true;
|
|
153
|
+
}
|
|
154
|
+
function isAuthUserActive(user) {
|
|
155
|
+
return user.isActive === undefined || user.isActive === true;
|
|
156
|
+
}
|
|
157
|
+
function matchesAuthVersion(issued, current) {
|
|
158
|
+
if (current === undefined)
|
|
159
|
+
return true;
|
|
160
|
+
return Number.isSafeInteger(current) && current >= 0 && typeof issued === "number" && Number.isSafeInteger(issued) && issued >= 0 && issued === current;
|
|
161
|
+
}
|
|
162
|
+
|
|
150
163
|
// ../../src/core/auth/sessionCookie.ts
|
|
151
164
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
152
165
|
|
|
166
|
+
// ../../src/core/http/cookies.ts
|
|
167
|
+
function readRequestCookie(request, name) {
|
|
168
|
+
const cookies = request.cookies;
|
|
169
|
+
if (cookies && typeof cookies.get === "function") {
|
|
170
|
+
const value = cookies.get(name);
|
|
171
|
+
if (value) {
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const header = request.headers.get("cookie");
|
|
176
|
+
if (!header) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
for (const part of header.split(";")) {
|
|
180
|
+
const idx = part.indexOf("=");
|
|
181
|
+
if (idx === -1)
|
|
182
|
+
continue;
|
|
183
|
+
const cookieName = part.slice(0, idx).trim();
|
|
184
|
+
if (cookieName !== name)
|
|
185
|
+
continue;
|
|
186
|
+
try {
|
|
187
|
+
return decodeURIComponent(part.slice(idx + 1).trim());
|
|
188
|
+
} catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
function readBunRequestCookie(request, name) {
|
|
195
|
+
return request.cookies.get(name) ?? readRequestCookie(request, name);
|
|
196
|
+
}
|
|
197
|
+
|
|
153
198
|
// ../../src/core/runtime/appEnv.ts
|
|
154
199
|
var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
|
|
155
200
|
function normalizeEnvValue(value) {
|
|
@@ -256,25 +301,12 @@ function sessionRememberTtlSeconds() {
|
|
|
256
301
|
function resolveSessionSecret() {
|
|
257
302
|
return requireConfiguredSecret(["SESSION_SECRET"], "session-secret");
|
|
258
303
|
}
|
|
259
|
-
function signSession(userId, issuedAt, ttlSeconds) {
|
|
260
|
-
const payload = ttlSeconds === undefined ? `${userId}.${issuedAt}` : `${userId}.${issuedAt}.${ttlSeconds}`;
|
|
304
|
+
function signSession(userId, issuedAt, ttlSeconds, authVersion) {
|
|
305
|
+
const payload = authVersion !== undefined ? `v2.${userId}.${issuedAt}.${ttlSeconds}.${authVersion}` : ttlSeconds === undefined ? `${userId}.${issuedAt}` : `${userId}.${issuedAt}.${ttlSeconds}`;
|
|
261
306
|
const signature = createHmac("sha256", resolveSessionSecret()).update(payload).digest("hex");
|
|
262
307
|
return `${payload}.${signature}`;
|
|
263
308
|
}
|
|
264
|
-
function
|
|
265
|
-
const cookieHeader = request.headers.get("cookie");
|
|
266
|
-
if (!cookieHeader) {
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
for (const part of cookieHeader.split(";")) {
|
|
270
|
-
const [name, ...rest] = part.trim().split("=");
|
|
271
|
-
if (name === cookieName) {
|
|
272
|
-
return decodeURIComponent(rest.join("="));
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
function readSignedSession(userIdRaw, issuedAtRaw, cookieSignature, ttlSeconds, remember) {
|
|
309
|
+
function readSignedSession(userIdRaw, issuedAtRaw, cookieSignature, ttlSeconds, remember, authVersion) {
|
|
278
310
|
const userId = Number.parseInt(userIdRaw, 10);
|
|
279
311
|
const issuedAt = Number.parseInt(issuedAtRaw, 10);
|
|
280
312
|
if (!Number.isInteger(userId) || userId <= 0 || !Number.isFinite(issuedAt)) {
|
|
@@ -286,7 +318,7 @@ function readSignedSession(userIdRaw, issuedAtRaw, cookieSignature, ttlSeconds,
|
|
|
286
318
|
if (Date.now() - issuedAt > ttlSeconds * 1000) {
|
|
287
319
|
return null;
|
|
288
320
|
}
|
|
289
|
-
const expectedSignature = (remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt)).split(".").pop();
|
|
321
|
+
const expectedSignature = (authVersion !== undefined ? signSession(userId, issuedAt, ttlSeconds, authVersion) : remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt)).split(".").pop();
|
|
290
322
|
if (!expectedSignature || !cookieSignature) {
|
|
291
323
|
return null;
|
|
292
324
|
}
|
|
@@ -298,14 +330,20 @@ function readSignedSession(userIdRaw, issuedAtRaw, cookieSignature, ttlSeconds,
|
|
|
298
330
|
if (!timingSafeEqual(expectedBuffer, actualBuffer)) {
|
|
299
331
|
return null;
|
|
300
332
|
}
|
|
301
|
-
return { userId, issuedAt };
|
|
333
|
+
return { userId, issuedAt, ...authVersion !== undefined ? { authVersion } : {} };
|
|
302
334
|
}
|
|
303
335
|
function readSession(request) {
|
|
304
|
-
const cookieValue =
|
|
336
|
+
const cookieValue = readRequestCookie(request, sessionCookieName());
|
|
305
337
|
if (!cookieValue) {
|
|
306
338
|
return null;
|
|
307
339
|
}
|
|
308
340
|
const parts = cookieValue.split(".");
|
|
341
|
+
if (parts.length === 6 && parts[0] === "v2") {
|
|
342
|
+
const fields = parts.slice(1, 5);
|
|
343
|
+
if (fields.some((value) => !/^(0|[1-9][0-9]*)$/.test(value) || !Number.isSafeInteger(Number(value))))
|
|
344
|
+
return null;
|
|
345
|
+
return readSignedSession(String(parts[1]), String(parts[2]), parts[5], Number(parts[3]), true, Number(parts[4]));
|
|
346
|
+
}
|
|
309
347
|
if (parts.length === 4) {
|
|
310
348
|
const [userIdRaw, issuedAtRaw, ttlRaw, cookieSignature] = parts;
|
|
311
349
|
return readSignedSession(String(userIdRaw), String(issuedAtRaw), cookieSignature, Number.parseInt(String(ttlRaw), 10), true);
|
|
@@ -330,15 +368,18 @@ function isSessionInvalidated(issuedAt, validAfter) {
|
|
|
330
368
|
return issuedAt < timestamp;
|
|
331
369
|
}
|
|
332
370
|
function createSessionCookieDetails(userId, options = {}) {
|
|
371
|
+
if (options.authVersion !== undefined && (!Number.isSafeInteger(options.authVersion) || options.authVersion < 0))
|
|
372
|
+
throw new RangeError("authVersion must be a non-negative safe integer.");
|
|
333
373
|
const issuedAt = Date.now();
|
|
334
374
|
const ttlSeconds = options.remember ? sessionRememberTtlSeconds() : sessionTtlSeconds();
|
|
335
|
-
const value = options.remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt);
|
|
375
|
+
const value = options.authVersion !== undefined ? signSession(userId, issuedAt, ttlSeconds, options.authVersion) : options.remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt);
|
|
336
376
|
const secure = isProductionEnv() ? "; Secure" : "";
|
|
337
377
|
return {
|
|
338
378
|
header: `${sessionCookieName()}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${ttlSeconds}${secure}`,
|
|
339
379
|
userId,
|
|
340
380
|
issuedAt,
|
|
341
|
-
ttlSeconds
|
|
381
|
+
ttlSeconds,
|
|
382
|
+
...options.authVersion !== undefined ? { authVersion: options.authVersion } : {}
|
|
342
383
|
};
|
|
343
384
|
}
|
|
344
385
|
function createSessionCookie(userId, options = {}) {
|
|
@@ -366,7 +407,9 @@ class SessionGuard {
|
|
|
366
407
|
}
|
|
367
408
|
try {
|
|
368
409
|
const user = await tokenService.findByIdOrThrow(session.userId);
|
|
369
|
-
if (
|
|
410
|
+
if (!isAccountActive(user) || !matchesAuthVersion(session.authVersion, user.auth_version))
|
|
411
|
+
return null;
|
|
412
|
+
if (user.auth_version === undefined && isSessionInvalidated(session.issuedAt, user.session_valid_after)) {
|
|
370
413
|
return null;
|
|
371
414
|
}
|
|
372
415
|
if (typeof tokenService.hasActiveBrowserSession === "function") {
|
|
@@ -378,6 +421,7 @@ class SessionGuard {
|
|
|
378
421
|
return {
|
|
379
422
|
id: user.id,
|
|
380
423
|
role: user.role,
|
|
424
|
+
...user.auth_version !== undefined ? { authVersion: user.auth_version } : {},
|
|
381
425
|
abilities: resolveAbilitiesForRole(user.role),
|
|
382
426
|
emailVerifiedAt: user.email_verified_at ?? null
|
|
383
427
|
};
|
|
@@ -19,7 +19,11 @@ function readRequestCookie(request, name) {
|
|
|
19
19
|
const cookieName = part.slice(0, idx).trim();
|
|
20
20
|
if (cookieName !== name)
|
|
21
21
|
continue;
|
|
22
|
-
|
|
22
|
+
try {
|
|
23
|
+
return decodeURIComponent(part.slice(idx + 1).trim());
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
23
27
|
}
|
|
24
28
|
return null;
|
|
25
29
|
}
|
|
@@ -139,7 +139,11 @@ function readRequestCookie(request, name) {
|
|
|
139
139
|
const cookieName = part.slice(0, idx).trim();
|
|
140
140
|
if (cookieName !== name)
|
|
141
141
|
continue;
|
|
142
|
-
|
|
142
|
+
try {
|
|
143
|
+
return decodeURIComponent(part.slice(idx + 1).trim());
|
|
144
|
+
} catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
143
147
|
}
|
|
144
148
|
return null;
|
|
145
149
|
}
|
|
@@ -135,7 +135,11 @@ function readRequestCookie(request, name) {
|
|
|
135
135
|
const cookieName = part.slice(0, idx).trim();
|
|
136
136
|
if (cookieName !== name)
|
|
137
137
|
continue;
|
|
138
|
-
|
|
138
|
+
try {
|
|
139
|
+
return decodeURIComponent(part.slice(idx + 1).trim());
|
|
140
|
+
} catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
139
143
|
}
|
|
140
144
|
return null;
|
|
141
145
|
}
|
|
@@ -106,7 +106,7 @@ function createRequirePasswordConfirmMiddleware() {
|
|
|
106
106
|
return Response.redirect("/login", 302);
|
|
107
107
|
}
|
|
108
108
|
const userId = resolveUserId(user);
|
|
109
|
-
if (hasFreshPasswordConfirmation(request, userId)) {
|
|
109
|
+
if (hasFreshPasswordConfirmation(request, userId, user.authVersion)) {
|
|
110
110
|
return await next();
|
|
111
111
|
}
|
|
112
112
|
if (requestPrefersJson(request)) {
|
|
@@ -306,6 +306,20 @@ async function dispatchQueuedModelEvents(queued) {
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
|
+
async function dispatchModelEvent(event, payload) {
|
|
310
|
+
await eventBus.dispatchTransactional(event, payload);
|
|
311
|
+
const state = deferredModelEvents.getStore();
|
|
312
|
+
const frame = state?.frames[state.frames.length - 1];
|
|
313
|
+
if (frame) {
|
|
314
|
+
frame.push({
|
|
315
|
+
event,
|
|
316
|
+
payload,
|
|
317
|
+
tenant: currentTenant()
|
|
318
|
+
});
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
await eventBus.dispatch(event, payload);
|
|
322
|
+
}
|
|
309
323
|
async function runWithDeferredModelEvents(callback) {
|
|
310
324
|
const existing = deferredModelEvents.getStore();
|
|
311
325
|
if (existing) {
|
|
@@ -691,6 +691,20 @@ async function dispatchQueuedModelEvents(queued) {
|
|
|
691
691
|
}
|
|
692
692
|
}
|
|
693
693
|
}
|
|
694
|
+
async function dispatchModelEvent(event, payload) {
|
|
695
|
+
await eventBus.dispatchTransactional(event, payload);
|
|
696
|
+
const state = deferredModelEvents.getStore();
|
|
697
|
+
const frame = state?.frames[state.frames.length - 1];
|
|
698
|
+
if (frame) {
|
|
699
|
+
frame.push({
|
|
700
|
+
event,
|
|
701
|
+
payload,
|
|
702
|
+
tenant: currentTenant()
|
|
703
|
+
});
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
await eventBus.dispatch(event, payload);
|
|
707
|
+
}
|
|
694
708
|
async function runWithDeferredModelEvents(callback) {
|
|
695
709
|
const existing = deferredModelEvents.getStore();
|
|
696
710
|
if (existing) {
|
|
@@ -306,6 +306,20 @@ async function dispatchQueuedModelEvents(queued) {
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
|
+
async function dispatchModelEvent(event, payload) {
|
|
310
|
+
await eventBus.dispatchTransactional(event, payload);
|
|
311
|
+
const state = deferredModelEvents.getStore();
|
|
312
|
+
const frame = state?.frames[state.frames.length - 1];
|
|
313
|
+
if (frame) {
|
|
314
|
+
frame.push({
|
|
315
|
+
event,
|
|
316
|
+
payload,
|
|
317
|
+
tenant: currentTenant()
|
|
318
|
+
});
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
await eventBus.dispatch(event, payload);
|
|
322
|
+
}
|
|
309
323
|
async function runWithDeferredModelEvents(callback) {
|
|
310
324
|
const existing = deferredModelEvents.getStore();
|
|
311
325
|
if (existing) {
|
|
@@ -239,6 +239,20 @@ async function dispatchQueuedModelEvents(queued) {
|
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
|
+
async function dispatchModelEvent(event, payload) {
|
|
243
|
+
await eventBus.dispatchTransactional(event, payload);
|
|
244
|
+
const state = deferredModelEvents.getStore();
|
|
245
|
+
const frame = state?.frames[state.frames.length - 1];
|
|
246
|
+
if (frame) {
|
|
247
|
+
frame.push({
|
|
248
|
+
event,
|
|
249
|
+
payload,
|
|
250
|
+
tenant: currentTenant()
|
|
251
|
+
});
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
await eventBus.dispatch(event, payload);
|
|
255
|
+
}
|
|
242
256
|
async function runWithDeferredModelEvents(callback) {
|
|
243
257
|
const existing = deferredModelEvents.getStore();
|
|
244
258
|
if (existing) {
|