@stackframe/stack-shared 2.7.26 → 2.7.28

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @stackframe/stack-shared
2
2
 
3
+ ## 2.7.28
4
+
5
+ ### Patch Changes
6
+
7
+ - Various changes
8
+
9
+ ## 2.7.27
10
+
11
+ ### Patch Changes
12
+
13
+ - Various changes
14
+
3
15
  ## 2.7.26
4
16
 
5
17
  ### Patch Changes
@@ -1,6 +1,7 @@
1
1
  import { InternalSession } from "../sessions";
2
2
  import { ApiKeysCrud } from "./crud/api-keys";
3
3
  import { EmailTemplateCrud, EmailTemplateType } from "./crud/email-templates";
4
+ import { InternalEmailsCrud } from "./crud/emails";
4
5
  import { ProjectsCrud } from "./crud/projects";
5
6
  import { SvixTokenCrud } from "./crud/svix-token";
6
7
  import { TeamPermissionDefinitionsCrud } from "./crud/team-permissions";
@@ -61,4 +62,5 @@ export declare class StackAdminInterface extends StackServerInterface {
61
62
  success: boolean;
62
63
  error_message?: string;
63
64
  }>;
65
+ listSentEmails(): Promise<InternalEmailsCrud["Admin"]["List"]>;
64
66
  }
@@ -136,4 +136,10 @@ export class StackAdminInterface extends StackServerInterface {
136
136
  }, null);
137
137
  return await response.json();
138
138
  }
139
+ async listSentEmails() {
140
+ const response = await this.sendAdminRequest("/internal/emails", {
141
+ method: "GET",
142
+ }, null);
143
+ return await response.json();
144
+ }
139
145
  }
@@ -7,6 +7,7 @@ import { ContactChannelsCrud } from './crud/contact-channels';
7
7
  import { CurrentUserCrud } from './crud/current-user';
8
8
  import { ConnectedAccountAccessTokenCrud } from './crud/oauth';
9
9
  import { InternalProjectsCrud, ProjectsCrud } from './crud/projects';
10
+ import { SessionsCrud } from './crud/sessions';
10
11
  import { TeamInvitationCrud } from './crud/team-invitation';
11
12
  import { TeamMemberProfilesCrud } from './crud/team-member-profiles';
12
13
  import { TeamPermissionsCrud } from './crud/team-permissions';
