@stackframe/js 2.8.56 → 2.8.59

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.
Files changed (72) hide show
  1. package/dist/esm/index.js.map +1 -1
  2. package/dist/esm/integrations/convex/component/convex.config.js.map +1 -1
  3. package/dist/esm/integrations/convex.js.map +1 -1
  4. package/dist/esm/lib/auth.js.map +1 -1
  5. package/dist/esm/lib/cookie.js.map +1 -1
  6. package/dist/esm/lib/stack-app/api-keys/index.js.map +1 -1
  7. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js +235 -0
  8. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  9. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +133 -23
  10. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  11. package/dist/esm/lib/stack-app/apps/implementations/common.js +2 -1
  12. package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
  13. package/dist/esm/lib/stack-app/apps/implementations/index.js.map +1 -1
  14. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +31 -23
  15. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  16. package/dist/esm/lib/stack-app/apps/index.js.map +1 -1
  17. package/dist/esm/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
  18. package/dist/esm/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
  19. package/dist/esm/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
  20. package/dist/esm/lib/stack-app/common.js.map +1 -1
  21. package/dist/esm/lib/stack-app/contact-channels/index.js.map +1 -1
  22. package/dist/esm/lib/stack-app/email-templates/index.js.map +1 -1
  23. package/dist/esm/lib/stack-app/index.js.map +1 -1
  24. package/dist/esm/lib/stack-app/internal-api-keys/index.js.map +1 -1
  25. package/dist/esm/lib/stack-app/permissions/index.js.map +1 -1
  26. package/dist/esm/lib/stack-app/projects/index.js +4 -0
  27. package/dist/esm/lib/stack-app/projects/index.js.map +1 -1
  28. package/dist/esm/lib/stack-app/teams/index.js.map +1 -1
  29. package/dist/esm/lib/stack-app/users/index.js +13 -12
  30. package/dist/esm/lib/stack-app/users/index.js.map +1 -1
  31. package/dist/esm/utils/url.js.map +1 -1
  32. package/dist/index.d.mts +285 -17
  33. package/dist/index.d.ts +285 -17
  34. package/dist/index.js.map +1 -1
  35. package/dist/integrations/convex/component/convex.config.js.map +1 -1
  36. package/dist/integrations/convex.js.map +1 -1
  37. package/dist/lib/auth.js.map +1 -1
  38. package/dist/lib/cookie.js.map +1 -1
  39. package/dist/lib/stack-app/api-keys/index.js.map +1 -1
  40. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js +235 -0
  41. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  42. package/dist/lib/stack-app/apps/implementations/client-app-impl.js +132 -22
  43. package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  44. package/dist/lib/stack-app/apps/implementations/common.js +2 -1
  45. package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
  46. package/dist/lib/stack-app/apps/implementations/index.js.map +1 -1
  47. package/dist/lib/stack-app/apps/implementations/server-app-impl.js +29 -21
  48. package/dist/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  49. package/dist/lib/stack-app/apps/index.js.map +1 -1
  50. package/dist/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
  51. package/dist/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
  52. package/dist/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
  53. package/dist/lib/stack-app/common.js.map +1 -1
  54. package/dist/lib/stack-app/connected-accounts/index.js.map +1 -1
  55. package/dist/lib/stack-app/contact-channels/index.js.map +1 -1
  56. package/dist/lib/stack-app/customers/index.js.map +1 -1
  57. package/dist/lib/stack-app/data-vault/index.js.map +1 -1
  58. package/dist/lib/stack-app/email/index.js.map +1 -1
  59. package/dist/lib/stack-app/email-templates/index.js.map +1 -1
  60. package/dist/lib/stack-app/index.js.map +1 -1
  61. package/dist/lib/stack-app/internal-api-keys/index.js.map +1 -1
  62. package/dist/lib/stack-app/notification-categories/index.js.map +1 -1
  63. package/dist/lib/stack-app/permissions/index.js.map +1 -1
  64. package/dist/lib/stack-app/project-configs/index.js.map +1 -1
  65. package/dist/lib/stack-app/projects/index.js +4 -0
  66. package/dist/lib/stack-app/projects/index.js.map +1 -1
  67. package/dist/lib/stack-app/teams/index.js.map +1 -1
  68. package/dist/lib/stack-app/users/index.js +15 -14
  69. package/dist/lib/stack-app/users/index.js.map +1 -1
  70. package/dist/utils/url.js.map +1 -1
  71. package/package.json +14 -13
  72. package/CHANGELOG.md +0 -2072
package/dist/index.d.ts CHANGED
@@ -37,6 +37,15 @@ type RedirectMethod = "window" | "none" | {
37
37
  };
