@stackframe/stack-shared 2.8.2 → 2.8.5
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 +18 -0
- package/dist/config/format.d.ts +38 -0
- package/dist/config/format.js +224 -0
- package/dist/config/schema.d.ts +721 -0
- package/dist/config/schema.js +185 -0
- package/dist/crud.js +1 -1
- package/dist/interface/adminInterface.d.ts +7 -7
- package/dist/interface/adminInterface.js +7 -7
- package/dist/interface/clientInterface.d.ts +46 -4
- package/dist/interface/clientInterface.js +66 -2
- package/dist/interface/crud/current-user.d.ts +2 -2
- package/dist/interface/crud/{api-keys.d.ts → internal-api-keys.d.ts} +7 -7
- package/dist/interface/crud/{api-keys.js → internal-api-keys.js} +10 -10
- package/dist/interface/crud/project-api-keys.d.ts +188 -0
- package/dist/interface/crud/project-api-keys.js +76 -0
- package/dist/interface/crud/projects.d.ts +53 -20
- package/dist/interface/crud/projects.js +15 -5
- package/dist/interface/crud/team-member-profiles.d.ts +4 -4
- package/dist/interface/crud/users.d.ts +8 -8
- package/dist/interface/serverInterface.d.ts +2 -1
- package/dist/interface/serverInterface.js +4 -0
- package/dist/interface/webhooks.d.ts +2 -2
- package/dist/known-errors.d.ts +35 -1
- package/dist/known-errors.js +42 -4
- package/dist/schema-fields.d.ts +6 -5
- package/dist/schema-fields.js +36 -3
- package/dist/utils/api-keys.d.ts +23 -0
- package/dist/utils/api-keys.js +76 -0
- package/dist/utils/bytes.d.ts +3 -0
- package/dist/utils/bytes.js +55 -6
- package/dist/utils/caches.d.ts +10 -10
- package/dist/utils/hashes.d.ts +1 -1
- package/dist/utils/hashes.js +1 -3
- package/dist/utils/objects.d.ts +35 -2
- package/dist/utils/objects.js +128 -0
- package/dist/utils/promises.d.ts +1 -1
- package/dist/utils/promises.js +9 -10
- package/dist/utils/stores.d.ts +6 -6
- package/dist/utils/types.d.ts +17 -0
- package/package.json +2 -1
|
@@ -43,8 +43,8 @@ export declare const usersCrudServerReadSchema: import("yup").ObjectSchema<{
|
|
|
43
43
|
client_read_only_metadata?: {} | null | undefined;
|
|
44
44
|
server_metadata?: {} | null | undefined;
|
|
45
45
|
id: string;
|
|
46
|
-
created_at_millis: number;
|
|
47
46
|
display_name: string;
|
|
47
|
+
created_at_millis: number;
|
|
48
48
|
profile_image_url: string | null;
|
|
49
49
|
} | null;
|
|
50
50
|
selected_team_id: string | null;
|
|
@@ -96,13 +96,13 @@ export declare const usersCrudServerReadSchema: import("yup").ObjectSchema<{
|
|
|
96
96
|
requires_totp_mfa: undefined;
|
|
97
97
|
}, "">;
|
|
98
98
|
export declare const usersCrudServerCreateSchema: import("yup").ObjectSchema<{
|
|
99
|
-
primary_email: string | null | undefined;
|
|
100
99
|
password: string | null | undefined;
|
|
101
100
|
display_name: string | null | undefined;
|
|
102
101
|
profile_image_url: string | null | undefined;
|
|
103
102
|
client_metadata: {} | null | undefined;
|
|
104
103
|
client_read_only_metadata: {} | null | undefined;
|
|
105
104
|
server_metadata: {} | null | undefined;
|
|
105
|
+
primary_email: string | null | undefined;
|
|
106
106
|
primary_email_verified: boolean | undefined;
|
|
107
107
|
primary_email_auth_enabled: boolean | undefined;
|
|
108
108
|
passkey_auth_enabled: boolean | undefined;
|
|
@@ -112,9 +112,9 @@ export declare const usersCrudServerCreateSchema: import("yup").ObjectSchema<{
|
|
|
112
112
|
is_anonymous: boolean | undefined;
|
|
113
113
|
} & {
|
|
114
114
|
oauth_providers: {
|
|
115
|
-
email: string | null;
|
|
116
115
|
id: string;
|
|
117
116
|
account_id: string;
|
|
117
|
+
email: string | null;
|
|
118
118
|
}[] | undefined;
|
|
119
119
|
is_anonymous: boolean | undefined;
|
|
120
120
|
}, import("yup").AnyObject, {
|
|
@@ -148,8 +148,8 @@ export declare const usersCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
148
148
|
client_read_only_metadata?: {} | null | undefined;
|
|
149
149
|
server_metadata?: {} | null | undefined;
|
|
150
150
|
id: string;
|
|
151
|
-
created_at_millis: number;
|
|
152
151
|
display_name: string;
|
|
152
|
+
created_at_millis: number;
|
|
153
153
|
profile_image_url: string | null;
|
|
154
154
|
} | null;
|
|
155
155
|
selected_team_id: string | null;
|
|
@@ -234,13 +234,13 @@ export declare const usersCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
234
234
|
is_anonymous: undefined;
|
|
235
235
|
}, "">;
|
|
236
236
|
serverCreateSchema: import("yup").ObjectSchema<{
|
|
237
|
-
primary_email: string | null | undefined;
|
|
238
237
|
password: string | null | undefined;
|
|
239
238
|
display_name: string | null | undefined;
|
|
240
239
|
profile_image_url: string | null | undefined;
|
|
241
240
|
client_metadata: {} | null | undefined;
|
|
242
241
|
client_read_only_metadata: {} | null | undefined;
|
|
243
242
|
server_metadata: {} | null | undefined;
|
|
243
|
+
primary_email: string | null | undefined;
|
|
244
244
|
primary_email_verified: boolean | undefined;
|
|
245
245
|
primary_email_auth_enabled: boolean | undefined;
|
|
246
246
|
passkey_auth_enabled: boolean | undefined;
|
|
@@ -250,9 +250,9 @@ export declare const usersCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
250
250
|
is_anonymous: boolean | undefined;
|
|
251
251
|
} & {
|
|
252
252
|
oauth_providers: {
|
|
253
|
-
email: string | null;
|
|
254
253
|
id: string;
|
|
255
254
|
account_id: string;
|
|
255
|
+
email: string | null;
|
|
256
256
|
}[] | undefined;
|
|
257
257
|
is_anonymous: boolean | undefined;
|
|
258
258
|
}, import("yup").AnyObject, {
|
|
@@ -316,8 +316,8 @@ export declare const userCreatedWebhookEvent: {
|
|
|
316
316
|
client_read_only_metadata?: {} | null | undefined;
|
|
317
317
|
server_metadata?: {} | null | undefined;
|
|
318
318
|
id: string;
|
|
319
|
-
created_at_millis: number;
|
|
320
319
|
display_name: string;
|
|
320
|
+
created_at_millis: number;
|
|
321
321
|
profile_image_url: string | null;
|
|
322
322
|
} | null;
|
|
323
323
|
selected_team_id: string | null;
|
|
@@ -387,8 +387,8 @@ export declare const userUpdatedWebhookEvent: {
|
|
|
387
387
|
client_read_only_metadata?: {} | null | undefined;
|
|
388
388
|
server_metadata?: {} | null | undefined;
|
|
389
389
|
id: string;
|
|
390
|
-
created_at_millis: number;
|
|
391
390
|
display_name: string;
|
|
391
|
+
created_at_millis: number;
|
|
392
392
|
profile_image_url: string | null;
|
|
393
393
|
} | null;
|
|
394
394
|
selected_team_id: string | null;
|
|
@@ -5,11 +5,11 @@ 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 { ProjectPermissionsCrud } from "./crud/project-permissions";
|
|
8
9
|
import { SessionsCrud } from "./crud/sessions";
|
|
9
10
|
import { TeamInvitationCrud } from "./crud/team-invitation";
|
|
10
11
|
import { TeamMemberProfilesCrud } from "./crud/team-member-profiles";
|
|
11
12
|
import { TeamMembershipsCrud } from "./crud/team-memberships";
|
|
12
|
-
import { ProjectPermissionsCrud } from "./crud/project-permissions";
|
|
13
13
|
import { TeamPermissionsCrud } from "./crud/team-permissions";
|
|
14
14
|
import { TeamsCrud } from "./crud/teams";
|
|
15
15
|
import { UsersCrud } from "./crud/users";
|
|
@@ -66,6 +66,7 @@ export declare class StackServerInterface extends StackClientInterface {
|
|
|
66
66
|
listServerTeams(options?: {
|
|
67
67
|
userId?: string;
|
|
68
68
|
}): Promise<TeamsCrud['Server']['Read'][]>;
|
|
69
|
+
getServerTeam(teamId: string): Promise<TeamsCrud['Server']['Read']>;
|
|
69
70
|
listServerTeamUsers(teamId: string): Promise<UsersCrud['Server']['Read'][]>;
|
|
70
71
|
createServerTeam(data: TeamsCrud['Server']['Create']): Promise<TeamsCrud['Server']['Read']>;
|
|
71
72
|
updateServerTeam(teamId: string, data: TeamsCrud['Server']['Update']): Promise<TeamsCrud['Server']['Read']>;
|
|
@@ -123,6 +123,10 @@ export class StackServerInterface extends StackClientInterface {
|
|
|
123
123
|
const result = await response.json();
|
|
124
124
|
return result.items;
|
|
125
125
|
}
|
|
126
|
+
async getServerTeam(teamId) {
|
|
127
|
+
const response = await this.sendServerRequest(`/teams/${teamId}`, {}, null);
|
|
128
|
+
return await response.json();
|
|
129
|
+
}
|
|
126
130
|
async listServerTeamUsers(teamId) {
|
|
127
131
|
const response = await this.sendServerRequest(`/users?team_id=${teamId}`, {}, null);
|
|
128
132
|
const result = await response.json();
|
|
@@ -21,8 +21,8 @@ export declare const webhookEvents: readonly [{
|
|
|
21
21
|
client_read_only_metadata?: {} | null | undefined;
|
|
22
22
|
server_metadata?: {} | null | undefined;
|
|
23
23
|
id: string;
|
|
24
|
-
created_at_millis: number;
|
|
25
24
|
display_name: string;
|
|
25
|
+
created_at_millis: number;
|
|
26
26
|
profile_image_url: string | null;
|
|
27
27
|
} | null;
|
|
28
28
|
selected_team_id: string | null;
|
|
@@ -91,8 +91,8 @@ export declare const webhookEvents: readonly [{
|
|
|
91
91
|
client_read_only_metadata?: {} | null | undefined;
|
|
92
92
|
server_metadata?: {} | null | undefined;
|
|
93
93
|
id: string;
|
|
94
|
-
created_at_millis: number;
|
|
95
94
|
display_name: string;
|
|
95
|
+
created_at_millis: number;
|
|
96
96
|
profile_image_url: string | null;
|
|
97
97
|
} | null;
|
|
98
98
|
selected_team_id: string | null;
|
package/dist/known-errors.d.ts
CHANGED
|
@@ -69,6 +69,15 @@ export declare const KnownErrors: {
|
|
|
69
69
|
PermissionIdAlreadyExists: KnownErrorConstructor<KnownError & KnownErrorBrand<"PERMISSION_ID_ALREADY_EXISTS">, [permissionId: string]> & {
|
|
70
70
|
errorCode: "PERMISSION_ID_ALREADY_EXISTS";
|
|
71
71
|
};
|
|
72
|
+
CliAuthError: KnownErrorConstructor<KnownError & KnownErrorBrand<"CLI_AUTH_ERROR">, [message: string]> & {
|
|
73
|
+
errorCode: "CLI_AUTH_ERROR";
|
|
74
|
+
};
|
|
75
|
+
CliAuthExpiredError: KnownErrorConstructor<KnownError & KnownErrorBrand<"CLI_AUTH_EXPIRED_ERROR">, [message?: string | undefined]> & {
|
|
76
|
+
errorCode: "CLI_AUTH_EXPIRED_ERROR";
|
|
77
|
+
};
|
|
78
|
+
CliAuthUsedError: KnownErrorConstructor<KnownError & KnownErrorBrand<"CLI_AUTH_USED_ERROR">, [message?: string | undefined]> & {
|
|
79
|
+
errorCode: "CLI_AUTH_USED_ERROR";
|
|
80
|
+
};
|
|
72
81
|
InvalidProjectAuthentication: KnownErrorConstructor<KnownError & KnownErrorBrand<"PROJECT_AUTHENTICATION_ERROR"> & {
|
|
73
82
|
constructorArgs: [statusCode: number, humanReadableMessage: string, details?: Json | undefined];
|
|
74
83
|
} & KnownErrorBrand<"INVALID_PROJECT_AUTHENTICATION">, [statusCode: number, humanReadableMessage: string, details?: Json | undefined]> & {
|
|
@@ -235,9 +244,16 @@ export declare const KnownErrors: {
|
|
|
235
244
|
UserNotFound: KnownErrorConstructor<KnownError & KnownErrorBrand<"USER_NOT_FOUND">, []> & {
|
|
236
245
|
errorCode: "USER_NOT_FOUND";
|
|
237
246
|
};
|
|
238
|
-
ApiKeyNotFound: KnownErrorConstructor<KnownError & KnownErrorBrand<"
|
|
247
|
+
ApiKeyNotFound: KnownErrorConstructor<KnownError & KnownErrorBrand<"API_KEY_NOT_VALID"> & {
|
|
248
|
+
constructorArgs: [statusCode: number, humanReadableMessage: string, details?: Json | undefined];
|
|
249
|
+
} & KnownErrorBrand<"API_KEY_NOT_FOUND">, []> & {
|
|
239
250
|
errorCode: "API_KEY_NOT_FOUND";
|
|
240
251
|
};
|
|
252
|
+
PublicApiKeyCannotBeRevoked: KnownErrorConstructor<KnownError & KnownErrorBrand<"API_KEY_NOT_VALID"> & {
|
|
253
|
+
constructorArgs: [statusCode: number, humanReadableMessage: string, details?: Json | undefined];
|
|
254
|
+
} & KnownErrorBrand<"PUBLIC_API_KEY_CANNOT_BE_REVOKED">, []> & {
|
|
255
|
+
errorCode: "PUBLIC_API_KEY_CANNOT_BE_REVOKED";
|
|
256
|
+
};
|
|
241
257
|
ProjectNotFound: KnownErrorConstructor<KnownError & KnownErrorBrand<"PROJECT_NOT_FOUND">, [projectId: string]> & {
|
|
242
258
|
errorCode: "PROJECT_NOT_FOUND";
|
|
243
259
|
};
|
|
@@ -403,5 +419,23 @@ export declare const KnownErrors: {
|
|
|
403
419
|
InvalidPollingCodeError: KnownErrorConstructor<KnownError & KnownErrorBrand<"INVALID_POLLING_CODE">, [details?: Json | undefined]> & {
|
|
404
420
|
errorCode: "INVALID_POLLING_CODE";
|
|
405
421
|
};
|
|
422
|
+
ApiKeyNotValid: KnownErrorConstructor<KnownError & KnownErrorBrand<"API_KEY_NOT_VALID">, [statusCode: number, humanReadableMessage: string, details?: Json | undefined]> & {
|
|
423
|
+
errorCode: "API_KEY_NOT_VALID";
|
|
424
|
+
};
|
|
425
|
+
ApiKeyExpired: KnownErrorConstructor<KnownError & KnownErrorBrand<"API_KEY_NOT_VALID"> & {
|
|
426
|
+
constructorArgs: [statusCode: number, humanReadableMessage: string, details?: Json | undefined];
|
|
427
|
+
} & KnownErrorBrand<"API_KEY_EXPIRED">, []> & {
|
|
428
|
+
errorCode: "API_KEY_EXPIRED";
|
|
429
|
+
};
|
|
430
|
+
ApiKeyRevoked: KnownErrorConstructor<KnownError & KnownErrorBrand<"API_KEY_NOT_VALID"> & {
|
|
431
|
+
constructorArgs: [statusCode: number, humanReadableMessage: string, details?: Json | undefined];
|
|
432
|
+
} & KnownErrorBrand<"API_KEY_REVOKED">, []> & {
|
|
433
|
+
errorCode: "API_KEY_REVOKED";
|
|
434
|
+
};
|
|
435
|
+
WrongApiKeyType: KnownErrorConstructor<KnownError & KnownErrorBrand<"API_KEY_NOT_VALID"> & {
|
|
436
|
+
constructorArgs: [statusCode: number, humanReadableMessage: string, details?: Json | undefined];
|
|
437
|
+
} & KnownErrorBrand<"WRONG_API_KEY_TYPE">, [expectedType: string, actualType: string]> & {
|
|
438
|
+
errorCode: "WRONG_API_KEY_TYPE";
|
|
439
|
+
};
|
|
406
440
|
};
|
|
407
441
|
export {};
|
package/dist/known-errors.js
CHANGED
|
@@ -293,10 +293,6 @@ const UserNotFound = createKnownErrorConstructor(KnownError, "USER_NOT_FOUND", (
|
|
|
293
293
|
404,
|
|
294
294
|
"User not found.",
|
|
295
295
|
], () => []);
|
|
296
|
-
const ApiKeyNotFound = createKnownErrorConstructor(KnownError, "API_KEY_NOT_FOUND", () => [
|
|
297
|
-
404,
|
|
298
|
-
"API key not found.",
|
|
299
|
-
], () => []);
|
|
300
296
|
const ProjectNotFound = createKnownErrorConstructor(KnownError, "PROJECT_NOT_FOUND", (projectId) => {
|
|
301
297
|
if (typeof projectId !== "string")
|
|
302
298
|
throw new StackAssertionError("projectId of KnownErrors.ProjectNotFound must be a string");
|
|
@@ -570,6 +566,40 @@ const InvalidPollingCodeError = createKnownErrorConstructor(KnownError, "INVALID
|
|
|
570
566
|
"The polling code is invalid or does not exist.",
|
|
571
567
|
details,
|
|
572
568
|
], (json) => [json]);
|
|
569
|
+
const CliAuthError = createKnownErrorConstructor(KnownError, "CLI_AUTH_ERROR", (message) => [
|
|
570
|
+
400,
|
|
571
|
+
message,
|
|
572
|
+
], (json) => [json.message]);
|
|
573
|
+
const CliAuthExpiredError = createKnownErrorConstructor(KnownError, "CLI_AUTH_EXPIRED_ERROR", (message = "CLI authentication request expired. Please try again.") => [
|
|
574
|
+
400,
|
|
575
|
+
message,
|
|
576
|
+
], (json) => [json.message]);
|
|
577
|
+
const CliAuthUsedError = createKnownErrorConstructor(KnownError, "CLI_AUTH_USED_ERROR", (message = "This authentication token has already been used.") => [
|
|
578
|
+
400,
|
|
579
|
+
message,
|
|
580
|
+
], (json) => [json.message]);
|
|
581
|
+
const ApiKeyNotValid = createKnownErrorConstructor(KnownError, "API_KEY_NOT_VALID", "inherit", "inherit");
|
|
582
|
+
const ApiKeyExpired = createKnownErrorConstructor(ApiKeyNotValid, "API_KEY_EXPIRED", () => [
|
|
583
|
+
401,
|
|
584
|
+
"API key has expired.",
|
|
585
|
+
], () => []);
|
|
586
|
+
const ApiKeyRevoked = createKnownErrorConstructor(ApiKeyNotValid, "API_KEY_REVOKED", () => [
|
|
587
|
+
401,
|
|
588
|
+
"API key has been revoked.",
|
|
589
|
+
], () => []);
|
|
590
|
+
const WrongApiKeyType = createKnownErrorConstructor(ApiKeyNotValid, "WRONG_API_KEY_TYPE", (expectedType, actualType) => [
|
|
591
|
+
400,
|
|
592
|
+
`This endpoint is for ${expectedType} API keys, but a ${actualType} API key was provided.`,
|
|
593
|
+
{ expected_type: expectedType, actual_type: actualType },
|
|
594
|
+
], (json) => [json.expected_type, json.actual_type]);
|
|
595
|
+
const ApiKeyNotFound = createKnownErrorConstructor(ApiKeyNotValid, "API_KEY_NOT_FOUND", () => [
|
|
596
|
+
404,
|
|
597
|
+
"API key not found.",
|
|
598
|
+
], () => []);
|
|
599
|
+
const PublicApiKeyCannotBeRevoked = createKnownErrorConstructor(ApiKeyNotValid, "PUBLIC_API_KEY_CANNOT_BE_REVOKED", () => [
|
|
600
|
+
400,
|
|
601
|
+
"Public API keys cannot be revoked by the secretscanner endpoint.",
|
|
602
|
+
], () => []);
|
|
573
603
|
const PermissionIdAlreadyExists = createKnownErrorConstructor(KnownError, "PERMISSION_ID_ALREADY_EXISTS", (permissionId) => [
|
|
574
604
|
400,
|
|
575
605
|
`Permission with ID "${permissionId}" already exists. Choose a different ID.`,
|
|
@@ -585,6 +615,9 @@ export const KnownErrors = {
|
|
|
585
615
|
AllOverloadsFailed,
|
|
586
616
|
ProjectAuthenticationError,
|
|
587
617
|
PermissionIdAlreadyExists,
|
|
618
|
+
CliAuthError,
|
|
619
|
+
CliAuthExpiredError,
|
|
620
|
+
CliAuthUsedError,
|
|
588
621
|
InvalidProjectAuthentication,
|
|
589
622
|
ProjectKeyWithoutAccessType,
|
|
590
623
|
InvalidAccessType,
|
|
@@ -622,6 +655,7 @@ export const KnownErrors = {
|
|
|
622
655
|
UserIdDoesNotExist,
|
|
623
656
|
UserNotFound,
|
|
624
657
|
ApiKeyNotFound,
|
|
658
|
+
PublicApiKeyCannotBeRevoked,
|
|
625
659
|
ProjectNotFound,
|
|
626
660
|
SignUpNotEnabled,
|
|
627
661
|
PasswordAuthenticationNotEnabled,
|
|
@@ -673,6 +707,10 @@ export const KnownErrors = {
|
|
|
673
707
|
OAuthProviderAccessDenied,
|
|
674
708
|
ContactChannelAlreadyUsedForAuthBySomeoneElse,
|
|
675
709
|
InvalidPollingCodeError,
|
|
710
|
+
ApiKeyNotValid,
|
|
711
|
+
ApiKeyExpired,
|
|
712
|
+
ApiKeyRevoked,
|
|
713
|
+
WrongApiKeyType,
|
|
676
714
|
};
|
|
677
715
|
// ensure that all known error codes are unique
|
|
678
716
|
const knownErrorCodes = new Set();
|
package/dist/schema-fields.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ declare module "yup" {
|
|
|
5
5
|
empty(): StringSchema<TType, TContext, TDefault, TFlags>;
|
|
6
6
|
}
|
|
7
7
|
interface Schema<TType, TContext, TDefault, TFlags> {
|
|
8
|
-
getNested<K extends keyof TType
|
|
9
|
-
concat<U extends yup.AnySchema>(schema: U): yup.Schema<Omit<TType
|
|
8
|
+
getNested<K extends keyof NonNullable<TType>>(path: K): yup.Schema<NonNullable<TType>[K], TContext, TDefault, TFlags>;
|
|
9
|
+
concat<U extends yup.AnySchema>(schema: U): yup.Schema<Omit<NonNullable<TType>, keyof yup.InferType<U>> & yup.InferType<U> | (TType & (null | undefined)), TContext, TDefault, TFlags>;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
export declare function yupValidate<S extends yup.ISchema<any>>(schema: S, obj: unknown, options?: yup.ValidateOptions & {
|
|
@@ -27,6 +27,7 @@ export declare function yupTuple<T extends [unknown, ...unknown[]]>(...args: Par
|
|
|
27
27
|
export declare function yupObject<A extends yup.Maybe<yup.AnyObject>, B extends yup.ObjectShape>(...args: Parameters<typeof yup.object<A, B>>): yup.ObjectSchema<yup.TypeFromShape<B, yup.AnyObject> extends infer T ? T extends yup.TypeFromShape<B, yup.AnyObject> ? T extends {} ? { [k in keyof T]: T[k]; } : T : never : never, yup.AnyObject, yup.DefaultFromShape<B> extends infer T_1 ? T_1 extends yup.DefaultFromShape<B> ? T_1 extends {} ? { [k_1 in keyof T_1]: T_1[k_1]; } : T_1 : never : never, "">;
|
|
28
28
|
export declare function yupNever(): yup.MixedSchema<never>;
|
|
29
29
|
export declare function yupUnion<T extends yup.ISchema<any>[]>(...args: T): yup.MixedSchema<yup.InferType<T[number]>>;
|
|
30
|
+
export declare function yupRecord<K extends yup.StringSchema, T extends yup.AnySchema>(keySchema: K, valueSchema: T): yup.MixedSchema<Record<string, yup.InferType<T>>>;
|
|
30
31
|
export declare function ensureObjectSchema<T extends yup.AnyObject>(schema: yup.Schema<T>): yup.ObjectSchema<T> & typeof schema;
|
|
31
32
|
export declare const adaptSchema: yup.MixedSchema<typeof StackAdaptSentinel | undefined, yup.AnyObject, undefined, "">;
|
|
32
33
|
/**
|
|
@@ -65,7 +66,7 @@ export declare const projectClientTeamCreationEnabledSchema: yup.BooleanSchema<b
|
|
|
65
66
|
export declare const projectClientUserDeletionEnabledSchema: yup.BooleanSchema<boolean | undefined, yup.AnyObject, undefined, "">;
|
|
66
67
|
export declare const projectSignUpEnabledSchema: yup.BooleanSchema<boolean | undefined, yup.AnyObject, undefined, "">;
|
|
67
68
|
export declare const projectCredentialEnabledSchema: yup.BooleanSchema<boolean | undefined, yup.AnyObject, undefined, "">;
|
|
68
|
-
export declare const oauthIdSchema: yup.StringSchema<"
|
|
69
|
+
export declare const oauthIdSchema: yup.StringSchema<"apple" | "x" | "google" | "github" | "microsoft" | "spotify" | "facebook" | "discord" | "gitlab" | "bitbucket" | "linkedin" | undefined, yup.AnyObject, undefined, "">;
|
|
69
70
|
export declare const oauthEnabledSchema: yup.BooleanSchema<boolean | undefined, yup.AnyObject, undefined, "">;
|
|
70
71
|
export declare const oauthTypeSchema: yup.StringSchema<"shared" | "standard" | undefined, yup.AnyObject, undefined, "">;
|
|
71
72
|
export declare const oauthClientIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
@@ -99,7 +100,7 @@ export declare const userClientReadOnlyMetadataSchema: yup.MixedSchema<{} | null
|
|
|
99
100
|
export declare const userServerMetadataSchema: yup.MixedSchema<{} | null, yup.AnyObject, undefined, "">;
|
|
100
101
|
export declare const userOAuthProviderSchema: yup.ObjectSchema<{
|
|
101
102
|
id: string;
|
|
102
|
-
type: "
|
|
103
|
+
type: "apple" | "x" | "google" | "github" | "microsoft" | "spotify" | "facebook" | "discord" | "gitlab" | "bitbucket" | "linkedin";
|
|
103
104
|
provider_user_id: string;
|
|
104
105
|
}, yup.AnyObject, {
|
|
105
106
|
id: undefined;
|
|
@@ -130,7 +131,7 @@ export declare const signInResponseSchema: yup.ObjectSchema<{
|
|
|
130
131
|
is_new_user: undefined;
|
|
131
132
|
user_id: undefined;
|
|
132
133
|
}, "">;
|
|
133
|
-
export declare const teamSystemPermissions: readonly ["$update_team", "$delete_team", "$read_members", "$remove_members", "$invite_members"];
|
|
134
|
+
export declare const teamSystemPermissions: readonly ["$update_team", "$delete_team", "$read_members", "$remove_members", "$invite_members", "$manage_api_keys"];
|
|
134
135
|
export declare const permissionDefinitionIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
135
136
|
export declare const customPermissionDefinitionIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
136
137
|
export declare const teamPermissionDescriptionSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
package/dist/schema-fields.js
CHANGED
|
@@ -118,9 +118,9 @@ export function yupObject(...args) {
|
|
|
118
118
|
if (unknownKeys.length > 0) {
|
|
119
119
|
// TODO "did you mean XYZ"
|
|
120
120
|
return context.createError({
|
|
121
|
-
message: `${context.path} contains unknown properties: ${unknownKeys.join(', ')}`,
|
|
121
|
+
message: `${context.path || "Object"} contains unknown properties: ${unknownKeys.join(', ')}`,
|
|
122
122
|
path: context.path,
|
|
123
|
-
params: { unknownKeys },
|
|
123
|
+
params: { unknownKeys, availableKeys },
|
|
124
124
|
});
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -147,7 +147,7 @@ export function yupUnion(...args) {
|
|
|
147
147
|
const errors = [];
|
|
148
148
|
for (const schema of args) {
|
|
149
149
|
try {
|
|
150
|
-
await schema
|
|
150
|
+
await yupValidate(schema, value, context.options);
|
|
151
151
|
return true;
|
|
152
152
|
}
|
|
153
153
|
catch (e) {
|
|
@@ -160,6 +160,38 @@ export function yupUnion(...args) {
|
|
|
160
160
|
});
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
|
+
export function yupRecord(keySchema, valueSchema) {
|
|
164
|
+
return yupObject().unknown(true).test('record', '${path} must be a record of valid values', async function (value, context) {
|
|
165
|
+
if (value == null)
|
|
166
|
+
return true;
|
|
167
|
+
const { path, createError } = this;
|
|
168
|
+
if (typeof value !== 'object') {
|
|
169
|
+
return createError({ message: `${path} must be an object` });
|
|
170
|
+
}
|
|
171
|
+
// Validate each property using the provided valueSchema
|
|
172
|
+
for (const key of Object.keys(value)) {
|
|
173
|
+
// Validate the key
|
|
174
|
+
await yupValidate(keySchema, key, context.options);
|
|
175
|
+
// Validate the value
|
|
176
|
+
try {
|
|
177
|
+
await yupValidate(valueSchema, value[key], {
|
|
178
|
+
...context.options,
|
|
179
|
+
context: {
|
|
180
|
+
...context.options.context,
|
|
181
|
+
path: path ? `${path}.${key}` : key,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
return createError({
|
|
187
|
+
path: path ? `${path}.${key}` : key,
|
|
188
|
+
message: e.message,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
163
195
|
export function ensureObjectSchema(schema) {
|
|
164
196
|
if (!(schema instanceof yup.ObjectSchema))
|
|
165
197
|
throw new StackAssertionError(`assertObjectSchema: schema is not an ObjectSchema: ${schema.describe().type}`);
|
|
@@ -326,6 +358,7 @@ export const teamSystemPermissions = [
|
|
|
326
358
|
'$read_members',
|
|
327
359
|
'$remove_members',
|
|
328
360
|
'$invite_members',
|
|
361
|
+
'$manage_api_keys',
|
|
329
362
|
];
|
|
330
363
|
export const permissionDefinitionIdSchema = yupString()
|
|
331
364
|
.matches(/^\$?[a-z0-9_:]+$/, 'Only lowercase letters, numbers, ":", "_" and optional "$" at the beginning are allowed')
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An api key has the following format:
|
|
3
|
+
* <prefix_without_underscores>_<secret_part_45_chars><id_part_32_chars><type_user_or_team_4_chars><scanner_and_marker_10_chars><checksum_8_chars>
|
|
4
|
+
*
|
|
5
|
+
* The scanner and marker is a base32 character that is used to determine if the api key is a public or private key
|
|
6
|
+
* and if it is a cloud or self-hosted key.
|
|
7
|
+
*
|
|
8
|
+
* The checksum is a crc32 checksum of the api key encoded in hex.
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
type ProjectApiKey = {
|
|
12
|
+
id: string;
|
|
13
|
+
prefix: string;
|
|
14
|
+
isPublic: boolean;
|
|
15
|
+
isCloudVersion: boolean;
|
|
16
|
+
secret: string;
|
|
17
|
+
checksum: string;
|
|
18
|
+
type: "user" | "team";
|
|
19
|
+
};
|
|
20
|
+
export declare function isApiKey(secret: string): boolean;
|
|
21
|
+
export declare function createProjectApiKey(options: Pick<ProjectApiKey, "id" | "isPublic" | "isCloudVersion" | "type">): string;
|
|
22
|
+
export declare function parseProjectApiKey(secret: string): ProjectApiKey;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { getBase32CharacterFromIndex } from "@stackframe/stack-shared/dist/utils/bytes";
|
|
2
|
+
import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto";
|
|
3
|
+
import { StackAssertionError } from "@stackframe/stack-shared/dist/utils/errors";
|
|
4
|
+
import crc32 from 'crc/crc32';
|
|
5
|
+
const STACK_AUTH_MARKER = "574ck4u7h";
|
|
6
|
+
// API key part lengths
|
|
7
|
+
const API_KEY_LENGTHS = {
|
|
8
|
+
SECRET_PART: 45,
|
|
9
|
+
ID_PART: 32,
|
|
10
|
+
TYPE_PART: 4,
|
|
11
|
+
SCANNER: 1,
|
|
12
|
+
MARKER: 9,
|
|
13
|
+
CHECKSUM: 8,
|
|
14
|
+
};
|
|
15
|
+
function createChecksumSync(checksummablePart) {
|
|
16
|
+
const data = new TextEncoder().encode(checksummablePart);
|
|
17
|
+
const calculated_checksum = crc32(data);
|
|
18
|
+
return calculated_checksum.toString(16).padStart(8, "0");
|
|
19
|
+
}
|
|
20
|
+
function createApiKeyParts(options) {
|
|
21
|
+
const { id, isPublic, isCloudVersion, type } = options;
|
|
22
|
+
const prefix = isPublic ? "pk" : "sk";
|
|
23
|
+
const scannerFlag = (isCloudVersion ? 0 : 1) + (isPublic ? 2 : 0) + ( /* version */0);
|
|
24
|
+
const secretPart = generateSecureRandomString();
|
|
25
|
+
const idPart = id.replace(/-/g, "");
|
|
26
|
+
const scannerAndMarker = getBase32CharacterFromIndex(scannerFlag).toLowerCase() + STACK_AUTH_MARKER;
|
|
27
|
+
const checksummablePart = `${prefix}_${secretPart}${idPart}${type}${scannerAndMarker}`;
|
|
28
|
+
return { checksummablePart, idPart, prefix, scannerAndMarker, type };
|
|
29
|
+
}
|
|
30
|
+
function parseApiKeyParts(secret) {
|
|
31
|
+
const regex = new RegExp(`^([a-zA-Z0-9_]+)_` + // prefix
|
|
32
|
+
`([a-zA-Z0-9_]{${API_KEY_LENGTHS.SECRET_PART}})` + // secretPart
|
|
33
|
+
`([a-zA-Z0-9_]{${API_KEY_LENGTHS.ID_PART}})` + // idPart
|
|
34
|
+
`([a-zA-Z0-9_]{${API_KEY_LENGTHS.TYPE_PART}})` + // type
|
|
35
|
+
`([a-zA-Z0-9_]{${API_KEY_LENGTHS.SCANNER}})` + // scanner
|
|
36
|
+
`(${STACK_AUTH_MARKER})` + // marker
|
|
37
|
+
`([a-zA-Z0-9_]{${API_KEY_LENGTHS.CHECKSUM}})$` // checksum
|
|
38
|
+
);
|
|
39
|
+
const match = secret.match(regex);
|
|
40
|
+
if (!match) {
|
|
41
|
+
throw new StackAssertionError("Invalid API key format");
|
|
42
|
+
}
|
|
43
|
+
const [, prefix, secretPart, idPart, type, scannerFlag, marker, checksum] = match;
|
|
44
|
+
const isCloudVersion = parseInt(scannerFlag, 32) % 2 === 0;
|
|
45
|
+
const isPublic = (parseInt(scannerFlag, 32) & 2) !== 0;
|
|
46
|
+
const checksummablePart = `${prefix}_${secretPart}${idPart}${type}${scannerFlag}${marker}`;
|
|
47
|
+
const restored_id = idPart.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, "$1-$2-$3-$4-$5");
|
|
48
|
+
if (!["user", "team"].includes(type)) {
|
|
49
|
+
throw new StackAssertionError("Invalid type");
|
|
50
|
+
}
|
|
51
|
+
return { checksummablePart, checksum, id: restored_id, isCloudVersion, isPublic, prefix, type: type };
|
|
52
|
+
}
|
|
53
|
+
export function isApiKey(secret) {
|
|
54
|
+
return secret.includes("_") && secret.includes(STACK_AUTH_MARKER);
|
|
55
|
+
}
|
|
56
|
+
export function createProjectApiKey(options) {
|
|
57
|
+
const { checksummablePart } = createApiKeyParts(options);
|
|
58
|
+
const checksum = createChecksumSync(checksummablePart);
|
|
59
|
+
return `${checksummablePart}${checksum}`;
|
|
60
|
+
}
|
|
61
|
+
export function parseProjectApiKey(secret) {
|
|
62
|
+
const { checksummablePart, checksum, id, isCloudVersion, isPublic, prefix, type } = parseApiKeyParts(secret);
|
|
63
|
+
const calculated_checksum = createChecksumSync(checksummablePart);
|
|
64
|
+
if (calculated_checksum !== checksum) {
|
|
65
|
+
throw new StackAssertionError("Checksum mismatch");
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
id,
|
|
69
|
+
prefix,
|
|
70
|
+
isPublic,
|
|
71
|
+
isCloudVersion,
|
|
72
|
+
secret,
|
|
73
|
+
checksum,
|
|
74
|
+
type,
|
|
75
|
+
};
|
|
76
|
+
}
|
package/dist/utils/bytes.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export declare function toHexString(input: Uint8Array): string;
|
|
2
|
+
export declare function getBase32CharacterFromIndex(index: number): string;
|
|
3
|
+
export declare function getBase32IndexFromCharacter(character: string): number;
|
|
1
4
|
export declare function encodeBase32(input: Uint8Array): string;
|
|
2
5
|
export declare function decodeBase32(input: string): Uint8Array;
|
|
3
6
|
export declare function encodeBase64(input: Uint8Array): string;
|
package/dist/utils/bytes.js
CHANGED
|
@@ -5,6 +5,43 @@ const crockfordReplacements = new Map([
|
|
|
5
5
|
["i", "1"],
|
|
6
6
|
["l", "1"],
|
|
7
7
|
]);
|
|
8
|
+
export function toHexString(input) {
|
|
9
|
+
return Array.from(input).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
10
|
+
}
|
|
11
|
+
import.meta.vitest?.test("toHexString", ({ expect }) => {
|
|
12
|
+
expect(toHexString(new Uint8Array([]))).toBe("");
|
|
13
|
+
expect(toHexString(new Uint8Array([0]))).toBe("00");
|
|
14
|
+
expect(toHexString(new Uint8Array([15]))).toBe("0f");
|
|
15
|
+
expect(toHexString(new Uint8Array([16]))).toBe("10");
|
|
16
|
+
expect(toHexString(new Uint8Array([255]))).toBe("ff");
|
|
17
|
+
expect(toHexString(new Uint8Array([1, 2, 3]))).toBe("010203");
|
|
18
|
+
});
|
|
19
|
+
export function getBase32CharacterFromIndex(index) {
|
|
20
|
+
if (index < 0 || index >= crockfordAlphabet.length) {
|
|
21
|
+
throw new StackAssertionError(`Invalid base32 index: ${index}`);
|
|
22
|
+
}
|
|
23
|
+
return crockfordAlphabet[index];
|
|
24
|
+
}
|
|
25
|
+
import.meta.vitest?.test("getBase32CharacterFromIndex", ({ expect }) => {
|
|
26
|
+
expect(getBase32CharacterFromIndex(0)).toBe("0");
|
|
27
|
+
expect(getBase32CharacterFromIndex(15)).toBe("F");
|
|
28
|
+
expect(() => getBase32CharacterFromIndex(32)).toThrow();
|
|
29
|
+
});
|
|
30
|
+
export function getBase32IndexFromCharacter(character) {
|
|
31
|
+
if (character.length !== 1) {
|
|
32
|
+
throw new StackAssertionError(`Invalid base32 character: ${character}`);
|
|
33
|
+
}
|
|
34
|
+
const index = crockfordAlphabet.indexOf(character.toUpperCase());
|
|
35
|
+
if (index === -1) {
|
|
36
|
+
throw new StackAssertionError(`Invalid base32 character: ${character}`);
|
|
37
|
+
}
|
|
38
|
+
return index;
|
|
39
|
+
}
|
|
40
|
+
import.meta.vitest?.test("getBase32IndexFromCharacter", ({ expect }) => {
|
|
41
|
+
expect(getBase32IndexFromCharacter("0")).toBe(0);
|
|
42
|
+
expect(getBase32IndexFromCharacter("F")).toBe(15);
|
|
43
|
+
expect(() => getBase32IndexFromCharacter("_")).toThrow();
|
|
44
|
+
});
|
|
8
45
|
export function encodeBase32(input) {
|
|
9
46
|
let bits = 0;
|
|
10
47
|
let value = 0;
|
|
@@ -13,12 +50,12 @@ export function encodeBase32(input) {
|
|
|
13
50
|
value = (value << 8) | input[i];
|
|
14
51
|
bits += 8;
|
|
15
52
|
while (bits >= 5) {
|
|
16
|
-
output +=
|
|
53
|
+
output += getBase32CharacterFromIndex((value >>> (bits - 5)) & 31);
|
|
17
54
|
bits -= 5;
|
|
18
55
|
}
|
|
19
56
|
}
|
|
20
57
|
if (bits > 0) {
|
|
21
|
-
output +=
|
|
58
|
+
output += getBase32CharacterFromIndex((value << (5 - bits)) & 31);
|
|
22
59
|
}
|
|
23
60
|
// sanity check
|
|
24
61
|
if (!isBase32(output)) {
|
|
@@ -26,6 +63,14 @@ export function encodeBase32(input) {
|
|
|
26
63
|
}
|
|
27
64
|
return output;
|
|
28
65
|
}
|
|
66
|
+
import.meta.vitest?.test("encodeBase32", ({ expect }) => {
|
|
67
|
+
expect(encodeBase32(new Uint8Array([]))).toBe("");
|
|
68
|
+
expect(encodeBase32(new Uint8Array([1]))).toBe("04");
|
|
69
|
+
expect(encodeBase32(new Uint8Array([15]))).toBe("1W");
|
|
70
|
+
expect(encodeBase32(new Uint8Array([16]))).toBe("20");
|
|
71
|
+
expect(encodeBase32(new Uint8Array([255]))).toBe("ZW");
|
|
72
|
+
expect(encodeBase32(new Uint8Array([255, 255]))).toBe("ZZZG");
|
|
73
|
+
});
|
|
29
74
|
export function decodeBase32(input) {
|
|
30
75
|
if (!isBase32(input)) {
|
|
31
76
|
throw new StackAssertionError("Invalid base32 string");
|
|
@@ -41,10 +86,7 @@ export function decodeBase32(input) {
|
|
|
41
86
|
if (crockfordReplacements.has(char)) {
|
|
42
87
|
char = crockfordReplacements.get(char);
|
|
43
88
|
}
|
|
44
|
-
const index =
|
|
45
|
-
if (index === -1) {
|
|
46
|
-
throw new Error(`Invalid character: ${char}`);
|
|
47
|
-
}
|
|
89
|
+
const index = getBase32IndexFromCharacter(char);
|
|
48
90
|
value = (value << 5) | index;
|
|
49
91
|
bits += 5;
|
|
50
92
|
if (bits >= 8) {
|
|
@@ -54,6 +96,13 @@ export function decodeBase32(input) {
|
|
|
54
96
|
}
|
|
55
97
|
return output;
|
|
56
98
|
}
|
|
99
|
+
import.meta.vitest?.test("decodeBase32", ({ expect }) => {
|
|
100
|
+
expect(decodeBase32("")).toEqual(new Uint8Array([]));
|
|
101
|
+
expect(decodeBase32("00")).toEqual(new Uint8Array([0]));
|
|
102
|
+
expect(decodeBase32("1W")).toEqual(new Uint8Array([15]));
|
|
103
|
+
expect(decodeBase32("20")).toEqual(new Uint8Array([16]));
|
|
104
|
+
expect(decodeBase32("ZW")).toEqual(new Uint8Array([255]));
|
|
105
|
+
});
|
|
57
106
|
export function encodeBase64(input) {
|
|
58
107
|
const res = btoa(String.fromCharCode(...input));
|
|
59
108
|
// Skip sanity check for test cases
|
package/dist/utils/caches.d.ts
CHANGED
|
@@ -17,16 +17,16 @@ export declare class AsyncCache<D extends any[], T> {
|
|
|
17
17
|
refreshWhere(predicate: (dependencies: D) => boolean): Promise<void>;
|
|
18
18
|
readonly isCacheAvailable: (key: D) => boolean;
|
|
19
19
|
readonly getIfCached: (key: D) => ({
|
|
20
|
-
status: "error";
|
|
21
|
-
error: unknown;
|
|
22
|
-
} & {
|
|
23
|
-
status: "error";
|
|
24
|
-
}) | ({
|
|
25
20
|
status: "pending";
|
|
26
21
|
} & {
|
|
27
22
|
progress: void;
|
|
28
23
|
} & {
|
|
29
24
|
status: "pending";
|
|
25
|
+
}) | ({
|
|
26
|
+
status: "error";
|
|
27
|
+
error: unknown;
|
|
28
|
+
} & {
|
|
29
|
+
status: "error";
|
|
30
30
|
}) | ({
|
|
31
31
|
status: "ok";
|
|
32
32
|
data: T;
|
|
@@ -57,16 +57,16 @@ declare class AsyncValueCache<T> {
|
|
|
57
57
|
});
|
|
58
58
|
isCacheAvailable(): boolean;
|
|
59
59
|
getIfCached(): ({
|
|
60
|
-
status: "error";
|
|
61
|
-
error: unknown;
|
|
62
|
-
} & {
|
|
63
|
-
status: "error";
|
|
64
|
-
}) | ({
|
|
65
60
|
status: "pending";
|
|
66
61
|
} & {
|
|
67
62
|
progress: void;
|
|
68
63
|
} & {
|
|
69
64
|
status: "pending";
|
|
65
|
+
}) | ({
|
|
66
|
+
status: "error";
|
|
67
|
+
error: unknown;
|
|
68
|
+
} & {
|
|
69
|
+
status: "error";
|
|
70
70
|
}) | ({
|
|
71
71
|
status: "ok";
|
|
72
72
|
data: T;
|
package/dist/utils/hashes.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function sha512(input: Uint8Array | string): Promise<
|
|
1
|
+
export declare function sha512(input: Uint8Array | string): Promise<Uint8Array>;
|
|
2
2
|
export declare function hashPassword(password: string): Promise<string>;
|
|
3
3
|
export declare function comparePassword(password: string, hash: string): Promise<boolean>;
|
|
4
4
|
export declare function isPasswordHashValid(hash: string): Promise<boolean>;
|