@@ -14,6 +15,7 @@ import { TeamsCrud } from './crud/teams';
14
15
  export type ClientInterfaceOptions = {
15
16
  clientVersion: string;
16
17
  getBaseUrl: () => string;
18
+ extraRequestHeaders: Record<string, string>;
17
19
  projectId: string;
18
20
  prepareRequest?: () => Promise<void>;
19
21
  } & ({
@@ -193,6 +195,9 @@ export declare class StackClientInterface {
193
195
  createClientContactChannel(data: ContactChannelsCrud['Client']['Create'], session: InternalSession): Promise<ContactChannelsCrud['Client']['Read']>;
194
196
  updateClientContactChannel(id: string, data: ContactChannelsCrud['Client']['Update'], session: InternalSession): Promise<ContactChannelsCrud['Client']['Read']>;
195
197
  deleteClientContactChannel(id: string, session: InternalSession): Promise<void>;
198
+ deleteSession(sessionId: string, session: InternalSession): Promise<void>;
199
+ listSessions(session: InternalSession): Promise<SessionsCrud['Client']['List']>;
196
200
  listClientContactChannels(session: InternalSession): Promise<ContactChannelsCrud['Client']['Read'][]>;
197
201
  sendCurrentUserContactChannelVerificationEmail(contactChannelId: string, callbackUrl: string, session: InternalSession): Promise<Result<undefined, KnownErrors["EmailAlreadyVerified"]>>;
202
+ cliLogin(loginCode: string, refreshToken: string, session: InternalSession): Promise<Result<undefined, KnownErrors["SchemaError"]>>;
198
203
  }
@@ -212,6 +212,7 @@ export class StackClientInterface {
212
212
  * the case (I haven't actually tested.)
213
213
  */
214
214
  "X-Stack-Random-Nonce": generateSecureRandomString(),
215
+ ...this.options.extraRequestHeaders,
215
216
  ...options.headers,
216
217
  },
217
218
  /**
@@ -876,6 +877,17 @@ export class StackClientInterface {
876
877
  method: "DELETE",
877
878
  }, session);
878
879
  }
880
+ async deleteSession(sessionId, session) {
881
+ await this.sendClientRequest(`/auth/sessions/${sessionId}?user_id=me`, {
882
+ method: "DELETE",
883
+ }, session);
884
+ }
885
+ async listSessions(session) {
886
+ const response = await this.sendClientRequest("/auth/sessions?user_id=me", {
887
+ method: "GET",
888
+ }, session);
889
+ return await response.json();
890
+ }
879
891
  async listClientContactChannels(session) {
880
892
  const response = await this.sendClientRequest("/contact-channels?user_id=me", {
881
893
  method: "GET",
@@ -896,4 +908,20 @@ export class StackClientInterface {
896
908
  }
897
909
  return Result.ok(undefined);
898
910
  }
911
+ async cliLogin(loginCode, refreshToken, session) {
912
+ const responseOrError = await this.sendClientRequestAndCatchKnownError("/auth/cli/complete", {
913
+ method: "POST",
914
+ headers: {
915
+ "Content-Type": "application/json"
916
+ },
917
+ body: JSON.stringify({
918
+ login_code: loginCode,
919
+ refresh_token: refreshToken,
920
+ }),
921
+ }, session, [KnownErrors.SchemaError]);
922
+ if (responseOrError.status === "error") {
923
+ return Result.error(responseOrError.error);
924
+ }
925
+ return Result.ok(undefined);
926
+ }
899
927
  }
@@ -0,0 +1,64 @@
1
+ import { CrudTypeOf } from "../../crud";
2
+ export declare const sentEmailReadSchema: import("yup").ObjectSchema<{
3
+ id: string;
4
+ subject: string;
5
+ sent_at_millis: number;
6
+ to: string[] | undefined;
7
+ sender_config: {
8
+ host?: string | undefined;
9
+ port?: number | undefined;
10
+ username?: string | undefined;
11
+ sender_name?: string | undefined;
12
+ sender_email?: string | undefined;
13
+ type: "shared" | "standard";
14
+ };
15
+ error: {} | null | undefined;
16
+ }, import("yup").AnyObject, {
17
+ id: undefined;
18
+ subject: undefined;
19
+ sent_at_millis: undefined;
20
+ to: undefined;
21
+ sender_config: {
22
+ type: undefined;
23
+ host: undefined;
24
+ port: undefined;
25
+ username: undefined;
26
+ password: undefined;
27
+ sender_name: undefined;
28
+ sender_email: undefined;
29
+ };
30
+ error: undefined;
31
+ }, "">;
32
+ export declare const internalEmailsCrud: import("../../crud").CrudSchemaFromOptions<{
33
+ adminReadSchema: import("yup").ObjectSchema<{
34
+ id: string;
35
+ subject: string;
36
+ sent_at_millis: number;
37
+ to: string[] | undefined;
38
+ sender_config: {
39
+ host?: string | undefined;
40
+ port?: number | undefined;
41
+ username?: string | undefined;
42
+ sender_name?: string | undefined;
43
+ sender_email?: string | undefined;
44
+ type: "shared" | "standard";
45
+ };
46
+ error: {} | null | undefined;
47
+ }, import("yup").AnyObject, {
48
+ id: undefined;
49
+ subject: undefined;
50
+ sent_at_millis: undefined;
51
+ to: undefined;
52
+ sender_config: {
53
+ type: undefined;
54
+ host: undefined;
55
+ port: undefined;
56
+ username: undefined;
57
+ password: undefined;
58
+ sender_name: undefined;
59
+ sender_email: undefined;
60
+ };
61
+ error: undefined;
62
+ }, "">;
63
+ }>;
64
+ export type InternalEmailsCrud = CrudTypeOf<typeof internalEmailsCrud>;
@@ -0,0 +1,14 @@
1
+ import { createCrud } from "../../crud";
2
+ import * as fieldSchema from "../../schema-fields";
3
+ import { emailConfigWithoutPasswordSchema } from "./projects";
4
+ export const sentEmailReadSchema = fieldSchema.yupObject({
5
+ id: fieldSchema.yupString().defined(),
6
+ subject: fieldSchema.yupString().defined(),
7
+ sent_at_millis: fieldSchema.yupNumber().defined(),
8
+ to: fieldSchema.yupArray(fieldSchema.yupString().defined()),
9
+ sender_config: emailConfigWithoutPasswordSchema.defined(),
10
+ error: fieldSchema.yupMixed().nullable().optional(),
11
+ }).defined();
12
+ export const internalEmailsCrud = createCrud({
13
+ adminReadSchema: sentEmailReadSchema,
14
+ });
@@ -16,6 +16,22 @@ export declare const emailConfigSchema: import("yup").ObjectSchema<{
16
16
  sender_name: undefined;
17
17
  sender_email: undefined;
18
18
  }, "">;
19
+ export declare const emailConfigWithoutPasswordSchema: import("yup").ObjectSchema<{
20
+ type: "shared" | "standard";
21
+ host: string | undefined;
22
+ port: number | undefined;
23
+ username: string | undefined;
24
+ sender_name: string | undefined;
25
+ sender_email: string | undefined;
26
+ }, import("yup").AnyObject, {
27
+ type: undefined;
28
+ host: undefined;
29
+ port: undefined;
30
+ username: undefined;
31
+ password: undefined;
32
+ sender_name: undefined;
33
+ sender_email: undefined;
34
+ }, "">;
19
35
  export declare const projectsCrudAdminReadSchema: import("yup").ObjectSchema<{
20
36
  id: string;
21
37
  display_name: string;
@@ -44,6 +44,7 @@ export const emailConfigSchema = yupObject({
44
44
  type: 'standard',
45
45
  }),
46
46
  });
47
+ export const emailConfigWithoutPasswordSchema = emailConfigSchema.pick(['type', 'host', 'port', 'username', 'sender_name', 'sender_email']);
47
48
  const domainSchema = yupObject({
48
49
  domain: schemaFields.urlSchema.defined()
49
50
  .matches(/^https?:\/\//, 'URL must start with http:// or https://')
@@ -0,0 +1,144 @@
1
+ import { CrudTypeOf } from "../../crud";
2
+ export declare const sessionsCrudServerCreateSchema: import("yup").ObjectSchema<{
3
+ user_id: string;
4
+ expires_in_millis: number;
5
+ is_impersonation: boolean;
6
+ }, import("yup").AnyObject, {
7
+ user_id: undefined;
8
+ expires_in_millis: number;
9
+ is_impersonation: false;
10
+ }, "">;
11
+ export declare const sessionsCreateOutputSchema: import("yup").ObjectSchema<{
12
+ refresh_token: string;
13
+ access_token: string;
14
+ }, import("yup").AnyObject, {
15
+ refresh_token: undefined;
16
+ access_token: undefined;
17
+ }, "">;
18
+ export declare const sessionsCrudReadSchema: import("yup").ObjectSchema<{
19
+ id: string;
20
+ user_id: string;
21
+ created_at: number;
22
+ is_impersonation: boolean;
23
+ last_used_at: number | undefined;
24
+ is_current_session: boolean | undefined;
25
+ last_used_at_end_user_ip_info: {
26
+ countryCode?: string | null | undefined;
27
+ regionCode?: string | null | undefined;
28
+ cityName?: string | null | undefined;
29
+ latitude?: number | null | undefined;
30
+ longitude?: number | null | undefined;
31
+ tzIdentifier?: string | null | undefined;
32
+ ip: string;
33
+ } | undefined;
34
+ }, import("yup").AnyObject, {
35
+ id: undefined;
36
+ user_id: undefined;
37
+ created_at: undefined;
38
+ is_impersonation: undefined;
39
+ last_used_at: undefined;
40
+ is_current_session: undefined;
41
+ last_used_at_end_user_ip_info: {
42
+ ip: undefined;
43
+ countryCode: undefined;
44
+ regionCode: undefined;
45
+ cityName: undefined;
46
+ latitude: undefined;
47
+ longitude: undefined;
48
+ tzIdentifier: undefined;
49
+ };
50
+ }, "">;
51
+ export declare const sessionsCrudDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
52
+ export declare const sessionsCrud: import("../../crud").CrudSchemaFromOptions<{
53
+ serverReadSchema: import("yup").ObjectSchema<{
54
+ id: string;
55
+ user_id: string;
56
+ created_at: number;
57
+ is_impersonation: boolean;
58
+ last_used_at: number | undefined;
59
+ is_current_session: boolean | undefined;
60
+ last_used_at_end_user_ip_info: {
61
+ countryCode?: string | null | undefined;
62
+ regionCode?: string | null | undefined;
63
+ cityName?: string | null | undefined;
64
+ latitude?: number | null | undefined;
65
+ longitude?: number | null | undefined;
66
+ tzIdentifier?: string | null | undefined;
67
+ ip: string;
68
+ } | undefined;
69
+ }, import("yup").AnyObject, {
70
+ id: undefined;
71
+ user_id: undefined;
72
+ created_at: undefined;
73
+ is_impersonation: undefined;
74
+ last_used_at: undefined;
75
+ is_current_session: undefined;
76
+ last_used_at_end_user_ip_info: {
77
+ ip: undefined;
78
+ countryCode: undefined;
79
+ regionCode: undefined;
80
+ cityName: undefined;
81
+ latitude: undefined;
82
+ longitude: undefined;
83
+ tzIdentifier: undefined;
84
+ };
85
+ }, "">;
86
+ serverDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
87
+ clientReadSchema: import("yup").ObjectSchema<{
88
+ id: string;
89
+ user_id: string;
90
+ created_at: number;
91
+ is_impersonation: boolean;
92
+ last_used_at: number | undefined;
93
+ is_current_session: boolean | undefined;
94
+ last_used_at_end_user_ip_info: {
95
+ countryCode?: string | null | undefined;
96
+ regionCode?: string | null | undefined;
97
+ cityName?: string | null | undefined;
98
+ latitude?: number | null | undefined;
99
+ longitude?: number | null | undefined;
100
+ tzIdentifier?: string | null | undefined;
101
+ ip: string;
102
+ } | undefined;
103
+ }, import("yup").AnyObject, {
104
+ id: undefined;
105
+ user_id: undefined;
106
+ created_at: undefined;
107
+ is_impersonation: undefined;
108
+ last_used_at: undefined;
109
+ is_current_session: undefined;
110
+ last_used_at_end_user_ip_info: {
111
+ ip: undefined;
112
+ countryCode: undefined;
113
+ regionCode: undefined;
114
+ cityName: undefined;
115
+ latitude: undefined;
116
+ longitude: undefined;
117
+ tzIdentifier: undefined;
118
+ };
119
+ }, "">;
120
+ clientDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
121
+ docs: {
122
+ serverList: {
123
+ summary: string;
124
+ description: string;
125
+ tags: string[];
126
+ };
127
+ serverDelete: {
128
+ summary: string;
129
+ description: string;
130
+ tags: string[];
131
+ };
132
+ clientList: {
133
+ summary: string;
134
+ description: string;
135
+ tags: string[];
136
+ };
137
+ clientDelete: {
138
+ summary: string;
139
+ description: string;
140
+ tags: string[];
141
+ };
142
+ };
143
+ }>;
144
+ export type SessionsCrud = CrudTypeOf<typeof sessionsCrud>;
@@ -0,0 +1,55 @@
1
+ import { createCrud } from "../../crud";
2
+ import { yupBoolean, yupMixed, yupNumber, yupObject, yupString } from "../../schema-fields";
3
+ import { geoInfoSchema } from "../../utils/geo";
4
+ // Create
5
+ export const sessionsCrudServerCreateSchema = yupObject({
6
+ user_id: yupString().uuid().defined(),
7
+ expires_in_millis: yupNumber().max(1000 * 60 * 60 * 24 * 367).default(1000 * 60 * 60 * 24 * 365),
8
+ is_impersonation: yupBoolean().default(false),
9
+ }).defined();
10
+ export const sessionsCreateOutputSchema = yupObject({
11
+ refresh_token: yupString().defined(),
12
+ access_token: yupString().defined(),
13
+ }).defined();
14
+ export const sessionsCrudReadSchema = yupObject({
15
+ id: yupString().defined(),
16
+ user_id: yupString().uuid().defined(),
17
+ created_at: yupNumber().defined(),
18
+ is_impersonation: yupBoolean().defined(),
19
+ last_used_at: yupNumber().optional(),
20
+ is_current_session: yupBoolean(),
21
+ // TODO move this to a shared type
22
+ // TODO: what about if not trusted?
23
+ last_used_at_end_user_ip_info: geoInfoSchema.optional(),
24
+ }).defined();
25
+ // Delete
26
+ export const sessionsCrudDeleteSchema = yupMixed();
27
+ export const sessionsCrud = createCrud({
28
+ // serverCreateSchema: sessionsCrudServerCreateSchema,
29
+ serverReadSchema: sessionsCrudReadSchema,
30
+ serverDeleteSchema: sessionsCrudDeleteSchema,
31
+ clientReadSchema: sessionsCrudReadSchema,
32
+ clientDeleteSchema: sessionsCrudDeleteSchema,
33
+ docs: {
34
+ serverList: {
35
+ summary: "List sessions",
36
+ description: "List all sessions for the current user.",
37
+ tags: ["Sessions"],
38
+ },
39
+ serverDelete: {
40
+ summary: "Delete session",
41
+ description: "Delete a session by ID.",
42
+ tags: ["Sessions"],
43
+ },
44
+ clientList: {
45
+ summary: "List sessions",
46
+ description: "List all sessions for the current user.",
47
+ tags: ["Sessions"],
48
+ },
49
+ clientDelete: {
50
+ summary: "Delete session",
51
+ description: "Delete a session by ID.",
52
+ tags: ["Sessions"],
53
+ },
54
+ },
55
+ });
@@ -46,6 +46,40 @@ export declare const teamPermissionsCrud: import("../../crud").CrudSchemaFromOpt
46
46
  };
47
47
  }>;
48
48
  export type TeamPermissionsCrud = CrudTypeOf<typeof teamPermissionsCrud>;
49
+ export declare const teamPermissionCreatedWebhookEvent: {
50
+ type: string;
51
+ schema: import("yup").ObjectSchema<{
52
+ id: string;
53
+ user_id: string;
54
+ team_id: string;
55
+ }, import("yup").AnyObject, {
56
+ id: undefined;
57
+ user_id: undefined;
58
+ team_id: undefined;
59
+ }, "">;
60
+ metadata: {
61
+ summary: string;
62
+ description: string;
63
+ tags: string[];
64
+ };
65
+ };
66
+ export declare const teamPermissionDeletedWebhookEvent: {
67
+ type: string;
68
+ schema: import("yup").ObjectSchema<{
69
+ id: string;
70
+ user_id: string;
71
+ team_id: string;
72
+ }, import("yup").AnyObject, {
73
+ id: undefined;
74
+ user_id: undefined;
75
+ team_id: undefined;
76
+ }, "">;
77
+ metadata: {
78
+ summary: string;
79
+ description: string;
80
+ tags: string[];
81
+ };
82
+ };
49
83
  export declare const teamPermissionDefinitionsCrudAdminReadSchema: import("yup").ObjectSchema<{
50
84
  id: string;
51
85
  description: string | undefined;
@@ -36,6 +36,24 @@ export const teamPermissionsCrud = createCrud({
36
36
  },
37
37
  },
38
38
  });
39
+ export const teamPermissionCreatedWebhookEvent = {
40
+ type: "team_permission.created",
41
+ schema: teamPermissionsCrud.server.readSchema,
42
+ metadata: {
43
+ summary: "Team Permission Created",
44
+ description: "This event is triggered when a team permission is created.",
45
+ tags: ["Teams"],
46
+ },
47
+ };
48
+ export const teamPermissionDeletedWebhookEvent = {
49
+ type: "team_permission.deleted",
50
+ schema: teamPermissionsCrud.server.readSchema,
51
+ metadata: {
52
+ summary: "Team Permission Deleted",
53
+ description: "This event is triggered when a team permission is deleted.",
54
+ tags: ["Teams"],
55
+ },
56
+ };
39
57
  // =============== Team permission definitions =================
40
58
  export const teamPermissionDefinitionsCrudAdminReadSchema = yupObject({
41
59
  id: schemaFields.teamPermissionDefinitionIdSchema.defined(),
@@ -5,6 +5,7 @@ import { ClientInterfaceOptions, StackClientInterface } from "./clientInterface"
5
5
  import { ContactChannelsCrud } from "./crud/contact-channels";
6
6
  import { CurrentUserCrud } from "./crud/current-user";
7
7
  import { ConnectedAccountAccessTokenCrud } from "./crud/oauth";
8
+ import { SessionsCrud } from "./crud/sessions";
8
9
  import { TeamInvitationCrud } from "./crud/team-invitation";
9
10
  import { TeamMemberProfilesCrud } from "./crud/team-member-profiles";
10
11
  import { TeamMembershipsCrud } from "./crud/team-memberships";
@@ -74,7 +75,7 @@ export declare class StackServerInterface extends StackClientInterface {
74
75
  }): Promise<void>;
75
76
  updateServerUser(userId: string, update: UsersCrud['Server']['Update']): Promise<UsersCrud['Server']['Read']>;
76
77
  createServerProviderAccessToken(userId: string, provider: string, scope: string): Promise<ConnectedAccountAccessTokenCrud['Server']['Read']>;
77
- createServerUserSession(userId: string, expiresInMillis: number): Promise<{
78
+ createServerUserSession(userId: string, expiresInMillis: number, isImpersonation: boolean): Promise<{
78
79
  accessToken: string;
79
80
  refreshToken: string;
80
81
  }>;
@@ -95,9 +96,15 @@ export declare class StackServerInterface extends StackClientInterface {
95
96
  deleteServerContactChannel(userId: string, contactChannelId: string): Promise<void>;
96
97
  listServerContactChannels(userId: string): Promise<ContactChannelsCrud['Server']['Read'][]>;
97
98
  sendServerContactChannelVerificationEmail(userId: string, contactChannelId: string, callbackUrl: string): Promise<void>;
99
+ listServerSessions(userId: string): Promise<SessionsCrud['Server']['Read'][]>;
100
+ deleteServerSession(sessionId: string): Promise<void>;
98
101
  sendServerTeamInvitation(options: {
99
102
  email: string;
100
103
  teamId: string;
101
104
  callbackUrl: string;
102
105
  }): Promise<void>;
106
+ updatePassword(options: {
107
+ oldPassword: string;
108
+ newPassword: string;
109
+ }): Promise<KnownErrors["PasswordConfirmationMismatch"] | KnownErrors["PasswordRequirementsNotMet"] | undefined>;
103
110
  }
@@ -58,10 +58,11 @@ export class StackServerInterface extends StackClientInterface {
58
58
  return user;
59
59
  }
60
60
  async getServerUserById(userId) {
61
- const response = await this.sendServerRequest(urlString `/users/${userId}`, {}, null);
62
- const user = await response.json();
63
- if (!user)
64
- return Result.error(new Error("Failed to get user"));
61
+ const responseOrError = await this.sendServerRequestAndCatchKnownError(urlString `/users/${userId}`, {}, null, [KnownErrors.UserNotFound]);
62
+ if (responseOrError.status === "error") {
63
+ return Result.error(responseOrError.error);
64
+ }
65
+ const user = await responseOrError.data.json();
65
66
  return Result.ok(user);
66
67
  }
67
68
  async listServerTeamInvitations(options) {
@@ -182,7 +183,7 @@ export class StackServerInterface extends StackClientInterface {
182
183
  }, null);
183
184
  return await response.json();
184
185
  }
185
- async createServerUserSession(userId, expiresInMillis) {
186
+ async createServerUserSession(userId, expiresInMillis, isImpersonation) {
186
187
  const response = await this.sendServerRequest("/auth/sessions", {
187
188
  method: "POST",
188
189
  headers: {
@@ -191,6 +192,7 @@ export class StackServerInterface extends StackClientInterface {
191
192
  body: JSON.stringify({
192
193
  user_id: userId,
193
194
  expires_in_millis: expiresInMillis,
195
+ is_impersonation: isImpersonation,
194
196
  }),
195
197
  }, null);
196
198
  const result = await response.json();
@@ -285,6 +287,17 @@ export class StackServerInterface extends StackClientInterface {
285
287
  body: JSON.stringify({ callback_url: callbackUrl }),
286
288
  }, null);
287
289
  }
290
+ async listServerSessions(userId) {
291
+ const response = await this.sendServerRequest(urlString `/auth/sessions?user_id=${userId}`, {
292
+ method: "GET",
293
+ }, null);
294
+ return await response.json();
295
+ }
296
+ async deleteServerSession(sessionId) {
297
+ await this.sendServerRequest(urlString `/auth/sessions/${sessionId}`, {
298
+ method: "DELETE",
299
+ }, null);
300
+ }
288
301
  async sendServerTeamInvitation(options) {
289
302
  await this.sendServerRequest("/team-invitations/send-code", {
290
303
  method: "POST",
@@ -298,4 +311,19 @@ export class StackServerInterface extends StackClientInterface {
298
311
  }),
299
312
  }, null);
300
313
  }
314
+ async updatePassword(options) {
315
+ const res = await this.sendServerRequestAndCatchKnownError("/auth/password/update", {
316
+ method: "POST",
317
+ headers: {
318
+ "Content-Type": "application/json"
319
+ },
320
+ body: JSON.stringify({
321
+ old_password: options.oldPassword,
322
+ new_password: options.newPassword,
323
+ }),
324
+ }, null, [KnownErrors.PasswordConfirmationMismatch, KnownErrors.PasswordRequirementsNotMet]);
325
+ if (res.status === "error") {
326
+ return res.error;
327
+ }
328
+ }
301
329
  }
@@ -46,6 +46,11 @@ export type KnownErrors = {
46
46
  [K in keyof typeof KnownErrors]: InstanceType<typeof KnownErrors[K]>;
47
47
  };
48
48
  export declare const KnownErrors: {
49
+ CannotDeleteCurrentSession: KnownErrorConstructor<KnownError & KnownErrorBrand<"REFRESH_TOKEN_ERROR"> & {
50
+ constructorArgs: [statusCode: number, humanReadableMessage: string, details?: Json | undefined];
51
+ } & KnownErrorBrand<"CANNOT_DELETE_CURRENT_SESSION">, []> & {
52
+ errorCode: "CANNOT_DELETE_CURRENT_SESSION";
53
+ };
49
54
  UnsupportedError: KnownErrorConstructor<KnownError & KnownErrorBrand<"UNSUPPORTED_ERROR">, [originalErrorCode: string]> & {
50
55
  errorCode: "UNSUPPORTED_ERROR";
51
56
  };
@@ -194,7 +199,7 @@ export declare const KnownErrors: {
194
199
  };
195
200
  AccessTokenExpired: KnownErrorConstructor<KnownError & KnownErrorBrand<"SESSION_AUTHENTICATION_ERROR"> & {
196
201
  constructorArgs: [statusCode: number, humanReadableMessage: string, details?: Json | undefined];
197
- } & KnownErrorBrand<"INVALID_SESSION_AUTHENTICATION"> & KnownErrorBrand<"INVALID_ACCESS_TOKEN"> & KnownErrorBrand<"ACCESS_TOKEN_EXPIRED">, [expiredAt: Date | undefined]> & {
202
+ } & KnownErrorBrand<"INVALID_SESSION_AUTHENTICATION"> & KnownErrorBrand<"INVALID_ACCESS_TOKEN"> & KnownErrorBrand<"ACCESS_TOKEN_EXPIRED">, [Date | undefined]> & {
198
203
  errorCode: "ACCESS_TOKEN_EXPIRED";
199
204
  };
200
205
  InvalidProjectForAccessToken: KnownErrorConstructor<KnownError & KnownErrorBrand<"SESSION_AUTHENTICATION_ERROR"> & {
@@ -386,5 +391,8 @@ export declare const KnownErrors: {
386
391
  ContactChannelAlreadyUsedForAuthBySomeoneElse: KnownErrorConstructor<KnownError & KnownErrorBrand<"CONTACT_CHANNEL_ALREADY_USED_FOR_AUTH_BY_SOMEONE_ELSE">, [type: "email", contactChannelValue?: string | undefined]> & {
387
392
  errorCode: "CONTACT_CHANNEL_ALREADY_USED_FOR_AUTH_BY_SOMEONE_ELSE";
388
393
  };
394
+ InvalidPollingCodeError: KnownErrorConstructor<KnownError & KnownErrorBrand<"INVALID_POLLING_CODE">, [details?: Json | undefined]> & {
395
+ errorCode: "INVALID_POLLING_CODE";
396
+ };
389
397
  };
390
398
  export {};
@@ -245,7 +245,7 @@ const AccessTokenExpired = createKnownErrorConstructor(InvalidAccessToken, "ACCE
245
245
  401,
246
246
  `Access token has expired. Please refresh it and try again.${expiredAt ? ` (The access token expired at ${expiredAt.toISOString()}.)` : ""}`,
247
247
  { expired_at_millis: expiredAt?.getTime() ?? null },
248
- ], (json) => [json.expired_at_millis ?? undefined]);
248
+ ], (json) => [json.expired_at_millis ? new Date(json.expired_at_millis) : undefined]);
249
249
  const InvalidProjectForAccessToken = createKnownErrorConstructor(InvalidAccessToken, "INVALID_PROJECT_FOR_ACCESS_TOKEN", () => [
250
250
  401,
251
251
  "Access token not valid for this project.",
@@ -255,6 +255,10 @@ const RefreshTokenNotFoundOrExpired = createKnownErrorConstructor(RefreshTokenEr
255
255
  401,
256
256
  "Refresh token not found for this project, or the session has expired/been revoked.",
257
257
  ], () => []);
258
+ const CannotDeleteCurrentSession = createKnownErrorConstructor(RefreshTokenError, "CANNOT_DELETE_CURRENT_SESSION", () => [
259
+ 400,
260
+ "Cannot delete the current session.",
261
+ ], () => []);
258
262
  const ProviderRejected = createKnownErrorConstructor(RefreshTokenError, "PROVIDER_REJECTED", () => [
259
263
  401,
260
264
  "The provider refused to refresh their token. This usually means that the provider used to authenticate the user no longer regards this session as valid, and the user must re-authenticate.",
@@ -542,7 +546,13 @@ const ContactChannelAlreadyUsedForAuthBySomeoneElse = createKnownErrorConstructo
542
546
  `This ${type} is already used for authentication by another account.`,
543
547
  { type, contact_channel_value: contactChannelValue ?? null },
544
548
  ], (json) => [json.type, json.contact_channel_value]);
549
+ const InvalidPollingCodeError = createKnownErrorConstructor(KnownError, "INVALID_POLLING_CODE", (details) => [
550
+ 400,
551
+ "The polling code is invalid or does not exist.",
552
+ details,
553
+ ], (json) => [json]);
545
554
  export const KnownErrors = {
555
+ CannotDeleteCurrentSession,
546
556
  UnsupportedError,
547
557
  BodyParsingError,
548
558
  SchemaError,
@@ -633,6 +643,7 @@ export const KnownErrors = {
633
643
  TeamPermissionNotFound,
634
644
  OAuthProviderAccessDenied,
635
645
  ContactChannelAlreadyUsedForAuthBySomeoneElse,
646
+ InvalidPollingCodeError,
636
647
  };
637
648
  // ensure that all known error codes are unique
638
649
  const knownErrorCodes = new Set();
@@ -0,0 +1,19 @@
1
+ import * as yup from "yup";
2
+ export declare const geoInfoSchema: yup.ObjectSchema<{
3
+ ip: string;
4
+ countryCode: string | null | undefined;
5
+ regionCode: string | null | undefined;
6
+ cityName: string | null | undefined;
7
+ latitude: number | null | undefined;
8
+ longitude: number | null | undefined;
9
+ tzIdentifier: string | null | undefined;
10
+ }, yup.AnyObject, {
11
+ ip: undefined;
12
+ countryCode: undefined;
13
+ regionCode: undefined;
14
+ cityName: undefined;
15
+ latitude: undefined;
16
+ longitude: undefined;
17
+ tzIdentifier: undefined;
18
+ }, "">;
19
+ export type GeoInfo = yup.InferType<typeof geoInfoSchema>;
@@ -0,0 +1,10 @@
1
+ import { yupNumber, yupObject, yupString } from "../schema-fields";
2
+ export const geoInfoSchema = yupObject({
3
+ ip: yupString().defined(),
4
+ countryCode: yupString().nullable(),
5
+ regionCode: yupString().nullable(),
6
+ cityName: yupString().nullable(),
7
+ latitude: yupNumber().nullable(),
8
+ longitude: yupNumber().nullable(),
9
+ tzIdentifier: yupString().nullable(),
10
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.7.26",
3
+ "version": "2.7.28",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",