@getstrata/core 1.0.8 → 1.1.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.
- package/CHANGELOG.md +52 -0
- package/dist/core/auth/authContext.d.ts +5 -2
- package/dist/core/auth/emailVerification.d.ts +1 -1
- package/dist/core/auth/guard.d.ts +5 -1
- package/dist/core/auth/jwtGuard.d.ts +6 -2
- package/dist/core/auth/oauth/oidcIdToken.d.ts +19 -0
- package/dist/core/auth/oauth/oidcProvider.d.ts +16 -4
- package/dist/core/auth/oauth/samlProvider.d.ts +7 -4
- package/dist/core/auth/oneTimeToken.d.ts +19 -0
- package/dist/core/auth/passwordLogin.d.ts +20 -0
- package/dist/core/auth/saml/samlAssertionReplay.d.ts +20 -0
- package/dist/core/auth/saml/samlServiceProvider.d.ts +51 -0
- package/dist/core/contracts/authUserDirectory.d.ts +2 -3
- package/dist/core/database/errors.d.ts +2 -1
- package/dist/core/http/response.d.ts +3 -1
- package/dist/core/mail/mailer.d.ts +6 -1
- package/dist/core/security/oauthState.d.ts +6 -2
- package/dist/core/security/safeFetch.d.ts +1 -0
- package/dist/core/security/safePath.d.ts +4 -0
- package/dist/core/security/safeUrl.d.ts +14 -1
- package/dist/core/security/totp.d.ts +1 -1
- package/dist/core/tenant/databaseTenantContext.d.ts +2 -1
- package/dist/core/tenant/enableTenantRls.d.ts +6 -0
- package/dist/core/tenant/postgresAppRole.d.ts +75 -0
- package/dist/entries/audit/exportAuditLogs.js +223 -40
- package/dist/entries/auth/accessControl.js +1 -0
- package/dist/entries/auth/basicAuthGuard.js +638 -17
- package/dist/entries/auth/emailVerification.js +1 -1
- package/dist/entries/auth/intendedUrlCookie.js +32 -2
- package/dist/entries/auth/jwt.js +1 -1
- package/dist/entries/auth/jwtGuard.js +192 -3
- package/dist/entries/auth/membershipMiddleware.js +1 -0
- package/dist/entries/auth/membershipScope.js +1 -0
- package/dist/entries/auth/membershipService.js +1 -0
- package/dist/entries/auth/oauth/oidcProvider.js +542 -20
- package/dist/entries/auth/oauth/providers.js +313 -5
- package/dist/entries/auth/oauth/samlProvider.js +552 -74
- package/dist/entries/auth/oneTimeToken.js +362 -0
- package/dist/entries/auth/password.js +1 -1
- package/dist/entries/auth/passwordLogin.js +548 -0
- package/dist/entries/auth/policy.js +1 -0
- package/dist/entries/auth/saml/samlServiceProvider.js +571 -0
- package/dist/entries/auth/scimAuthMiddleware.js +10 -3
- package/dist/entries/auth/sessionCookie.js +1 -1
- package/dist/entries/auth/sessionGuard.js +1 -1
- package/dist/entries/auth/tokenHash.js +2 -6
- package/dist/entries/crypto/fieldEncryption.js +1 -1
- package/dist/entries/crypto/mfaSecret.js +31 -5
- package/dist/entries/database/errors.js +29 -12
- package/dist/entries/database/model.js +9 -9
- package/dist/entries/facades.js +72 -9
- package/dist/entries/http/authMiddleware.js +7 -14
- package/dist/entries/http/corsMiddleware.js +69 -2
- package/dist/entries/http/csrfMiddleware.js +33 -43
- package/dist/entries/http/csrfToken.js +2 -2
- package/dist/entries/http/flashMiddleware.js +4 -2
- package/dist/entries/http/flashSession.js +4 -2
- package/dist/entries/http/formRequest.js +2 -2
- package/dist/entries/http/memoryThrottleMiddleware.js +63 -0
- package/dist/entries/http/pagination.js +2 -2
- package/dist/entries/http/requirePasswordConfirmMiddleware.js +36 -3
- package/dist/entries/http/requireWebAuthMiddleware.js +32 -2
- package/dist/entries/http/response.js +101 -45
- package/dist/entries/http/routeModelBinding.js +2 -2
- package/dist/entries/http/safeInternalPath.js +32 -2
- package/dist/entries/http/scimThrottleMiddleware.js +7 -1
- package/dist/entries/http/securedRouteModelBinding.js +2 -2
- package/dist/entries/http/securityHeadersMiddleware.js +3 -64
- package/dist/entries/http/signedUrl.js +6 -5
- package/dist/entries/http/throttleMiddleware.js +63 -0
- package/dist/entries/http/validation.js +2 -2
- package/dist/entries/http/webFormRequest.js +2 -2
- package/dist/entries/jobs/exportAuditLogsJob.js +223 -40
- package/dist/entries/mail/mailer.js +54 -8
- package/dist/entries/media/imageTransform.js +12 -1
- package/dist/entries/openapi/generator.js +0 -7
- package/dist/entries/security/oauthState.js +30 -39
- package/dist/entries/security/publicReads.js +1 -1
- package/dist/entries/security/recoveryCodes.js +2 -2
- package/dist/entries/security/safeFetch.js +195 -94
- package/dist/entries/security/safePath.js +25 -0
- package/dist/entries/security/scimTenantTokens.js +10 -3
- package/dist/entries/security/totp.js +16 -4
- package/dist/entries/storage/storage.js +24 -2
- package/dist/entries/tenant/databaseTenantContext.js +34 -12
- package/dist/entries/tenant/enableTenantRls.js +385 -0
- package/dist/entries/tracing/tracingMiddleware.js +308 -5
- package/dist/framework/public-api.d.ts +10 -3
- package/dist/index.js +2767 -1515
- package/package.json +32 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// ../../src/core/http/safeInternalPath.ts
|
|
3
|
+
var NESTED_REDIRECT_KEYS = new Set(["redirect", "next", "return", "returnTo", "return_to"]);
|
|
3
4
|
function looksLikeExternalTarget(value) {
|
|
4
5
|
const trimmed = value.trim();
|
|
5
6
|
if (!trimmed.startsWith("/") || trimmed.startsWith("//") || trimmed.includes("\\")) {
|
|
@@ -18,11 +19,40 @@ function looksLikeExternalTarget(value) {
|
|
|
18
19
|
}
|
|
19
20
|
return false;
|
|
20
21
|
}
|
|
22
|
+
function sanitizeNestedQuery(search) {
|
|
23
|
+
if (!search) {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
|
|
27
|
+
const next = new URLSearchParams;
|
|
28
|
+
for (const [key, value] of params.entries()) {
|
|
29
|
+
if (NESTED_REDIRECT_KEYS.has(key)) {
|
|
30
|
+
const sanitized = sanitizeInternalPath(value, "/");
|
|
31
|
+
next.set(key, sanitized);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (looksLikeExternalTarget(value) && value.includes("://")) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
next.set(key, value);
|
|
38
|
+
}
|
|
39
|
+
const serialized = next.toString();
|
|
40
|
+
return serialized ? `?${serialized}` : "";
|
|
41
|
+
}
|
|
21
42
|
function sanitizeInternalPath(raw, fallback = "/") {
|
|
22
|
-
|
|
43
|
+
const trimmed = raw.trim();
|
|
44
|
+
if (looksLikeExternalTarget(trimmed)) {
|
|
45
|
+
return fallback;
|
|
46
|
+
}
|
|
47
|
+
const queryIndex = trimmed.indexOf("?");
|
|
48
|
+
const hashIndex = trimmed.indexOf("#");
|
|
49
|
+
const end = [queryIndex, hashIndex].filter((index) => index >= 0).sort((a, b) => a - b)[0];
|
|
50
|
+
const pathname = end === undefined ? trimmed : trimmed.slice(0, end);
|
|
51
|
+
if (looksLikeExternalTarget(pathname)) {
|
|
23
52
|
return fallback;
|
|
24
53
|
}
|
|
25
|
-
|
|
54
|
+
const search = queryIndex >= 0 ? trimmed.slice(queryIndex, hashIndex >= 0 ? hashIndex : undefined) : "";
|
|
55
|
+
return `${pathname}${sanitizeNestedQuery(search)}`;
|
|
26
56
|
}
|
|
27
57
|
function safeInternalRedirectPath(request, fallback = "/") {
|
|
28
58
|
const url = new URL(request.url);
|
package/dist/entries/auth/jwt.js
CHANGED
|
@@ -154,7 +154,7 @@ function verifyJwt(token, secret) {
|
|
|
154
154
|
if (!payload || payload.sub === undefined || payload.sub === null) {
|
|
155
155
|
return null;
|
|
156
156
|
}
|
|
157
|
-
if (typeof payload.exp
|
|
157
|
+
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp) || payload.exp * 1000 <= Date.now()) {
|
|
158
158
|
return null;
|
|
159
159
|
}
|
|
160
160
|
return payload;
|
|
@@ -1,4 +1,49 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// ../../src/core/contracts/serviceTokens.ts
|
|
3
|
+
var CORE_CONFIG_TOKEN = "core.config";
|
|
4
|
+
var CORE_CACHE_TOKEN = "core.cache";
|
|
5
|
+
var CORE_QUEUE_TOKEN = "core.queue";
|
|
6
|
+
var CORE_EVENT_BUS_TOKEN = "core.eventBus";
|
|
7
|
+
var CORE_POLICY_GATE_TOKEN = "core.policyGate";
|
|
8
|
+
var CORE_AUTH_TOKEN = "core.auth";
|
|
9
|
+
var CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
|
|
10
|
+
var CORE_ABILITY_CHECKER_TOKEN = "core.abilityChecker";
|
|
11
|
+
var CORE_AUTH_USER_DIRECTORY_TOKEN = "core.authUserDirectory";
|
|
12
|
+
function isAbilityChecker(value) {
|
|
13
|
+
if (!value || typeof value !== "object") {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const candidate = value;
|
|
17
|
+
return typeof candidate.tokenCan === "function" && typeof candidate.requireAbility === "function";
|
|
18
|
+
}
|
|
19
|
+
function isAuthUserDirectory(value) {
|
|
20
|
+
if (!value || typeof value !== "object") {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return typeof value.findByIdOrThrow === "function";
|
|
24
|
+
}
|
|
25
|
+
function resolveAbilityChecker(container) {
|
|
26
|
+
if (container.has(CORE_ABILITY_CHECKER_TOKEN)) {
|
|
27
|
+
return container.resolve(CORE_ABILITY_CHECKER_TOKEN);
|
|
28
|
+
}
|
|
29
|
+
return container.resolve(CORE_TOKEN_SERVICE_TOKEN);
|
|
30
|
+
}
|
|
31
|
+
function resolveAuthUserDirectory(container) {
|
|
32
|
+
if (container.has(CORE_AUTH_USER_DIRECTORY_TOKEN)) {
|
|
33
|
+
const directory = container.resolve(CORE_AUTH_USER_DIRECTORY_TOKEN);
|
|
34
|
+
if (isAuthUserDirectory(directory)) {
|
|
35
|
+
return directory;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (container.has(CORE_TOKEN_SERVICE_TOKEN)) {
|
|
39
|
+
const tokenService = container.resolve(CORE_TOKEN_SERVICE_TOKEN);
|
|
40
|
+
if (isAuthUserDirectory(tokenService)) {
|
|
41
|
+
return tokenService;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
2
47
|
// ../../src/core/http/statelessAuth.ts
|
|
3
48
|
function authorizationScheme(request) {
|
|
4
49
|
const header = request.headers.get("authorization")?.trim() ?? "";
|
|
@@ -196,13 +241,130 @@ function verifyJwt(token, secret) {
|
|
|
196
241
|
if (!payload || payload.sub === undefined || payload.sub === null) {
|
|
197
242
|
return null;
|
|
198
243
|
}
|
|
199
|
-
if (typeof payload.exp
|
|
244
|
+
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp) || payload.exp * 1000 <= Date.now()) {
|
|
200
245
|
return null;
|
|
201
246
|
}
|
|
202
247
|
return payload;
|
|
203
248
|
}
|
|
204
249
|
|
|
250
|
+
// ../../src/core/auth/sessionCookie.ts
|
|
251
|
+
import { createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
252
|
+
var SESSION_COOKIE = appCookieName("session");
|
|
253
|
+
var SESSION_TTL_SECONDS = 60 * 60 * 24 * 7;
|
|
254
|
+
var SESSION_REMEMBER_TTL_SECONDS = 60 * 60 * 24 * 30;
|
|
255
|
+
function sessionCookieName() {
|
|
256
|
+
return process.env.SESSION_COOKIE_NAME?.trim() || appCookieName("session");
|
|
257
|
+
}
|
|
258
|
+
function parsePositiveSeconds(raw, fallback) {
|
|
259
|
+
const parsed = Number.parseInt(raw ?? "", 10);
|
|
260
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
261
|
+
}
|
|
262
|
+
function sessionTtlSeconds() {
|
|
263
|
+
return parsePositiveSeconds(process.env.SESSION_TTL_SECONDS, SESSION_TTL_SECONDS);
|
|
264
|
+
}
|
|
265
|
+
function sessionRememberTtlSeconds() {
|
|
266
|
+
return parsePositiveSeconds(process.env.SESSION_REMEMBER_TTL_SECONDS, SESSION_REMEMBER_TTL_SECONDS);
|
|
267
|
+
}
|
|
268
|
+
function resolveSessionSecret() {
|
|
269
|
+
return requireConfiguredSecret(["SESSION_SECRET"], "session-secret");
|
|
270
|
+
}
|
|
271
|
+
function signSession(userId, issuedAt, ttlSeconds) {
|
|
272
|
+
const payload = ttlSeconds === undefined ? `${userId}.${issuedAt}` : `${userId}.${issuedAt}.${ttlSeconds}`;
|
|
273
|
+
const signature = createHmac2("sha256", resolveSessionSecret()).update(payload).digest("hex");
|
|
274
|
+
return `${payload}.${signature}`;
|
|
275
|
+
}
|
|
276
|
+
function readCookieValue(request, cookieName) {
|
|
277
|
+
const cookieHeader = request.headers.get("cookie");
|
|
278
|
+
if (!cookieHeader) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
for (const part of cookieHeader.split(";")) {
|
|
282
|
+
const [name, ...rest] = part.trim().split("=");
|
|
283
|
+
if (name === cookieName) {
|
|
284
|
+
return decodeURIComponent(rest.join("="));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
function readSignedSession(userIdRaw, issuedAtRaw, cookieSignature, ttlSeconds, remember) {
|
|
290
|
+
const userId = Number.parseInt(userIdRaw, 10);
|
|
291
|
+
const issuedAt = Number.parseInt(issuedAtRaw, 10);
|
|
292
|
+
if (!Number.isInteger(userId) || userId <= 0 || !Number.isFinite(issuedAt)) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
if (!Number.isInteger(ttlSeconds) || ttlSeconds <= 0) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
if (Date.now() - issuedAt > ttlSeconds * 1000) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
const expectedSignature = (remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt)).split(".").pop();
|
|
302
|
+
if (!expectedSignature || !cookieSignature) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
const expectedBuffer = Buffer.from(expectedSignature);
|
|
306
|
+
const actualBuffer = Buffer.from(cookieSignature);
|
|
307
|
+
if (expectedBuffer.length !== actualBuffer.length) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
if (!timingSafeEqual2(expectedBuffer, actualBuffer)) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
return { userId, issuedAt };
|
|
314
|
+
}
|
|
315
|
+
function readSession(request) {
|
|
316
|
+
const cookieValue = readCookieValue(request, sessionCookieName());
|
|
317
|
+
if (!cookieValue) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
const parts = cookieValue.split(".");
|
|
321
|
+
if (parts.length === 4) {
|
|
322
|
+
const [userIdRaw, issuedAtRaw, ttlRaw, cookieSignature] = parts;
|
|
323
|
+
return readSignedSession(String(userIdRaw), String(issuedAtRaw), cookieSignature, Number.parseInt(String(ttlRaw), 10), true);
|
|
324
|
+
}
|
|
325
|
+
if (parts.length !== 3) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
const [userIdRaw, issuedAtRaw, cookieSignature] = parts;
|
|
329
|
+
return readSignedSession(String(userIdRaw), String(issuedAtRaw), cookieSignature, sessionTtlSeconds(), false);
|
|
330
|
+
}
|
|
331
|
+
function readSessionUserId(request) {
|
|
332
|
+
return readSession(request)?.userId ?? null;
|
|
333
|
+
}
|
|
334
|
+
function isSessionInvalidated(issuedAt, validAfter) {
|
|
335
|
+
if (!validAfter) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
const timestamp = validAfter instanceof Date ? validAfter.getTime() : Date.parse(String(validAfter));
|
|
339
|
+
if (!Number.isFinite(timestamp)) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
return issuedAt < timestamp;
|
|
343
|
+
}
|
|
344
|
+
function createSessionCookieDetails(userId, options = {}) {
|
|
345
|
+
const issuedAt = Date.now();
|
|
346
|
+
const ttlSeconds = options.remember ? sessionRememberTtlSeconds() : sessionTtlSeconds();
|
|
347
|
+
const value = options.remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt);
|
|
348
|
+
const secure = isProductionEnv() ? "; Secure" : "";
|
|
349
|
+
return {
|
|
350
|
+
header: `${sessionCookieName()}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${ttlSeconds}${secure}`,
|
|
351
|
+
userId,
|
|
352
|
+
issuedAt,
|
|
353
|
+
ttlSeconds
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function createSessionCookie(userId, options = {}) {
|
|
357
|
+
return createSessionCookieDetails(userId, options).header;
|
|
358
|
+
}
|
|
359
|
+
function clearSessionCookie() {
|
|
360
|
+
const secure = isProductionEnv() ? "; Secure" : "";
|
|
361
|
+
return `${sessionCookieName()}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0${secure}`;
|
|
362
|
+
}
|
|
363
|
+
|
|
205
364
|
// ../../src/core/auth/jwtGuard.ts
|
|
365
|
+
function isServiceContainer(value) {
|
|
366
|
+
return "has" in value && "resolve" in value && typeof value.has === "function";
|
|
367
|
+
}
|
|
206
368
|
function authUserFromJwt(payload) {
|
|
207
369
|
return {
|
|
208
370
|
id: payload.sub,
|
|
@@ -211,13 +373,20 @@ function authUserFromJwt(payload) {
|
|
|
211
373
|
...payload.emailVerifiedAt !== undefined ? { emailVerifiedAt: payload.emailVerifiedAt } : {}
|
|
212
374
|
};
|
|
213
375
|
}
|
|
376
|
+
function jwtSubjectId(payload) {
|
|
377
|
+
const userId = typeof payload.sub === "number" ? payload.sub : Number.parseInt(String(payload.sub), 10);
|
|
378
|
+
if (!Number.isInteger(userId) || userId <= 0) {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
return userId;
|
|
382
|
+
}
|
|
214
383
|
|
|
215
384
|
class JwtGuard {
|
|
216
385
|
options;
|
|
217
386
|
constructor(options = {}) {
|
|
218
|
-
this.options = options;
|
|
387
|
+
this.options = isServiceContainer(options) ? { container: options } : options;
|
|
219
388
|
}
|
|
220
|
-
resolve(request) {
|
|
389
|
+
async resolve(request) {
|
|
221
390
|
const token = readBearerToken(request);
|
|
222
391
|
if (token?.split(".").length !== 3) {
|
|
223
392
|
return null;
|
|
@@ -226,6 +395,26 @@ class JwtGuard {
|
|
|
226
395
|
if (!payload) {
|
|
227
396
|
return null;
|
|
228
397
|
}
|
|
398
|
+
if (typeof payload.iat !== "number" || !Number.isFinite(payload.iat)) {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
const directory = this.options.directory ?? (this.options.container ? resolveAuthUserDirectory(this.options.container) : null);
|
|
402
|
+
if (!directory) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
const userId = jwtSubjectId(payload);
|
|
406
|
+
if (userId === null) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
let record;
|
|
410
|
+
try {
|
|
411
|
+
record = await directory.findByIdOrThrow(userId);
|
|
412
|
+
} catch {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
if (isSessionInvalidated(payload.iat * 1000, record.session_valid_after)) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
229
418
|
return authUserFromJwt(payload);
|
|
230
419
|
}
|
|
231
420
|
}
|
|
@@ -18,6 +18,7 @@ import { ForbiddenError } from "@getstrata/core/errors/http";
|
|
|
18
18
|
|
|
19
19
|
// ../../src/core/auth/authContext.ts
|
|
20
20
|
var authContext = createAsyncContextStore("@getstrata/authContext");
|
|
21
|
+
var credentialSourceContext = createAsyncContextStore("@getstrata/credentialSource");
|
|
21
22
|
function currentAuthUser() {
|
|
22
23
|
return authContext.getStore() ?? null;
|
|
23
24
|
}
|
|
@@ -22,6 +22,7 @@ function createAsyncContextStore(key) {
|
|
|
22
22
|
|
|
23
23
|
// ../../src/core/auth/authContext.ts
|
|
24
24
|
var authContext = createAsyncContextStore("@getstrata/authContext");
|
|
25
|
+
var credentialSourceContext = createAsyncContextStore("@getstrata/credentialSource");
|
|
25
26
|
function currentAuthUser() {
|
|
26
27
|
return authContext.getStore() ?? null;
|
|
27
28
|
}
|
|
@@ -21,6 +21,7 @@ function createAsyncContextStore(key) {
|
|
|
21
21
|
|
|
22
22
|
// ../../src/core/auth/authContext.ts
|
|
23
23
|
var authContext = createAsyncContextStore("@getstrata/authContext");
|
|
24
|
+
var credentialSourceContext = createAsyncContextStore("@getstrata/credentialSource");
|
|
24
25
|
function currentAuthUser() {
|
|
25
26
|
return authContext.getStore() ?? null;
|
|
26
27
|
}
|