@stackframe/stack-shared 2.5.4 → 2.5.6

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,18 @@
1
1
  # @stackframe/stack-shared
2
2
 
3
+ ## 2.5.6
4
+
5
+ ### Patch Changes
6
+
7
+ - Various bugfixes
8
+ - @stackframe/stack-sc@2.5.6
9
+
10
+ ## 2.5.5
11
+
12
+ ### Patch Changes
13
+
14
+ - @stackframe/stack-sc@2.5.5
15
+
3
16
  ## 2.5.4
4
17
 
5
18
  ### Patch Changes
@@ -18,6 +18,9 @@ export declare const projectsCrudServerReadSchema: import("yup").ObjectSchema<{
18
18
  id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
19
19
  enabled: NonNullable<boolean | undefined>;
20
20
  }[];
21
+ enabled_oauth_providers: {
22
+ id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
23
+ }[];
21
24
  domains: {
22
25
  domain: string;
23
26
  handler_path: string;
@@ -52,6 +55,7 @@ export declare const projectsCrudServerReadSchema: import("yup").ObjectSchema<{
52
55
  credential_enabled: undefined;
53
56
  magic_link_enabled: undefined;
54
57
  oauth_providers: undefined;
58
+ enabled_oauth_providers: undefined;
55
59
  domains: undefined;
56
60
  email_config: {
57
61
  type: undefined;
@@ -73,7 +77,7 @@ export declare const projectsCrudClientReadSchema: import("yup").ObjectSchema<{
73
77
  config: {
74
78
  credential_enabled: NonNullable<boolean | undefined>;
75
79
  magic_link_enabled: NonNullable<boolean | undefined>;
76
- oauth_providers: {
80
+ enabled_oauth_providers: {
77
81
  id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
78
82
  }[];
79
83
  };
@@ -83,7 +87,7 @@ export declare const projectsCrudClientReadSchema: import("yup").ObjectSchema<{
83
87
  config: {
84
88
  credential_enabled: undefined;
85
89
  magic_link_enabled: undefined;
86
- oauth_providers: undefined;
90
+ enabled_oauth_providers: undefined;
87
91
  };
88
92
  }, "">;
89
93
  export declare const projectsCrudServerUpdateSchema: import("yup").ObjectSchema<{
@@ -179,7 +183,7 @@ export declare const projectsCrud: import("../../crud").CrudSchemaFromOptions<{
179
183
  config: {
180
184
  credential_enabled: NonNullable<boolean | undefined>;
181
185
  magic_link_enabled: NonNullable<boolean | undefined>;
182
- oauth_providers: {
186
+ enabled_oauth_providers: {
183
187
  id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
184
188
  }[];
185
189
  };
@@ -189,7 +193,7 @@ export declare const projectsCrud: import("../../crud").CrudSchemaFromOptions<{
189
193
  config: {
190
194
  credential_enabled: undefined;
191
195
  magic_link_enabled: undefined;
192
- oauth_providers: undefined;
196
+ enabled_oauth_providers: undefined;
193
197
  };
194
198
  }, "">;
195
199
  serverReadSchema: import("yup").ObjectSchema<{
@@ -211,6 +215,9 @@ export declare const projectsCrud: import("../../crud").CrudSchemaFromOptions<{
211
215
  id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
212
216
  enabled: NonNullable<boolean | undefined>;
213
217
  }[];
218
+ enabled_oauth_providers: {
219
+ id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
220
+ }[];
214
221
  domains: {
215
222
  domain: string;
216
223
  handler_path: string;
@@ -245,6 +252,7 @@ export declare const projectsCrud: import("../../crud").CrudSchemaFromOptions<{
245
252
  credential_enabled: undefined;
246
253
  magic_link_enabled: undefined;
247
254
  oauth_providers: undefined;
255
+ enabled_oauth_providers: undefined;
248
256
  domains: undefined;
249
257
  email_config: {
250
258
  type: undefined;
@@ -341,6 +349,9 @@ export declare const internalProjectsCrud: import("../../crud").CrudSchemaFromOp
341
349
  id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
342
350
  enabled: NonNullable<boolean | undefined>;
343
351
  }[];
352
+ enabled_oauth_providers: {
353
+ id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
354
+ }[];
344
355
  domains: {
345
356
  domain: string;
346
357
  handler_path: string;
@@ -375,6 +386,7 @@ export declare const internalProjectsCrud: import("../../crud").CrudSchemaFromOp
375
386
  credential_enabled: undefined;
376
387
  magic_link_enabled: undefined;
377
388
  oauth_providers: undefined;
389
+ enabled_oauth_providers: undefined;
378
390
  domains: undefined;
379
391
  email_config: {
380
392
  type: undefined;
@@ -11,6 +11,9 @@ const oauthProviderSchema = yupObject({
11
11
  client_id: yupRequiredWhen(schemaFields.oauthClientIdSchema, 'type', 'standard'),
12
12
  client_secret: yupRequiredWhen(schemaFields.oauthClientSecretSchema, 'type', 'standard'),
13
13
  });
14
+ const enabledOAuthProviderSchema = yupObject({
15
+ id: schemaFields.oauthIdSchema.required(),
16
+ });
14
17
  const emailConfigSchema = yupObject({
15
18
  type: schemaFields.emailTypeSchema.required(),
16
19
  host: yupRequiredWhen(schemaFields.emailHostSchema, 'type', 'standard'),
@@ -37,6 +40,7 @@ export const projectsCrudServerReadSchema = yupObject({
37
40
  credential_enabled: schemaFields.projectCredentialEnabledSchema.required(),
38
41
  magic_link_enabled: schemaFields.projectMagicLinkEnabledSchema.required(),
39
42
  oauth_providers: yupArray(oauthProviderSchema.required()).required(),
43
+ enabled_oauth_providers: yupArray(enabledOAuthProviderSchema.required()).required(),
40
44
  domains: yupArray(domainSchema.required()).required(),
41
45
  email_config: emailConfigSchema.required(),
42
46
  create_team_on_sign_up: schemaFields.projectCreateTeamOnSignUpSchema.required(),
@@ -50,9 +54,7 @@ export const projectsCrudClientReadSchema = yupObject({
50
54
  config: yupObject({
51
55
  credential_enabled: schemaFields.projectCredentialEnabledSchema.required(),
52
56
  magic_link_enabled: schemaFields.projectMagicLinkEnabledSchema.required(),
53
- oauth_providers: yupArray(yupObject({
54
- id: schemaFields.oauthIdSchema.required(),
55
- }).required()).required(),
57
+ enabled_oauth_providers: yupArray(enabledOAuthProviderSchema.required()).required(),
56
58
  }).required(),
57
59
  }).required();
58
60
  export const projectsCrudServerUpdateSchema = yupObject({
@@ -3,7 +3,7 @@ import * as schemaFields from "../../schema-fields";
3
3
  import { yupMixed, yupObject } from "../../schema-fields";
4
4
  // =============== Team permissions =================
5
5
  export const teamPermissionsCrudClientReadSchema = yupObject({
6
- id: schemaFields.teamPermissionIdSchema.required(),
6
+ id: schemaFields.teamPermissionDefinitionIdSchema.required(),
7
7
  user_id: schemaFields.userIdSchema.required(),
8
8
  team_id: schemaFields.teamIdSchema.required(),
9
9
  }).required();
@@ -38,17 +38,17 @@ export const teamPermissionsCrud = createCrud({
38
38
  });
39
39
  // =============== Team permission definitions =================
40
40
  export const teamPermissionDefinitionsCrudAdminReadSchema = yupObject({
41
- id: schemaFields.teamPermissionIdSchema.required(),
41
+ id: schemaFields.teamPermissionDefinitionIdSchema.required(),
42
42
  description: schemaFields.teamPermissionDescriptionSchema.optional(),
43
43
  contained_permission_ids: schemaFields.containedPermissionIdsSchema.required()
44
44
  }).required();
45
45
  export const teamPermissionDefinitionsCrudAdminCreateSchema = yupObject({
46
- id: schemaFields.customTeamPermissionIdSchema.required(),
46
+ id: schemaFields.customTeamPermissionDefinitionIdSchema.required(),
47
47
  description: schemaFields.teamPermissionDescriptionSchema.optional(),
48
48
  contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional()
49
49
  }).required();
50
50
  export const teamPermissionDefinitionsCrudAdminUpdateSchema = yupObject({
51
- id: schemaFields.customTeamPermissionIdSchema.optional(),
51
+ id: schemaFields.customTeamPermissionDefinitionIdSchema.optional(),
52
52
  description: schemaFields.teamPermissionDescriptionSchema.optional(),
53
53
  contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional()
54
54
  }).required();
@@ -3,7 +3,7 @@ import * as schemaFields from "../../schema-fields";
3
3
  import { yupMixed, yupObject } from "../../schema-fields";
4
4
  // Team permissions
5
5
  export const teamPermissionsCrudClientReadSchema = yupObject({
6
- id: schemaFields.teamPermissionIdSchema.required(),
6
+ id: schemaFields.teamPermissionDefinitionIdSchema.required(),
7
7
  user_id: schemaFields.userIdSchema.required(),
8
8
  team_id: schemaFields.teamIdSchema.required(),
9
9
  }).required();
@@ -38,17 +38,17 @@ export const teamPermissionsCrud = createCrud({
38
38
  });
39
39
  // Team permission definitions
40
40
  export const teamPermissionDefinitionsCrudServerReadSchema = yupObject({
41
- id: schemaFields.teamPermissionIdSchema.required(),
41
+ id: schemaFields.teamPermissionDefinitionIdSchema.required(),
42
42
  description: schemaFields.teamPermissionDescriptionSchema.optional(),
43
43
  contained_permission_ids: schemaFields.containedPermissionIdsSchema.required()
44
44
  }).required();
45
45
  export const teamPermissionDefinitionsCrudServerCreateSchema = yupObject({
46
- id: schemaFields.customTeamPermissionIdSchema.required(),
46
+ id: schemaFields.customTeamPermissionDefinitionIdSchema.required(),
47
47
  description: schemaFields.teamPermissionDescriptionSchema.optional(),
48
48
  contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional()
49
49
  }).required();
50
50
  export const teamPermissionDefinitionsCrudServerUpdateSchema = yupObject({
51
- id: schemaFields.customTeamPermissionIdSchema.required(),
51
+ id: schemaFields.customTeamPermissionDefinitionIdSchema.required(),
52
52
  description: schemaFields.teamPermissionDescriptionSchema.optional(),
53
53
  contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional()
54
54
  }).required();
@@ -345,5 +345,8 @@ export declare const KnownErrors: {
345
345
  UserAuthenticationRequired: KnownErrorConstructor<KnownError & KnownErrorBrand<"USER_AUTHENTICATION_REQUIRED">, []> & {
346
346
  errorCode: "USER_AUTHENTICATION_REQUIRED";
347
347
  };
348
+ TeamMembershipAlreadyExists: KnownErrorConstructor<KnownError & KnownErrorBrand<"TEAM_MEMBERSHIP_ALREADY_EXISTS">, []> & {
349
+ errorCode: "TEAM_MEMBERSHIP_ALREADY_EXISTS";
350
+ };
348
351
  };
349
352
  export {};
@@ -394,6 +394,13 @@ const TeamNotFound = createKnownErrorConstructor(KnownError, "TEAM_NOT_FOUND", (
394
394
  team_id: teamId,
395
395
  },
396
396
  ], (json) => [json.team_id]);
397
+ const TeamAlreadyExists = createKnownErrorConstructor(KnownError, "TEAM_ALREADY_EXISTS", (teamId) => [
398
+ 400,
399
+ `Team ${teamId} already exists.`,
400
+ {
401
+ team_id: teamId,
402
+ },
403
+ ], (json) => [json.team_id]);
397
404
  const TeamMembershipNotFound = createKnownErrorConstructor(KnownError, "TEAM_MEMBERSHIP_NOT_FOUND", (teamId, userId) => [
398
405
  404,
399
406
  `User ${userId} is not found in team ${teamId}.`,
@@ -453,6 +460,10 @@ const UserAuthenticationRequired = createKnownErrorConstructor(KnownError, "USER
453
460
  401,
454
461
  "User authentication required for this endpoint.",
455
462
  ], () => []);
463
+ const TeamMembershipAlreadyExists = createKnownErrorConstructor(KnownError, "TEAM_MEMBERSHIP_ALREADY_EXISTS", () => [
464
+ 400,
465
+ "Team membership already exists.",
466
+ ], () => []);
456
467
  export const KnownErrors = {
457
468
  UnsupportedError,
458
469
  BodyParsingError,
@@ -529,6 +540,7 @@ export const KnownErrors = {
529
540
  OuterOAuthTimeout,
530
541
  OAuthProviderNotFoundOrNotEnabled,
531
542
  UserAuthenticationRequired,
543
+ TeamMembershipAlreadyExists,
532
544
  };
533
545
  // ensure that all known error codes are unique
534
546
  const knownErrorCodes = new Set();
@@ -79,8 +79,8 @@ export declare const signInResponseSchema: yup.ObjectSchema<{
79
79
  user_id: undefined;
80
80
  }, "">;
81
81
  export declare const teamSystemPermissions: readonly ["$update_team", "$delete_team", "$read_members", "$remove_members", "$invite_members"];
82
- export declare const teamPermissionIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
83
- export declare const customTeamPermissionIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
82
+ export declare const teamPermissionDefinitionIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
83
+ export declare const customTeamPermissionDefinitionIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
84
84
  export declare const teamPermissionDescriptionSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
85
85
  export declare const containedPermissionIdsSchema: yup.ArraySchema<string[] | undefined, yup.AnyObject, undefined, "">;
86
86
  export declare const teamIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
@@ -1,4 +1,5 @@
1
1
  import * as yup from "yup";
2
+ import { isUuid } from "./utils/uuids";
2
3
  const _idDescription = (identify) => `The immutable ID used to uniquely identify this ${identify}`;
3
4
  const _displayNameDescription = (identify) => `Human-readable ${identify} display name, used in places like frontend UI. This is not a unique identifier.`;
4
5
  const _clientMetaDataDescription = (identify) => `Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client.`;
@@ -90,7 +91,7 @@ export const clientOrHigherAuthTypeSchema = yupString().oneOf(['client', 'server
90
91
  export const serverOrHigherAuthTypeSchema = yupString().oneOf(['server', 'admin']);
91
92
  export const adminAuthTypeSchema = yupString().oneOf(['admin']);
92
93
  // Projects
93
- export const projectIdSchema = yupString().meta({ openapiField: { description: _idDescription('project'), exampleValue: 'e0b52f4d-dece-408c-af49-d23061bb0f8d' } });
94
+ export const projectIdSchema = yupString().test((v) => v === undefined || v === "internal" || isUuid(v)).meta({ openapiField: { description: _idDescription('project'), exampleValue: 'e0b52f4d-dece-408c-af49-d23061bb0f8d' } });
94
95
  export const projectDisplayNameSchema = yupString().meta({ openapiField: { description: _displayNameDescription('project'), exampleValue: 'MyMusic' } });
95
96
  export const projectDescriptionSchema = yupString().nullable().meta({ openapiField: { description: 'A human readable description of the project', exampleValue: 'A music streaming service' } });
96
97
  export const projectCreatedAtMillisSchema = yupNumber().meta({ openapiField: { description: _createdAtMillisDescription('project'), exampleValue: 1630000000000 } });
@@ -166,7 +167,7 @@ export const teamSystemPermissions = [
166
167
  '$remove_members',
167
168
  '$invite_members',
168
169
  ];
169
- export const teamPermissionIdSchema = yupString()
170
+ export const teamPermissionDefinitionIdSchema = yupString()
170
171
  .matches(/^\$?[a-z0-9_:]+$/, 'Only lowercase letters, numbers, ":", "_" and optional "$" at the beginning are allowed')
171
172
  .test('is-system-permission', 'System permissions must start with a dollar sign', (value, ctx) => {
172
173
  if (!value)
@@ -177,11 +178,11 @@ export const teamPermissionIdSchema = yupString()
177
178
  return true;
178
179
  })
179
180
  .meta({ openapiField: { description: `The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, ":", and "_" characters, or one of the system permissions: ${teamSystemPermissions.join(', ')}`, exampleValue: '$read_secret_info' } });
180
- export const customTeamPermissionIdSchema = yupString()
181
+ export const customTeamPermissionDefinitionIdSchema = yupString()
181
182
  .matches(/^[a-z0-9_:]+$/, 'Only lowercase letters, numbers, ":", "_" are allowed')
182
183
  .meta({ openapiField: { description: 'The permission ID used to uniquely identify a permission. Can only contain lowercase letters, numbers, ":", and "_" characters', exampleValue: 'read_secret_info' } });
183
184
  export const teamPermissionDescriptionSchema = yupString().meta({ openapiField: { description: 'A human-readable description of the permission', exampleValue: 'Read secret information' } });
184
- export const containedPermissionIdsSchema = yupArray(teamPermissionIdSchema.required()).meta({ openapiField: { description: 'The IDs of the permissions that are contained in this permission', exampleValue: ['read_public_info'] } });
185
+ export const containedPermissionIdsSchema = yupArray(teamPermissionDefinitionIdSchema.required()).meta({ openapiField: { description: 'The IDs of the permissions that are contained in this permission', exampleValue: ['read_public_info'] } });
185
186
  // Teams
186
187
  export const teamIdSchema = yupString().uuid().meta({ openapiField: { description: _idDescription('team'), exampleValue: 'ad962777-8244-496a-b6a2-e0c6a449c79e' } });
187
188
  export const teamDisplayNameSchema = yupString().meta({ openapiField: { description: _displayNameDescription('team'), exampleValue: 'My Team' } });
@@ -95,7 +95,7 @@ export function runAsynchronouslyWithAlert(...args) {
95
95
  return runAsynchronously(args[0], {
96
96
  ...args[1],
97
97
  onError: error => {
98
- alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === "development" ? `check the browser console for the full error. ${error}` : "report this to the developer."}`);
98
+ alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === "development" ? `check the browser console for the full error. ${error}` : "report this to the developer."}\n\n${error}`);
99
99
  args[1]?.onError?.(error);
100
100
  },
101
101
  }, ...args.slice(2));
@@ -101,6 +101,7 @@ class RetryError extends AggregateError {
101
101
  return this.errors.length;
102
102
  }
103
103
  }
104
+ RetryError.prototype.name = "RetryError";
104
105
  async function retry(fn, retries, { exponentialDelayBase = 2000 }) {
105
106
  const errors = [];
106
107
  for (let i = 0; i < retries; i++) {
@@ -1,3 +1,4 @@
1
1
  export type IsAny<T> = 0 extends (1 & T) ? true : false;
2
2
  export type isNullish<T> = T extends null | undefined ? true : false;
3
3
  export type NullishCoalesce<T, U> = T extends null | undefined ? U : T;
4
+ export type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
@@ -1 +1,2 @@
1
1
  export declare function generateUuid(): string;
2
+ export declare function isUuid(str: string): boolean;
@@ -3,3 +3,6 @@ export function generateUuid() {
3
3
  // crypto.randomUuid is not supported in all browsers, so this is a polyfill
4
4
  return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c => (+c ^ globalVar.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16));
5
5
  }
6
+ export function isUuid(str) {
7
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(str);
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.5.4",
3
+ "version": "2.5.6",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -36,7 +36,7 @@
36
36
  "jose": "^5.2.2",
37
37
  "oauth4webapi": "^2.10.3",
38
38
  "uuid": "^9.0.1",
39
- "@stackframe/stack-sc": "2.5.4"
39
+ "@stackframe/stack-sc": "2.5.6"
40
40
  },
41
41
  "devDependencies": {
42
42
  "rimraf": "^5.0.5",