@resultdev/sdk 0.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.
@@ -0,0 +1,441 @@
1
+ import {
2
+ ERROR_CODES
3
+ } from "../chunk-Y7VCTXPN.js";
4
+
5
+ // ../../node_modules/.bun/@insforge+sdk@1.4.4/node_modules/@insforge/sdk/dist/ssr/middleware.mjs
6
+ function decodeBase64Url(input) {
7
+ const normalized = input.replace(/-/g, "+").replace(/_/g, "/");
8
+ const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
9
+ const binary = atob(padded);
10
+ const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
11
+ return new TextDecoder().decode(bytes);
12
+ }
13
+ function getJwtExpiration(token) {
14
+ if (!token) {
15
+ return null;
16
+ }
17
+ const [, payload] = token.split(".");
18
+ if (!payload) {
19
+ return null;
20
+ }
21
+ try {
22
+ const parsed = JSON.parse(decodeBase64Url(payload));
23
+ if (typeof parsed.exp !== "number" || !Number.isFinite(parsed.exp)) {
24
+ return null;
25
+ }
26
+ return new Date(parsed.exp * 1e3);
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+ function isJwtExpiredOrExpiring(token, leewaySeconds = 60) {
32
+ if (!token) {
33
+ return false;
34
+ }
35
+ const expires = getJwtExpiration(token);
36
+ if (!expires) {
37
+ return true;
38
+ }
39
+ return expires.getTime() <= Date.now() + leewaySeconds * 1e3;
40
+ }
41
+ var DEFAULT_ACCESS_TOKEN_COOKIE = "insforge_access_token";
42
+ var DEFAULT_REFRESH_TOKEN_COOKIE = "insforge_refresh_token";
43
+ var EXPIRED_DATE = /* @__PURE__ */ new Date(0);
44
+ function getAccessTokenCookieName(names) {
45
+ return names?.accessToken ?? DEFAULT_ACCESS_TOKEN_COOKIE;
46
+ }
47
+ function getRefreshTokenCookieName(names) {
48
+ return names?.refreshToken ?? DEFAULT_REFRESH_TOKEN_COOKIE;
49
+ }
50
+ function getCookieValue(cookies, name) {
51
+ if (!cookies) {
52
+ return null;
53
+ }
54
+ const value = cookies.get(name);
55
+ if (typeof value === "string") {
56
+ return value || null;
57
+ }
58
+ if (value && typeof value.value === "string") {
59
+ return value.value || null;
60
+ }
61
+ return null;
62
+ }
63
+ function getCookieValueFromHeader(cookieHeader, name) {
64
+ if (!cookieHeader) {
65
+ return null;
66
+ }
67
+ const parts = cookieHeader.split(";");
68
+ for (const part of parts) {
69
+ const [rawName, ...rawValue] = part.trim().split("=");
70
+ if (rawName !== name) {
71
+ continue;
72
+ }
73
+ try {
74
+ return decodeURIComponent(rawValue.join("="));
75
+ } catch {
76
+ return rawValue.join("=");
77
+ }
78
+ }
79
+ return null;
80
+ }
81
+ function defaultCookieOptions() {
82
+ const secure = typeof process !== "undefined" ? process.env.NODE_ENV === "production" : typeof location !== "undefined" && location.protocol === "https:";
83
+ return {
84
+ path: "/",
85
+ sameSite: "lax",
86
+ secure
87
+ };
88
+ }
89
+ function accessTokenCookieOptions(token, overrides) {
90
+ return {
91
+ ...defaultCookieOptions(),
92
+ httpOnly: false,
93
+ expires: getJwtExpiration(token) ?? void 0,
94
+ ...overrides
95
+ };
96
+ }
97
+ function refreshTokenCookieOptions(token, overrides) {
98
+ return {
99
+ ...defaultCookieOptions(),
100
+ httpOnly: true,
101
+ expires: getJwtExpiration(token) ?? void 0,
102
+ ...overrides
103
+ };
104
+ }
105
+ function expiredCookieOptions(overrides) {
106
+ const { expires: _expires, maxAge: _maxAge, ...safeOverrides } = overrides ?? {};
107
+ return {
108
+ ...defaultCookieOptions(),
109
+ ...safeOverrides,
110
+ expires: EXPIRED_DATE,
111
+ maxAge: 0
112
+ };
113
+ }
114
+ function setCookie(cookies, name, value, options) {
115
+ if (!cookies?.set) {
116
+ return;
117
+ }
118
+ cookies.set(name, value, options);
119
+ }
120
+ function deleteCookie(cookies, name, options) {
121
+ if (!cookies) {
122
+ return;
123
+ }
124
+ if (cookies.set) {
125
+ cookies.set(name, "", expiredCookieOptions(options));
126
+ return;
127
+ }
128
+ cookies.delete?.(name);
129
+ }
130
+ function serializeCookie(name, value, options = {}) {
131
+ const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
132
+ if (options.maxAge !== void 0) {
133
+ parts.push(`Max-Age=${options.maxAge}`);
134
+ }
135
+ if (options.domain) {
136
+ parts.push(`Domain=${options.domain}`);
137
+ }
138
+ if (options.path) {
139
+ parts.push(`Path=${options.path}`);
140
+ }
141
+ if (options.expires) {
142
+ parts.push(`Expires=${options.expires.toUTCString()}`);
143
+ }
144
+ if (options.httpOnly) {
145
+ parts.push("HttpOnly");
146
+ }
147
+ if (options.secure) {
148
+ parts.push("Secure");
149
+ }
150
+ if (options.sameSite) {
151
+ const sameSite = options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1);
152
+ parts.push(`SameSite=${sameSite}`);
153
+ }
154
+ return parts.join("; ");
155
+ }
156
+ function appendSetCookie(headers, name, value, options) {
157
+ headers.append("Set-Cookie", serializeCookie(name, value, options));
158
+ }
159
+ function setAuthCookies(cookies, tokens, settings = {}) {
160
+ const accessName = getAccessTokenCookieName(settings.names);
161
+ const refreshName = getRefreshTokenCookieName(settings.names);
162
+ const accessOptions = accessTokenCookieOptions(tokens.accessToken, settings.options?.accessToken);
163
+ setCookie(cookies, accessName, tokens.accessToken, accessOptions);
164
+ if (tokens.refreshToken) {
165
+ setCookie(
166
+ cookies,
167
+ refreshName,
168
+ tokens.refreshToken,
169
+ refreshTokenCookieOptions(tokens.refreshToken, settings.options?.refreshToken)
170
+ );
171
+ }
172
+ }
173
+ function clearAuthCookies(cookies, settings = {}) {
174
+ const accessName = getAccessTokenCookieName(settings.names);
175
+ const refreshName = getRefreshTokenCookieName(settings.names);
176
+ const accessOptions = expiredCookieOptions(settings.options?.accessToken);
177
+ const refreshOptions = expiredCookieOptions(settings.options?.refreshToken);
178
+ deleteCookie(cookies, accessName, accessOptions);
179
+ deleteCookie(cookies, refreshName, refreshOptions);
180
+ }
181
+ function setAuthCookieHeaders(headers, tokens, settings = {}) {
182
+ const accessName = getAccessTokenCookieName(settings.names);
183
+ const refreshName = getRefreshTokenCookieName(settings.names);
184
+ appendSetCookie(
185
+ headers,
186
+ accessName,
187
+ tokens.accessToken,
188
+ accessTokenCookieOptions(tokens.accessToken, settings.options?.accessToken)
189
+ );
190
+ if (tokens.refreshToken) {
191
+ appendSetCookie(
192
+ headers,
193
+ refreshName,
194
+ tokens.refreshToken,
195
+ refreshTokenCookieOptions(tokens.refreshToken, settings.options?.refreshToken)
196
+ );
197
+ }
198
+ }
199
+ function clearAuthCookieHeaders(headers, settings = {}) {
200
+ appendSetCookie(
201
+ headers,
202
+ getAccessTokenCookieName(settings.names),
203
+ "",
204
+ expiredCookieOptions(settings.options?.accessToken)
205
+ );
206
+ appendSetCookie(
207
+ headers,
208
+ getRefreshTokenCookieName(settings.names),
209
+ "",
210
+ expiredCookieOptions(settings.options?.refreshToken)
211
+ );
212
+ }
213
+ var InsForgeError = class _InsForgeError extends Error {
214
+ constructor(message, statusCode, error, nextActions) {
215
+ super(message);
216
+ this.name = "InsForgeError";
217
+ this.statusCode = statusCode;
218
+ this.error = error;
219
+ this.nextActions = nextActions;
220
+ }
221
+ static fromApiError(apiError) {
222
+ return new _InsForgeError(
223
+ apiError.message,
224
+ apiError.statusCode,
225
+ apiError.error,
226
+ apiError.nextActions
227
+ );
228
+ }
229
+ };
230
+ function jsonResponse(body, init = {}, headers = new Headers(init.headers)) {
231
+ headers.set("Content-Type", "application/json");
232
+ return new Response(JSON.stringify(body), {
233
+ ...init,
234
+ headers
235
+ });
236
+ }
237
+ function normalizeError(error) {
238
+ if (error instanceof InsForgeError) {
239
+ return error;
240
+ }
241
+ if (error && typeof error === "object") {
242
+ const body = error;
243
+ return new InsForgeError(
244
+ typeof body.message === "string" ? body.message : "Failed to refresh auth session",
245
+ typeof body.statusCode === "number" ? body.statusCode : 500,
246
+ typeof body.error === "string" ? body.error : ERROR_CODES.UNKNOWN_ERROR
247
+ );
248
+ }
249
+ return new InsForgeError(
250
+ error instanceof Error ? error.message : "Failed to refresh auth session",
251
+ 500,
252
+ ERROR_CODES.UNKNOWN_ERROR
253
+ );
254
+ }
255
+ async function readJson(response) {
256
+ const contentType = response.headers.get("content-type");
257
+ if (!contentType?.includes("json")) {
258
+ return null;
259
+ }
260
+ return response.json();
261
+ }
262
+ function readRefreshToken(options) {
263
+ if (options.refreshToken) {
264
+ return options.refreshToken;
265
+ }
266
+ const refreshCookieName = getRefreshTokenCookieName(options.names);
267
+ const cookieValue = getCookieValue(options.cookies, refreshCookieName);
268
+ if (cookieValue) {
269
+ return cookieValue;
270
+ }
271
+ return getCookieValueFromHeader(options.request?.headers.get("cookie"), refreshCookieName);
272
+ }
273
+ async function refreshAuth(options = {}) {
274
+ const headers = new Headers();
275
+ const refreshToken = readRefreshToken(options);
276
+ if (!refreshToken) {
277
+ clearAuthCookieHeaders(headers, options);
278
+ const error2 = new InsForgeError(
279
+ "Refresh token cookie is missing",
280
+ 401,
281
+ ERROR_CODES.AUTH_UNAUTHORIZED
282
+ );
283
+ return {
284
+ response: jsonResponse(
285
+ {
286
+ error: error2.error,
287
+ message: error2.message,
288
+ statusCode: error2.statusCode
289
+ },
290
+ { status: error2.statusCode },
291
+ headers
292
+ ),
293
+ data: null,
294
+ accessToken: null,
295
+ refreshToken: null,
296
+ error: error2
297
+ };
298
+ }
299
+ let { baseUrl, anonKey } = options;
300
+ try {
301
+ baseUrl || (baseUrl = process.env.NEXT_PUBLIC_INSFORGE_URL);
302
+ anonKey || (anonKey = process.env.NEXT_PUBLIC_INSFORGE_ANON_KEY);
303
+ } catch {
304
+ }
305
+ if (!baseUrl || !anonKey) {
306
+ throw new Error(
307
+ "Missing InsForge baseUrl or anonKey. Pass baseUrl and anonKey to refreshAuth() or set NEXT_PUBLIC_INSFORGE_URL and NEXT_PUBLIC_INSFORGE_ANON_KEY."
308
+ );
309
+ }
310
+ const fetchImpl = options.fetch ?? (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
311
+ if (!fetchImpl) {
312
+ throw new Error("Fetch is not available. Please provide a fetch implementation.");
313
+ }
314
+ const requestHeaders = new Headers(options.headers);
315
+ requestHeaders.set("Authorization", `Bearer ${anonKey}`);
316
+ requestHeaders.set("Content-Type", "application/json");
317
+ requestHeaders.set("Accept", "application/json");
318
+ let data = null;
319
+ let error = null;
320
+ try {
321
+ const response = await fetchImpl(
322
+ new URL("/api/auth/refresh?client_type=mobile", baseUrl).toString(),
323
+ {
324
+ method: "POST",
325
+ headers: requestHeaders,
326
+ body: JSON.stringify({ refresh_token: refreshToken })
327
+ }
328
+ );
329
+ const body = await readJson(response);
330
+ if (!response.ok) {
331
+ error = normalizeError(
332
+ body ?? {
333
+ message: "Failed to refresh auth session",
334
+ statusCode: response.status,
335
+ error: ERROR_CODES.UNKNOWN_ERROR
336
+ }
337
+ );
338
+ } else {
339
+ data = body;
340
+ }
341
+ } catch (caught) {
342
+ error = normalizeError(caught);
343
+ }
344
+ if (error || !data?.accessToken) {
345
+ clearAuthCookieHeaders(headers, options);
346
+ const normalized = normalizeError(error);
347
+ return {
348
+ response: jsonResponse(
349
+ {
350
+ error: normalized.error,
351
+ message: normalized.message,
352
+ statusCode: normalized.statusCode
353
+ },
354
+ { status: normalized.statusCode || 500 },
355
+ headers
356
+ ),
357
+ data: null,
358
+ accessToken: null,
359
+ refreshToken: null,
360
+ error: normalized
361
+ };
362
+ }
363
+ const nextRefreshToken = data.refreshToken ?? refreshToken;
364
+ setAuthCookieHeaders(
365
+ headers,
366
+ {
367
+ accessToken: data.accessToken,
368
+ refreshToken: nextRefreshToken
369
+ },
370
+ options
371
+ );
372
+ const responseBody = {
373
+ accessToken: data.accessToken,
374
+ user: data.user,
375
+ csrfToken: data.csrfToken
376
+ };
377
+ return {
378
+ response: jsonResponse(responseBody, { status: 200 }, headers),
379
+ data: responseBody,
380
+ accessToken: data.accessToken,
381
+ refreshToken: nextRefreshToken,
382
+ error: null
383
+ };
384
+ }
385
+ async function updateSession(options) {
386
+ const accessCookieName = getAccessTokenCookieName(options.names);
387
+ const refreshCookieName = getRefreshTokenCookieName(options.names);
388
+ const accessToken = getCookieValue(options.requestCookies, accessCookieName);
389
+ if (accessToken && !isJwtExpiredOrExpiring(accessToken, options.refreshLeewaySeconds)) {
390
+ return {
391
+ refreshed: false,
392
+ accessToken,
393
+ error: null
394
+ };
395
+ }
396
+ const refreshToken = getCookieValue(options.requestCookies, refreshCookieName);
397
+ if (!refreshToken) {
398
+ if (accessToken) {
399
+ clearAuthCookies(options.requestCookies, options);
400
+ clearAuthCookies(options.responseCookies, options);
401
+ }
402
+ return {
403
+ refreshed: false,
404
+ accessToken: null,
405
+ error: null
406
+ };
407
+ }
408
+ const result = await refreshAuth({
409
+ ...options,
410
+ refreshToken
411
+ });
412
+ if (result.error || !result.accessToken) {
413
+ clearAuthCookies(options.requestCookies, options);
414
+ clearAuthCookies(options.responseCookies, options);
415
+ return {
416
+ refreshed: false,
417
+ accessToken: null,
418
+ error: result.error
419
+ };
420
+ }
421
+ const tokens = {
422
+ accessToken: result.accessToken,
423
+ refreshToken: result.refreshToken ?? refreshToken
424
+ };
425
+ setAuthCookies(options.requestCookies, tokens, options);
426
+ setAuthCookies(options.responseCookies, tokens, options);
427
+ return {
428
+ refreshed: true,
429
+ accessToken: result.accessToken,
430
+ error: null
431
+ };
432
+ }
433
+ export {
434
+ DEFAULT_ACCESS_TOKEN_COOKIE,
435
+ DEFAULT_REFRESH_TOKEN_COOKIE,
436
+ clearAuthCookies,
437
+ getAccessTokenCookieName,
438
+ getRefreshTokenCookieName,
439
+ setAuthCookies,
440
+ updateSession
441
+ };