38
38
  type GetCurrentUserOptions<HasTokenStore> = {
39
39
  or?: 'redirect' | 'throw' | 'return-null' | 'anonymous' | /** @deprecated */ 'anonymous-if-exists[deprecated]';
40
+ /**
41
+ * Whether to include restricted users (users who haven't completed onboarding requirements like email verification).
42
+ * By default, restricted users are filtered out (treated similar to anonymous users).
43
+ *
44
+ * Note: This option cannot be set to false when `or: 'anonymous'` is used, as all anonymous users are also restricted.
45
+ *
46
+ * @default false
47
+ */
48
+ includeRestricted?: boolean;
40
49
  tokenStore?: TokenStoreInit;
41
50
  } & (HasTokenStore extends false ? {
42
51
  tokenStore: TokenStoreInit;
@@ -84,6 +93,7 @@ type HandlerUrls = {
84
93
  teamInvitation: string;
85
94
  mfa: string;
86
95
  error: string;
96
+ onboarding: string;
87
97
  };
88
98
  type OAuthScopesOnSignIn = {
89
99
  [key in ProviderType]: string[];
@@ -99,6 +109,20 @@ type AuthLike<ExtraOptions = {}> = {
99
109
  signOut(options?: {
100
110
  redirectUrl?: URL | string;
101
111
  }): Promise<void>;
112
+ /**
113
+ * Returns the current access token, or null if the user is not signed in.
114
+ *
115
+ * The access token is a short-lived JWT that can be used to authenticate requests to external servers.
116
+ * It will be automatically refreshed when it expires.
117
+ */
118
+ getAccessToken(options?: {} & ExtraOptions): Promise<string | null>;
119
+ /**
120
+ * Returns the current refresh token, or null if the user is not signed in.
121
+ *
122
+ * The refresh token is a long-lived token that can be used to obtain new access tokens.
123
+ * It should be kept secret and never exposed to the client.
124
+ */
125
+ getRefreshToken(options?: {} & ExtraOptions): Promise<string | null>;
102
126
  /**
103
127
  * Returns headers for sending authenticated HTTP requests to external servers. Most commonly used in cross-origin
104
128
  * requests. Similar to `getAuthJson`, but specifically for HTTP requests.
@@ -115,8 +139,8 @@ type AuthLike<ExtraOptions = {}> = {
115
139
  * must include `x-stack-auth` in the [`Access-Control-Allow-Headers` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers)
116
140
  * of the CORS preflight response.
117
141
  *
118
- * If you are not using HTTP (and hence cannot set headers), you will need to use the `getAuthJson()` function
119
- * instead.
142
+ * If you are not using HTTP (and hence cannot set headers), you will need to use the `getAccessToken()` and
143
+ * `getRefreshToken()` functions instead.
120
144
  *
121
145
  * Example:
122
146
  *
@@ -140,6 +164,8 @@ type AuthLike<ExtraOptions = {}> = {
140
164
  "x-stack-auth": string;
141
165
  }>;
142
166
  /**
167
+ * @deprecated Use `getAccessToken()` and `getRefreshToken()` instead.
168
+ *
143
169
  * Creates a JSON-serializable object containing the information to authenticate a user on an external server.
144
170
  * Similar to `getAuthHeaders`, but returns an object that can be sent over any protocol instead of just
145
171
  * HTTP headers.
@@ -208,6 +234,17 @@ type CustomerProduct = {
208
234
  customerType: "user" | "team" | "custom";
209
235
  isServerOnly: boolean;
210
236
  stackable: boolean;
237
+ type: "one_time" | "subscription";
238
+ subscription: null | {
239
+ currentPeriodEnd: Date | null;
240
+ cancelAtPeriodEnd: boolean;
241
+ isCancelable: boolean;
242
+ };
243
+ switchOptions?: Array<{
244
+ productId: string;
245
+ displayName: string;
246
+ prices: InlineProduct["prices"];
247
+ }>;
211
248
  };
212
249
  type CustomerProductsList = CustomerProduct[] & {
213
250
  nextCursor: string | null;
@@ -223,6 +260,21 @@ type CustomerProductsRequestOptions = ({
223
260
  } & CustomerProductsListOptions) | ({
224
261
  customCustomerId: string;
225
262
  } & CustomerProductsListOptions);
263
+ type CustomerDefaultPaymentMethod = {
264
+ id: string;
265
+ brand: string | null;
266
+ last4: string | null;
267
+ exp_month: number | null;
268
+ exp_year: number | null;
269
+ } | null;
270
+ type CustomerBilling = {
271
+ hasCustomer: boolean;
272
+ defaultPaymentMethod: CustomerDefaultPaymentMethod;
273
+ };
274
+ type CustomerPaymentMethodSetupIntent = {
275
+ clientSecret: string;
276
+ stripeAccountId: string;
277
+ };
226
278
  type Customer<IsServer extends boolean = false> = {
227
279
  readonly id: string;
228
280
  createCheckoutUrl(options: ({
@@ -232,7 +284,16 @@ type Customer<IsServer extends boolean = false> = {
232
284
  product: InlineProduct;
233
285
  returnUrl?: string;
234
286
  } : never))): Promise<string>;
235
- } & AsyncStoreProperty<"item", [
287
+ createPaymentMethodSetupIntent(): Promise<CustomerPaymentMethodSetupIntent>;
288
+ setDefaultPaymentMethodFromSetupIntent(setupIntentId: string): Promise<CustomerDefaultPaymentMethod>;
289
+ switchSubscription(options: {
290
+ fromProductId: string;
291
+ toProductId: string;
292
+ priceId?: string;
293
+ quantity?: number;
294
+ }): Promise<void>;
295
+ } & AsyncStoreProperty<"billing", [
296
+ ], CustomerBilling, false> & AsyncStoreProperty<"item", [
236
297
  itemId: string
237
298
  ], IsServer extends true ? ServerItem : Item, false> & AsyncStoreProperty<"products", [
238
299
  options?: CustomerProductsListOptions
@@ -254,6 +315,137 @@ type AdminSentEmail = {
254
315
  sentAt: Date;
255
316
  error?: unknown;
256
317
  };
318
+ type AdminEmailOutboxRecipient = {
319
+ type: "user-primary-email";
320
+ userId: string;
321
+ } | {
322
+ type: "user-custom-emails";
323
+ userId: string;
324
+ emails: string[];
325
+ } | {
326
+ type: "custom-emails";
327
+ emails: string[];
328
+ };
329
+ type AdminEmailOutboxStatus = "paused" | "preparing" | "rendering" | "render-error" | "scheduled" | "queued" | "sending" | "server-error" | "skipped" | "bounced" | "delivery-delayed" | "sent" | "opened" | "clicked" | "marked-as-spam";
330
+ type AdminEmailOutboxSimpleStatus = "in-progress" | "ok" | "error";
331
+ type AdminEmailOutboxBase = {
332
+ id: string;
333
+ createdAt: Date;
334
+ updatedAt: Date;
335
+ to: AdminEmailOutboxRecipient;
336
+ scheduledAt: Date;
337
+ isPaused: false;
338
+ hasRendered: false;
339
+ hasDelivered: false;
340
+ };
341
+ type AdminEmailOutboxRenderedFields = Omit<AdminEmailOutboxBase, "hasRendered"> & {
342
+ hasRendered: true;
343
+ startedRenderingAt: Date;
344
+ renderedAt: Date;
345
+ subject: string;
346
+ html: string | null;
347
+ text: string | null;
348
+ isTransactional: boolean;
349
+ isHighPriority: boolean;
350
+ notificationCategoryId: string | null;
351
+ };
352
+ type AdminEmailOutboxStartedSendingFields = AdminEmailOutboxRenderedFields & {
353
+ startedSendingAt: Date;
354
+ };
355
+ type AdminEmailOutboxFinishedDeliveringFields = Omit<AdminEmailOutboxStartedSendingFields, "hasDelivered"> & {
356
+ hasDelivered: true;
357
+ deliveredAt: Date;
358
+ };
359
+ type AdminEmailOutboxPaused = Omit<AdminEmailOutboxBase, "isPaused"> & {
360
+ status: "paused";
361
+ simpleStatus: "in-progress";
362
+ isPaused: true;
363
+ };
364
+ type AdminEmailOutboxPreparing = AdminEmailOutboxBase & {
365
+ status: "preparing";
366
+ simpleStatus: "in-progress";
367
+ };
368
+ type AdminEmailOutboxRendering = AdminEmailOutboxBase & {
369
+ status: "rendering";
370
+ simpleStatus: "in-progress";
371
+ startedRenderingAt: Date;
372
+ };
373
+ type AdminEmailOutboxRenderError = AdminEmailOutboxBase & {
374
+ status: "render-error";
375
+ simpleStatus: "error";
376
+ startedRenderingAt: Date;
377
+ renderedAt: Date;
378
+ renderError: string;
379
+ };
380
+ type AdminEmailOutboxScheduled = AdminEmailOutboxRenderedFields & {
381
+ status: "scheduled";
382
+ simpleStatus: "in-progress";
383
+ };
384
+ type AdminEmailOutboxQueued = AdminEmailOutboxRenderedFields & {
385
+ status: "queued";
386
+ simpleStatus: "in-progress";
387
+ };
388
+ type AdminEmailOutboxSending = AdminEmailOutboxStartedSendingFields & {
389
+ status: "sending";
390
+ simpleStatus: "in-progress";
391
+ };
392
+ type AdminEmailOutboxServerError = AdminEmailOutboxStartedSendingFields & {
393
+ status: "server-error";
394
+ simpleStatus: "error";
395
+ errorAt: Date;
396
+ serverError: string;
397
+ };
398
+ type AdminEmailOutboxSkipped = Omit<AdminEmailOutboxBase, "hasRendered"> & {
399
+ status: "skipped";
400
+ simpleStatus: "ok";
401
+ hasRendered: boolean;
402
+ skippedAt: Date;
403
+ skippedReason: string;
404
+ skippedDetails: Record<string, unknown>;
405
+ startedRenderingAt?: Date;
406
+ renderedAt?: Date;
407
+ subject?: string;
408
+ html?: string | null;
409
+ text?: string | null;
410
+ isTransactional?: boolean;
411
+ isHighPriority?: boolean;
412
+ notificationCategoryId?: string | null;
413
+ startedSendingAt?: Date;
414
+ };
415
+ type AdminEmailOutboxBounced = AdminEmailOutboxStartedSendingFields & {
416
+ status: "bounced";
417
+ simpleStatus: "error";
418
+ bouncedAt: Date;
419
+ };
420
+ type AdminEmailOutboxDeliveryDelayed = AdminEmailOutboxStartedSendingFields & {
421
+ status: "delivery-delayed";
422
+ simpleStatus: "ok";
423
+ deliveryDelayedAt: Date;
424
+ };
425
+ type AdminEmailOutboxSent = AdminEmailOutboxFinishedDeliveringFields & {
426
+ status: "sent";
427
+ simpleStatus: "ok";
428
+ canHaveDeliveryInfo: boolean;
429
+ };
430
+ type AdminEmailOutboxOpened = AdminEmailOutboxFinishedDeliveringFields & {
431
+ status: "opened";
432
+ simpleStatus: "ok";
433
+ openedAt: Date;
434
+ canHaveDeliveryInfo: true;
435
+ };
436
+ type AdminEmailOutboxClicked = AdminEmailOutboxFinishedDeliveringFields & {
437
+ status: "clicked";
438
+ simpleStatus: "ok";
439
+ clickedAt: Date;
440
+ canHaveDeliveryInfo: true;
441
+ };
442
+ type AdminEmailOutboxMarkedAsSpam = AdminEmailOutboxFinishedDeliveringFields & {
443
+ status: "marked-as-spam";
444
+ simpleStatus: "ok";
445
+ markedAsSpamAt: Date;
446
+ canHaveDeliveryInfo: true;
447
+ };
448
+ type AdminEmailOutbox = AdminEmailOutboxPaused | AdminEmailOutboxPreparing | AdminEmailOutboxRendering | AdminEmailOutboxRenderError | AdminEmailOutboxScheduled | AdminEmailOutboxQueued | AdminEmailOutboxSending | AdminEmailOutboxServerError | AdminEmailOutboxSkipped | AdminEmailOutboxBounced | AdminEmailOutboxDeliveryDelayed | AdminEmailOutboxSent | AdminEmailOutboxOpened | AdminEmailOutboxClicked | AdminEmailOutboxMarkedAsSpam;
257
449
  type SendEmailOptionsBase = {
258
450
  themeId?: string | null | false;
259
451
  subject?: string;
@@ -278,6 +470,25 @@ type SendEmailOptions = SendEmailOptionsBase & XOR<[
278
470
  draftId: string;
279
471
  }
280
472
  ]>;
473
+ type EmailDeliveryWindowStats = {
474
+ sent: number;
475
+ bounced: number;
476
+ marked_as_spam: number;
477
+ };
478
+ type EmailDeliveryStats = {
479
+ hour: EmailDeliveryWindowStats;
480
+ day: EmailDeliveryWindowStats;
481
+ week: EmailDeliveryWindowStats;
482
+ month: EmailDeliveryWindowStats;
483
+ };
484
+ type EmailDeliveryCapacity = {
485
+ rate_per_second: number;
486
+ penalty_factor: number;
487
+ };
488
+ type EmailDeliveryInfo = {
489
+ stats: EmailDeliveryStats;
490
+ capacity: EmailDeliveryCapacity;
491
+ };
281
492
 
282
493
  type InternalApiKeyBase = {
283
494
  id: string;
@@ -477,18 +688,17 @@ type ServerOAuthProvider = {
477
688
  }): Promise<Result<void, InstanceType<typeof KnownErrors.OAuthProviderAccountIdAlreadyUsedForSignIn>>>;
478
689
  delete(): Promise<void>;
479
690
  };
480
- type Session = {
481
- getTokens(): Promise<{
482
- accessToken: string | null;
483
- refreshToken: string | null;
484
- }>;
485
- };
486
691
  /**
487
692
  * Contains everything related to the current user session.
488
693
  */
489
694
  type Auth = AuthLike<{}> & {
490
695
  readonly _internalSession: InternalSession;
491
- readonly currentSession: Session;
696
+ readonly currentSession: {
697
+ getTokens(): Promise<{
698
+ accessToken: string | null;
699
+ refreshToken: string | null;
700
+ }>;
701
+ };
492
702
  };
493
703
  /**
494
704
  * ```
@@ -534,6 +744,18 @@ type BaseUser = {
534
744
  readonly passkeyAuthEnabled: boolean;
535
745
  readonly isMultiFactorRequired: boolean;
536
746
  readonly isAnonymous: boolean;
747
+ /**
748
+ * Whether the user is in restricted state (signed up but hasn't completed onboarding requirements).
749
+ * For example, if email verification is required but the user hasn't verified their email yet.
750
+ */
751
+ readonly isRestricted: boolean;
752
+ /**
753
+ * The reason why the user is restricted, e.g., { type: "email_not_verified" } or { type: "anonymous" }.
754
+ * Null if the user is not restricted.
755
+ */
756
+ readonly restrictedReason: {
757
+ type: "anonymous" | "email_not_verified";
758
+ } | null;
537
759
  toClientJson(): CurrentUserCrud["Client"]["Read"];
538
760
  /**
539
761
  * @deprecated, use contact channel's usedForAuth instead
@@ -547,7 +769,7 @@ type BaseUser = {
547
769
  }[];
548
770
  };
549
771
  type UserExtra = {
550
- setDisplayName(displayName: string): Promise<void>;
772
+ setDisplayName(displayName: string | null): Promise<void>;
551
773
  /** @deprecated Use contact channel's sendVerificationEmail instead */
552
774
  sendVerificationEmail(): Promise<KnownErrors["EmailAlreadyVerified"] | void>;
553
775
  setClientMetadata(metadata: any): Promise<void>;
@@ -585,7 +807,7 @@ type UserExtra = {
585
807
  recursive?: boolean;
586
808
  }): Promise<TeamPermission[]>;
587
809
  readonly selectedTeam: Team | null;
588
- setSelectedTeam(team: Team | null): Promise<void>;
810
+ setSelectedTeam(teamOrId: string | Team | null): Promise<void>;
589
811
  createTeam(data: TeamCreateOptions): Promise<Team>;
590
812
  leaveTeam(team: Team): Promise<void>;
591
813
  getActiveSessions(): Promise<ActiveSession[]>;
@@ -610,8 +832,8 @@ type User = BaseUser;
610
832
  type CurrentUser = BaseUser & Auth & UserExtra & Customer;
611
833
  type CurrentInternalUser = CurrentUser & InternalUserExtra;
612
834
  type ProjectCurrentUser<ProjectId> = ProjectId extends "internal" ? CurrentInternalUser : CurrentUser;
613
- type TokenPartialUser = Pick<User, "id" | "displayName" | "primaryEmail" | "primaryEmailVerified" | "isAnonymous">;
614
- type SyncedPartialUser = TokenPartialUser & Pick<User, "id" | "displayName" | "primaryEmail" | "primaryEmailVerified" | "profileImageUrl" | "signedUpAt" | "clientMetadata" | "clientReadOnlyMetadata" | "isAnonymous" | "hasPassword">;
835
+ type TokenPartialUser = Pick<User, "id" | "displayName" | "primaryEmail" | "primaryEmailVerified" | "isAnonymous" | "isRestricted" | "restrictedReason">;
836
+ type SyncedPartialUser = TokenPartialUser & Pick<User, "id" | "displayName" | "primaryEmail" | "primaryEmailVerified" | "profileImageUrl" | "signedUpAt" | "clientMetadata" | "clientReadOnlyMetadata" | "isAnonymous" | "hasPassword" | "isRestricted" | "restrictedReason">;
615
837
  type ActiveSession = {
616
838
  id: string;
617
839
  userId: string;
@@ -622,13 +844,14 @@ type ActiveSession = {
622
844
  geoInfo?: GeoInfo;
623
845
  };
624
846
  type UserUpdateOptions = {
625
- displayName?: string;
847
+ displayName?: string | null;
626
848
  clientMetadata?: ReadonlyJson;
627
849
  selectedTeamId?: string | null;
628
850
  totpMultiFactorSecret?: Uint8Array | null;
629
851
  profileImageUrl?: string | null;
630
852
  otpAuthEnabled?: boolean;
631
853
  passkeyAuthEnabled?: boolean;
854
+ primaryEmail?: string | null;
632
855
  };
633
856
  type ServerBaseUser = {
634
857
  setPrimaryEmail(email: string | null, options?: {
@@ -664,7 +887,12 @@ type ServerBaseUser = {
664
887
  createSession(options?: {
665
888
  expiresInMillis?: number;
666
889
  isImpersonation?: boolean;
667
- }): Promise<Session>;
890
+ }): Promise<{
891
+ getTokens(): Promise<{
892
+ accessToken: string | null;
893
+ refreshToken: string | null;
894
+ }>;
895
+ }>;
668
896
  } & AsyncStoreProperty<"team", [id: string], ServerTeam | null, false> & AsyncStoreProperty<"teams", [], ServerTeam[], true> & AsyncStoreProperty<"permission", [scope: Team, permissionId: string, options?: {
669
897
  direct?: boolean;
670
898
  }], AdminTeamPermission | null, false> & AsyncStoreProperty<"permissions", [scope: Team, options?: {
@@ -768,6 +996,15 @@ type ServerListUsersOptions = {
768
996
  orderBy?: 'signedUpAt';
769
997
  desc?: boolean;
770
998
  query?: string;
999
+ /**
1000
+ * Whether to include restricted users (users who haven't completed onboarding requirements).
1001
+ * Defaults to false.
1002
+ */
1003
+ includeRestricted?: boolean;
1004
+ /**
1005
+ * Whether to include anonymous users (and restricted users).
1006
+ * Defaults to false.
1007
+ */
771
1008
  includeAnonymous?: boolean;
772
1009
  };
773
1010
  type ServerTeamCreateOptions = TeamCreateOptions & {
@@ -848,6 +1085,7 @@ type StackServerApp<HasTokenStore extends boolean = boolean, ProjectId extends s
848
1085
  allowConnectedAccounts: boolean;
849
1086
  }): Promise<Result<ServerOAuthProvider, InstanceType<typeof KnownErrors.OAuthProviderAccountIdAlreadyUsedForSignIn>>>;
850
1087
  sendEmail(options: SendEmailOptions): Promise<void>;
1088
+ getEmailDeliveryStats(): Promise<EmailDeliveryInfo>;
851
1089
  } & AsyncStoreProperty<"user", [id: string], ServerUser | null, false> & Omit<AsyncStoreProperty<"users", [], ServerUser[], true>, "listUsers" | "useUsers"> & AsyncStoreProperty<"teams", [], ServerTeam[], true> & AsyncStoreProperty<"dataVaultStore", [id: string], DataVaultStore, false> & AsyncStoreProperty<"item", [
852
1090
  {
853
1091
  itemId: string;
@@ -864,6 +1102,21 @@ type StackServerApp<HasTokenStore extends boolean = boolean, ProjectId extends s
864
1102
  ], CustomerProductsList, true> & StackClientApp<HasTokenStore, ProjectId>);
865
1103
  declare const StackServerApp: StackServerAppConstructor;
866
1104
 
1105
+ type EmailOutboxListOptions = {
1106
+ status?: string;
1107
+ simpleStatus?: string;
1108
+ limit?: number;
1109
+ cursor?: string;
1110
+ };
1111
+ type EmailOutboxListResult = {
1112
+ items: AdminEmailOutbox[];
1113
+ nextCursor: string | null;
1114
+ };
1115
+ type EmailOutboxUpdateOptions = {
1116
+ isPaused?: boolean;
1117
+ scheduledAtMillis?: number;
1118
+ cancel?: boolean;
1119
+ };
867
1120
  type StackAdminAppConstructorOptions<HasTokenStore extends boolean, ProjectId extends string> = (StackServerAppConstructorOptions<HasTokenStore, ProjectId> & {
868
1121
  superSecretAdminKey?: string;
869
1122
  projectOwnerSession?: InternalSession;
@@ -988,6 +1241,12 @@ type StackAdminApp<HasTokenStore extends boolean = boolean, ProjectId extends st
988
1241
  type: "subscription" | "one-time-purchase";
989
1242
  id: string;
990
1243
  }): Promise<void>;
1244
+ listOutboxEmails(options?: EmailOutboxListOptions): Promise<EmailOutboxListResult>;
1245
+ getOutboxEmail(id: string): Promise<AdminEmailOutbox>;
1246
+ updateOutboxEmail(id: string, options: EmailOutboxUpdateOptions): Promise<AdminEmailOutbox>;
1247
+ pauseOutboxEmail(id: string): Promise<AdminEmailOutbox>;
1248
+ unpauseOutboxEmail(id: string): Promise<AdminEmailOutbox>;
1249
+ cancelOutboxEmail(id: string): Promise<AdminEmailOutbox>;
991
1250
  } & StackServerApp<HasTokenStore, ProjectId>);
992
1251
  declare const StackAdminApp: StackAdminAppConstructor;
993
1252
 
@@ -1005,6 +1264,9 @@ type ProjectConfig = {
1005
1264
  type OAuthProviderConfig = {
1006
1265
  readonly id: string;
1007
1266
  };
1267
+ /**
1268
+ * @deprecated This type is deprecated. Use the new config override setup instead.
1269
+ */
1008
1270
  type AdminProjectConfig = {
1009
1271
  readonly signUpEnabled: boolean;
1010
1272
  readonly credentialEnabled: boolean;
@@ -1238,6 +1500,12 @@ type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId extends s
1238
1500
  or: 'anonymous';
1239
1501
  }): Promise<ProjectCurrentUser<ProjectId>>;
1240
1502
  getUser(options?: GetCurrentUserOptions<HasTokenStore>): Promise<ProjectCurrentUser<ProjectId> | null>;
1503
+ cancelSubscription(options: {
1504
+ productId: string;
1505
+ } | {
1506
+ productId: string;
1507
+ teamId: string;
1508
+ }): Promise<void>;
1241
1509
  getPartialUser(options: GetCurrentPartialUserOptions<HasTokenStore> & {
1242
1510
  from: 'token';
1243
1511
  }): Promise<TokenPartialUser | null>;
@@ -1274,4 +1542,4 @@ type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId extends s
1274
1542
  }>);
1275
1543
  declare const StackClientApp: StackClientAppConstructor;
1276
1544
 
1277
- export { type AdminDomainConfig, type AdminEmailConfig, type AdminOAuthProviderConfig, type AdminOwnedProject, type AdminProject, type AdminProjectConfig, type AdminProjectConfigUpdateOptions, type AdminProjectCreateOptions, type AdminProjectPermission, type AdminProjectPermissionDefinition, type AdminProjectPermissionDefinitionCreateOptions, type AdminProjectPermissionDefinitionUpdateOptions, type AdminProjectUpdateOptions, type AdminSentEmail, type AdminTeamPermission, type AdminTeamPermissionDefinition, type AdminTeamPermissionDefinitionCreateOptions, type AdminTeamPermissionDefinitionUpdateOptions, type Auth, type Connection, type ContactChannel, type CurrentInternalServerUser, type CurrentInternalUser, type CurrentServerUser, type CurrentUser, type EditableTeamMemberProfile, type GetCurrentUserOptions, type GetCurrentUserOptions as GetUserOptions, type HandlerUrls, type InternalApiKey, type InternalApiKeyBase, type InternalApiKeyBaseCrudRead, type InternalApiKeyCreateOptions, type InternalApiKeyFirstView, type OAuthConnection, type OAuthProvider, type OAuthProviderConfig, type OAuthScopesOnSignIn, type Project, type ProjectConfig, type ServerContactChannel, type ServerListUsersOptions, type ServerOAuthProvider, type ServerTeam, type ServerTeamCreateOptions, type ServerTeamMemberProfile, type ServerTeamUpdateOptions, type ServerTeamUser, type ServerUser, type Session, StackAdminApp, type StackAdminAppConstructor, type StackAdminAppConstructorOptions, StackClientApp, type StackClientAppConstructor, type StackClientAppConstructorOptions, type StackClientAppJson, StackServerApp, type StackServerAppConstructor, type StackServerAppConstructorOptions, type Team, type TeamCreateOptions, type TeamInvitation, type TeamMemberProfile, type TeamUpdateOptions, type TeamUser, type User, stackAppInternalsSymbol };
1545
+ export { type AdminDomainConfig, type AdminEmailConfig, type AdminEmailOutbox, type AdminEmailOutboxRecipient, type AdminEmailOutboxSimpleStatus, type AdminEmailOutboxStatus, type AdminOAuthProviderConfig, type AdminOwnedProject, type AdminProject, type AdminProjectConfig, type AdminProjectConfigUpdateOptions, type AdminProjectCreateOptions, type AdminProjectPermission, type AdminProjectPermissionDefinition, type AdminProjectPermissionDefinitionCreateOptions, type AdminProjectPermissionDefinitionUpdateOptions, type AdminProjectUpdateOptions, type AdminSentEmail, type AdminTeamPermission, type AdminTeamPermissionDefinition, type AdminTeamPermissionDefinitionCreateOptions, type AdminTeamPermissionDefinitionUpdateOptions, type Auth, type Connection, type ContactChannel, type CurrentInternalServerUser, type CurrentInternalUser, type CurrentServerUser, type CurrentUser, type EditableTeamMemberProfile, type EmailOutboxListOptions, type EmailOutboxListResult, type EmailOutboxUpdateOptions, type GetCurrentUserOptions, type GetCurrentUserOptions as GetUserOptions, type HandlerUrls, type InternalApiKey, type InternalApiKeyBase, type InternalApiKeyBaseCrudRead, type InternalApiKeyCreateOptions, type InternalApiKeyFirstView, type OAuthConnection, type OAuthProvider, type OAuthProviderConfig, type OAuthScopesOnSignIn, type Project, type ProjectConfig, type ServerContactChannel, type ServerListUsersOptions, type ServerOAuthProvider, type ServerTeam, type ServerTeamCreateOptions, type ServerTeamMemberProfile, type ServerTeamUpdateOptions, type ServerTeamUser, type ServerUser, StackAdminApp, type StackAdminAppConstructor, type StackAdminAppConstructorOptions, StackClientApp, type StackClientAppConstructor, type StackClientAppConstructorOptions, type StackClientAppJson, StackServerApp, type StackServerAppConstructor, type StackServerAppConstructorOptions, type Team, type TeamCreateOptions, type TeamInvitation, type TeamMemberProfile, type TeamUpdateOptions, type TeamUser, type User, stackAppInternalsSymbol };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nexport * from './lib/stack-app';\n\nexport { getConvexProvidersConfig } from \"./integrations/convex\";\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,0BAAc,qCAJd;AAMA,oBAAyC;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nexport * from './lib/stack-app';\n\nexport { getConvexProvidersConfig } from \"./integrations/convex\";\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,0BAAc,qCAJd;AAMA,oBAAyC;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/integrations/convex/component/convex.config.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { defineComponent } from \"convex/server\";\n\nconst component = defineComponent(\"stack_auth\");\n\nexport default component;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,oBAAgC;AAEhC,IAAM,gBAAY,+BAAgB,YAAY;AAE9C,IAAO,wBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../../src/integrations/convex/component/convex.config.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { defineComponent } from \"convex/server\";\n\nconst component = defineComponent(\"stack_auth\");\n\nexport default component;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,oBAAgC;AAEhC,IAAM,gBAAY,+BAAgB,YAAY;AAE9C,IAAO,wBAAQ;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/integrations/convex.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { urlString } from \"@stackframe/stack-shared/dist/utils/urls\";\nimport { defaultBaseUrl } from \"../lib/stack-app/apps/implementations/common\";\n\nexport function getConvexProvidersConfig(options: {\n baseUrl?: string,\n projectId: string,\n}) {\n const baseUrl = options.baseUrl || defaultBaseUrl;\n const projectId = options.projectId;\n return [\n {\n type: \"customJwt\",\n issuer: new URL(urlString`/api/v1/projects/${projectId}`, baseUrl),\n jwks: new URL(urlString`/api/v1/projects/${projectId}/.well-known/jwks.json`, baseUrl),\n algorithm: \"ES256\",\n },\n {\n type: \"customJwt\",\n issuer: new URL(urlString`/api/v1/projects-anonymous-users/${projectId}`, baseUrl),\n jwks: new URL(urlString`/api/v1/projects/${projectId}/.well-known/jwks.json?include_anonymous=true`, baseUrl),\n algorithm: \"ES256\",\n },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,kBAA0B;AAC1B,oBAA+B;AAExB,SAAS,yBAAyB,SAGtC;AACD,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,YAAY,QAAQ;AAC1B,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,QAAQ,IAAI,IAAI,yCAA6B,SAAS,IAAI,OAAO;AAAA,MACjE,MAAM,IAAI,IAAI,yCAA6B,SAAS,0BAA0B,OAAO;AAAA,MACrF,WAAW;AAAA,IACb;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,QAAQ,IAAI,IAAI,yDAA6C,SAAS,IAAI,OAAO;AAAA,MACjF,MAAM,IAAI,IAAI,yCAA6B,SAAS,iDAAiD,OAAO;AAAA,MAC5G,WAAW;AAAA,IACb;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/integrations/convex.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { urlString } from \"@stackframe/stack-shared/dist/utils/urls\";\nimport { defaultBaseUrl } from \"../lib/stack-app/apps/implementations/common\";\n\nexport function getConvexProvidersConfig(options: {\n baseUrl?: string,\n projectId: string,\n}) {\n const baseUrl = options.baseUrl || defaultBaseUrl;\n const projectId = options.projectId;\n return [\n {\n type: \"customJwt\",\n issuer: new URL(urlString`/api/v1/projects/${projectId}`, baseUrl),\n jwks: new URL(urlString`/api/v1/projects/${projectId}/.well-known/jwks.json`, baseUrl),\n algorithm: \"ES256\",\n },\n {\n type: \"customJwt\",\n issuer: new URL(urlString`/api/v1/projects-anonymous-users/${projectId}`, baseUrl),\n jwks: new URL(urlString`/api/v1/projects/${projectId}/.well-known/jwks.json?include_anonymous=true`, baseUrl),\n algorithm: \"ES256\",\n },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,kBAA0B;AAC1B,oBAA+B;AAExB,SAAS,yBAAyB,SAGtC;AACD,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,YAAY,QAAQ;AAC1B,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,QAAQ,IAAI,IAAI,yCAA6B,SAAS,IAAI,OAAO;AAAA,MACjE,MAAM,IAAI,IAAI,yCAA6B,SAAS,0BAA0B,OAAO;AAAA,MACrF,WAAW;AAAA,IACb;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,QAAQ,IAAI,IAAI,yDAA6C,SAAS,IAAI,OAAO;AAAA,MACjF,MAAM,IAAI,IAAI,yCAA6B,SAAS,iDAAiD,OAAO;AAAA,MAC5G,WAAW;AAAA,IACb;AAAA,EACF;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/auth.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { KnownError, StackClientInterface } from \"@stackframe/stack-shared\";\nimport { InternalSession } from \"@stackframe/stack-shared/dist/sessions\";\nimport { StackAssertionError, throwErr } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { neverResolve } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport { deindent } from \"@stackframe/stack-shared/dist/utils/strings\";\nimport { constructRedirectUrl } from \"../utils/url\";\nimport { consumeVerifierAndStateCookie, saveVerifierAndState } from \"./cookie\";\n\nexport async function signInWithOAuth(\n iface: StackClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n },\n session: InternalSession,\n) {\n const { codeChallenge, state } = await saveVerifierAndState();\n const location = await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl, \"redirectUrl\"),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl, \"errorRedirectUrl\"),\n codeChallenge,\n state,\n type: \"authenticate\",\n providerScope: options.providerScope,\n session,\n });\n window.location.assign(location);\n await neverResolve();\n}\n\nexport async function addNewOAuthProviderOrScope(\n iface: StackClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n },\n session: InternalSession,\n) {\n const { codeChallenge, state } = await saveVerifierAndState();\n const location = await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl, \"redirectUrl\"),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl, \"errorRedirectUrl\"),\n afterCallbackRedirectUrl: constructRedirectUrl(window.location.href, \"afterCallbackRedirectUrl\"),\n codeChallenge,\n state,\n type: \"link\",\n session,\n providerScope: options.providerScope,\n });\n window.location.assign(location);\n await neverResolve();\n}\n\n/**\n * Checks if the current URL has the query parameters for an OAuth callback, and if so, removes them.\n *\n * Must be synchronous for the logic in callOAuthCallback to work without race conditions.\n */\nfunction consumeOAuthCallbackQueryParams() {\n const requiredParams = [\"code\", \"state\"];\n const originalUrl = new URL(window.location.href);\n for (const param of requiredParams) {\n if (!originalUrl.searchParams.has(param)) {\n console.warn(new Error(`Missing required query parameter on OAuth callback: ${param}. Maybe you opened or reloaded the oauth-callback page from your history?`));\n return null;\n }\n }\n\n const expectedState = originalUrl.searchParams.get(\"state\") ?? throwErr(\"This should never happen; isn't state required above?\");\n const cookieResult = consumeVerifierAndStateCookie(expectedState);\n\n if (!cookieResult) {\n // If the state can't be found in the cookies, then the callback wasn't meant for us.\n // Maybe the website uses another OAuth library?\n console.warn(deindent`\n Stack found an outer OAuth callback state in the query parameters, but not in cookies.\n \n This could have multiple reasons:\n - The cookie expired, because the OAuth flow took too long.\n - The user's browser deleted the cookie, either manually or because of a very strict cookie policy.\n - The cookie was already consumed by this page, and the user already logged in.\n - You are using another OAuth client library with the same callback URL as Stack.\n - The user opened the OAuth callback page from their history.\n\n Either way, it is probably safe to ignore this warning unless you are debugging an OAuth issue.\n `);\n return null;\n }\n\n\n const newUrl = new URL(originalUrl);\n for (const param of requiredParams) {\n newUrl.searchParams.delete(param);\n }\n\n // let's get rid of the authorization code in the history as we\n // don't redirect to `redirectUrl` if there's a validation error\n // (as the redirectUrl might be malicious!).\n //\n // We use history.replaceState instead of location.assign(...) to\n // prevent an unnecessary reload\n window.history.replaceState({}, \"\", newUrl.toString());\n\n return {\n originalUrl,\n codeVerifier: cookieResult.codeVerifier,\n state: expectedState,\n };\n}\n\nexport async function callOAuthCallback(\n iface: StackClientInterface,\n redirectUrl: string,\n) {\n // note: this part of the function (until the return) needs\n // to be synchronous, to prevent race conditions when\n // callOAuthCallback is called multiple times in parallel\n const consumed = consumeOAuthCallbackQueryParams();\n if (!consumed) return Result.ok(undefined);\n\n // the rest can be asynchronous (we now know that we are the\n // intended recipient of the callback, and the only instance\n // of callOAuthCallback that's running)\n try {\n return Result.ok(await iface.callOAuthCallback({\n oauthParams: consumed.originalUrl.searchParams,\n redirectUri: constructRedirectUrl(redirectUrl, \"redirectUri\"),\n codeVerifier: consumed.codeVerifier,\n state: consumed.state,\n }));\n } catch (e) {\n if (KnownError.isKnownError(e)) {\n throw e;\n }\n throw new StackAssertionError(\"Error signing in during OAuth callback. Please try again.\", { cause: e });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,0BAAiD;AAEjD,oBAA8C;AAC9C,sBAA6B;AAC7B,qBAAuB;AACvB,qBAAyB;AACzB,iBAAqC;AACrC,oBAAoE;AAEpE,eAAsB,gBACpB,OACA,SAMA,SACA;AACA,QAAM,EAAE,eAAe,MAAM,IAAI,UAAM,oCAAqB;AAC5D,QAAM,WAAW,MAAM,MAAM,YAAY;AAAA,IACvC,UAAU,QAAQ;AAAA,IAClB,iBAAa,iCAAqB,QAAQ,aAAa,aAAa;AAAA,IACpE,sBAAkB,iCAAqB,QAAQ,kBAAkB,kBAAkB;AAAA,IACnF;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,eAAe,QAAQ;AAAA,IACvB;AAAA,EACF,CAAC;AACD,SAAO,SAAS,OAAO,QAAQ;AAC/B,YAAM,8BAAa;AACrB;AAEA,eAAsB,2BACpB,OACA,SAMA,SACA;AACA,QAAM,EAAE,eAAe,MAAM,IAAI,UAAM,oCAAqB;AAC5D,QAAM,WAAW,MAAM,MAAM,YAAY;AAAA,IACvC,UAAU,QAAQ;AAAA,IAClB,iBAAa,iCAAqB,QAAQ,aAAa,aAAa;AAAA,IACpE,sBAAkB,iCAAqB,QAAQ,kBAAkB,kBAAkB;AAAA,IACnF,8BAA0B,iCAAqB,OAAO,SAAS,MAAM,0BAA0B;AAAA,IAC/F;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,eAAe,QAAQ;AAAA,EACzB,CAAC;AACD,SAAO,SAAS,OAAO,QAAQ;AAC/B,YAAM,8BAAa;AACrB;AAOA,SAAS,kCAAkC;AACzC,QAAM,iBAAiB,CAAC,QAAQ,OAAO;AACvC,QAAM,cAAc,IAAI,IAAI,OAAO,SAAS,IAAI;AAChD,aAAW,SAAS,gBAAgB;AAClC,QAAI,CAAC,YAAY,aAAa,IAAI,KAAK,GAAG;AACxC,cAAQ,KAAK,IAAI,MAAM,uDAAuD,KAAK,2EAA2E,CAAC;AAC/J,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,gBAAgB,YAAY,aAAa,IAAI,OAAO,SAAK,wBAAS,uDAAuD;AAC/H,QAAM,mBAAe,6CAA8B,aAAa;AAEhE,MAAI,CAAC,cAAc;AAGjB,YAAQ,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAWZ;AACD,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,IAAI,IAAI,WAAW;AAClC,aAAW,SAAS,gBAAgB;AAClC,WAAO,aAAa,OAAO,KAAK;AAAA,EAClC;AAQA,SAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,OAAO,SAAS,CAAC;AAErD,SAAO;AAAA,IACL;AAAA,IACA,cAAc,aAAa;AAAA,IAC3B,OAAO;AAAA,EACT;AACF;AAEA,eAAsB,kBACpB,OACA,aACA;AAIA,QAAM,WAAW,gCAAgC;AACjD,MAAI,CAAC,SAAU,QAAO,sBAAO,GAAG,MAAS;AAKzC,MAAI;AACF,WAAO,sBAAO,GAAG,MAAM,MAAM,kBAAkB;AAAA,MAC7C,aAAa,SAAS,YAAY;AAAA,MAClC,iBAAa,iCAAqB,aAAa,aAAa;AAAA,MAC5D,cAAc,SAAS;AAAA,MACvB,OAAO,SAAS;AAAA,IAClB,CAAC,CAAC;AAAA,EACJ,SAAS,GAAG;AACV,QAAI,+BAAW,aAAa,CAAC,GAAG;AAC9B,YAAM;AAAA,IACR;AACA,UAAM,IAAI,kCAAoB,6DAA6D,EAAE,OAAO,EAAE,CAAC;AAAA,EACzG;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/lib/auth.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { KnownError, StackClientInterface } from \"@stackframe/stack-shared\";\nimport { InternalSession } from \"@stackframe/stack-shared/dist/sessions\";\nimport { StackAssertionError, throwErr } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { neverResolve } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport { deindent } from \"@stackframe/stack-shared/dist/utils/strings\";\nimport { constructRedirectUrl } from \"../utils/url\";\nimport { consumeVerifierAndStateCookie, saveVerifierAndState } from \"./cookie\";\n\nexport async function signInWithOAuth(\n iface: StackClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n },\n session: InternalSession,\n) {\n const { codeChallenge, state } = await saveVerifierAndState();\n const location = await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl, \"redirectUrl\"),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl, \"errorRedirectUrl\"),\n codeChallenge,\n state,\n type: \"authenticate\",\n providerScope: options.providerScope,\n session,\n });\n window.location.assign(location);\n await neverResolve();\n}\n\nexport async function addNewOAuthProviderOrScope(\n iface: StackClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n },\n session: InternalSession,\n) {\n const { codeChallenge, state } = await saveVerifierAndState();\n const location = await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl, \"redirectUrl\"),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl, \"errorRedirectUrl\"),\n afterCallbackRedirectUrl: constructRedirectUrl(window.location.href, \"afterCallbackRedirectUrl\"),\n codeChallenge,\n state,\n type: \"link\",\n session,\n providerScope: options.providerScope,\n });\n window.location.assign(location);\n await neverResolve();\n}\n\n/**\n * Checks if the current URL has the query parameters for an OAuth callback, and if so, removes them.\n *\n * Must be synchronous for the logic in callOAuthCallback to work without race conditions.\n */\nfunction consumeOAuthCallbackQueryParams() {\n const requiredParams = [\"code\", \"state\"];\n const originalUrl = new URL(window.location.href);\n for (const param of requiredParams) {\n if (!originalUrl.searchParams.has(param)) {\n console.warn(new Error(`Missing required query parameter on OAuth callback: ${param}. Maybe you opened or reloaded the oauth-callback page from your history?`));\n return null;\n }\n }\n\n const expectedState = originalUrl.searchParams.get(\"state\") ?? throwErr(\"This should never happen; isn't state required above?\");\n const cookieResult = consumeVerifierAndStateCookie(expectedState);\n\n if (!cookieResult) {\n // If the state can't be found in the cookies, then the callback wasn't meant for us.\n // Maybe the website uses another OAuth library?\n console.warn(deindent`\n Stack found an outer OAuth callback state in the query parameters, but not in cookies.\n \n This could have multiple reasons:\n - The cookie expired, because the OAuth flow took too long.\n - The user's browser deleted the cookie, either manually or because of a very strict cookie policy.\n - The cookie was already consumed by this page, and the user already logged in.\n - You are using another OAuth client library with the same callback URL as Stack.\n - The user opened the OAuth callback page from their history.\n\n Either way, it is probably safe to ignore this warning unless you are debugging an OAuth issue.\n `);\n return null;\n }\n\n\n const newUrl = new URL(originalUrl);\n for (const param of requiredParams) {\n newUrl.searchParams.delete(param);\n }\n\n // let's get rid of the authorization code in the history as we\n // don't redirect to `redirectUrl` if there's a validation error\n // (as the redirectUrl might be malicious!).\n //\n // We use history.replaceState instead of location.assign(...) to\n // prevent an unnecessary reload\n window.history.replaceState({}, \"\", newUrl.toString());\n\n return {\n originalUrl,\n codeVerifier: cookieResult.codeVerifier,\n state: expectedState,\n };\n}\n\nexport async function callOAuthCallback(\n iface: StackClientInterface,\n redirectUrl: string,\n) {\n // note: this part of the function (until the return) needs\n // to be synchronous, to prevent race conditions when\n // callOAuthCallback is called multiple times in parallel\n const consumed = consumeOAuthCallbackQueryParams();\n if (!consumed) return Result.ok(undefined);\n\n // the rest can be asynchronous (we now know that we are the\n // intended recipient of the callback, and the only instance\n // of callOAuthCallback that's running)\n try {\n return Result.ok(await iface.callOAuthCallback({\n oauthParams: consumed.originalUrl.searchParams,\n redirectUri: constructRedirectUrl(redirectUrl, \"redirectUri\"),\n codeVerifier: consumed.codeVerifier,\n state: consumed.state,\n }));\n } catch (e) {\n if (KnownError.isKnownError(e)) {\n throw e;\n }\n throw new StackAssertionError(\"Error signing in during OAuth callback. Please try again.\", { cause: e });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,0BAAiD;AAEjD,oBAA8C;AAC9C,sBAA6B;AAC7B,qBAAuB;AACvB,qBAAyB;AACzB,iBAAqC;AACrC,oBAAoE;AAEpE,eAAsB,gBACpB,OACA,SAMA,SACA;AACA,QAAM,EAAE,eAAe,MAAM,IAAI,UAAM,oCAAqB;AAC5D,QAAM,WAAW,MAAM,MAAM,YAAY;AAAA,IACvC,UAAU,QAAQ;AAAA,IAClB,iBAAa,iCAAqB,QAAQ,aAAa,aAAa;AAAA,IACpE,sBAAkB,iCAAqB,QAAQ,kBAAkB,kBAAkB;AAAA,IACnF;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,eAAe,QAAQ;AAAA,IACvB;AAAA,EACF,CAAC;AACD,SAAO,SAAS,OAAO,QAAQ;AAC/B,YAAM,8BAAa;AACrB;AAEA,eAAsB,2BACpB,OACA,SAMA,SACA;AACA,QAAM,EAAE,eAAe,MAAM,IAAI,UAAM,oCAAqB;AAC5D,QAAM,WAAW,MAAM,MAAM,YAAY;AAAA,IACvC,UAAU,QAAQ;AAAA,IAClB,iBAAa,iCAAqB,QAAQ,aAAa,aAAa;AAAA,IACpE,sBAAkB,iCAAqB,QAAQ,kBAAkB,kBAAkB;AAAA,IACnF,8BAA0B,iCAAqB,OAAO,SAAS,MAAM,0BAA0B;AAAA,IAC/F;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,eAAe,QAAQ;AAAA,EACzB,CAAC;AACD,SAAO,SAAS,OAAO,QAAQ;AAC/B,YAAM,8BAAa;AACrB;AAOA,SAAS,kCAAkC;AACzC,QAAM,iBAAiB,CAAC,QAAQ,OAAO;AACvC,QAAM,cAAc,IAAI,IAAI,OAAO,SAAS,IAAI;AAChD,aAAW,SAAS,gBAAgB;AAClC,QAAI,CAAC,YAAY,aAAa,IAAI,KAAK,GAAG;AACxC,cAAQ,KAAK,IAAI,MAAM,uDAAuD,KAAK,2EAA2E,CAAC;AAC/J,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,gBAAgB,YAAY,aAAa,IAAI,OAAO,SAAK,wBAAS,uDAAuD;AAC/H,QAAM,mBAAe,6CAA8B,aAAa;AAEhE,MAAI,CAAC,cAAc;AAGjB,YAAQ,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAWZ;AACD,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,IAAI,IAAI,WAAW;AAClC,aAAW,SAAS,gBAAgB;AAClC,WAAO,aAAa,OAAO,KAAK;AAAA,EAClC;AAQA,SAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,OAAO,SAAS,CAAC;AAErD,SAAO;AAAA,IACL;AAAA,IACA,cAAc,aAAa;AAAA,IAC3B,OAAO;AAAA,EACT;AACF;AAEA,eAAsB,kBACpB,OACA,aACA;AAIA,QAAM,WAAW,gCAAgC;AACjD,MAAI,CAAC,SAAU,QAAO,sBAAO,GAAG,MAAS;AAKzC,MAAI;AACF,WAAO,sBAAO,GAAG,MAAM,MAAM,kBAAkB;AAAA,MAC7C,aAAa,SAAS,YAAY;AAAA,MAClC,iBAAa,iCAAqB,aAAa,aAAa;AAAA,MAC5D,cAAc,SAAS;AAAA,MACvB,OAAO,SAAS;AAAA,IAClB,CAAC,CAAC;AAAA,EACJ,SAAS,GAAG;AACV,QAAI,+BAAW,aAAa,CAAC,GAAG;AAC9B,YAAM;AAAA,IACR;AACA,UAAM,IAAI,kCAAoB,6DAA6D,EAAE,OAAO,EAAE,CAAC;AAAA,EACzG;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/cookie.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { isBrowserLike } from '@stackframe/stack-shared/dist/utils/env';\nimport { StackAssertionError } from '@stackframe/stack-shared/dist/utils/errors';\nimport Cookies from \"js-cookie\";\nimport { calculatePKCECodeChallenge, generateRandomCodeVerifier, generateRandomState } from \"oauth4webapi\";\n\n\n// INFO: This file is used to manage cookies. It also sets some cookie flags automatically, see this description.\n//\n// It provides asynchronous setCookie, getCookie, deleteCookie, etc. functions that can be used in various environments\n// (browser + Next.js for now). Under the hood, they just get a CookieHelper object and then set the cookies there.\n//\n// The CookieHelper object is a simple object that lets you set, get and delete cookies synchronously. Acquiring one\n// is asynchronous (except for browser environments, where they can be acquired synchronously), but once you have it,\n// you can use it synchronously. This function is useful if you cannot await in the calling code, but otherwise you\n// should prefer to await the functions directly.\n//\n// Some cookie flags are set automatically by the CookieHelper (and hence also the <xyz>Cookie functions).\n// In particular:\n// - SameSite is set to `Lax` by default, which is already true in Chromium-based browsers, so this creates\n// compatibility with other browsers that use either Strict or None (particularly Safari and Firefox, and older\n// versions of Chrome). If Partitioned is automatically set (as described below), then this value is set to `None`\n// instead.\n// - Secure is set depending on whether we could successfully determine that the client is on HTTPS. For this, we use a\n// set of heuristics:\n// - In a browser environment, we check window.location.protocol which is always accurate\n// - In a Next.js server environment:\n// - First we check the `stack-is-https` cookie, which is set in various places on the\n// client with a Secure attribute. If that one is passed on to the server, we know that the client is on HTTPS\n// and we can set the Secure flag on the cookie. TODO: Should we also do this with a second cookie with a\n// __Host- prefix, so a malicious subdomain of the current domain cannot forcibly enable HTTPS mode and\n// therefore prevent new cookies from being set?\n// - Otherwise, we check the X-Forwarded-Proto header. If that one is `https`, we know that the client is\n// (pretending to be) on HTTPS and we can set the Secure flag on the cookie. Note that this header is\n// spoofable by malicious clients (so is the cookie actually), but since setting this value can only *increase*\n// security (and therefore prevent setting of a cookie), and requires a malicious client, this is still safe.\n// - If neither of the above is true, we don't set the Secure flag on the cookie.\n// - Partitioned is set depending on whether it is needed & supported. Unfortunately, the fact that Partitioned\n// cookies require SameSite=None, browsers that don't support it will still set them as normal third-party cookies,\n// which are fundamentally unsafe. Therefore, we need to take extra care that we only ever set Partitioned cookies\n// if we know for sure that the browser supports it.\n// - In a browser environment, we check:\n// - Whether `Secure` is set. If it's not, we don't set Partitioned.\n// - Whether we can set & retrieve cookies without Partitioned being set. If this is the case, we are likely in a\n// top-level context or a browser that partitions cookies by default (eg. Firefox). In this case, we don't need\n// Partitioned and can just proceed as normal.\n// - Whether CHIPS is supported. To prevent the case where CHIPS is not supported but third-party cookies are (in\n// which we would accidentally set SameSite=None without Partitioned as the latter requires the former), we\n// check this by running a simple test with document.cookie.\n// - Whether the browser supports Partitioned cookies. If yes, set Partitioned. Otherwise, don't set Partitioned.\n// Since there's no easy cross-compat way to do this (CookieStore and document.cookie do not return whether a\n// cookie is partitioned on some/all versions of Safari and Firefox), we use a heuristic; we run this test by\n// creating two cookies with the same name: One with Partitioned and one without. If there are two resulting\n// cookies, that means they were put into different jars, implying that the browser supports Partitioned cookies\n// (but doesn't partition cookies by default). If they result in just one cookie, that could mean that the\n// browser doesn't support Partitioned cookies, or that the browser doesn't put partitioned cookies into\n// different jars by default, in which case we still don't know. This heuristic works on Chrome, but may\n// incorrectly conclude that some other browsers don't support Partitioned. But from a security perspective,\n// that is better than accidentally setting SameSite=None without Partitioned. TODO: Find a better heuristic to\n// to determine whether the browser supports Partitioned cookies or not.\n// - In a Next.js server environment, right now we do nothing because of the complexity involved :( TODO: In the\n// future, we could improve this for example by setting hint cookies from the client, but we need to make sure that\n// no malicious actor (eg. on a malicious subdomain) can forcefully enable Partitioned cookies on a browser that\n// does not support it.\n\n\ntype SetCookieOptions = { maxAge: number | \"session\", noOpIfServerComponent?: boolean, domain?: string, secure?: boolean };\ntype DeleteCookieOptions = { noOpIfServerComponent?: boolean, domain?: string };\n\nfunction ensureClient() {\n if (!isBrowserLike()) {\n throw new Error(\"cookieClient functions can only be called in a browser environment, yet window is undefined\");\n }\n}\n\nexport type CookieHelper = {\n get: (name: string) => string | null,\n getAll: () => Record<string, string>,\n set: (name: string, value: string, options: SetCookieOptions) => void,\n setOrDelete: (name: string, value: string | null, options: SetCookieOptions & DeleteCookieOptions) => void,\n delete: (name: string, options: DeleteCookieOptions) => void,\n};\n\nconst placeholderCookieHelperIdentity = { \"placeholder cookie helper identity\": true };\nexport async function createPlaceholderCookieHelper(): Promise<CookieHelper> {\n function throwError(): never {\n throw new StackAssertionError(\"Throwing cookie helper is just a placeholder. This should never be called\");\n }\n return {\n get: throwError,\n getAll: throwError,\n set: throwError,\n setOrDelete: throwError,\n delete: throwError,\n };\n}\n\nexport async function createCookieHelper(): Promise<CookieHelper> {\n if (isBrowserLike()) {\n return createBrowserCookieHelper();\n } else {\n return await createPlaceholderCookieHelper();\n }\n}\n\nexport function createBrowserCookieHelper(): CookieHelper {\n return {\n get: getCookieClient,\n getAll: getAllCookiesClient,\n set: setCookieClient,\n setOrDelete: setOrDeleteCookieClient,\n delete: deleteCookieClient,\n };\n}\n\nfunction handleCookieError(e: unknown, options: DeleteCookieOptions | SetCookieOptions) {\n if (e instanceof Error && e.message.includes(\"Cookies can only be modified in\")) {\n if (options.noOpIfServerComponent) {\n // ignore\n } else {\n throw new StackAssertionError(\"Attempted to set cookie in server component. Pass { noOpIfServerComponent: true } in the options of Stack's cookie functions if this is intentional and you want to ignore this error. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#options\");\n }\n } else {\n throw e;\n }\n}\n\n\nexport function getCookieClient(name: string): string | null {\n const all = getAllCookiesClient();\n return all[name] ?? null;\n}\n\nexport function getAllCookiesClient(): Record<string, string> {\n ensureClient();\n // set a helper cookie, see comment in `NextCookieHelper.set` above\n Cookies.set(\"stack-is-https\", \"true\", { secure: true, expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365) });\n return Cookies.get();\n}\n\nexport async function getCookie(name: string): Promise<string | null> {\n const cookieHelper = await createCookieHelper();\n return cookieHelper.get(name);\n}\n\nexport async function isSecure(): Promise<boolean> {\n if (isBrowserLike()) {\n return determineSecureFromClientContext();\n }\n return false;\n}\n\nfunction determineSecureFromClientContext(): boolean {\n return typeof window !== \"undefined\" && window.location.protocol === \"https:\";\n}\n\n\nlet _shouldSetPartitionedClientCache: boolean | undefined = undefined;\nfunction shouldSetPartitionedClient() {\n return _shouldSetPartitionedClientCache ??= _internalShouldSetPartitionedClient();\n}\nfunction _internalShouldSetPartitionedClient() {\n ensureClient();\n\n if (!(determineSecureFromClientContext())) {\n return false;\n }\n\n // check whether we can set & retrieve normal cookies (either because we're on a top-level/same-origin context or the browser partitions cookies by default)\n const cookie1Name = \"__Host-stack-temporary-chips-test-\" + Math.random().toString(36).substring(2, 15);\n document.cookie = `${cookie1Name}=value1; Secure; path=/`;\n const cookies1 = document.cookie.split(\"; \");\n document.cookie = `${cookie1Name}=delete1; Secure; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;`;\n if (cookies1.some((c) => c.startsWith(cookie1Name + \"=\"))) {\n return false;\n }\n\n\n // check whether Partitioned cookies are supported by the browser\n // TODO: See comment at the top. Feels like we should find a better way to do this\n const cookie2Name = \"__Host-stack-temporary-chips-test-\" + Math.random().toString(36).substring(2, 15);\n\n // just to be safe, delete the cookie first to avoid weird RNG-prediction attacks\n // I don't know what they look like (since this is a host cookie) but better safe than sorry\n // (this function should be 100% bulletproof so we don't accidentally fall back to non-partitioned third party cookies on unsupported browsers)\n document.cookie = `${cookie2Name}=delete1; Secure; SameSite=None; Partitioned; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n document.cookie = `${cookie2Name}=delete2; Secure; SameSite=None; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n\n // set the cookie, once partitioned and once not partitioned\n document.cookie = `${cookie2Name}=set1; Secure; SameSite=None; Partitioned; path=/`;\n document.cookie = `${cookie2Name}=set2; Secure; SameSite=None; path=/`;\n\n // check if there are two cookies\n const cookies2 = document.cookie.split(\"; \");\n const numberOfCookiesWithThisName = cookies2.filter((c) => c.startsWith(cookie2Name + \"=\")).length;\n\n // clean up\n document.cookie = `${cookie2Name}=delete3; Secure; SameSite=None; Partitioned; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n document.cookie = `${cookie2Name}=delete4; Secure; SameSite=None; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n\n return numberOfCookiesWithThisName === 2;\n}\n\nfunction setCookieClientInternal(name: string, value: string, options: SetCookieOptions) {\n const secure = options.secure ?? determineSecureFromClientContext();\n const partitioned = shouldSetPartitionedClient();\n Cookies.set(name, value, {\n expires: options.maxAge === \"session\" ? undefined : new Date(Date.now() + (options.maxAge) * 1000),\n domain: options.domain,\n secure,\n sameSite: \"Lax\",\n ...(partitioned ? {\n partitioned,\n sameSite: \"None\",\n } : {}),\n });\n}\n\nfunction deleteCookieClientInternal(name: string, options: DeleteCookieOptions) {\n for (const partitioned of [true, false]) {\n if (options.domain !== undefined) {\n Cookies.remove(name, { domain: options.domain, secure: determineSecureFromClientContext(), partitioned });\n }\n Cookies.remove(name, { secure: determineSecureFromClientContext(), partitioned });\n }\n}\n\nexport function setOrDeleteCookieClient(name: string, value: string | null, options: SetCookieOptions & DeleteCookieOptions) {\n ensureClient();\n if (value === null) {\n deleteCookieClientInternal(name, options);\n } else {\n setCookieClientInternal(name, value, options);\n }\n}\n\nexport async function setOrDeleteCookie(name: string, value: string | null, options: SetCookieOptions & DeleteCookieOptions) {\n const cookieHelper = await createCookieHelper();\n cookieHelper.setOrDelete(name, value, options);\n}\n\nexport function deleteCookieClient(name: string, options: DeleteCookieOptions) {\n ensureClient();\n deleteCookieClientInternal(name, options);\n}\n\nexport async function deleteCookie(name: string, options: DeleteCookieOptions) {\n const cookieHelper = await createCookieHelper();\n cookieHelper.delete(name, options);\n}\n\nexport function setCookieClient(name: string, value: string, options: SetCookieOptions) {\n ensureClient();\n setCookieClientInternal(name, value, options);\n}\n\nexport async function setCookie(name: string, value: string, options: SetCookieOptions) {\n const cookieHelper = await createCookieHelper();\n cookieHelper.set(name, value, options);\n}\n\nexport async function saveVerifierAndState() {\n const codeVerifier = generateRandomCodeVerifier();\n const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);\n const state = generateRandomState();\n\n await setCookie(\"stack-oauth-outer-\" + state, codeVerifier, { maxAge: 60 * 60 });\n\n return {\n codeChallenge,\n state,\n };\n}\n\nexport function consumeVerifierAndStateCookie(state: string) {\n ensureClient();\n const cookieName = \"stack-oauth-outer-\" + state;\n const codeVerifier = getCookieClient(cookieName);\n if (!codeVerifier) {\n return null;\n }\n deleteCookieClient(cookieName, {});\n return {\n codeVerifier,\n };\n}\n"],"mappings":"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","names":["Cookies"]}
1
+ {"version":3,"sources":["../../src/lib/cookie.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { isBrowserLike } from '@stackframe/stack-shared/dist/utils/env';\nimport { StackAssertionError } from '@stackframe/stack-shared/dist/utils/errors';\nimport Cookies from \"js-cookie\";\nimport { calculatePKCECodeChallenge, generateRandomCodeVerifier, generateRandomState } from \"oauth4webapi\";\n\n\n// INFO: This file is used to manage cookies. It also sets some cookie flags automatically, see this description.\n//\n// It provides asynchronous setCookie, getCookie, deleteCookie, etc. functions that can be used in various environments\n// (browser + Next.js for now). Under the hood, they just get a CookieHelper object and then set the cookies there.\n//\n// The CookieHelper object is a simple object that lets you set, get and delete cookies synchronously. Acquiring one\n// is asynchronous (except for browser environments, where they can be acquired synchronously), but once you have it,\n// you can use it synchronously. This function is useful if you cannot await in the calling code, but otherwise you\n// should prefer to await the functions directly.\n//\n// Some cookie flags are set automatically by the CookieHelper (and hence also the <xyz>Cookie functions).\n// In particular:\n// - SameSite is set to `Lax` by default, which is already true in Chromium-based browsers, so this creates\n// compatibility with other browsers that use either Strict or None (particularly Safari and Firefox, and older\n// versions of Chrome). If Partitioned is automatically set (as described below), then this value is set to `None`\n// instead.\n// - Secure is set depending on whether we could successfully determine that the client is on HTTPS. For this, we use a\n// set of heuristics:\n// - In a browser environment, we check window.location.protocol which is always accurate\n// - In a Next.js server environment:\n// - First we check the `stack-is-https` cookie, which is set in various places on the\n// client with a Secure attribute. If that one is passed on to the server, we know that the client is on HTTPS\n// and we can set the Secure flag on the cookie. TODO: Should we also do this with a second cookie with a\n// __Host- prefix, so a malicious subdomain of the current domain cannot forcibly enable HTTPS mode and\n// therefore prevent new cookies from being set?\n// - Otherwise, we check the X-Forwarded-Proto header. If that one is `https`, we know that the client is\n// (pretending to be) on HTTPS and we can set the Secure flag on the cookie. Note that this header is\n// spoofable by malicious clients (so is the cookie actually), but since setting this value can only *increase*\n// security (and therefore prevent setting of a cookie), and requires a malicious client, this is still safe.\n// - If neither of the above is true, we don't set the Secure flag on the cookie.\n// - Partitioned is set depending on whether it is needed & supported. Unfortunately, the fact that Partitioned\n// cookies require SameSite=None, browsers that don't support it will still set them as normal third-party cookies,\n// which are fundamentally unsafe. Therefore, we need to take extra care that we only ever set Partitioned cookies\n// if we know for sure that the browser supports it.\n// - In a browser environment, we check:\n// - Whether `Secure` is set. If it's not, we don't set Partitioned.\n// - Whether we can set & retrieve cookies without Partitioned being set. If this is the case, we are likely in a\n// top-level context or a browser that partitions cookies by default (eg. Firefox). In this case, we don't need\n// Partitioned and can just proceed as normal.\n// - Whether CHIPS is supported. To prevent the case where CHIPS is not supported but third-party cookies are (in\n// which we would accidentally set SameSite=None without Partitioned as the latter requires the former), we\n// check this by running a simple test with document.cookie.\n// - Whether the browser supports Partitioned cookies. If yes, set Partitioned. Otherwise, don't set Partitioned.\n// Since there's no easy cross-compat way to do this (CookieStore and document.cookie do not return whether a\n// cookie is partitioned on some/all versions of Safari and Firefox), we use a heuristic; we run this test by\n// creating two cookies with the same name: One with Partitioned and one without. If there are two resulting\n// cookies, that means they were put into different jars, implying that the browser supports Partitioned cookies\n// (but doesn't partition cookies by default). If they result in just one cookie, that could mean that the\n// browser doesn't support Partitioned cookies, or that the browser doesn't put partitioned cookies into\n// different jars by default, in which case we still don't know. This heuristic works on Chrome, but may\n// incorrectly conclude that some other browsers don't support Partitioned. But from a security perspective,\n// that is better than accidentally setting SameSite=None without Partitioned. TODO: Find a better heuristic to\n// to determine whether the browser supports Partitioned cookies or not.\n// - In a Next.js server environment, right now we do nothing because of the complexity involved :( TODO: In the\n// future, we could improve this for example by setting hint cookies from the client, but we need to make sure that\n// no malicious actor (eg. on a malicious subdomain) can forcefully enable Partitioned cookies on a browser that\n// does not support it.\n\n\ntype SetCookieOptions = { maxAge: number | \"session\", noOpIfServerComponent?: boolean, domain?: string, secure?: boolean };\ntype DeleteCookieOptions = { noOpIfServerComponent?: boolean, domain?: string };\n\nfunction ensureClient() {\n if (!isBrowserLike()) {\n throw new Error(\"cookieClient functions can only be called in a browser environment, yet window is undefined\");\n }\n}\n\nexport type CookieHelper = {\n get: (name: string) => string | null,\n getAll: () => Record<string, string>,\n set: (name: string, value: string, options: SetCookieOptions) => void,\n setOrDelete: (name: string, value: string | null, options: SetCookieOptions & DeleteCookieOptions) => void,\n delete: (name: string, options: DeleteCookieOptions) => void,\n};\n\nconst placeholderCookieHelperIdentity = { \"placeholder cookie helper identity\": true };\nexport async function createPlaceholderCookieHelper(): Promise<CookieHelper> {\n function throwError(): never {\n throw new StackAssertionError(\"Throwing cookie helper is just a placeholder. This should never be called\");\n }\n return {\n get: throwError,\n getAll: throwError,\n set: throwError,\n setOrDelete: throwError,\n delete: throwError,\n };\n}\n\nexport async function createCookieHelper(): Promise<CookieHelper> {\n if (isBrowserLike()) {\n return createBrowserCookieHelper();\n } else {\n return await createPlaceholderCookieHelper();\n }\n}\n\nexport function createBrowserCookieHelper(): CookieHelper {\n return {\n get: getCookieClient,\n getAll: getAllCookiesClient,\n set: setCookieClient,\n setOrDelete: setOrDeleteCookieClient,\n delete: deleteCookieClient,\n };\n}\n\nfunction handleCookieError(e: unknown, options: DeleteCookieOptions | SetCookieOptions) {\n if (e instanceof Error && e.message.includes(\"Cookies can only be modified in\")) {\n if (options.noOpIfServerComponent) {\n // ignore\n } else {\n throw new StackAssertionError(\"Attempted to set cookie in server component. Pass { noOpIfServerComponent: true } in the options of Stack's cookie functions if this is intentional and you want to ignore this error. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#options\");\n }\n } else {\n throw e;\n }\n}\n\n\nexport function getCookieClient(name: string): string | null {\n const all = getAllCookiesClient();\n return all[name] ?? null;\n}\n\nexport function getAllCookiesClient(): Record<string, string> {\n ensureClient();\n // set a helper cookie, see comment in `NextCookieHelper.set` above\n Cookies.set(\"stack-is-https\", \"true\", { secure: true, expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365) });\n return Cookies.get();\n}\n\nexport async function getCookie(name: string): Promise<string | null> {\n const cookieHelper = await createCookieHelper();\n return cookieHelper.get(name);\n}\n\nexport async function isSecure(): Promise<boolean> {\n if (isBrowserLike()) {\n return determineSecureFromClientContext();\n }\n return false;\n}\n\nfunction determineSecureFromClientContext(): boolean {\n return typeof window !== \"undefined\" && window.location.protocol === \"https:\";\n}\n\n\nlet _shouldSetPartitionedClientCache: boolean | undefined = undefined;\nfunction shouldSetPartitionedClient() {\n return _shouldSetPartitionedClientCache ??= _internalShouldSetPartitionedClient();\n}\nfunction _internalShouldSetPartitionedClient() {\n ensureClient();\n\n if (!(determineSecureFromClientContext())) {\n return false;\n }\n\n // check whether we can set & retrieve normal cookies (either because we're on a top-level/same-origin context or the browser partitions cookies by default)\n const cookie1Name = \"__Host-stack-temporary-chips-test-\" + Math.random().toString(36).substring(2, 15);\n document.cookie = `${cookie1Name}=value1; Secure; path=/`;\n const cookies1 = document.cookie.split(\"; \");\n document.cookie = `${cookie1Name}=delete1; Secure; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;`;\n if (cookies1.some((c) => c.startsWith(cookie1Name + \"=\"))) {\n return false;\n }\n\n\n // check whether Partitioned cookies are supported by the browser\n // TODO: See comment at the top. Feels like we should find a better way to do this\n const cookie2Name = \"__Host-stack-temporary-chips-test-\" + Math.random().toString(36).substring(2, 15);\n\n // just to be safe, delete the cookie first to avoid weird RNG-prediction attacks\n // I don't know what they look like (since this is a host cookie) but better safe than sorry\n // (this function should be 100% bulletproof so we don't accidentally fall back to non-partitioned third party cookies on unsupported browsers)\n document.cookie = `${cookie2Name}=delete1; Secure; SameSite=None; Partitioned; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n document.cookie = `${cookie2Name}=delete2; Secure; SameSite=None; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n\n // set the cookie, once partitioned and once not partitioned\n document.cookie = `${cookie2Name}=set1; Secure; SameSite=None; Partitioned; path=/`;\n document.cookie = `${cookie2Name}=set2; Secure; SameSite=None; path=/`;\n\n // check if there are two cookies\n const cookies2 = document.cookie.split(\"; \");\n const numberOfCookiesWithThisName = cookies2.filter((c) => c.startsWith(cookie2Name + \"=\")).length;\n\n // clean up\n document.cookie = `${cookie2Name}=delete3; Secure; SameSite=None; Partitioned; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n document.cookie = `${cookie2Name}=delete4; Secure; SameSite=None; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n\n return numberOfCookiesWithThisName === 2;\n}\n\nfunction setCookieClientInternal(name: string, value: string, options: SetCookieOptions) {\n const secure = options.secure ?? determineSecureFromClientContext();\n const partitioned = shouldSetPartitionedClient();\n Cookies.set(name, value, {\n expires: options.maxAge === \"session\" ? undefined : new Date(Date.now() + (options.maxAge) * 1000),\n domain: options.domain,\n secure,\n sameSite: \"Lax\",\n ...(partitioned ? {\n partitioned,\n sameSite: \"None\",\n } : {}),\n });\n}\n\nfunction deleteCookieClientInternal(name: string, options: DeleteCookieOptions) {\n for (const partitioned of [true, false]) {\n if (options.domain !== undefined) {\n Cookies.remove(name, { domain: options.domain, secure: determineSecureFromClientContext(), partitioned });\n }\n Cookies.remove(name, { secure: determineSecureFromClientContext(), partitioned });\n }\n}\n\nexport function setOrDeleteCookieClient(name: string, value: string | null, options: SetCookieOptions & DeleteCookieOptions) {\n ensureClient();\n if (value === null) {\n deleteCookieClientInternal(name, options);\n } else {\n setCookieClientInternal(name, value, options);\n }\n}\n\nexport async function setOrDeleteCookie(name: string, value: string | null, options: SetCookieOptions & DeleteCookieOptions) {\n const cookieHelper = await createCookieHelper();\n cookieHelper.setOrDelete(name, value, options);\n}\n\nexport function deleteCookieClient(name: string, options: DeleteCookieOptions) {\n ensureClient();\n deleteCookieClientInternal(name, options);\n}\n\nexport async function deleteCookie(name: string, options: DeleteCookieOptions) {\n const cookieHelper = await createCookieHelper();\n cookieHelper.delete(name, options);\n}\n\nexport function setCookieClient(name: string, value: string, options: SetCookieOptions) {\n ensureClient();\n setCookieClientInternal(name, value, options);\n}\n\nexport async function setCookie(name: string, value: string, options: SetCookieOptions) {\n const cookieHelper = await createCookieHelper();\n cookieHelper.set(name, value, options);\n}\n\nexport async function saveVerifierAndState() {\n const codeVerifier = generateRandomCodeVerifier();\n const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);\n const state = generateRandomState();\n\n await setCookie(\"stack-oauth-outer-\" + state, codeVerifier, { maxAge: 60 * 60 });\n\n return {\n codeChallenge,\n state,\n };\n}\n\nexport function consumeVerifierAndStateCookie(state: string) {\n ensureClient();\n const cookieName = \"stack-oauth-outer-\" + state;\n const codeVerifier = getCookieClient(cookieName);\n if (!codeVerifier) {\n return null;\n }\n deleteCookieClient(cookieName, {});\n return {\n codeVerifier,\n };\n}\n"],"mappings":"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","names":["Cookies"]}