@sylphx/sdk 0.9.0 → 0.10.1
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/README.md +13 -12
- package/dist/index.d.ts +143 -310
- package/dist/index.mjs +492 -246
- package/dist/index.mjs.map +1 -1
- package/dist/nextjs/index.d.ts +19 -6
- package/dist/nextjs/index.mjs +127 -22
- package/dist/nextjs/index.mjs.map +1 -1
- package/dist/react/index.d.ts +106 -317
- package/dist/react/index.mjs +1417 -1075
- package/dist/react/index.mjs.map +1 -1
- package/dist/server/index.d.ts +41 -34
- package/dist/server/index.mjs +81 -66
- package/dist/server/index.mjs.map +1 -1
- package/dist/web-analytics.mjs.map +1 -1
- package/package.json +2 -2
package/dist/nextjs/index.d.ts
CHANGED
|
@@ -80,8 +80,7 @@ interface SylphxMiddlewareConfig {
|
|
|
80
80
|
*
|
|
81
81
|
* Use case: Platform Console uses dynamically generated keys.
|
|
82
82
|
*
|
|
83
|
-
* @default credential parsed from process.env.SYLPHX_SECRET_URL
|
|
84
|
-
* to process.env.SYLPHX_SECRET_KEY for legacy apps
|
|
83
|
+
* @default credential parsed from process.env.SYLPHX_SECRET_URL
|
|
85
84
|
*/
|
|
86
85
|
secretKey?: string;
|
|
87
86
|
/**
|
|
@@ -96,7 +95,7 @@ interface SylphxMiddlewareConfig {
|
|
|
96
95
|
* Platform URL for API calls.
|
|
97
96
|
* Override for self-hosted or same-origin deployments.
|
|
98
97
|
*
|
|
99
|
-
* @default resolved from SYLPHX_URL,
|
|
98
|
+
* @default resolved from SYLPHX_SECRET_URL, SYLPHX_URL, SYLPHX_BAAS_URL, or SYLPHX_RUNTIME_URL
|
|
100
99
|
*/
|
|
101
100
|
platformUrl?: string;
|
|
102
101
|
/**
|
|
@@ -113,6 +112,20 @@ interface SylphxMiddlewareConfig {
|
|
|
113
112
|
* ```
|
|
114
113
|
*/
|
|
115
114
|
onResponse?: (response: NextResponse, request: NextRequest) => void | Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Require authenticated requests to carry an active organization context.
|
|
117
|
+
* When true, protected routes without an `org_id` JWT claim redirect to
|
|
118
|
+
* `orgSelectionUrl`.
|
|
119
|
+
*
|
|
120
|
+
* @default false
|
|
121
|
+
*/
|
|
122
|
+
orgRequired?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* URL for selecting an active organization when `orgRequired` is enabled.
|
|
125
|
+
*
|
|
126
|
+
* @default '/select-organization'
|
|
127
|
+
*/
|
|
128
|
+
orgSelectionUrl?: string;
|
|
116
129
|
}
|
|
117
130
|
/**
|
|
118
131
|
* Create Sylphx middleware — State of the Art
|
|
@@ -138,6 +151,7 @@ interface SylphxMiddlewareConfig {
|
|
|
138
151
|
* ```
|
|
139
152
|
*/
|
|
140
153
|
declare function createSylphxMiddleware(userConfig?: SylphxMiddlewareConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
154
|
+
declare const sylphxMiddleware: typeof createSylphxMiddleware;
|
|
141
155
|
/**
|
|
142
156
|
* Create recommended matcher config
|
|
143
157
|
*/
|
|
@@ -225,8 +239,7 @@ interface UserCookieData {
|
|
|
225
239
|
* Configure the SDK for server-side usage
|
|
226
240
|
*
|
|
227
241
|
* NOTE: This is optional! The SDK auto-configures from environment variables:
|
|
228
|
-
* - SYLPHX_SECRET_URL
|
|
229
|
-
* - SYLPHX_SECRET_KEY (legacy fallback)
|
|
242
|
+
* - SYLPHX_SECRET_URL
|
|
230
243
|
*
|
|
231
244
|
* Use this only if you need to override the default configuration.
|
|
232
245
|
*
|
|
@@ -575,4 +588,4 @@ declare function clearAuthCookiesMiddleware(response: NextResponse, namespace: s
|
|
|
575
588
|
*/
|
|
576
589
|
declare function parseUserCookie(value: string): UserCookieData | null;
|
|
577
590
|
|
|
578
|
-
export { type AuthCookiesData, type AuthResult, REFRESH_TOKEN_LIFETIME, SECURE_COOKIE_OPTIONS, SESSION_TOKEN_LIFETIME, SESSION_TOKEN_LIFETIME_MS, type SylphxMiddlewareConfig, TOKEN_EXPIRY_BUFFER_MS, USER_COOKIE_OPTIONS, type UserCookieData, auth, clearAuthCookies, clearAuthCookiesMiddleware, configureServer, createMatcher, createSylphxMiddleware, currentUser, currentUserId, decodeUserId, encodeUserId, getAuthCookies, getAuthorizationUrl, getCookieNames, getNamespace, getSessionToken, handleCallback, hasRefreshToken, isSessionExpired, parseUserCookie, setAuthCookies, setAuthCookiesMiddleware, signOut, syncAuthToCookies };
|
|
591
|
+
export { type AuthCookiesData, type AuthResult, REFRESH_TOKEN_LIFETIME, SECURE_COOKIE_OPTIONS, SESSION_TOKEN_LIFETIME, SESSION_TOKEN_LIFETIME_MS, type SylphxMiddlewareConfig, TOKEN_EXPIRY_BUFFER_MS, USER_COOKIE_OPTIONS, type UserCookieData, auth, clearAuthCookies, clearAuthCookiesMiddleware, configureServer, createMatcher, createSylphxMiddleware, currentUser, currentUserId, decodeUserId, encodeUserId, getAuthCookies, getAuthorizationUrl, getCookieNames, getNamespace, getSessionToken, handleCallback, hasRefreshToken, isSessionExpired, parseUserCookie, setAuthCookies, setAuthCookiesMiddleware, signOut, sylphxMiddleware, syncAuthToCookies };
|
package/dist/nextjs/index.mjs
CHANGED
|
@@ -4,7 +4,6 @@ import { NextResponse } from "next/server";
|
|
|
4
4
|
// src/constants.ts
|
|
5
5
|
var ENV_URL = "SYLPHX_URL";
|
|
6
6
|
var ENV_SECRET_URL = "SYLPHX_SECRET_URL";
|
|
7
|
-
var ENV_SECRET_KEY = "SYLPHX_SECRET_KEY";
|
|
8
7
|
var DEFAULT_SDK_API_HOST = "api.sylphx.com";
|
|
9
8
|
var SDK_PLATFORM = typeof window !== "undefined" ? "browser" : typeof process !== "undefined" && process.versions?.node ? "node" : "unknown";
|
|
10
9
|
var TOKEN_EXPIRY_BUFFER_MS = 3e4;
|
|
@@ -34,13 +33,14 @@ var JWK_CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
|
34
33
|
var ETAG_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
35
34
|
|
|
36
35
|
// src/key-validation.ts
|
|
37
|
-
var PUBLIC_KEY_PATTERN = /^pk_(dev|stg|prod)_[a-z0-9]{12}_[a-f0-9]{32}$/;
|
|
36
|
+
var PUBLIC_KEY_PATTERN = /^pk_(dev|stg|prod|prev)(?:_[a-z0-9]{12})?_[a-f0-9]{32}$/;
|
|
38
37
|
var APP_ID_PATTERN = /^(app|pk)_(dev|stg|prod|prev)_[a-z0-9_-]+$/;
|
|
39
|
-
var SECRET_KEY_PATTERN = /^sk_(dev|stg|prod)_[a-z0-9_-]+$/;
|
|
38
|
+
var SECRET_KEY_PATTERN = /^sk_(dev|stg|prod|prev)_[a-z0-9_-]+$/;
|
|
40
39
|
var ENV_PREFIX_MAP = {
|
|
41
40
|
dev: "development",
|
|
42
41
|
stg: "staging",
|
|
43
|
-
prod: "production"
|
|
42
|
+
prod: "production",
|
|
43
|
+
prev: "preview"
|
|
44
44
|
};
|
|
45
45
|
function detectKeyIssues(key) {
|
|
46
46
|
const issues = [];
|
|
@@ -65,7 +65,7 @@ The SDK will automatically sanitize the key, but fixing the source is recommende
|
|
|
65
65
|
}
|
|
66
66
|
function createInvalidKeyError(keyType, key, envVarName) {
|
|
67
67
|
const maskedKey = key.length > 20 ? `${key.slice(0, 20)}...` : key;
|
|
68
|
-
const formatHint = keyType === "appId" ? "pk_(dev|stg|prod)_{ref}_{hex} or app_(dev|stg|prod)_[id]" : "sk_(dev|stg|prod)_{ref}_{hex}";
|
|
68
|
+
const formatHint = keyType === "appId" ? "pk_(dev|stg|prod|prev)_{ref}_{hex} or app_(dev|stg|prod|prev)_[id]" : "sk_(dev|stg|prod|prev)_{ref}_{hex}";
|
|
69
69
|
const keyTypeName = keyType === "appId" ? "App ID" : "Secret Key";
|
|
70
70
|
return `[Sylphx] Invalid ${keyTypeName} format.
|
|
71
71
|
|
|
@@ -78,7 +78,7 @@ You can find your keys in the Sylphx Console \u2192 API Keys.
|
|
|
78
78
|
Common issues:
|
|
79
79
|
\u2022 Key has uppercase characters (must be lowercase)
|
|
80
80
|
\u2022 Key has wrong prefix (App ID: pk_ or app_, Secret Key: sk_)
|
|
81
|
-
\u2022 Key has invalid environment (must be dev, stg, or
|
|
81
|
+
\u2022 Key has invalid environment (must be dev, stg, prod, or prev)
|
|
82
82
|
\u2022 Key was copied with extra whitespace`;
|
|
83
83
|
}
|
|
84
84
|
function extractEnvironment(key) {
|
|
@@ -125,7 +125,7 @@ function validateKeyForType(key, keyType, pattern, envVarName) {
|
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
function validatePublicKey(key) {
|
|
128
|
-
return validateKeyForType(key, "publicKey", PUBLIC_KEY_PATTERN, "
|
|
128
|
+
return validateKeyForType(key, "publicKey", PUBLIC_KEY_PATTERN, "publishable credential");
|
|
129
129
|
}
|
|
130
130
|
function validateAppId(key) {
|
|
131
131
|
return validateKeyForType(key, "appId", APP_ID_PATTERN, "NEXT_PUBLIC_SYLPHX_APP_ID");
|
|
@@ -141,7 +141,7 @@ function validateAndSanitizeAppId(key) {
|
|
|
141
141
|
return result.sanitizedKey;
|
|
142
142
|
}
|
|
143
143
|
function validateSecretKey(key) {
|
|
144
|
-
return validateKeyForType(key, "secret", SECRET_KEY_PATTERN, "
|
|
144
|
+
return validateKeyForType(key, "secret", SECRET_KEY_PATTERN, "secret credential");
|
|
145
145
|
}
|
|
146
146
|
function validateAndSanitizeSecretKey(key) {
|
|
147
147
|
const result = validateSecretKey(key);
|
|
@@ -176,7 +176,7 @@ function detectEnvironment(key) {
|
|
|
176
176
|
}
|
|
177
177
|
function getCookieNamespace(secretKey) {
|
|
178
178
|
const env = detectEnvironment(secretKey);
|
|
179
|
-
const shortEnv = env === "development" ? "dev" : env === "staging" ? "stg" : "prod";
|
|
179
|
+
const shortEnv = env === "development" ? "dev" : env === "staging" ? "stg" : env === "preview" ? "prev" : "prod";
|
|
180
180
|
return `sylphx_${shortEnv}`;
|
|
181
181
|
}
|
|
182
182
|
|
|
@@ -302,7 +302,7 @@ function parseUserCookie(value) {
|
|
|
302
302
|
// src/connection-url.ts
|
|
303
303
|
var SYLPHX_PROTOCOL = "sylphx:";
|
|
304
304
|
var DEFAULT_VERSION = "v1";
|
|
305
|
-
var CREDENTIAL_REGEX = /^(pk|sk)_(dev|stg|prod|prev)_[a-f0-9]{32,64}$/;
|
|
305
|
+
var CREDENTIAL_REGEX = /^(pk|sk)_(dev|stg|prod|prev)(?:_[a-z0-9]{12})?_[a-f0-9]{32,64}$/;
|
|
306
306
|
var VERSION_REGEX = /^v[0-9]+$/;
|
|
307
307
|
var SLUG_REGEX = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
|
|
308
308
|
var InvalidConnectionUrlError = class _InvalidConnectionUrlError extends Error {
|
|
@@ -319,7 +319,7 @@ function fail(reason) {
|
|
|
319
319
|
function parseCredential(raw) {
|
|
320
320
|
const match = CREDENTIAL_REGEX.exec(raw);
|
|
321
321
|
if (!match) {
|
|
322
|
-
fail(`credential must match (pk|sk)_(dev|stg|prod|prev)_
|
|
322
|
+
fail(`credential must match (pk|sk)_(dev|stg|prod|prev)(_{ref})?_{hex}, got "${raw}"`);
|
|
323
323
|
}
|
|
324
324
|
return {
|
|
325
325
|
credentialType: match[1],
|
|
@@ -414,12 +414,6 @@ function secretKeyFromConnectionUrl(value) {
|
|
|
414
414
|
if (!parsed || parsed.credentialType !== "sk") return null;
|
|
415
415
|
return parsed.credential;
|
|
416
416
|
}
|
|
417
|
-
function platformUrlFromLegacyKey(secretKey) {
|
|
418
|
-
if (!secretKey) return null;
|
|
419
|
-
const parts = secretKey.trim().toLowerCase().split("_");
|
|
420
|
-
const embeddedRef = parts.length === 4 ? parts[2] : null;
|
|
421
|
-
return embeddedRef ? `https://${embeddedRef}.${DEFAULT_SDK_API_HOST}` : null;
|
|
422
|
-
}
|
|
423
417
|
function resolveNextjsPlatformUrl(options) {
|
|
424
418
|
if (options.explicitPlatformUrl) return normalizePlatformUrl(options.explicitPlatformUrl);
|
|
425
419
|
const fromExplicitSecretUrl = platformUrlFromConnectionUrl(options.secretUrl);
|
|
@@ -430,8 +424,6 @@ function resolveNextjsPlatformUrl(options) {
|
|
|
430
424
|
if (fromConnectionUrl) return fromConnectionUrl;
|
|
431
425
|
const fromBaasOverride = process.env.SYLPHX_BAAS_URL ?? process.env.SYLPHX_RUNTIME_URL;
|
|
432
426
|
if (fromBaasOverride) return normalizePlatformUrl(fromBaasOverride);
|
|
433
|
-
const fromLegacyKey = platformUrlFromLegacyKey(options.secretKey);
|
|
434
|
-
if (fromLegacyKey) return fromLegacyKey;
|
|
435
427
|
throw new SylphxRoutingConfigurationError(
|
|
436
428
|
'[Sylphx] BaaS routing target is required for @sylphx/sdk/nextjs. Set SYLPHX_SECRET_URL="sylphx://sk_<env>_<hex>@<tenant>.api.sylphx.com" or SYLPHX_URL="sylphx://<credential>@<tenant>.api.sylphx.com" or pass platformUrl explicitly. New-format sk_* credentials do not carry routing material.'
|
|
437
429
|
);
|
|
@@ -444,7 +436,7 @@ function resolveNextjsSecretKey(options) {
|
|
|
444
436
|
if (fromSecretUrl) return fromSecretUrl;
|
|
445
437
|
const fromGenericUrl = secretKeyFromConnectionUrl(process.env[ENV_URL]);
|
|
446
438
|
if (fromGenericUrl) return fromGenericUrl;
|
|
447
|
-
return
|
|
439
|
+
return null;
|
|
448
440
|
}
|
|
449
441
|
|
|
450
442
|
// src/nextjs/middleware.ts
|
|
@@ -457,7 +449,8 @@ function decodeJwtPayload(token) {
|
|
|
457
449
|
if (parts.length !== 3) return null;
|
|
458
450
|
const payload = parts[1];
|
|
459
451
|
const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
460
|
-
const
|
|
452
|
+
const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
|
|
453
|
+
const jsonPayload = atob(padded);
|
|
461
454
|
return JSON.parse(jsonPayload);
|
|
462
455
|
} catch {
|
|
463
456
|
return null;
|
|
@@ -571,6 +564,99 @@ function handleToken(request, ctx) {
|
|
|
571
564
|
ctx.log("Token returned");
|
|
572
565
|
return NextResponse.json({ accessToken: sessionToken });
|
|
573
566
|
}
|
|
567
|
+
function resolveOrgScopedTokenExpiresIn(data) {
|
|
568
|
+
if (typeof data.expiresIn === "number") return data.expiresIn;
|
|
569
|
+
if (typeof data.expires_in === "number") return data.expires_in;
|
|
570
|
+
return SESSION_TOKEN_LIFETIME;
|
|
571
|
+
}
|
|
572
|
+
function resolveOrgScopedTokenType(data) {
|
|
573
|
+
if (data.tokenType) return data.tokenType;
|
|
574
|
+
if (data.token_type) return data.token_type;
|
|
575
|
+
return "Bearer";
|
|
576
|
+
}
|
|
577
|
+
function parseUserCookie2(value) {
|
|
578
|
+
if (!value) return null;
|
|
579
|
+
try {
|
|
580
|
+
return JSON.parse(value);
|
|
581
|
+
} catch {
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
async function handleSwitchOrg(request, ctx) {
|
|
586
|
+
ctx.log("Switch org request");
|
|
587
|
+
if (request.method !== "POST") {
|
|
588
|
+
return NextResponse.json({ error: "Method not allowed" }, { status: 405 });
|
|
589
|
+
}
|
|
590
|
+
const sessionToken = request.cookies.get(ctx.cookieNames.SESSION)?.value;
|
|
591
|
+
if (!sessionToken || isTokenExpired(sessionToken)) {
|
|
592
|
+
return NextResponse.json({ error: "Not authenticated", accessToken: null }, { status: 401 });
|
|
593
|
+
}
|
|
594
|
+
let orgId = null;
|
|
595
|
+
try {
|
|
596
|
+
const body = await request.json();
|
|
597
|
+
orgId = typeof body.orgId === "string" && body.orgId.trim() ? body.orgId.trim() : null;
|
|
598
|
+
} catch {
|
|
599
|
+
return NextResponse.json({ error: "Invalid request body" }, { status: 400 });
|
|
600
|
+
}
|
|
601
|
+
if (!orgId) {
|
|
602
|
+
return NextResponse.json({ error: "orgId is required" }, { status: 400 });
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
const res = await fetch(`${ctx.platformUrl}/v1/auth/switch-org`, {
|
|
606
|
+
method: "POST",
|
|
607
|
+
headers: {
|
|
608
|
+
"Content-Type": "application/json",
|
|
609
|
+
"x-app-secret": ctx.secretKey,
|
|
610
|
+
Authorization: `Bearer ${sessionToken}`
|
|
611
|
+
},
|
|
612
|
+
body: JSON.stringify({ orgId })
|
|
613
|
+
});
|
|
614
|
+
const data = await res.json().catch(() => ({}));
|
|
615
|
+
if (!res.ok) {
|
|
616
|
+
return NextResponse.json(
|
|
617
|
+
{ error: data.error || data.message || "switch_org_failed" },
|
|
618
|
+
{ status: res.status }
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
const accessToken = data.accessToken ?? data.access_token;
|
|
622
|
+
if (!accessToken) {
|
|
623
|
+
return NextResponse.json({ error: "invalid_response" }, { status: 502 });
|
|
624
|
+
}
|
|
625
|
+
const expiresIn = resolveOrgScopedTokenExpiresIn(data);
|
|
626
|
+
const expiresAt = Date.now() + expiresIn * 1e3;
|
|
627
|
+
const response = NextResponse.json({
|
|
628
|
+
accessToken,
|
|
629
|
+
token: accessToken,
|
|
630
|
+
expiresIn,
|
|
631
|
+
tokenType: resolveOrgScopedTokenType(data),
|
|
632
|
+
user: data.user ?? null
|
|
633
|
+
});
|
|
634
|
+
response.cookies.set(ctx.cookieNames.SESSION, accessToken, {
|
|
635
|
+
...SECURE_COOKIE_OPTIONS,
|
|
636
|
+
maxAge: expiresIn
|
|
637
|
+
});
|
|
638
|
+
const existingUser = parseUserCookie2(request.cookies.get(ctx.cookieNames.USER)?.value);
|
|
639
|
+
const user = data.user ?? existingUser?.user;
|
|
640
|
+
if (user) {
|
|
641
|
+
response.cookies.set(
|
|
642
|
+
ctx.cookieNames.USER,
|
|
643
|
+
JSON.stringify({
|
|
644
|
+
user,
|
|
645
|
+
expiresAt
|
|
646
|
+
}),
|
|
647
|
+
{
|
|
648
|
+
...USER_COOKIE_OPTIONS,
|
|
649
|
+
maxAge: expiresIn
|
|
650
|
+
}
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
ctx.log("Switch org success", { orgId });
|
|
654
|
+
return response;
|
|
655
|
+
} catch (err) {
|
|
656
|
+
ctx.log("Switch org error", err);
|
|
657
|
+
return NextResponse.json({ error: "internal_error" }, { status: 500 });
|
|
658
|
+
}
|
|
659
|
+
}
|
|
574
660
|
async function refreshTokens(refreshToken, ctx) {
|
|
575
661
|
ctx.log("Refreshing tokens");
|
|
576
662
|
try {
|
|
@@ -609,7 +695,7 @@ function createSylphxMiddleware(userConfig = {}) {
|
|
|
609
695
|
});
|
|
610
696
|
if (!rawSecretKey) {
|
|
611
697
|
throw new Error(
|
|
612
|
-
"[Sylphx] Server connection URL is required.\nEither pass secretUrl in config or set SYLPHX_SECRET_URL env var
|
|
698
|
+
"[Sylphx] Server connection URL is required.\nEither pass secretUrl in config or set SYLPHX_SECRET_URL env var."
|
|
613
699
|
);
|
|
614
700
|
}
|
|
615
701
|
secretKey = validateAndSanitizeSecretKey(rawSecretKey);
|
|
@@ -636,6 +722,8 @@ function createSylphxMiddleware(userConfig = {}) {
|
|
|
636
722
|
afterSignInUrl: userConfig.afterSignInUrl ?? "/dashboard",
|
|
637
723
|
authPrefix: userConfig.authPrefix ?? "/auth",
|
|
638
724
|
debug: userConfig.debug ?? false,
|
|
725
|
+
orgRequired: userConfig.orgRequired ?? false,
|
|
726
|
+
orgSelectionUrl: userConfig.orgSelectionUrl ?? "/select-organization",
|
|
639
727
|
onResponse: userConfig.onResponse
|
|
640
728
|
};
|
|
641
729
|
const publicRoutes = [
|
|
@@ -684,20 +772,26 @@ function createSylphxMiddleware(userConfig = {}) {
|
|
|
684
772
|
if (pathname === `${config.authPrefix}/token`) {
|
|
685
773
|
return handleToken(request, ctx);
|
|
686
774
|
}
|
|
775
|
+
if (pathname === `${config.authPrefix}/switch-org`) {
|
|
776
|
+
return handleSwitchOrg(request, ctx);
|
|
777
|
+
}
|
|
687
778
|
const sessionToken = request.cookies.get(cookieNames.SESSION)?.value;
|
|
688
779
|
const refreshToken = request.cookies.get(cookieNames.REFRESH)?.value;
|
|
689
780
|
const hasValidSession = sessionToken && !isTokenExpired(sessionToken);
|
|
690
781
|
const response = NextResponse.next();
|
|
691
782
|
let isAuthenticated = hasValidSession;
|
|
783
|
+
let activeSessionToken = hasValidSession ? sessionToken : null;
|
|
692
784
|
if (!hasValidSession && refreshToken) {
|
|
693
785
|
log("Session expired, refreshing");
|
|
694
786
|
const tokens = await refreshTokens(refreshToken, ctx);
|
|
695
787
|
if (tokens) {
|
|
696
788
|
setAuthCookiesMiddleware(response, namespace, tokens);
|
|
697
789
|
isAuthenticated = true;
|
|
790
|
+
activeSessionToken = tokens.accessToken;
|
|
698
791
|
} else {
|
|
699
792
|
clearAuthCookiesMiddleware(response, namespace);
|
|
700
793
|
isAuthenticated = false;
|
|
794
|
+
activeSessionToken = null;
|
|
701
795
|
}
|
|
702
796
|
}
|
|
703
797
|
const isPublic = matchesAny(pathname, publicRoutes);
|
|
@@ -711,12 +805,22 @@ function createSylphxMiddleware(userConfig = {}) {
|
|
|
711
805
|
log("Redirecting from sign-in to dashboard");
|
|
712
806
|
return NextResponse.redirect(new URL(config.afterSignInUrl, request.url));
|
|
713
807
|
}
|
|
808
|
+
if (config.orgRequired && !isPublic && isAuthenticated && activeSessionToken && !matchesPattern(pathname, config.orgSelectionUrl)) {
|
|
809
|
+
const payload = decodeJwtPayload(activeSessionToken);
|
|
810
|
+
if (!payload?.org_id) {
|
|
811
|
+
log("Redirecting to organization selection");
|
|
812
|
+
const url = new URL(config.orgSelectionUrl, request.url);
|
|
813
|
+
url.searchParams.set("redirect_to", pathname);
|
|
814
|
+
return NextResponse.redirect(url);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
714
817
|
if (config.onResponse) {
|
|
715
818
|
await config.onResponse(response, request);
|
|
716
819
|
}
|
|
717
820
|
return response;
|
|
718
821
|
};
|
|
719
822
|
}
|
|
823
|
+
var sylphxMiddleware = createSylphxMiddleware;
|
|
720
824
|
function createMatcher() {
|
|
721
825
|
return {
|
|
722
826
|
matcher: ["/((?!_next|monitoring|.*\\..*).*)", "/"]
|
|
@@ -2187,6 +2291,7 @@ export {
|
|
|
2187
2291
|
setAuthCookies,
|
|
2188
2292
|
setAuthCookiesMiddleware,
|
|
2189
2293
|
signOut,
|
|
2294
|
+
sylphxMiddleware,
|
|
2190
2295
|
syncAuthToCookies
|
|
2191
2296
|
};
|
|
2192
2297
|
//# sourceMappingURL=index.mjs.map
|