@stackframe/js 2.8.48 → 2.8.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/esm/lib/cookie.js +36 -7
- package/dist/esm/lib/cookie.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js +17 -0
- package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +255 -56
- package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/common.js +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +40 -1
- package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/esm/lib/stack-app/common.js.map +1 -1
- package/dist/esm/lib/stack-app/users/index.js.map +1 -1
- package/dist/index.d.mts +97 -79
- package/dist/index.d.ts +97 -79
- package/dist/lib/cookie.js +38 -7
- package/dist/lib/cookie.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/admin-app-impl.js +17 -0
- package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/client-app-impl.js +254 -55
- package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/common.js +1 -1
- package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/server-app-impl.js +49 -0
- package/dist/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/lib/stack-app/common.js.map +1 -1
- package/dist/lib/stack-app/users/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -36,6 +36,7 @@ module.exports = __toCommonJS(client_app_impl_exports);
|
|
|
36
36
|
var import_browser = require("@simplewebauthn/browser");
|
|
37
37
|
var import_stack_shared = require("@stackframe/stack-shared");
|
|
38
38
|
var import_sessions = require("@stackframe/stack-shared/dist/sessions");
|
|
39
|
+
var import_bytes = require("@stackframe/stack-shared/dist/utils/bytes");
|
|
39
40
|
var import_env = require("@stackframe/stack-shared/dist/utils/env");
|
|
40
41
|
var import_errors = require("@stackframe/stack-shared/dist/utils/errors");
|
|
41
42
|
var import_maps = require("@stackframe/stack-shared/dist/utils/maps");
|
|
@@ -57,6 +58,7 @@ var import_projects = require("../../projects/index.js");
|
|
|
57
58
|
var import_teams = require("../../teams/index.js");
|
|
58
59
|
var import_users = require("../../users/index.js");
|
|
59
60
|
var import_common2 = require("./common.js");
|
|
61
|
+
var import_json = require("@stackframe/stack-shared/dist/utils/json");
|
|
60
62
|
var isReactServer = false;
|
|
61
63
|
var process = globalThis.process ?? { env: {} };
|
|
62
64
|
var allClientApps = /* @__PURE__ */ new Map();
|
|
@@ -205,11 +207,15 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
|
|
|
205
207
|
this._convexPartialUserCache = (0, import_common2.createCache)(
|
|
206
208
|
async ([ctx]) => await this._getPartialUserFromConvex(ctx)
|
|
207
209
|
);
|
|
210
|
+
this._trustedParentDomainCache = (0, import_common2.createCache)(
|
|
211
|
+
async ([domain]) => await this._getTrustedParentDomain(domain)
|
|
212
|
+
);
|
|
208
213
|
this._anonymousSignUpInProgress = null;
|
|
209
214
|
this._memoryTokenStore = (0, import_common2.createEmptyTokenStore)();
|
|
210
215
|
this._nextServerCookiesTokenStores = /* @__PURE__ */ new WeakMap();
|
|
211
216
|
this._requestTokenStores = /* @__PURE__ */ new WeakMap();
|
|
212
217
|
this._storedBrowserCookieTokenStore = null;
|
|
218
|
+
this._mostRecentQueuedCookieRefreshIndex = 0;
|
|
213
219
|
/**
|
|
214
220
|
* A map from token stores and session keys to sessions.
|
|
215
221
|
*
|
|
@@ -225,13 +231,17 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
|
|
|
225
231
|
}
|
|
226
232
|
this._options = resolvedOptions;
|
|
227
233
|
this._extraOptions = extraOptions;
|
|
234
|
+
const projectId = resolvedOptions.projectId ?? (0, import_common2.getDefaultProjectId)();
|
|
235
|
+
if (projectId !== "internal" && !projectId.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i)) {
|
|
236
|
+
throw new Error(`Invalid project ID: ${projectId}. Project IDs must be UUIDs. Please check your environment variables and/or your StackApp.`);
|
|
237
|
+
}
|
|
228
238
|
if (extraOptions && extraOptions.interface) {
|
|
229
239
|
this._interface = extraOptions.interface;
|
|
230
240
|
} else {
|
|
231
241
|
this._interface = new import_stack_shared.StackClientInterface({
|
|
232
242
|
getBaseUrl: () => (0, import_common2.getBaseUrl)(resolvedOptions.baseUrl),
|
|
233
243
|
extraRequestHeaders: resolvedOptions.extraRequestHeaders ?? (0, import_common2.getDefaultExtraRequestHeaders)(),
|
|
234
|
-
projectId
|
|
244
|
+
projectId,
|
|
235
245
|
clientVersion: import_common2.clientVersion,
|
|
236
246
|
publishableClientKey: resolvedOptions.publishableClientKey ?? (0, import_common2.getDefaultPublishableClientKey)(),
|
|
237
247
|
prepareRequest: async () => {
|
|
@@ -325,13 +335,90 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
|
|
|
325
335
|
(0, import_promises.runAsynchronously)(this._checkFeatureSupport(name, options));
|
|
326
336
|
throw new import_errors.StackAssertionError(`${name} is not currently supported. Please reach out to Stack support for more information.`);
|
|
327
337
|
}
|
|
338
|
+
get _legacyRefreshTokenCookieName() {
|
|
339
|
+
return `stack-refresh-${this.projectId}`;
|
|
340
|
+
}
|
|
328
341
|
get _refreshTokenCookieName() {
|
|
329
342
|
return `stack-refresh-${this.projectId}`;
|
|
330
343
|
}
|
|
344
|
+
_getRefreshTokenDefaultCookieNameForSecure(secure) {
|
|
345
|
+
return `${secure ? "__Host-" : ""}${this._refreshTokenCookieName}--default`;
|
|
346
|
+
}
|
|
347
|
+
_getCustomRefreshCookieName(domain) {
|
|
348
|
+
const encoded = (0, import_bytes.encodeBase32)(new TextEncoder().encode(domain.toLowerCase()));
|
|
349
|
+
return `${this._refreshTokenCookieName}--custom-${encoded}`;
|
|
350
|
+
}
|
|
351
|
+
_formatRefreshCookieValue(refreshToken, updatedAt) {
|
|
352
|
+
return JSON.stringify({
|
|
353
|
+
refresh_token: refreshToken,
|
|
354
|
+
updated_at_millis: updatedAt
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
_formatAccessCookieValue(refreshToken, accessToken) {
|
|
358
|
+
return refreshToken && accessToken ? JSON.stringify([refreshToken, accessToken]) : null;
|
|
359
|
+
}
|
|
360
|
+
_parseStructuredRefreshCookie(value) {
|
|
361
|
+
if (!value) {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
const parsed = (0, import_json.parseJson)(value);
|
|
365
|
+
if (parsed.status !== "ok" || typeof parsed.data !== "object" || parsed.data === null) {
|
|
366
|
+
console.warn("Failed to parse structured refresh cookie");
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
const data = parsed.data;
|
|
370
|
+
const refreshToken = "refresh_token" in data && typeof data.refresh_token === "string" ? data.refresh_token : null;
|
|
371
|
+
const updatedAt = "updated_at_millis" in data && typeof data.updated_at_millis === "number" ? data.updated_at_millis : null;
|
|
372
|
+
if (!refreshToken) {
|
|
373
|
+
console.warn("Refresh token not found in structured refresh cookie");
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
return {
|
|
377
|
+
refreshToken,
|
|
378
|
+
updatedAt
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
_extractRefreshTokenFromCookieMap(cookies) {
|
|
382
|
+
const { legacyNames, structuredPrefixes } = this._getRefreshTokenCookieNamePatterns();
|
|
383
|
+
for (const name of legacyNames) {
|
|
384
|
+
const value = cookies[name];
|
|
385
|
+
if (value) {
|
|
386
|
+
return { refreshToken: value, updatedAt: null };
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
let selected = null;
|
|
390
|
+
for (const [name, value] of Object.entries(cookies)) {
|
|
391
|
+
if (!structuredPrefixes.some((prefix) => name.startsWith(prefix))) continue;
|
|
392
|
+
const parsed = this._parseStructuredRefreshCookie(value);
|
|
393
|
+
if (!parsed) continue;
|
|
394
|
+
const candidateUpdatedAt = parsed.updatedAt ?? Number.NEGATIVE_INFINITY;
|
|
395
|
+
const selectedUpdatedAt = selected?.updatedAt ?? Number.NEGATIVE_INFINITY;
|
|
396
|
+
if (!selected || candidateUpdatedAt > selectedUpdatedAt) {
|
|
397
|
+
selected = parsed;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (!selected) {
|
|
401
|
+
return { refreshToken: null, updatedAt: null };
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
refreshToken: selected.refreshToken,
|
|
405
|
+
updatedAt: selected.updatedAt ?? null
|
|
406
|
+
};
|
|
407
|
+
}
|
|
331
408
|
_getTokensFromCookies(cookies) {
|
|
332
|
-
const refreshToken = cookies
|
|
333
|
-
const
|
|
334
|
-
|
|
409
|
+
const { refreshToken } = this._extractRefreshTokenFromCookieMap(cookies);
|
|
410
|
+
const accessTokenCookie = cookies[this._accessTokenCookieName] ?? null;
|
|
411
|
+
let accessToken = null;
|
|
412
|
+
if (accessTokenCookie && accessTokenCookie.startsWith('["')) {
|
|
413
|
+
const parsed = (0, import_json.parseJson)(accessTokenCookie);
|
|
414
|
+
if (parsed.status === "ok" && typeof parsed.data === "object" && parsed.data !== null && Array.isArray(parsed.data) && parsed.data.length === 2 && typeof parsed.data[0] === "string" && typeof parsed.data[1] === "string") {
|
|
415
|
+
if (parsed.data[0] === refreshToken) {
|
|
416
|
+
accessToken = parsed.data[1];
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
console.warn("Access token cookie has invalid format");
|
|
420
|
+
}
|
|
421
|
+
}
|
|
335
422
|
return {
|
|
336
423
|
refreshToken,
|
|
337
424
|
accessToken
|
|
@@ -340,17 +427,98 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
|
|
|
340
427
|
get _accessTokenCookieName() {
|
|
341
428
|
return `stack-access`;
|
|
342
429
|
}
|
|
430
|
+
_getAllBrowserCookies() {
|
|
431
|
+
if (!(0, import_env.isBrowserLike)()) {
|
|
432
|
+
throw new import_errors.StackAssertionError("Cannot get browser cookies on the server!");
|
|
433
|
+
}
|
|
434
|
+
return cookie.parse(document.cookie || "");
|
|
435
|
+
}
|
|
436
|
+
_getRefreshTokenCookieNamePatterns() {
|
|
437
|
+
return {
|
|
438
|
+
legacyNames: [this._legacyRefreshTokenCookieName, "stack-refresh"],
|
|
439
|
+
structuredPrefixes: [
|
|
440
|
+
`${this._refreshTokenCookieName}--`,
|
|
441
|
+
`__Host-${this._refreshTokenCookieName}--`
|
|
442
|
+
]
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
_collectRefreshTokenCookieNames(cookies) {
|
|
446
|
+
const { legacyNames, structuredPrefixes } = this._getRefreshTokenCookieNamePatterns();
|
|
447
|
+
const names = /* @__PURE__ */ new Set();
|
|
448
|
+
for (const name of legacyNames) {
|
|
449
|
+
if (cookies[name]) {
|
|
450
|
+
names.add(name);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
for (const name of Object.keys(cookies)) {
|
|
454
|
+
if (structuredPrefixes.some((prefix) => name.startsWith(prefix))) {
|
|
455
|
+
names.add(name);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return names;
|
|
459
|
+
}
|
|
460
|
+
_prepareRefreshCookieUpdate(existingCookies, refreshToken, accessToken, defaultCookieName) {
|
|
461
|
+
const cookieNames = this._collectRefreshTokenCookieNames(existingCookies);
|
|
462
|
+
cookieNames.delete(defaultCookieName);
|
|
463
|
+
const updatedAt = refreshToken ? Date.now() : null;
|
|
464
|
+
const refreshCookieValue = refreshToken && updatedAt !== null ? this._formatRefreshCookieValue(refreshToken, updatedAt) : null;
|
|
465
|
+
const accessTokenPayload = this._formatAccessCookieValue(refreshToken, accessToken);
|
|
466
|
+
return {
|
|
467
|
+
updatedAt,
|
|
468
|
+
refreshCookieValue,
|
|
469
|
+
accessTokenPayload,
|
|
470
|
+
cookieNamesToDelete: [...cookieNames]
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
_queueCustomRefreshCookieUpdate(refreshToken, updatedAt, context) {
|
|
474
|
+
(0, import_promises.runAsynchronously)(async () => {
|
|
475
|
+
this._mostRecentQueuedCookieRefreshIndex++;
|
|
476
|
+
const updateIndex = this._mostRecentQueuedCookieRefreshIndex;
|
|
477
|
+
let hostname;
|
|
478
|
+
if ((0, import_env.isBrowserLike)()) {
|
|
479
|
+
hostname = window.location.hostname;
|
|
480
|
+
}
|
|
481
|
+
if (!hostname) {
|
|
482
|
+
console.warn("No hostname found when queueing custom refresh cookie update");
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const domain = await this._trustedParentDomainCache.getOrWait([hostname], "read-write");
|
|
486
|
+
const setCookie = async (targetDomain, value2) => {
|
|
487
|
+
const name = this._getCustomRefreshCookieName(targetDomain);
|
|
488
|
+
const options = { maxAge: 60 * 60 * 24 * 365, domain: targetDomain, noOpIfServerComponent: true };
|
|
489
|
+
if (context === "browser") {
|
|
490
|
+
(0, import_cookie.setOrDeleteCookieClient)(name, value2, options);
|
|
491
|
+
} else {
|
|
492
|
+
await (0, import_cookie.setOrDeleteCookie)(name, value2, options);
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
if (domain.status === "error" || !domain.data || updateIndex !== this._mostRecentQueuedCookieRefreshIndex) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const value = refreshToken && updatedAt ? this._formatRefreshCookieValue(refreshToken, updatedAt) : null;
|
|
499
|
+
await setCookie(domain.data, value);
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
async _getTrustedParentDomain(currentDomain) {
|
|
503
|
+
const project = import_results.Result.orThrow(await this._interface.getClientProject());
|
|
504
|
+
const domains = project.config.domains.map((d) => d.domain.trim().replace(/^https?:\/\//, "").split("/")[0]?.toLowerCase());
|
|
505
|
+
const trustedWildcards = domains.filter((d) => d.startsWith("**."));
|
|
506
|
+
const parts = currentDomain.split(".");
|
|
507
|
+
for (let i = parts.length - 2; i >= 0; i--) {
|
|
508
|
+
const parentDomain = parts.slice(i).join(".");
|
|
509
|
+
if (domains.includes(parentDomain) && trustedWildcards.includes("**." + parentDomain)) {
|
|
510
|
+
return parentDomain;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
343
515
|
_getBrowserCookieTokenStore() {
|
|
344
516
|
if (!(0, import_env.isBrowserLike)()) {
|
|
345
517
|
throw new Error("Cannot use cookie token store on the server!");
|
|
346
518
|
}
|
|
347
519
|
if (this._storedBrowserCookieTokenStore === null) {
|
|
348
520
|
const getCurrentValue = (old) => {
|
|
349
|
-
const tokens = this._getTokensFromCookies(
|
|
350
|
-
refreshTokenCookie: (0, import_cookie.getCookieClient)(this._refreshTokenCookieName) ?? (0, import_cookie.getCookieClient)("stack-refresh"),
|
|
351
|
-
// keep old cookie name for backwards-compatibility
|
|
352
|
-
accessTokenCookie: (0, import_cookie.getCookieClient)(this._accessTokenCookieName)
|
|
353
|
-
});
|
|
521
|
+
const tokens = this._getTokensFromCookies(this._getAllBrowserCookies());
|
|
354
522
|
return {
|
|
355
523
|
refreshToken: tokens.refreshToken,
|
|
356
524
|
accessToken: tokens.accessToken ?? (old?.refreshToken === tokens.refreshToken ? old.accessToken : null)
|
|
@@ -369,9 +537,19 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
|
|
|
369
537
|
}, 100);
|
|
370
538
|
this._storedBrowserCookieTokenStore.onChange((value) => {
|
|
371
539
|
try {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
540
|
+
const refreshToken = value.refreshToken;
|
|
541
|
+
const secure = window.location.protocol === "https:";
|
|
542
|
+
const defaultName = this._getRefreshTokenDefaultCookieNameForSecure(secure);
|
|
543
|
+
const { updatedAt, refreshCookieValue, accessTokenPayload, cookieNamesToDelete } = this._prepareRefreshCookieUpdate(
|
|
544
|
+
this._getAllBrowserCookies(),
|
|
545
|
+
refreshToken,
|
|
546
|
+
value.accessToken ?? null,
|
|
547
|
+
defaultName
|
|
548
|
+
);
|
|
549
|
+
(0, import_cookie.setOrDeleteCookieClient)(defaultName, refreshCookieValue, { maxAge: 60 * 60 * 24 * 365, secure });
|
|
550
|
+
(0, import_cookie.setOrDeleteCookieClient)(this._accessTokenCookieName, accessTokenPayload, { maxAge: 60 * 60 * 24 });
|
|
551
|
+
cookieNamesToDelete.forEach((name) => (0, import_cookie.deleteCookieClient)(name));
|
|
552
|
+
this._queueCustomRefreshCookieUpdate(refreshToken, updatedAt, "browser");
|
|
375
553
|
hasSucceededInWriting = true;
|
|
376
554
|
} catch (e) {
|
|
377
555
|
if (!(0, import_env.isBrowserLike)()) {
|
|
@@ -394,18 +572,31 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
|
|
|
394
572
|
if ((0, import_env.isBrowserLike)()) {
|
|
395
573
|
return this._getBrowserCookieTokenStore();
|
|
396
574
|
} else {
|
|
397
|
-
const tokens = this._getTokensFromCookies(
|
|
398
|
-
refreshTokenCookie: cookieHelper.get(this._refreshTokenCookieName) ?? cookieHelper.get("stack-refresh"),
|
|
399
|
-
// keep old cookie name for backwards-compatibility
|
|
400
|
-
accessTokenCookie: cookieHelper.get(this._accessTokenCookieName)
|
|
401
|
-
});
|
|
575
|
+
const tokens = this._getTokensFromCookies(cookieHelper.getAll());
|
|
402
576
|
const store = new import_stores.Store(tokens);
|
|
403
577
|
store.onChange((value) => {
|
|
404
578
|
(0, import_promises.runAsynchronously)(async () => {
|
|
579
|
+
const refreshToken = value.refreshToken;
|
|
580
|
+
const secure = await (0, import_cookie.isSecure)();
|
|
581
|
+
const defaultName = this._getRefreshTokenDefaultCookieNameForSecure(secure);
|
|
582
|
+
const { updatedAt, refreshCookieValue, accessTokenPayload, cookieNamesToDelete } = this._prepareRefreshCookieUpdate(
|
|
583
|
+
cookieHelper.getAll(),
|
|
584
|
+
refreshToken,
|
|
585
|
+
value.accessToken ?? null,
|
|
586
|
+
defaultName
|
|
587
|
+
);
|
|
405
588
|
await Promise.all([
|
|
406
|
-
(0, import_cookie.setOrDeleteCookie)(
|
|
407
|
-
(0, import_cookie.setOrDeleteCookie)(this._accessTokenCookieName,
|
|
589
|
+
(0, import_cookie.setOrDeleteCookie)(defaultName, refreshCookieValue, { maxAge: 60 * 60 * 24 * 365, noOpIfServerComponent: true }),
|
|
590
|
+
(0, import_cookie.setOrDeleteCookie)(this._accessTokenCookieName, accessTokenPayload, { maxAge: 60 * 60 * 24, noOpIfServerComponent: true })
|
|
408
591
|
]);
|
|
592
|
+
if (cookieNamesToDelete.length > 0) {
|
|
593
|
+
await Promise.all(
|
|
594
|
+
cookieNamesToDelete.map(
|
|
595
|
+
(name) => (0, import_cookie.setOrDeleteCookie)(name, null, { noOpIfServerComponent: true })
|
|
596
|
+
)
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
this._queueCustomRefreshCookieUpdate(refreshToken, updatedAt, "server");
|
|
409
600
|
});
|
|
410
601
|
});
|
|
411
602
|
return store;
|
|
@@ -436,11 +627,7 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
|
|
|
436
627
|
}
|
|
437
628
|
const cookieHeader = tokenStoreInit.headers.get("cookie");
|
|
438
629
|
const parsed = cookie.parse(cookieHeader || "");
|
|
439
|
-
const res = new import_stores.Store(
|
|
440
|
-
refreshToken: parsed[this._refreshTokenCookieName] || parsed["stack-refresh"] || null,
|
|
441
|
-
// keep old cookie name for backwards-compatibility
|
|
442
|
-
accessToken: parsed[this._accessTokenCookieName] || null
|
|
443
|
-
});
|
|
630
|
+
const res = new import_stores.Store(this._getTokensFromCookies(parsed));
|
|
444
631
|
this._requestTokenStores.set(tokenStoreInit, res);
|
|
445
632
|
return res;
|
|
446
633
|
} else if ("accessToken" in tokenStoreInit || "refreshToken" in tokenStoreInit) {
|
|
@@ -757,35 +944,6 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
|
|
|
757
944
|
const tokens = await this.currentSession.getTokens();
|
|
758
945
|
return tokens;
|
|
759
946
|
},
|
|
760
|
-
async registerPasskey(options) {
|
|
761
|
-
const hostname = (await app._getCurrentUrl())?.hostname;
|
|
762
|
-
if (!hostname) {
|
|
763
|
-
throw new import_errors.StackAssertionError("hostname must be provided if the Stack App does not have a redirect method");
|
|
764
|
-
}
|
|
765
|
-
const initiationResult = await app._interface.initiatePasskeyRegistration({}, session);
|
|
766
|
-
if (initiationResult.status !== "ok") {
|
|
767
|
-
return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyRegistrationFailed("Failed to get initiation options for passkey registration"));
|
|
768
|
-
}
|
|
769
|
-
const { options_json, code } = initiationResult.data;
|
|
770
|
-
if (options_json.rp.id !== "THIS_VALUE_WILL_BE_REPLACED.example.com") {
|
|
771
|
-
throw new import_errors.StackAssertionError(`Expected returned RP ID from server to equal sentinel, but found ${options_json.rp.id}`);
|
|
772
|
-
}
|
|
773
|
-
options_json.rp.id = hostname;
|
|
774
|
-
let attResp;
|
|
775
|
-
try {
|
|
776
|
-
attResp = await (0, import_browser.startRegistration)({ optionsJSON: options_json });
|
|
777
|
-
} catch (error) {
|
|
778
|
-
if (error instanceof import_browser.WebAuthnError) {
|
|
779
|
-
return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyWebAuthnError(error.message, error.name));
|
|
780
|
-
} else {
|
|
781
|
-
(0, import_errors.captureError)("passkey-registration-failed", error);
|
|
782
|
-
return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyRegistrationFailed("Failed to start passkey registration due to unknown error"));
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
const registrationResult = await app._interface.registerPasskey({ credential: attResp, code }, session);
|
|
786
|
-
await app._refreshUser(session);
|
|
787
|
-
return registrationResult;
|
|
788
|
-
},
|
|
789
947
|
signOut(options) {
|
|
790
948
|
return app._signOut(session, options);
|
|
791
949
|
}
|
|
@@ -970,6 +1128,35 @@ var __StackClientAppImplIncomplete = class __StackClientAppImplIncomplete {
|
|
|
970
1128
|
async getOAuthProvider(id) {
|
|
971
1129
|
const providers = await this.listOAuthProviders();
|
|
972
1130
|
return providers.find((p) => p.id === id) ?? null;
|
|
1131
|
+
},
|
|
1132
|
+
async registerPasskey(options) {
|
|
1133
|
+
const hostname = (await app._getCurrentUrl())?.hostname;
|
|
1134
|
+
if (!hostname) {
|
|
1135
|
+
throw new import_errors.StackAssertionError("hostname must be provided if the Stack App does not have a redirect method");
|
|
1136
|
+
}
|
|
1137
|
+
const initiationResult = await app._interface.initiatePasskeyRegistration({}, session);
|
|
1138
|
+
if (initiationResult.status !== "ok") {
|
|
1139
|
+
return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyRegistrationFailed("Failed to get initiation options for passkey registration"));
|
|
1140
|
+
}
|
|
1141
|
+
const { options_json, code } = initiationResult.data;
|
|
1142
|
+
if (options_json.rp.id !== "THIS_VALUE_WILL_BE_REPLACED.example.com") {
|
|
1143
|
+
throw new import_errors.StackAssertionError(`Expected returned RP ID from server to equal sentinel, but found ${options_json.rp.id}`);
|
|
1144
|
+
}
|
|
1145
|
+
options_json.rp.id = hostname;
|
|
1146
|
+
let attResp;
|
|
1147
|
+
try {
|
|
1148
|
+
attResp = await (0, import_browser.startRegistration)({ optionsJSON: options_json });
|
|
1149
|
+
} catch (error) {
|
|
1150
|
+
if (error instanceof import_browser.WebAuthnError) {
|
|
1151
|
+
return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyWebAuthnError(error.message, error.name));
|
|
1152
|
+
} else {
|
|
1153
|
+
(0, import_errors.captureError)("passkey-registration-failed", error);
|
|
1154
|
+
return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyRegistrationFailed("Failed to start passkey registration due to unknown error"));
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
const registrationResult = await app._interface.registerPasskey({ credential: attResp, code }, session);
|
|
1158
|
+
await app._refreshUser(session);
|
|
1159
|
+
return registrationResult;
|
|
973
1160
|
}
|
|
974
1161
|
};
|
|
975
1162
|
}
|
|
@@ -1652,10 +1839,22 @@ ${url}`);
|
|
|
1652
1839
|
});
|
|
1653
1840
|
}
|
|
1654
1841
|
async signOut(options) {
|
|
1655
|
-
const user = await this.getUser();
|
|
1842
|
+
const user = await this.getUser({ tokenStore: options?.tokenStore ?? void 0 });
|
|
1843
|
+
if (user) {
|
|
1844
|
+
await user.signOut({ redirectUrl: options?.redirectUrl });
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
async getAuthHeaders(options) {
|
|
1848
|
+
return {
|
|
1849
|
+
"x-stack-auth": JSON.stringify(await this.getAuthJson(options))
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
async getAuthJson(options) {
|
|
1853
|
+
const user = await this.getUser({ tokenStore: options?.tokenStore ?? void 0 });
|
|
1656
1854
|
if (user) {
|
|
1657
|
-
await user.
|
|
1855
|
+
return await user.getAuthJson();
|
|
1658
1856
|
}
|
|
1857
|
+
return { accessToken: null, refreshToken: null };
|
|
1659
1858
|
}
|
|
1660
1859
|
async getProject() {
|
|
1661
1860
|
const crud = import_results.Result.orThrow(await this._currentProjectCache.getOrWait([], "write-only"));
|