@insforge/sdk 1.4.3 → 1.4.5-beta.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/README.md +124 -143
- package/SDK-REFERENCE.md +146 -168
- package/dist/{client-B6eZHolm.d.mts → client-BZyLCjO1.d.mts} +44 -120
- package/dist/{client-DUmOm_3W.d.ts → client-Dh7GOydb.d.ts} +44 -120
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +556 -423
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +559 -423
- package/dist/index.mjs.map +1 -1
- package/dist/ssr/middleware.js +71 -52
- package/dist/ssr/middleware.js.map +1 -1
- package/dist/ssr/middleware.mjs +71 -52
- package/dist/ssr/middleware.mjs.map +1 -1
- package/dist/ssr.d.mts +1 -1
- package/dist/ssr.d.ts +1 -1
- package/dist/ssr.js +651 -539
- package/dist/ssr.js.map +1 -1
- package/dist/ssr.mjs +655 -540
- package/dist/ssr.mjs.map +1 -1
- package/package.json +12 -5
package/dist/ssr/middleware.js
CHANGED
|
@@ -33,18 +33,19 @@ module.exports = __toCommonJS(middleware_exports);
|
|
|
33
33
|
// src/lib/jwt.ts
|
|
34
34
|
function decodeBase64Url(input) {
|
|
35
35
|
const normalized = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
36
|
-
const padded = normalized.padEnd(
|
|
37
|
-
normalized.length + (4 - normalized.length % 4) % 4,
|
|
38
|
-
"="
|
|
39
|
-
);
|
|
36
|
+
const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
|
|
40
37
|
const binary = atob(padded);
|
|
41
38
|
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
42
39
|
return new TextDecoder().decode(bytes);
|
|
43
40
|
}
|
|
44
41
|
function getJwtExpiration(token) {
|
|
45
|
-
if (!token)
|
|
42
|
+
if (!token) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
46
45
|
const [, payload] = token.split(".");
|
|
47
|
-
if (!payload)
|
|
46
|
+
if (!payload) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
48
49
|
try {
|
|
49
50
|
const parsed = JSON.parse(decodeBase64Url(payload));
|
|
50
51
|
if (typeof parsed.exp !== "number" || !Number.isFinite(parsed.exp)) {
|
|
@@ -56,9 +57,13 @@ function getJwtExpiration(token) {
|
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
function isJwtExpiredOrExpiring(token, leewaySeconds = 60) {
|
|
59
|
-
if (!token)
|
|
60
|
+
if (!token) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
60
63
|
const expires = getJwtExpiration(token);
|
|
61
|
-
if (!expires)
|
|
64
|
+
if (!expires) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
62
67
|
return expires.getTime() <= Date.now() + leewaySeconds * 1e3;
|
|
63
68
|
}
|
|
64
69
|
|
|
@@ -73,18 +78,28 @@ function getRefreshTokenCookieName(names) {
|
|
|
73
78
|
return names?.refreshToken ?? DEFAULT_REFRESH_TOKEN_COOKIE;
|
|
74
79
|
}
|
|
75
80
|
function getCookieValue(cookies, name) {
|
|
76
|
-
if (!cookies)
|
|
81
|
+
if (!cookies) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
77
84
|
const value = cookies.get(name);
|
|
78
|
-
if (typeof value === "string")
|
|
79
|
-
|
|
85
|
+
if (typeof value === "string") {
|
|
86
|
+
return value || null;
|
|
87
|
+
}
|
|
88
|
+
if (value && typeof value.value === "string") {
|
|
89
|
+
return value.value || null;
|
|
90
|
+
}
|
|
80
91
|
return null;
|
|
81
92
|
}
|
|
82
93
|
function getCookieValueFromHeader(cookieHeader, name) {
|
|
83
|
-
if (!cookieHeader)
|
|
94
|
+
if (!cookieHeader) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
84
97
|
const parts = cookieHeader.split(";");
|
|
85
98
|
for (const part of parts) {
|
|
86
99
|
const [rawName, ...rawValue] = part.trim().split("=");
|
|
87
|
-
if (rawName !== name)
|
|
100
|
+
if (rawName !== name) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
88
103
|
try {
|
|
89
104
|
return decodeURIComponent(rawValue.join("="));
|
|
90
105
|
} catch {
|
|
@@ -127,11 +142,15 @@ function expiredCookieOptions(overrides) {
|
|
|
127
142
|
};
|
|
128
143
|
}
|
|
129
144
|
function setCookie(cookies, name, value, options) {
|
|
130
|
-
if (!cookies?.set)
|
|
145
|
+
if (!cookies?.set) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
131
148
|
cookies.set(name, value, options);
|
|
132
149
|
}
|
|
133
150
|
function deleteCookie(cookies, name, options) {
|
|
134
|
-
if (!cookies)
|
|
151
|
+
if (!cookies) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
135
154
|
if (cookies.set) {
|
|
136
155
|
cookies.set(name, "", expiredCookieOptions(options));
|
|
137
156
|
return;
|
|
@@ -140,12 +159,24 @@ function deleteCookie(cookies, name, options) {
|
|
|
140
159
|
}
|
|
141
160
|
function serializeCookie(name, value, options = {}) {
|
|
142
161
|
const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
|
|
143
|
-
if (options.maxAge !== void 0)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (options.
|
|
147
|
-
|
|
148
|
-
|
|
162
|
+
if (options.maxAge !== void 0) {
|
|
163
|
+
parts.push(`Max-Age=${options.maxAge}`);
|
|
164
|
+
}
|
|
165
|
+
if (options.domain) {
|
|
166
|
+
parts.push(`Domain=${options.domain}`);
|
|
167
|
+
}
|
|
168
|
+
if (options.path) {
|
|
169
|
+
parts.push(`Path=${options.path}`);
|
|
170
|
+
}
|
|
171
|
+
if (options.expires) {
|
|
172
|
+
parts.push(`Expires=${options.expires.toUTCString()}`);
|
|
173
|
+
}
|
|
174
|
+
if (options.httpOnly) {
|
|
175
|
+
parts.push("HttpOnly");
|
|
176
|
+
}
|
|
177
|
+
if (options.secure) {
|
|
178
|
+
parts.push("Secure");
|
|
179
|
+
}
|
|
149
180
|
if (options.sameSite) {
|
|
150
181
|
const sameSite = options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1);
|
|
151
182
|
parts.push(`SameSite=${sameSite}`);
|
|
@@ -158,20 +189,14 @@ function appendSetCookie(headers, name, value, options) {
|
|
|
158
189
|
function setAuthCookies(cookies, tokens, settings = {}) {
|
|
159
190
|
const accessName = getAccessTokenCookieName(settings.names);
|
|
160
191
|
const refreshName = getRefreshTokenCookieName(settings.names);
|
|
161
|
-
const accessOptions = accessTokenCookieOptions(
|
|
162
|
-
tokens.accessToken,
|
|
163
|
-
settings.options?.accessToken
|
|
164
|
-
);
|
|
192
|
+
const accessOptions = accessTokenCookieOptions(tokens.accessToken, settings.options?.accessToken);
|
|
165
193
|
setCookie(cookies, accessName, tokens.accessToken, accessOptions);
|
|
166
194
|
if (tokens.refreshToken) {
|
|
167
195
|
setCookie(
|
|
168
196
|
cookies,
|
|
169
197
|
refreshName,
|
|
170
198
|
tokens.refreshToken,
|
|
171
|
-
refreshTokenCookieOptions(
|
|
172
|
-
tokens.refreshToken,
|
|
173
|
-
settings.options?.refreshToken
|
|
174
|
-
)
|
|
199
|
+
refreshTokenCookieOptions(tokens.refreshToken, settings.options?.refreshToken)
|
|
175
200
|
);
|
|
176
201
|
}
|
|
177
202
|
}
|
|
@@ -197,10 +222,7 @@ function setAuthCookieHeaders(headers, tokens, settings = {}) {
|
|
|
197
222
|
headers,
|
|
198
223
|
refreshName,
|
|
199
224
|
tokens.refreshToken,
|
|
200
|
-
refreshTokenCookieOptions(
|
|
201
|
-
tokens.refreshToken,
|
|
202
|
-
settings.options?.refreshToken
|
|
203
|
-
)
|
|
225
|
+
refreshTokenCookieOptions(tokens.refreshToken, settings.options?.refreshToken)
|
|
204
226
|
);
|
|
205
227
|
}
|
|
206
228
|
}
|
|
@@ -248,7 +270,9 @@ function jsonResponse(body, init = {}, headers = new Headers(init.headers)) {
|
|
|
248
270
|
});
|
|
249
271
|
}
|
|
250
272
|
function normalizeError(error) {
|
|
251
|
-
if (error instanceof InsForgeError)
|
|
273
|
+
if (error instanceof InsForgeError) {
|
|
274
|
+
return error;
|
|
275
|
+
}
|
|
252
276
|
if (error && typeof error === "object") {
|
|
253
277
|
const body = error;
|
|
254
278
|
return new InsForgeError(
|
|
@@ -265,18 +289,21 @@ function normalizeError(error) {
|
|
|
265
289
|
}
|
|
266
290
|
async function readJson(response) {
|
|
267
291
|
const contentType = response.headers.get("content-type");
|
|
268
|
-
if (!contentType?.includes("json"))
|
|
292
|
+
if (!contentType?.includes("json")) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
269
295
|
return response.json();
|
|
270
296
|
}
|
|
271
297
|
function readRefreshToken(options) {
|
|
272
|
-
if (options.refreshToken)
|
|
298
|
+
if (options.refreshToken) {
|
|
299
|
+
return options.refreshToken;
|
|
300
|
+
}
|
|
273
301
|
const refreshCookieName = getRefreshTokenCookieName(options.names);
|
|
274
302
|
const cookieValue = getCookieValue(options.cookies, refreshCookieName);
|
|
275
|
-
if (cookieValue)
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
);
|
|
303
|
+
if (cookieValue) {
|
|
304
|
+
return cookieValue;
|
|
305
|
+
}
|
|
306
|
+
return getCookieValueFromHeader(options.request?.headers.get("cookie"), refreshCookieName);
|
|
280
307
|
}
|
|
281
308
|
async function refreshAuth(options = {}) {
|
|
282
309
|
const headers = new Headers();
|
|
@@ -317,9 +344,7 @@ async function refreshAuth(options = {}) {
|
|
|
317
344
|
}
|
|
318
345
|
const fetchImpl = options.fetch ?? (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
319
346
|
if (!fetchImpl) {
|
|
320
|
-
throw new Error(
|
|
321
|
-
"Fetch is not available. Please provide a fetch implementation."
|
|
322
|
-
);
|
|
347
|
+
throw new Error("Fetch is not available. Please provide a fetch implementation.");
|
|
323
348
|
}
|
|
324
349
|
const requestHeaders = new Headers(options.headers);
|
|
325
350
|
requestHeaders.set("Authorization", `Bearer ${anonKey}`);
|
|
@@ -397,10 +422,7 @@ async function refreshAuth(options = {}) {
|
|
|
397
422
|
async function updateSession(options) {
|
|
398
423
|
const accessCookieName = getAccessTokenCookieName(options.names);
|
|
399
424
|
const refreshCookieName = getRefreshTokenCookieName(options.names);
|
|
400
|
-
const accessToken = getCookieValue(
|
|
401
|
-
options.requestCookies,
|
|
402
|
-
accessCookieName
|
|
403
|
-
);
|
|
425
|
+
const accessToken = getCookieValue(options.requestCookies, accessCookieName);
|
|
404
426
|
if (accessToken && !isJwtExpiredOrExpiring(accessToken, options.refreshLeewaySeconds)) {
|
|
405
427
|
return {
|
|
406
428
|
refreshed: false,
|
|
@@ -408,10 +430,7 @@ async function updateSession(options) {
|
|
|
408
430
|
error: null
|
|
409
431
|
};
|
|
410
432
|
}
|
|
411
|
-
const refreshToken = getCookieValue(
|
|
412
|
-
options.requestCookies,
|
|
413
|
-
refreshCookieName
|
|
414
|
-
);
|
|
433
|
+
const refreshToken = getCookieValue(options.requestCookies, refreshCookieName);
|
|
415
434
|
if (!refreshToken) {
|
|
416
435
|
if (accessToken) {
|
|
417
436
|
clearAuthCookies(options.requestCookies, options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ssr/middleware.ts","../../src/lib/jwt.ts","../../src/ssr/cookies.ts","../../src/types.ts","../../src/ssr/refresh.ts","../../src/ssr/update-session.ts"],"sourcesContent":["export {\n updateSession,\n type UpdateSessionOptions,\n type UpdateSessionResult,\n} from './update-session';\nexport {\n DEFAULT_ACCESS_TOKEN_COOKIE,\n DEFAULT_REFRESH_TOKEN_COOKIE,\n clearAuthCookies,\n getAccessTokenCookieName,\n getRefreshTokenCookieName,\n setAuthCookies,\n type AuthCookieNames,\n type AuthCookieOptions,\n type AuthCookieSettings,\n type CookieOptions,\n type CookieReader,\n type CookieStore,\n type CookieWriter,\n} from './cookies';\n","function decodeBase64Url(input: string): string {\n const normalized = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = normalized.padEnd(\n normalized.length + ((4 - (normalized.length % 4)) % 4),\n '=',\n );\n\n const binary = atob(padded);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return new TextDecoder().decode(bytes);\n}\n\nexport function getJwtExpiration(token: string | null | undefined): Date | null {\n if (!token) return null;\n\n const [, payload] = token.split('.');\n if (!payload) return null;\n\n try {\n const parsed = JSON.parse(decodeBase64Url(payload)) as { exp?: unknown };\n if (typeof parsed.exp !== 'number' || !Number.isFinite(parsed.exp)) {\n return null;\n }\n return new Date(parsed.exp * 1000);\n } catch {\n return null;\n }\n}\n\nexport function isJwtExpiredOrExpiring(\n token: string | null | undefined,\n leewaySeconds = 60,\n): boolean {\n if (!token) return false;\n const expires = getJwtExpiration(token);\n if (!expires) return true;\n\n return expires.getTime() <= Date.now() + leewaySeconds * 1000;\n}\n","import { getJwtExpiration } from '../lib/jwt';\n\nexport const DEFAULT_ACCESS_TOKEN_COOKIE = 'insforge_access_token';\nexport const DEFAULT_REFRESH_TOKEN_COOKIE = 'insforge_refresh_token';\n\nexport interface AuthCookieNames {\n accessToken?: string;\n refreshToken?: string;\n}\n\nexport interface CookieOptions {\n domain?: string;\n path?: string;\n expires?: Date;\n maxAge?: number;\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: 'lax' | 'strict' | 'none';\n}\n\nexport interface AuthCookieOptions {\n accessToken?: CookieOptions;\n refreshToken?: CookieOptions;\n}\n\nexport type CookieStoreValue =\n | string\n | { value?: string | null }\n | undefined\n | null;\n\nexport interface CookieReader {\n get(name: string): CookieStoreValue;\n}\n\nexport interface CookieWriter {\n set?(name: string, value: string, options?: CookieOptions): unknown;\n set?(options: { name: string; value: string } & CookieOptions): unknown;\n delete?(name: string): unknown;\n delete?(options: { name: string } & CookieOptions): unknown;\n}\n\nexport interface CookieStore extends CookieReader, CookieWriter {}\n\nexport interface AuthCookieSettings {\n names?: AuthCookieNames;\n options?: AuthCookieOptions;\n}\n\nconst EXPIRED_DATE = new Date(0);\n\nexport function getAccessTokenCookieName(names?: AuthCookieNames): string {\n return names?.accessToken ?? DEFAULT_ACCESS_TOKEN_COOKIE;\n}\n\nexport function getRefreshTokenCookieName(names?: AuthCookieNames): string {\n return names?.refreshToken ?? DEFAULT_REFRESH_TOKEN_COOKIE;\n}\n\nexport function getCookieValue(\n cookies: CookieReader | undefined,\n name: string,\n): string | null {\n if (!cookies) return null;\n\n const value = cookies.get(name);\n if (typeof value === 'string') return value || null;\n if (value && typeof value.value === 'string') return value.value || null;\n return null;\n}\n\nexport function getCookieValueFromHeader(\n cookieHeader: string | null | undefined,\n name: string,\n): string | null {\n if (!cookieHeader) return null;\n\n const parts = cookieHeader.split(';');\n for (const part of parts) {\n const [rawName, ...rawValue] = part.trim().split('=');\n if (rawName !== name) continue;\n try {\n return decodeURIComponent(rawValue.join('='));\n } catch {\n return rawValue.join('=');\n }\n }\n return null;\n}\n\nexport function getBrowserCookie(name: string): string | null {\n if (typeof document === 'undefined') return null;\n return getCookieValueFromHeader(document.cookie, name);\n}\n\nfunction defaultCookieOptions(): CookieOptions {\n const secure =\n typeof process !== 'undefined'\n ? process.env.NODE_ENV === 'production'\n : typeof location !== 'undefined' && location.protocol === 'https:';\n\n return {\n path: '/',\n sameSite: 'lax',\n secure,\n };\n}\n\nexport function accessTokenCookieOptions(\n token: string,\n overrides?: CookieOptions,\n): CookieOptions {\n return {\n ...defaultCookieOptions(),\n httpOnly: false,\n expires: getJwtExpiration(token) ?? undefined,\n ...overrides,\n };\n}\n\nexport function refreshTokenCookieOptions(\n token: string,\n overrides?: CookieOptions,\n): CookieOptions {\n return {\n ...defaultCookieOptions(),\n httpOnly: true,\n expires: getJwtExpiration(token) ?? undefined,\n ...overrides,\n };\n}\n\nexport function expiredCookieOptions(overrides?: CookieOptions): CookieOptions {\n const { expires: _expires, maxAge: _maxAge, ...safeOverrides } = overrides ?? {};\n return {\n ...defaultCookieOptions(),\n ...safeOverrides,\n expires: EXPIRED_DATE,\n maxAge: 0,\n };\n}\n\nexport function setCookie(\n cookies: CookieWriter | undefined,\n name: string,\n value: string,\n options?: CookieOptions,\n): void {\n if (!cookies?.set) return;\n cookies.set(name, value, options);\n}\n\nexport function deleteCookie(\n cookies: CookieWriter | undefined,\n name: string,\n options?: CookieOptions,\n): void {\n if (!cookies) return;\n if (cookies.set) {\n cookies.set(name, '', expiredCookieOptions(options));\n return;\n }\n cookies.delete?.(name);\n}\n\nexport function serializeCookie(\n name: string,\n value: string,\n options: CookieOptions = {},\n): string {\n const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];\n\n if (options.maxAge !== undefined) parts.push(`Max-Age=${options.maxAge}`);\n if (options.domain) parts.push(`Domain=${options.domain}`);\n if (options.path) parts.push(`Path=${options.path}`);\n if (options.expires) parts.push(`Expires=${options.expires.toUTCString()}`);\n if (options.httpOnly) parts.push('HttpOnly');\n if (options.secure) parts.push('Secure');\n if (options.sameSite) {\n const sameSite =\n options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1);\n parts.push(`SameSite=${sameSite}`);\n }\n\n return parts.join('; ');\n}\n\nexport function appendSetCookie(\n headers: Headers,\n name: string,\n value: string,\n options?: CookieOptions,\n): void {\n headers.append('Set-Cookie', serializeCookie(name, value, options));\n}\n\nexport function setAuthCookies(\n cookies: CookieWriter | undefined,\n tokens: {\n accessToken: string;\n refreshToken?: string | null;\n },\n settings: AuthCookieSettings = {},\n): void {\n const accessName = getAccessTokenCookieName(settings.names);\n const refreshName = getRefreshTokenCookieName(settings.names);\n const accessOptions = accessTokenCookieOptions(\n tokens.accessToken,\n settings.options?.accessToken,\n );\n\n setCookie(cookies, accessName, tokens.accessToken, accessOptions);\n if (tokens.refreshToken) {\n setCookie(\n cookies,\n refreshName,\n tokens.refreshToken,\n refreshTokenCookieOptions(\n tokens.refreshToken,\n settings.options?.refreshToken,\n ),\n );\n }\n}\n\nexport function clearAuthCookies(\n cookies: CookieWriter | undefined,\n settings: AuthCookieSettings = {},\n): void {\n const accessName = getAccessTokenCookieName(settings.names);\n const refreshName = getRefreshTokenCookieName(settings.names);\n const accessOptions = expiredCookieOptions(settings.options?.accessToken);\n const refreshOptions = expiredCookieOptions(settings.options?.refreshToken);\n\n deleteCookie(cookies, accessName, accessOptions);\n deleteCookie(cookies, refreshName, refreshOptions);\n}\n\nexport function setAuthCookieHeaders(\n headers: Headers,\n tokens: {\n accessToken: string;\n refreshToken?: string | null;\n },\n settings: AuthCookieSettings = {},\n): void {\n const accessName = getAccessTokenCookieName(settings.names);\n const refreshName = getRefreshTokenCookieName(settings.names);\n\n appendSetCookie(\n headers,\n accessName,\n tokens.accessToken,\n accessTokenCookieOptions(tokens.accessToken, settings.options?.accessToken),\n );\n if (tokens.refreshToken) {\n appendSetCookie(\n headers,\n refreshName,\n tokens.refreshToken,\n refreshTokenCookieOptions(\n tokens.refreshToken,\n settings.options?.refreshToken,\n ),\n );\n }\n}\n\nexport function clearAuthCookieHeaders(\n headers: Headers,\n settings: AuthCookieSettings = {},\n): void {\n appendSetCookie(\n headers,\n getAccessTokenCookieName(settings.names),\n '',\n expiredCookieOptions(settings.options?.accessToken),\n );\n appendSetCookie(\n headers,\n getRefreshTokenCookieName(settings.names),\n '',\n expiredCookieOptions(settings.options?.refreshToken),\n );\n}\n","/**\n * InsForge SDK Types - only SDK-specific types here\n * Use @insforge/shared-schemas directly for API types\n */\n\nimport type { ErrorCode, UserSchema } from '@insforge/shared-schemas';\n\nexport type InsForgeErrorCode = ErrorCode | (string & {});\n\nexport interface InsForgeConfig {\n /**\n * The base URL of the InsForge backend API\n * @default \"http://localhost:7130\"\n */\n baseUrl?: string;\n\n /**\n * Anonymous API key (optional)\n * Used for public/unauthenticated requests when no user token is set\n */\n anonKey?: string;\n\n /**\n * Static access token (optional)\n * Seeds the client with a fixed bearer token used for all authenticated\n * requests — e.g. a user JWT inside an edge function, or a server-signed\n * JWT from an external auth provider. Disables automatic token refresh\n * and implies server mode unless `isServerMode` is set explicitly.\n */\n accessToken?: string;\n\n /**\n * @deprecated Use `accessToken` instead. Same behavior; `accessToken`\n * takes precedence when both are provided.\n */\n edgeFunctionToken?: string;\n\n /**\n * Direct URL to Deno Subhosting functions (optional)\n * When provided, SDK will try this URL first for function invocations.\n * Falls back to proxy URL if subhosting returns 404.\n * @example \"https://{appKey}.functions.insforge.app\"\n */\n functionsUrl?: string;\n\n /**\n * Custom fetch implementation (useful for Node.js environments)\n */\n fetch?: typeof fetch;\n\n /**\n * Enable server-side auth mode (SSR/Node runtime)\n * In this mode auth endpoints use `client_type=mobile` and refresh_token body flow.\n *\n * @deprecated Use `createServerClient()`, `createBrowserClient()`, and\n * `updateSession()` from `@insforge/sdk/ssr` for SSR apps.\n * @default false\n */\n isServerMode?: boolean;\n\n /**\n * Advanced auth module options.\n */\n auth?: {\n /**\n * Detect and exchange OAuth callback parameters on browser client\n * initialization. SSR browser clients disable this so auth mutations can\n * stay server-owned.\n * @default true\n */\n detectOAuthCallback?: boolean;\n };\n\n /**\n * Database module options.\n */\n db?: {\n /**\n * Default Postgres schema for database queries. Maps to PostgREST's\n * `Accept-Profile`/`Content-Profile` headers. Override per-query with\n * `client.database.schema('other')`.\n * @default \"public\"\n */\n schema?: string;\n };\n\n /**\n * Custom headers to include with every request\n */\n headers?: Record<string, string>;\n\n /**\n * Enable debug logging for HTTP requests and responses.\n * When true, request/response details are logged to the console.\n * Can also be a custom log function for advanced use cases.\n * @default false\n */\n debug?: boolean | ((message: string, ...args: any[]) => void);\n\n /**\n * Request timeout in milliseconds.\n * Requests that exceed this duration will be aborted.\n * Set to 0 to disable timeout.\n * @default 30000\n */\n timeout?: number;\n\n /**\n * Maximum number of retry attempts for failed requests.\n * Retries are triggered on network errors and server errors (5xx).\n * Client errors (4xx) are never retried.\n * Set to 0 to disable retries.\n * @default 3\n */\n retryCount?: number;\n\n /**\n * Initial delay in milliseconds before the first retry.\n * The delay doubles with each subsequent attempt (exponential backoff)\n * with ±15% jitter to prevent thundering herd.\n * @default 500\n */\n retryDelay?: number;\n}\n\nexport type InsForgeAdminConfig = Omit<\n InsForgeConfig,\n 'anonKey' | 'accessToken' | 'edgeFunctionToken' | 'isServerMode'\n> & {\n /**\n * Project admin API key. Keep this server-side only.\n */\n apiKey: string;\n};\n\nexport interface AuthSession {\n user: UserSchema;\n accessToken: string;\n expiresAt?: Date;\n}\n\nexport interface AuthRefreshResponse {\n user: UserSchema;\n accessToken: string;\n csrfToken?: string;\n refreshToken?: string;\n}\n\nexport interface ApiError {\n error: InsForgeErrorCode;\n message: string;\n statusCode: number;\n nextActions?: string;\n}\n\nexport class InsForgeError extends Error {\n public statusCode: number;\n public error: InsForgeErrorCode;\n public nextActions?: string;\n\n constructor(\n message: string,\n statusCode: number,\n error: InsForgeErrorCode,\n nextActions?: string,\n ) {\n super(message);\n this.name = 'InsForgeError';\n this.statusCode = statusCode;\n this.error = error;\n this.nextActions = nextActions;\n }\n\n static fromApiError(apiError: ApiError): InsForgeError {\n return new InsForgeError(\n apiError.message,\n apiError.statusCode,\n apiError.error,\n apiError.nextActions,\n );\n }\n}\n","import {\n InsForgeError,\n type AuthRefreshResponse,\n type InsForgeConfig,\n} from '../types';\nimport { ERROR_CODES } from '@insforge/shared-schemas';\nimport {\n clearAuthCookieHeaders,\n getCookieValue,\n getCookieValueFromHeader,\n getRefreshTokenCookieName,\n setAuthCookieHeaders,\n type AuthCookieSettings,\n type CookieStore,\n} from './cookies';\n\nexport interface RefreshAuthOptions\n extends Omit<\n InsForgeConfig,\n 'accessToken' | 'edgeFunctionToken' | 'isServerMode' | 'auth'\n >,\n AuthCookieSettings {\n request?: Request;\n cookies?: Pick<CookieStore, 'get'>;\n refreshToken?: string;\n}\n\nexport interface RefreshAuthResult {\n response: Response;\n data: AuthRefreshResponse | null;\n accessToken: string | null;\n refreshToken: string | null;\n error: InsForgeError | null;\n}\n\nexport type RefreshAuthRouteHandler = (request: Request) => Promise<Response>;\n\nfunction jsonResponse(\n body: unknown,\n init: ResponseInit = {},\n headers = new Headers(init.headers),\n): Response {\n headers.set('Content-Type', 'application/json');\n return new Response(JSON.stringify(body), {\n ...init,\n headers,\n });\n}\n\nfunction normalizeError(error: unknown): InsForgeError {\n if (error instanceof InsForgeError) return error;\n\n if (error && typeof error === 'object') {\n const body = error as {\n error?: unknown;\n message?: unknown;\n statusCode?: unknown;\n };\n return new InsForgeError(\n typeof body.message === 'string'\n ? body.message\n : 'Failed to refresh auth session',\n typeof body.statusCode === 'number' ? body.statusCode : 500,\n typeof body.error === 'string'\n ? body.error\n : ERROR_CODES.UNKNOWN_ERROR,\n );\n }\n\n return new InsForgeError(\n error instanceof Error ? error.message : 'Failed to refresh auth session',\n 500,\n ERROR_CODES.UNKNOWN_ERROR,\n );\n}\n\nasync function readJson(response: Response): Promise<unknown> {\n const contentType = response.headers.get('content-type');\n if (!contentType?.includes('json')) return null;\n return response.json();\n}\n\nfunction readRefreshToken(options: RefreshAuthOptions): string | null {\n if (options.refreshToken) return options.refreshToken;\n\n const refreshCookieName = getRefreshTokenCookieName(options.names);\n const cookieValue = getCookieValue(options.cookies, refreshCookieName);\n if (cookieValue) return cookieValue;\n\n return getCookieValueFromHeader(\n options.request?.headers.get('cookie'),\n refreshCookieName,\n );\n}\n\nexport async function refreshAuth(\n options: RefreshAuthOptions = {},\n): Promise<RefreshAuthResult> {\n const headers = new Headers();\n const refreshToken = readRefreshToken(options);\n\n if (!refreshToken) {\n clearAuthCookieHeaders(headers, options);\n const error = new InsForgeError(\n 'Refresh token cookie is missing',\n 401,\n ERROR_CODES.AUTH_UNAUTHORIZED,\n );\n return {\n response: jsonResponse(\n {\n error: error.error,\n message: error.message,\n statusCode: error.statusCode,\n },\n { status: error.statusCode },\n headers,\n ),\n data: null,\n accessToken: null,\n refreshToken: null,\n error,\n };\n }\n\n let { baseUrl, anonKey } = options;\n try {\n baseUrl ||= process.env.NEXT_PUBLIC_INSFORGE_URL;\n anonKey ||= process.env.NEXT_PUBLIC_INSFORGE_ANON_KEY;\n } catch {\n // process may be unavailable outside Next.js/browser-bundled envs.\n }\n if (!baseUrl || !anonKey) {\n throw new Error(\n 'Missing InsForge baseUrl or anonKey. Pass baseUrl and anonKey to refreshAuth() or set NEXT_PUBLIC_INSFORGE_URL and NEXT_PUBLIC_INSFORGE_ANON_KEY.',\n );\n }\n\n const fetchImpl =\n options.fetch ??\n (globalThis.fetch\n ? globalThis.fetch.bind(globalThis)\n : (undefined as typeof fetch | undefined));\n if (!fetchImpl) {\n throw new Error(\n 'Fetch is not available. Please provide a fetch implementation.',\n );\n }\n\n const requestHeaders = new Headers(options.headers);\n requestHeaders.set('Authorization', `Bearer ${anonKey}`);\n requestHeaders.set('Content-Type', 'application/json');\n requestHeaders.set('Accept', 'application/json');\n\n let data: AuthRefreshResponse | null = null;\n let error: InsForgeError | null = null;\n\n try {\n const response = await fetchImpl(\n new URL('/api/auth/refresh?client_type=mobile', baseUrl).toString(),\n {\n method: 'POST',\n headers: requestHeaders,\n body: JSON.stringify({ refresh_token: refreshToken }),\n },\n );\n const body = await readJson(response);\n if (!response.ok) {\n error = normalizeError(\n body ?? {\n message: 'Failed to refresh auth session',\n statusCode: response.status,\n error: ERROR_CODES.UNKNOWN_ERROR,\n },\n );\n } else {\n data = body as AuthRefreshResponse;\n }\n } catch (caught) {\n error = normalizeError(caught);\n }\n\n if (error || !data?.accessToken) {\n clearAuthCookieHeaders(headers, options);\n const normalized = normalizeError(error);\n return {\n response: jsonResponse(\n {\n error: normalized.error,\n message: normalized.message,\n statusCode: normalized.statusCode,\n },\n { status: normalized.statusCode || 500 },\n headers,\n ),\n data: null,\n accessToken: null,\n refreshToken: null,\n error: normalized,\n };\n }\n\n const nextRefreshToken = data.refreshToken ?? refreshToken;\n setAuthCookieHeaders(\n headers,\n {\n accessToken: data.accessToken,\n refreshToken: nextRefreshToken,\n },\n options,\n );\n\n const responseBody: AuthRefreshResponse = {\n accessToken: data.accessToken,\n user: data.user,\n csrfToken: data.csrfToken,\n };\n\n return {\n response: jsonResponse(responseBody, { status: 200 }, headers),\n data: responseBody,\n accessToken: data.accessToken,\n refreshToken: nextRefreshToken,\n error: null,\n };\n}\n\nexport function createRefreshAuthRouter(\n options: Omit<RefreshAuthOptions, 'request'> = {},\n): { POST: RefreshAuthRouteHandler } {\n return {\n POST: async (request: Request) =>\n (await refreshAuth({ ...options, request })).response,\n };\n}\n","import { isJwtExpiredOrExpiring } from '../lib/jwt';\nimport type { InsForgeConfig, InsForgeError } from '../types';\nimport {\n clearAuthCookies,\n getAccessTokenCookieName,\n getCookieValue,\n getRefreshTokenCookieName,\n setAuthCookies,\n type AuthCookieSettings,\n type CookieStore,\n} from './cookies';\nimport { refreshAuth } from './refresh';\n\nexport interface UpdateSessionOptions\n extends Omit<\n InsForgeConfig,\n 'accessToken' | 'edgeFunctionToken' | 'isServerMode' | 'auth'\n >,\n AuthCookieSettings {\n requestCookies: CookieStore;\n responseCookies: CookieStore;\n refreshLeewaySeconds?: number;\n}\n\nexport interface UpdateSessionResult {\n refreshed: boolean;\n accessToken: string | null;\n error: InsForgeError | null;\n}\n\nexport async function updateSession(\n options: UpdateSessionOptions,\n): Promise<UpdateSessionResult> {\n const accessCookieName = getAccessTokenCookieName(options.names);\n const refreshCookieName = getRefreshTokenCookieName(options.names);\n const accessToken = getCookieValue(\n options.requestCookies,\n accessCookieName,\n );\n\n if (\n accessToken &&\n !isJwtExpiredOrExpiring(accessToken, options.refreshLeewaySeconds)\n ) {\n return {\n refreshed: false,\n accessToken,\n error: null,\n };\n }\n\n const refreshToken = getCookieValue(\n options.requestCookies,\n refreshCookieName,\n );\n if (!refreshToken) {\n if (accessToken) {\n clearAuthCookies(options.requestCookies, options);\n clearAuthCookies(options.responseCookies, options);\n }\n return {\n refreshed: false,\n accessToken: null,\n error: null,\n };\n }\n\n const result = await refreshAuth({\n ...options,\n refreshToken,\n });\n\n if (result.error || !result.accessToken) {\n clearAuthCookies(options.requestCookies, options);\n clearAuthCookies(options.responseCookies, options);\n return {\n refreshed: false,\n accessToken: null,\n error: result.error,\n };\n }\n\n const tokens = {\n accessToken: result.accessToken,\n refreshToken: result.refreshToken ?? refreshToken,\n };\n setAuthCookies(options.requestCookies, tokens, options);\n setAuthCookies(options.responseCookies, tokens, options);\n\n return {\n refreshed: true,\n accessToken: result.accessToken,\n error: null,\n };\n}\n"],"mappings":"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","names":["error"]}
|
|
1
|
+
{"version":3,"sources":["../../src/ssr/middleware.ts","../../src/lib/jwt.ts","../../src/ssr/cookies.ts","../../src/types.ts","../../src/ssr/refresh.ts","../../src/ssr/update-session.ts"],"sourcesContent":["export {\n updateSession,\n type UpdateSessionOptions,\n type UpdateSessionResult,\n} from './update-session';\nexport {\n DEFAULT_ACCESS_TOKEN_COOKIE,\n DEFAULT_REFRESH_TOKEN_COOKIE,\n clearAuthCookies,\n getAccessTokenCookieName,\n getRefreshTokenCookieName,\n setAuthCookies,\n type AuthCookieNames,\n type AuthCookieOptions,\n type AuthCookieSettings,\n type CookieOptions,\n type CookieReader,\n type CookieStore,\n type CookieWriter,\n} from './cookies';\n","function decodeBase64Url(input: string): string {\n const normalized = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = normalized.padEnd(normalized.length + ((4 - (normalized.length % 4)) % 4), '=');\n\n const binary = atob(padded);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return new TextDecoder().decode(bytes);\n}\n\nexport function getJwtExpiration(token: string | null | undefined): Date | null {\n if (!token) {\n return null;\n }\n\n const [, payload] = token.split('.');\n if (!payload) {\n return null;\n }\n\n try {\n const parsed = JSON.parse(decodeBase64Url(payload)) as { exp?: unknown };\n if (typeof parsed.exp !== 'number' || !Number.isFinite(parsed.exp)) {\n return null;\n }\n return new Date(parsed.exp * 1000);\n } catch {\n return null;\n }\n}\n\nexport function isJwtExpiredOrExpiring(\n token: string | null | undefined,\n leewaySeconds = 60\n): boolean {\n if (!token) {\n return false;\n }\n const expires = getJwtExpiration(token);\n if (!expires) {\n return true;\n }\n\n return expires.getTime() <= Date.now() + leewaySeconds * 1000;\n}\n","import { getJwtExpiration } from '../lib/jwt';\n\nexport const DEFAULT_ACCESS_TOKEN_COOKIE = 'insforge_access_token';\nexport const DEFAULT_REFRESH_TOKEN_COOKIE = 'insforge_refresh_token';\n\nexport interface AuthCookieNames {\n accessToken?: string;\n refreshToken?: string;\n}\n\nexport interface CookieOptions {\n domain?: string;\n path?: string;\n expires?: Date;\n maxAge?: number;\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: 'lax' | 'strict' | 'none';\n}\n\nexport interface AuthCookieOptions {\n accessToken?: CookieOptions;\n refreshToken?: CookieOptions;\n}\n\nexport type CookieStoreValue = string | { value?: string | null } | undefined | null;\n\nexport interface CookieReader {\n get(name: string): CookieStoreValue;\n}\n\nexport interface CookieWriter {\n set?(name: string, value: string, options?: CookieOptions): unknown;\n set?(options: { name: string; value: string } & CookieOptions): unknown;\n delete?(name: string): unknown;\n delete?(options: { name: string } & CookieOptions): unknown;\n}\n\nexport interface CookieStore extends CookieReader, CookieWriter {}\n\nexport interface AuthCookieSettings {\n names?: AuthCookieNames;\n options?: AuthCookieOptions;\n}\n\nconst EXPIRED_DATE = new Date(0);\n\nexport function getAccessTokenCookieName(names?: AuthCookieNames): string {\n return names?.accessToken ?? DEFAULT_ACCESS_TOKEN_COOKIE;\n}\n\nexport function getRefreshTokenCookieName(names?: AuthCookieNames): string {\n return names?.refreshToken ?? DEFAULT_REFRESH_TOKEN_COOKIE;\n}\n\nexport function getCookieValue(cookies: CookieReader | undefined, name: string): string | null {\n if (!cookies) {\n return null;\n }\n\n const value = cookies.get(name);\n if (typeof value === 'string') {\n return value || null;\n }\n if (value && typeof value.value === 'string') {\n return value.value || null;\n }\n return null;\n}\n\nexport function getCookieValueFromHeader(\n cookieHeader: string | null | undefined,\n name: string\n): string | null {\n if (!cookieHeader) {\n return null;\n }\n\n const parts = cookieHeader.split(';');\n for (const part of parts) {\n const [rawName, ...rawValue] = part.trim().split('=');\n if (rawName !== name) {\n continue;\n }\n try {\n return decodeURIComponent(rawValue.join('='));\n } catch {\n return rawValue.join('=');\n }\n }\n return null;\n}\n\nexport function getBrowserCookie(name: string): string | null {\n if (typeof document === 'undefined') {\n return null;\n }\n return getCookieValueFromHeader(document.cookie, name);\n}\n\nfunction defaultCookieOptions(): CookieOptions {\n const secure =\n typeof process !== 'undefined'\n ? process.env.NODE_ENV === 'production'\n : typeof location !== 'undefined' && location.protocol === 'https:';\n\n return {\n path: '/',\n sameSite: 'lax',\n secure,\n };\n}\n\nexport function accessTokenCookieOptions(token: string, overrides?: CookieOptions): CookieOptions {\n return {\n ...defaultCookieOptions(),\n httpOnly: false,\n expires: getJwtExpiration(token) ?? undefined,\n ...overrides,\n };\n}\n\nexport function refreshTokenCookieOptions(token: string, overrides?: CookieOptions): CookieOptions {\n return {\n ...defaultCookieOptions(),\n httpOnly: true,\n expires: getJwtExpiration(token) ?? undefined,\n ...overrides,\n };\n}\n\nexport function expiredCookieOptions(overrides?: CookieOptions): CookieOptions {\n const { expires: _expires, maxAge: _maxAge, ...safeOverrides } = overrides ?? {};\n return {\n ...defaultCookieOptions(),\n ...safeOverrides,\n expires: EXPIRED_DATE,\n maxAge: 0,\n };\n}\n\nexport function setCookie(\n cookies: CookieWriter | undefined,\n name: string,\n value: string,\n options?: CookieOptions\n): void {\n if (!cookies?.set) {\n return;\n }\n cookies.set(name, value, options);\n}\n\nexport function deleteCookie(\n cookies: CookieWriter | undefined,\n name: string,\n options?: CookieOptions\n): void {\n if (!cookies) {\n return;\n }\n if (cookies.set) {\n cookies.set(name, '', expiredCookieOptions(options));\n return;\n }\n cookies.delete?.(name);\n}\n\nexport function serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];\n\n if (options.maxAge !== undefined) {\n parts.push(`Max-Age=${options.maxAge}`);\n }\n if (options.domain) {\n parts.push(`Domain=${options.domain}`);\n }\n if (options.path) {\n parts.push(`Path=${options.path}`);\n }\n if (options.expires) {\n parts.push(`Expires=${options.expires.toUTCString()}`);\n }\n if (options.httpOnly) {\n parts.push('HttpOnly');\n }\n if (options.secure) {\n parts.push('Secure');\n }\n if (options.sameSite) {\n const sameSite = options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1);\n parts.push(`SameSite=${sameSite}`);\n }\n\n return parts.join('; ');\n}\n\nexport function appendSetCookie(\n headers: Headers,\n name: string,\n value: string,\n options?: CookieOptions\n): void {\n headers.append('Set-Cookie', serializeCookie(name, value, options));\n}\n\nexport function setAuthCookies(\n cookies: CookieWriter | undefined,\n tokens: {\n accessToken: string;\n refreshToken?: string | null;\n },\n settings: AuthCookieSettings = {}\n): void {\n const accessName = getAccessTokenCookieName(settings.names);\n const refreshName = getRefreshTokenCookieName(settings.names);\n const accessOptions = accessTokenCookieOptions(tokens.accessToken, settings.options?.accessToken);\n\n setCookie(cookies, accessName, tokens.accessToken, accessOptions);\n if (tokens.refreshToken) {\n setCookie(\n cookies,\n refreshName,\n tokens.refreshToken,\n refreshTokenCookieOptions(tokens.refreshToken, settings.options?.refreshToken)\n );\n }\n}\n\nexport function clearAuthCookies(\n cookies: CookieWriter | undefined,\n settings: AuthCookieSettings = {}\n): void {\n const accessName = getAccessTokenCookieName(settings.names);\n const refreshName = getRefreshTokenCookieName(settings.names);\n const accessOptions = expiredCookieOptions(settings.options?.accessToken);\n const refreshOptions = expiredCookieOptions(settings.options?.refreshToken);\n\n deleteCookie(cookies, accessName, accessOptions);\n deleteCookie(cookies, refreshName, refreshOptions);\n}\n\nexport function setAuthCookieHeaders(\n headers: Headers,\n tokens: {\n accessToken: string;\n refreshToken?: string | null;\n },\n settings: AuthCookieSettings = {}\n): void {\n const accessName = getAccessTokenCookieName(settings.names);\n const refreshName = getRefreshTokenCookieName(settings.names);\n\n appendSetCookie(\n headers,\n accessName,\n tokens.accessToken,\n accessTokenCookieOptions(tokens.accessToken, settings.options?.accessToken)\n );\n if (tokens.refreshToken) {\n appendSetCookie(\n headers,\n refreshName,\n tokens.refreshToken,\n refreshTokenCookieOptions(tokens.refreshToken, settings.options?.refreshToken)\n );\n }\n}\n\nexport function clearAuthCookieHeaders(headers: Headers, settings: AuthCookieSettings = {}): void {\n appendSetCookie(\n headers,\n getAccessTokenCookieName(settings.names),\n '',\n expiredCookieOptions(settings.options?.accessToken)\n );\n appendSetCookie(\n headers,\n getRefreshTokenCookieName(settings.names),\n '',\n expiredCookieOptions(settings.options?.refreshToken)\n );\n}\n","/**\n * InsForge SDK Types - only SDK-specific types here\n * Use @insforge/shared-schemas directly for API types\n */\n\nimport type { ErrorCode, UserSchema } from '@insforge/shared-schemas';\n\nexport type InsForgeErrorCode = ErrorCode | (string & {});\n\nexport interface InsForgeConfig {\n /**\n * The base URL of the InsForge backend API\n * @default \"http://localhost:7130\"\n */\n baseUrl?: string;\n\n /**\n * Anonymous API key (optional)\n * Used for public/unauthenticated requests when no user token is set\n */\n anonKey?: string;\n\n /**\n * Static access token (optional)\n * Seeds the client with a fixed bearer token used for all authenticated\n * requests — e.g. a user JWT inside an edge function, or a server-signed\n * JWT from an external auth provider. Disables automatic token refresh\n * and implies server mode unless `isServerMode` is set explicitly.\n */\n accessToken?: string;\n\n /**\n * @deprecated Use `accessToken` instead. Same behavior; `accessToken`\n * takes precedence when both are provided.\n */\n edgeFunctionToken?: string;\n\n /**\n * Direct URL to Deno Subhosting functions (optional)\n * When provided, SDK will try this URL first for function invocations.\n * Falls back to proxy URL if subhosting returns 404.\n * @example \"https://{appKey}.functions.insforge.app\"\n */\n functionsUrl?: string;\n\n /**\n * Custom fetch implementation (useful for Node.js environments)\n */\n fetch?: typeof fetch;\n\n /**\n * Enable server-side auth mode (SSR/Node runtime)\n * In this mode auth endpoints use `client_type=mobile` and refresh_token body flow.\n *\n * @deprecated Use `createServerClient()`, `createBrowserClient()`, and\n * `updateSession()` from `@insforge/sdk/ssr` for SSR apps.\n * @default false\n */\n isServerMode?: boolean;\n\n /**\n * Advanced auth module options.\n */\n auth?: {\n /**\n * Detect and exchange OAuth callback parameters on browser client\n * initialization. SSR browser clients disable this so auth mutations can\n * stay server-owned.\n * @default true\n */\n detectOAuthCallback?: boolean;\n };\n\n /**\n * Database module options.\n */\n db?: {\n /**\n * Default Postgres schema for database queries. Maps to PostgREST's\n * `Accept-Profile`/`Content-Profile` headers. Override per-query with\n * `client.database.schema('other')`.\n * @default \"public\"\n */\n schema?: string;\n };\n\n /**\n * Custom headers to include with every request\n */\n headers?: Record<string, string>;\n\n /**\n * Enable debug logging for HTTP requests and responses.\n * When true, request/response details are logged to the console.\n * Can also be a custom log function for advanced use cases.\n * @default false\n */\n debug?: boolean | ((message: string, ...args: any[]) => void);\n\n /**\n * Request timeout in milliseconds.\n * Requests that exceed this duration will be aborted.\n * Set to 0 to disable timeout.\n * @default 30000\n */\n timeout?: number;\n\n /**\n * Maximum number of retry attempts for failed requests.\n * Retries are triggered on network errors and server errors (5xx).\n * Client errors (4xx) are never retried.\n * Set to 0 to disable retries.\n * @default 3\n */\n retryCount?: number;\n\n /**\n * Initial delay in milliseconds before the first retry.\n * The delay doubles with each subsequent attempt (exponential backoff)\n * with ±15% jitter to prevent thundering herd.\n * @default 500\n */\n retryDelay?: number;\n}\n\nexport type InsForgeAdminConfig = Omit<\n InsForgeConfig,\n 'anonKey' | 'accessToken' | 'edgeFunctionToken' | 'isServerMode'\n> & {\n /**\n * Project admin API key. Keep this server-side only.\n */\n apiKey: string;\n};\n\nexport interface AuthSession {\n user: UserSchema;\n accessToken: string;\n expiresAt?: Date;\n}\n\nexport interface AuthRefreshResponse {\n user: UserSchema;\n accessToken: string;\n csrfToken?: string;\n refreshToken?: string;\n}\n\nexport interface ApiError {\n error: InsForgeErrorCode;\n message: string;\n statusCode: number;\n nextActions?: string;\n}\n\nexport class InsForgeError extends Error {\n public statusCode: number;\n public error: InsForgeErrorCode;\n public nextActions?: string;\n\n constructor(message: string, statusCode: number, error: InsForgeErrorCode, nextActions?: string) {\n super(message);\n this.name = 'InsForgeError';\n this.statusCode = statusCode;\n this.error = error;\n this.nextActions = nextActions;\n }\n\n static fromApiError(apiError: ApiError): InsForgeError {\n return new InsForgeError(\n apiError.message,\n apiError.statusCode,\n apiError.error,\n apiError.nextActions\n );\n }\n}\n","import { InsForgeError, type AuthRefreshResponse, type InsForgeConfig } from '../types';\nimport { ERROR_CODES } from '@insforge/shared-schemas';\nimport {\n clearAuthCookieHeaders,\n getCookieValue,\n getCookieValueFromHeader,\n getRefreshTokenCookieName,\n setAuthCookieHeaders,\n type AuthCookieSettings,\n type CookieStore,\n} from './cookies';\n\nexport interface RefreshAuthOptions\n extends\n Omit<InsForgeConfig, 'accessToken' | 'edgeFunctionToken' | 'isServerMode' | 'auth'>,\n AuthCookieSettings {\n request?: Request;\n cookies?: Pick<CookieStore, 'get'>;\n refreshToken?: string;\n}\n\nexport interface RefreshAuthResult {\n response: Response;\n data: AuthRefreshResponse | null;\n accessToken: string | null;\n refreshToken: string | null;\n error: InsForgeError | null;\n}\n\nexport type RefreshAuthRouteHandler = (request: Request) => Promise<Response>;\n\nfunction jsonResponse(\n body: unknown,\n init: ResponseInit = {},\n headers = new Headers(init.headers)\n): Response {\n headers.set('Content-Type', 'application/json');\n return new Response(JSON.stringify(body), {\n ...init,\n headers,\n });\n}\n\nfunction normalizeError(error: unknown): InsForgeError {\n if (error instanceof InsForgeError) {\n return error;\n }\n\n if (error && typeof error === 'object') {\n const body = error as {\n error?: unknown;\n message?: unknown;\n statusCode?: unknown;\n };\n return new InsForgeError(\n typeof body.message === 'string' ? body.message : 'Failed to refresh auth session',\n typeof body.statusCode === 'number' ? body.statusCode : 500,\n typeof body.error === 'string' ? body.error : ERROR_CODES.UNKNOWN_ERROR\n );\n }\n\n return new InsForgeError(\n error instanceof Error ? error.message : 'Failed to refresh auth session',\n 500,\n ERROR_CODES.UNKNOWN_ERROR\n );\n}\n\nasync function readJson(response: Response): Promise<unknown> {\n const contentType = response.headers.get('content-type');\n if (!contentType?.includes('json')) {\n return null;\n }\n return response.json();\n}\n\nfunction readRefreshToken(options: RefreshAuthOptions): string | null {\n if (options.refreshToken) {\n return options.refreshToken;\n }\n\n const refreshCookieName = getRefreshTokenCookieName(options.names);\n const cookieValue = getCookieValue(options.cookies, refreshCookieName);\n if (cookieValue) {\n return cookieValue;\n }\n\n return getCookieValueFromHeader(options.request?.headers.get('cookie'), refreshCookieName);\n}\n\nexport async function refreshAuth(options: RefreshAuthOptions = {}): Promise<RefreshAuthResult> {\n const headers = new Headers();\n const refreshToken = readRefreshToken(options);\n\n if (!refreshToken) {\n clearAuthCookieHeaders(headers, options);\n const error = new InsForgeError(\n 'Refresh token cookie is missing',\n 401,\n ERROR_CODES.AUTH_UNAUTHORIZED\n );\n return {\n response: jsonResponse(\n {\n error: error.error,\n message: error.message,\n statusCode: error.statusCode,\n },\n { status: error.statusCode },\n headers\n ),\n data: null,\n accessToken: null,\n refreshToken: null,\n error,\n };\n }\n\n let { baseUrl, anonKey } = options;\n try {\n baseUrl ||= process.env.NEXT_PUBLIC_INSFORGE_URL;\n anonKey ||= process.env.NEXT_PUBLIC_INSFORGE_ANON_KEY;\n } catch {\n // process may be unavailable outside Next.js/browser-bundled envs.\n }\n if (!baseUrl || !anonKey) {\n throw new Error(\n 'Missing InsForge baseUrl or anonKey. Pass baseUrl and anonKey to refreshAuth() or set NEXT_PUBLIC_INSFORGE_URL and NEXT_PUBLIC_INSFORGE_ANON_KEY.'\n );\n }\n\n const fetchImpl =\n options.fetch ??\n (globalThis.fetch\n ? globalThis.fetch.bind(globalThis)\n : (undefined as typeof fetch | undefined));\n if (!fetchImpl) {\n throw new Error('Fetch is not available. Please provide a fetch implementation.');\n }\n\n const requestHeaders = new Headers(options.headers);\n requestHeaders.set('Authorization', `Bearer ${anonKey}`);\n requestHeaders.set('Content-Type', 'application/json');\n requestHeaders.set('Accept', 'application/json');\n\n let data: AuthRefreshResponse | null = null;\n let error: InsForgeError | null = null;\n\n try {\n const response = await fetchImpl(\n new URL('/api/auth/refresh?client_type=mobile', baseUrl).toString(),\n {\n method: 'POST',\n headers: requestHeaders,\n body: JSON.stringify({ refresh_token: refreshToken }),\n }\n );\n const body = await readJson(response);\n if (!response.ok) {\n error = normalizeError(\n body ?? {\n message: 'Failed to refresh auth session',\n statusCode: response.status,\n error: ERROR_CODES.UNKNOWN_ERROR,\n }\n );\n } else {\n data = body as AuthRefreshResponse;\n }\n } catch (caught) {\n error = normalizeError(caught);\n }\n\n if (error || !data?.accessToken) {\n clearAuthCookieHeaders(headers, options);\n const normalized = normalizeError(error);\n return {\n response: jsonResponse(\n {\n error: normalized.error,\n message: normalized.message,\n statusCode: normalized.statusCode,\n },\n { status: normalized.statusCode || 500 },\n headers\n ),\n data: null,\n accessToken: null,\n refreshToken: null,\n error: normalized,\n };\n }\n\n const nextRefreshToken = data.refreshToken ?? refreshToken;\n setAuthCookieHeaders(\n headers,\n {\n accessToken: data.accessToken,\n refreshToken: nextRefreshToken,\n },\n options\n );\n\n const responseBody: AuthRefreshResponse = {\n accessToken: data.accessToken,\n user: data.user,\n csrfToken: data.csrfToken,\n };\n\n return {\n response: jsonResponse(responseBody, { status: 200 }, headers),\n data: responseBody,\n accessToken: data.accessToken,\n refreshToken: nextRefreshToken,\n error: null,\n };\n}\n\nexport function createRefreshAuthRouter(options: Omit<RefreshAuthOptions, 'request'> = {}): {\n POST: RefreshAuthRouteHandler;\n} {\n return {\n POST: async (request: Request) => (await refreshAuth({ ...options, request })).response,\n };\n}\n","import { isJwtExpiredOrExpiring } from '../lib/jwt';\nimport type { InsForgeConfig, InsForgeError } from '../types';\nimport {\n clearAuthCookies,\n getAccessTokenCookieName,\n getCookieValue,\n getRefreshTokenCookieName,\n setAuthCookies,\n type AuthCookieSettings,\n type CookieStore,\n} from './cookies';\nimport { refreshAuth } from './refresh';\n\nexport interface UpdateSessionOptions\n extends\n Omit<InsForgeConfig, 'accessToken' | 'edgeFunctionToken' | 'isServerMode' | 'auth'>,\n AuthCookieSettings {\n requestCookies: CookieStore;\n responseCookies: CookieStore;\n refreshLeewaySeconds?: number;\n}\n\nexport interface UpdateSessionResult {\n refreshed: boolean;\n accessToken: string | null;\n error: InsForgeError | null;\n}\n\nexport async function updateSession(options: UpdateSessionOptions): Promise<UpdateSessionResult> {\n const accessCookieName = getAccessTokenCookieName(options.names);\n const refreshCookieName = getRefreshTokenCookieName(options.names);\n const accessToken = getCookieValue(options.requestCookies, accessCookieName);\n\n if (accessToken && !isJwtExpiredOrExpiring(accessToken, options.refreshLeewaySeconds)) {\n return {\n refreshed: false,\n accessToken,\n error: null,\n };\n }\n\n const refreshToken = getCookieValue(options.requestCookies, refreshCookieName);\n if (!refreshToken) {\n if (accessToken) {\n clearAuthCookies(options.requestCookies, options);\n clearAuthCookies(options.responseCookies, options);\n }\n return {\n refreshed: false,\n accessToken: null,\n error: null,\n };\n }\n\n const result = await refreshAuth({\n ...options,\n refreshToken,\n });\n\n if (result.error || !result.accessToken) {\n clearAuthCookies(options.requestCookies, options);\n clearAuthCookies(options.responseCookies, options);\n return {\n refreshed: false,\n accessToken: null,\n error: result.error,\n };\n }\n\n const tokens = {\n accessToken: result.accessToken,\n refreshToken: result.refreshToken ?? refreshToken,\n };\n setAuthCookies(options.requestCookies, tokens, options);\n setAuthCookies(options.responseCookies, tokens, options);\n\n return {\n refreshed: true,\n accessToken: result.accessToken,\n error: null,\n };\n}\n"],"mappings":"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","names":["error"]}
|
package/dist/ssr/middleware.mjs
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// src/lib/jwt.ts
|
|
2
2
|
function decodeBase64Url(input) {
|
|
3
3
|
const normalized = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
4
|
-
const padded = normalized.padEnd(
|
|
5
|
-
normalized.length + (4 - normalized.length % 4) % 4,
|
|
6
|
-
"="
|
|
7
|
-
);
|
|
4
|
+
const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
|
|
8
5
|
const binary = atob(padded);
|
|
9
6
|
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
10
7
|
return new TextDecoder().decode(bytes);
|
|
11
8
|
}
|
|
12
9
|
function getJwtExpiration(token) {
|
|
13
|
-
if (!token)
|
|
10
|
+
if (!token) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
14
13
|
const [, payload] = token.split(".");
|
|
15
|
-
if (!payload)
|
|
14
|
+
if (!payload) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
16
17
|
try {
|
|
17
18
|
const parsed = JSON.parse(decodeBase64Url(payload));
|
|
18
19
|
if (typeof parsed.exp !== "number" || !Number.isFinite(parsed.exp)) {
|
|
@@ -24,9 +25,13 @@ function getJwtExpiration(token) {
|
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
function isJwtExpiredOrExpiring(token, leewaySeconds = 60) {
|
|
27
|
-
if (!token)
|
|
28
|
+
if (!token) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
28
31
|
const expires = getJwtExpiration(token);
|
|
29
|
-
if (!expires)
|
|
32
|
+
if (!expires) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
30
35
|
return expires.getTime() <= Date.now() + leewaySeconds * 1e3;
|
|
31
36
|
}
|
|
32
37
|
|
|
@@ -41,18 +46,28 @@ function getRefreshTokenCookieName(names) {
|
|
|
41
46
|
return names?.refreshToken ?? DEFAULT_REFRESH_TOKEN_COOKIE;
|
|
42
47
|
}
|
|
43
48
|
function getCookieValue(cookies, name) {
|
|
44
|
-
if (!cookies)
|
|
49
|
+
if (!cookies) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
45
52
|
const value = cookies.get(name);
|
|
46
|
-
if (typeof value === "string")
|
|
47
|
-
|
|
53
|
+
if (typeof value === "string") {
|
|
54
|
+
return value || null;
|
|
55
|
+
}
|
|
56
|
+
if (value && typeof value.value === "string") {
|
|
57
|
+
return value.value || null;
|
|
58
|
+
}
|
|
48
59
|
return null;
|
|
49
60
|
}
|
|
50
61
|
function getCookieValueFromHeader(cookieHeader, name) {
|
|
51
|
-
if (!cookieHeader)
|
|
62
|
+
if (!cookieHeader) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
52
65
|
const parts = cookieHeader.split(";");
|
|
53
66
|
for (const part of parts) {
|
|
54
67
|
const [rawName, ...rawValue] = part.trim().split("=");
|
|
55
|
-
if (rawName !== name)
|
|
68
|
+
if (rawName !== name) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
56
71
|
try {
|
|
57
72
|
return decodeURIComponent(rawValue.join("="));
|
|
58
73
|
} catch {
|
|
@@ -95,11 +110,15 @@ function expiredCookieOptions(overrides) {
|
|
|
95
110
|
};
|
|
96
111
|
}
|
|
97
112
|
function setCookie(cookies, name, value, options) {
|
|
98
|
-
if (!cookies?.set)
|
|
113
|
+
if (!cookies?.set) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
99
116
|
cookies.set(name, value, options);
|
|
100
117
|
}
|
|
101
118
|
function deleteCookie(cookies, name, options) {
|
|
102
|
-
if (!cookies)
|
|
119
|
+
if (!cookies) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
103
122
|
if (cookies.set) {
|
|
104
123
|
cookies.set(name, "", expiredCookieOptions(options));
|
|
105
124
|
return;
|
|
@@ -108,12 +127,24 @@ function deleteCookie(cookies, name, options) {
|
|
|
108
127
|
}
|
|
109
128
|
function serializeCookie(name, value, options = {}) {
|
|
110
129
|
const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
|
|
111
|
-
if (options.maxAge !== void 0)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (options.
|
|
115
|
-
|
|
116
|
-
|
|
130
|
+
if (options.maxAge !== void 0) {
|
|
131
|
+
parts.push(`Max-Age=${options.maxAge}`);
|
|
132
|
+
}
|
|
133
|
+
if (options.domain) {
|
|
134
|
+
parts.push(`Domain=${options.domain}`);
|
|
135
|
+
}
|
|
136
|
+
if (options.path) {
|
|
137
|
+
parts.push(`Path=${options.path}`);
|
|
138
|
+
}
|
|
139
|
+
if (options.expires) {
|
|
140
|
+
parts.push(`Expires=${options.expires.toUTCString()}`);
|
|
141
|
+
}
|
|
142
|
+
if (options.httpOnly) {
|
|
143
|
+
parts.push("HttpOnly");
|
|
144
|
+
}
|
|
145
|
+
if (options.secure) {
|
|
146
|
+
parts.push("Secure");
|
|
147
|
+
}
|
|
117
148
|
if (options.sameSite) {
|
|
118
149
|
const sameSite = options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1);
|
|
119
150
|
parts.push(`SameSite=${sameSite}`);
|
|
@@ -126,20 +157,14 @@ function appendSetCookie(headers, name, value, options) {
|
|
|
126
157
|
function setAuthCookies(cookies, tokens, settings = {}) {
|
|
127
158
|
const accessName = getAccessTokenCookieName(settings.names);
|
|
128
159
|
const refreshName = getRefreshTokenCookieName(settings.names);
|
|
129
|
-
const accessOptions = accessTokenCookieOptions(
|
|
130
|
-
tokens.accessToken,
|
|
131
|
-
settings.options?.accessToken
|
|
132
|
-
);
|
|
160
|
+
const accessOptions = accessTokenCookieOptions(tokens.accessToken, settings.options?.accessToken);
|
|
133
161
|
setCookie(cookies, accessName, tokens.accessToken, accessOptions);
|
|
134
162
|
if (tokens.refreshToken) {
|
|
135
163
|
setCookie(
|
|
136
164
|
cookies,
|
|
137
165
|
refreshName,
|
|
138
166
|
tokens.refreshToken,
|
|
139
|
-
refreshTokenCookieOptions(
|
|
140
|
-
tokens.refreshToken,
|
|
141
|
-
settings.options?.refreshToken
|
|
142
|
-
)
|
|
167
|
+
refreshTokenCookieOptions(tokens.refreshToken, settings.options?.refreshToken)
|
|
143
168
|
);
|
|
144
169
|
}
|
|
145
170
|
}
|
|
@@ -165,10 +190,7 @@ function setAuthCookieHeaders(headers, tokens, settings = {}) {
|
|
|
165
190
|
headers,
|
|
166
191
|
refreshName,
|
|
167
192
|
tokens.refreshToken,
|
|
168
|
-
refreshTokenCookieOptions(
|
|
169
|
-
tokens.refreshToken,
|
|
170
|
-
settings.options?.refreshToken
|
|
171
|
-
)
|
|
193
|
+
refreshTokenCookieOptions(tokens.refreshToken, settings.options?.refreshToken)
|
|
172
194
|
);
|
|
173
195
|
}
|
|
174
196
|
}
|
|
@@ -216,7 +238,9 @@ function jsonResponse(body, init = {}, headers = new Headers(init.headers)) {
|
|
|
216
238
|
});
|
|
217
239
|
}
|
|
218
240
|
function normalizeError(error) {
|
|
219
|
-
if (error instanceof InsForgeError)
|
|
241
|
+
if (error instanceof InsForgeError) {
|
|
242
|
+
return error;
|
|
243
|
+
}
|
|
220
244
|
if (error && typeof error === "object") {
|
|
221
245
|
const body = error;
|
|
222
246
|
return new InsForgeError(
|
|
@@ -233,18 +257,21 @@ function normalizeError(error) {
|
|
|
233
257
|
}
|
|
234
258
|
async function readJson(response) {
|
|
235
259
|
const contentType = response.headers.get("content-type");
|
|
236
|
-
if (!contentType?.includes("json"))
|
|
260
|
+
if (!contentType?.includes("json")) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
237
263
|
return response.json();
|
|
238
264
|
}
|
|
239
265
|
function readRefreshToken(options) {
|
|
240
|
-
if (options.refreshToken)
|
|
266
|
+
if (options.refreshToken) {
|
|
267
|
+
return options.refreshToken;
|
|
268
|
+
}
|
|
241
269
|
const refreshCookieName = getRefreshTokenCookieName(options.names);
|
|
242
270
|
const cookieValue = getCookieValue(options.cookies, refreshCookieName);
|
|
243
|
-
if (cookieValue)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
);
|
|
271
|
+
if (cookieValue) {
|
|
272
|
+
return cookieValue;
|
|
273
|
+
}
|
|
274
|
+
return getCookieValueFromHeader(options.request?.headers.get("cookie"), refreshCookieName);
|
|
248
275
|
}
|
|
249
276
|
async function refreshAuth(options = {}) {
|
|
250
277
|
const headers = new Headers();
|
|
@@ -285,9 +312,7 @@ async function refreshAuth(options = {}) {
|
|
|
285
312
|
}
|
|
286
313
|
const fetchImpl = options.fetch ?? (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
287
314
|
if (!fetchImpl) {
|
|
288
|
-
throw new Error(
|
|
289
|
-
"Fetch is not available. Please provide a fetch implementation."
|
|
290
|
-
);
|
|
315
|
+
throw new Error("Fetch is not available. Please provide a fetch implementation.");
|
|
291
316
|
}
|
|
292
317
|
const requestHeaders = new Headers(options.headers);
|
|
293
318
|
requestHeaders.set("Authorization", `Bearer ${anonKey}`);
|
|
@@ -365,10 +390,7 @@ async function refreshAuth(options = {}) {
|
|
|
365
390
|
async function updateSession(options) {
|
|
366
391
|
const accessCookieName = getAccessTokenCookieName(options.names);
|
|
367
392
|
const refreshCookieName = getRefreshTokenCookieName(options.names);
|
|
368
|
-
const accessToken = getCookieValue(
|
|
369
|
-
options.requestCookies,
|
|
370
|
-
accessCookieName
|
|
371
|
-
);
|
|
393
|
+
const accessToken = getCookieValue(options.requestCookies, accessCookieName);
|
|
372
394
|
if (accessToken && !isJwtExpiredOrExpiring(accessToken, options.refreshLeewaySeconds)) {
|
|
373
395
|
return {
|
|
374
396
|
refreshed: false,
|
|
@@ -376,10 +398,7 @@ async function updateSession(options) {
|
|
|
376
398
|
error: null
|
|
377
399
|
};
|
|
378
400
|
}
|
|
379
|
-
const refreshToken = getCookieValue(
|
|
380
|
-
options.requestCookies,
|
|
381
|
-
refreshCookieName
|
|
382
|
-
);
|
|
401
|
+
const refreshToken = getCookieValue(options.requestCookies, refreshCookieName);
|
|
383
402
|
if (!refreshToken) {
|
|
384
403
|
if (accessToken) {
|
|
385
404
|
clearAuthCookies(options.requestCookies, options);
|