@stackframe/stack-shared 2.7.30 → 2.8.2
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 +14 -0
- package/dist/interface/adminInterface.d.ts +9 -4
- package/dist/interface/adminInterface.js +33 -4
- package/dist/interface/clientInterface.d.ts +4 -0
- package/dist/interface/clientInterface.js +6 -1
- package/dist/interface/crud/project-permissions.d.ts +155 -0
- package/dist/interface/crud/project-permissions.js +100 -0
- package/dist/interface/crud/projects.d.ts +24 -0
- package/dist/interface/crud/projects.js +2 -0
- package/dist/interface/crud/team-permissions.js +7 -7
- package/dist/interface/serverInterface.d.ts +5 -0
- package/dist/interface/serverInterface.js +8 -0
- package/dist/interface/webhooks.d.ts +32 -0
- package/dist/interface/webhooks.js +3 -0
- package/dist/known-errors.d.ts +6 -0
- package/dist/known-errors.js +17 -0
- package/dist/schema-fields.d.ts +2 -2
- package/dist/schema-fields.js +3 -3
- package/dist/utils/errors.js +1 -5
- package/dist/utils/results.js +5 -5
- package/dist/utils/strings.d.ts +1 -0
- package/dist/utils/strings.js +73 -17
- package/dist/utils/strings.nicify.test.js +214 -0
- package/package.json +1 -1
- package/dist/utils/strings.test.js +0 -26
- /package/dist/utils/{strings.test.d.ts → strings.nicify.test.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,7 @@ import { InternalSession } from "../sessions";
|
|
|
2
2
|
import { ApiKeysCrud } from "./crud/api-keys";
|
|
3
3
|
import { EmailTemplateCrud, EmailTemplateType } from "./crud/email-templates";
|
|
4
4
|
import { InternalEmailsCrud } from "./crud/emails";
|
|
5
|
+
import { ProjectPermissionDefinitionsCrud } from "./crud/project-permissions";
|
|
5
6
|
import { ProjectsCrud } from "./crud/projects";
|
|
6
7
|
import { SvixTokenCrud } from "./crud/svix-token";
|
|
7
8
|
import { TeamPermissionDefinitionsCrud } from "./crud/team-permissions";
|
|
@@ -41,10 +42,14 @@ export declare class StackAdminInterface extends StackServerInterface {
|
|
|
41
42
|
listEmailTemplates(): Promise<EmailTemplateCrud['Admin']['Read'][]>;
|
|
42
43
|
updateEmailTemplate(type: EmailTemplateType, data: EmailTemplateCrud['Admin']['Update']): Promise<EmailTemplateCrud['Admin']['Read']>;
|
|
43
44
|
resetEmailTemplate(type: EmailTemplateType): Promise<void>;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
listTeamPermissionDefinitions(): Promise<TeamPermissionDefinitionsCrud['Admin']['Read'][]>;
|
|
46
|
+
createTeamPermissionDefinition(data: TeamPermissionDefinitionsCrud['Admin']['Create']): Promise<TeamPermissionDefinitionsCrud['Admin']['Read']>;
|
|
47
|
+
updateTeamPermissionDefinition(permissionId: string, data: TeamPermissionDefinitionsCrud['Admin']['Update']): Promise<TeamPermissionDefinitionsCrud['Admin']['Read']>;
|
|
48
|
+
deleteTeamPermissionDefinition(permissionId: string): Promise<void>;
|
|
49
|
+
listProjectPermissionDefinitions(): Promise<ProjectPermissionDefinitionsCrud['Admin']['Read'][]>;
|
|
50
|
+
createProjectPermissionDefinition(data: ProjectPermissionDefinitionsCrud['Admin']['Create']): Promise<ProjectPermissionDefinitionsCrud['Admin']['Read']>;
|
|
51
|
+
updateProjectPermissionDefinition(permissionId: string, data: ProjectPermissionDefinitionsCrud['Admin']['Update']): Promise<ProjectPermissionDefinitionsCrud['Admin']['Read']>;
|
|
52
|
+
deleteProjectPermissionDefinition(permissionId: string): Promise<void>;
|
|
48
53
|
getSvixToken(): Promise<SvixTokenCrud["Admin"]["Read"]>;
|
|
49
54
|
deleteProject(): Promise<void>;
|
|
50
55
|
getMetrics(): Promise<any>;
|
|
@@ -77,12 +77,13 @@ export class StackAdminInterface extends StackServerInterface {
|
|
|
77
77
|
async resetEmailTemplate(type) {
|
|
78
78
|
await this.sendAdminRequest(`/email-templates/${type}`, { method: "DELETE" }, null);
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
// Team permission definitions methods
|
|
81
|
+
async listTeamPermissionDefinitions() {
|
|
81
82
|
const response = await this.sendAdminRequest(`/team-permission-definitions`, {}, null);
|
|
82
83
|
const result = await response.json();
|
|
83
84
|
return result.items;
|
|
84
85
|
}
|
|
85
|
-
async
|
|
86
|
+
async createTeamPermissionDefinition(data) {
|
|
86
87
|
const response = await this.sendAdminRequest("/team-permission-definitions", {
|
|
87
88
|
method: "POST",
|
|
88
89
|
headers: {
|
|
@@ -92,7 +93,7 @@ export class StackAdminInterface extends StackServerInterface {
|
|
|
92
93
|
}, null);
|
|
93
94
|
return await response.json();
|
|
94
95
|
}
|
|
95
|
-
async
|
|
96
|
+
async updateTeamPermissionDefinition(permissionId, data) {
|
|
96
97
|
const response = await this.sendAdminRequest(`/team-permission-definitions/${permissionId}`, {
|
|
97
98
|
method: "PATCH",
|
|
98
99
|
headers: {
|
|
@@ -102,9 +103,37 @@ export class StackAdminInterface extends StackServerInterface {
|
|
|
102
103
|
}, null);
|
|
103
104
|
return await response.json();
|
|
104
105
|
}
|
|
105
|
-
async
|
|
106
|
+
async deleteTeamPermissionDefinition(permissionId) {
|
|
106
107
|
await this.sendAdminRequest(`/team-permission-definitions/${permissionId}`, { method: "DELETE" }, null);
|
|
107
108
|
}
|
|
109
|
+
async listProjectPermissionDefinitions() {
|
|
110
|
+
const response = await this.sendAdminRequest(`/project-permission-definitions`, {}, null);
|
|
111
|
+
const result = await response.json();
|
|
112
|
+
return result.items;
|
|
113
|
+
}
|
|
114
|
+
async createProjectPermissionDefinition(data) {
|
|
115
|
+
const response = await this.sendAdminRequest("/project-permission-definitions", {
|
|
116
|
+
method: "POST",
|
|
117
|
+
headers: {
|
|
118
|
+
"content-type": "application/json",
|
|
119
|
+
},
|
|
120
|
+
body: JSON.stringify(data),
|
|
121
|
+
}, null);
|
|
122
|
+
return await response.json();
|
|
123
|
+
}
|
|
124
|
+
async updateProjectPermissionDefinition(permissionId, data) {
|
|
125
|
+
const response = await this.sendAdminRequest(`/project-permission-definitions/${permissionId}`, {
|
|
126
|
+
method: "PATCH",
|
|
127
|
+
headers: {
|
|
128
|
+
"content-type": "application/json",
|
|
129
|
+
},
|
|
130
|
+
body: JSON.stringify(data),
|
|
131
|
+
}, null);
|
|
132
|
+
return await response.json();
|
|
133
|
+
}
|
|
134
|
+
async deleteProjectPermissionDefinition(permissionId) {
|
|
135
|
+
await this.sendAdminRequest(`/project-permission-definitions/${permissionId}`, { method: "DELETE" }, null);
|
|
136
|
+
}
|
|
108
137
|
async getSvixToken() {
|
|
109
138
|
const response = await this.sendAdminRequest("/webhooks/svix-token", {
|
|
110
139
|
method: "POST",
|
|
@@ -6,6 +6,7 @@ import { Result } from "../utils/results";
|
|
|
6
6
|
import { ContactChannelsCrud } from './crud/contact-channels';
|
|
7
7
|
import { CurrentUserCrud } from './crud/current-user';
|
|
8
8
|
import { ConnectedAccountAccessTokenCrud } from './crud/oauth';
|
|
9
|
+
import { ProjectPermissionsCrud } from './crud/project-permissions';
|
|
9
10
|
import { InternalProjectsCrud, ProjectsCrud } from './crud/projects';
|
|
10
11
|
import { SessionsCrud } from './crud/sessions';
|
|
11
12
|
import { TeamInvitationCrud } from './crud/team-invitation';
|
|
@@ -187,6 +188,9 @@ export declare class StackClientInterface {
|
|
|
187
188
|
teamId: string;
|
|
188
189
|
recursive: boolean;
|
|
189
190
|
}, session: InternalSession): Promise<TeamPermissionsCrud['Client']['Read'][]>;
|
|
191
|
+
listCurrentUserProjectPermissions(options: {
|
|
192
|
+
recursive: boolean;
|
|
193
|
+
}, session: InternalSession): Promise<ProjectPermissionsCrud['Client']['Read'][]>;
|
|
190
194
|
listCurrentUserTeams(session: InternalSession): Promise<TeamsCrud["Client"]["Read"][]>;
|
|
191
195
|
getClientProject(): Promise<Result<ProjectsCrud['Client']['Read'], KnownErrors["ProjectNotFound"]>>;
|
|
192
196
|
updateClientUser(update: CurrentUserCrud["Client"]["Update"], session: InternalSession): Promise<void>;
|
|
@@ -85,7 +85,7 @@ export class StackClientInterface {
|
|
|
85
85
|
// try to diagnose the error for the user
|
|
86
86
|
if (retriedResult.status === "error") {
|
|
87
87
|
if (globalVar.navigator && !globalVar.navigator.onLine) {
|
|
88
|
-
throw new Error("Failed to send Stack network request. It seems like you are offline. (window.navigator.onLine is falsy)", { cause: retriedResult.error });
|
|
88
|
+
throw new Error("Failed to send Stack network request. It seems like you are offline, please check your internet connection and try again. This is not an error with Stack Auth. (window.navigator.onLine is falsy)", { cause: retriedResult.error });
|
|
89
89
|
}
|
|
90
90
|
throw await this._createNetworkError(retriedResult.error, session, requestType);
|
|
91
91
|
}
|
|
@@ -790,6 +790,11 @@ export class StackClientInterface {
|
|
|
790
790
|
const result = await response.json();
|
|
791
791
|
return result.items;
|
|
792
792
|
}
|
|
793
|
+
async listCurrentUserProjectPermissions(options, session) {
|
|
794
|
+
const response = await this.sendClientRequest(`/project-permissions?user_id=me&recursive=${options.recursive}`, {}, session);
|
|
795
|
+
const result = await response.json();
|
|
796
|
+
return result.items;
|
|
797
|
+
}
|
|
793
798
|
async listCurrentUserTeams(session) {
|
|
794
799
|
const response = await this.sendClientRequest("/teams?user_id=me", {}, session);
|
|
795
800
|
const result = await response.json();
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { CrudTypeOf } from "../../crud";
|
|
2
|
+
export declare const projectPermissionsCrudClientReadSchema: import("yup").ObjectSchema<{
|
|
3
|
+
id: string;
|
|
4
|
+
user_id: string;
|
|
5
|
+
}, import("yup").AnyObject, {
|
|
6
|
+
id: undefined;
|
|
7
|
+
user_id: undefined;
|
|
8
|
+
}, "">;
|
|
9
|
+
export declare const projectPermissionsCrudServerCreateSchema: import("yup").ObjectSchema<{}, import("yup").AnyObject, {}, "">;
|
|
10
|
+
export declare const projectPermissionsCrudServerDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
11
|
+
export declare const projectPermissionsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
12
|
+
clientReadSchema: import("yup").ObjectSchema<{
|
|
13
|
+
id: string;
|
|
14
|
+
user_id: string;
|
|
15
|
+
}, import("yup").AnyObject, {
|
|
16
|
+
id: undefined;
|
|
17
|
+
user_id: undefined;
|
|
18
|
+
}, "">;
|
|
19
|
+
serverCreateSchema: import("yup").ObjectSchema<{}, import("yup").AnyObject, {}, "">;
|
|
20
|
+
serverDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
21
|
+
docs: {
|
|
22
|
+
clientList: {
|
|
23
|
+
summary: string;
|
|
24
|
+
description: string;
|
|
25
|
+
tags: string[];
|
|
26
|
+
};
|
|
27
|
+
serverList: {
|
|
28
|
+
summary: string;
|
|
29
|
+
description: string;
|
|
30
|
+
tags: string[];
|
|
31
|
+
};
|
|
32
|
+
serverCreate: {
|
|
33
|
+
summary: string;
|
|
34
|
+
description: string;
|
|
35
|
+
tags: string[];
|
|
36
|
+
};
|
|
37
|
+
serverDelete: {
|
|
38
|
+
summary: string;
|
|
39
|
+
description: string;
|
|
40
|
+
tags: string[];
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
}>;
|
|
44
|
+
export type ProjectPermissionsCrud = CrudTypeOf<typeof projectPermissionsCrud>;
|
|
45
|
+
export declare const projectPermissionCreatedWebhookEvent: {
|
|
46
|
+
type: string;
|
|
47
|
+
schema: import("yup").ObjectSchema<{
|
|
48
|
+
id: string;
|
|
49
|
+
user_id: string;
|
|
50
|
+
}, import("yup").AnyObject, {
|
|
51
|
+
id: undefined;
|
|
52
|
+
user_id: undefined;
|
|
53
|
+
}, "">;
|
|
54
|
+
metadata: {
|
|
55
|
+
summary: string;
|
|
56
|
+
description: string;
|
|
57
|
+
tags: string[];
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
export declare const projectPermissionDeletedWebhookEvent: {
|
|
61
|
+
type: string;
|
|
62
|
+
schema: import("yup").ObjectSchema<{
|
|
63
|
+
id: string;
|
|
64
|
+
user_id: string;
|
|
65
|
+
}, import("yup").AnyObject, {
|
|
66
|
+
id: undefined;
|
|
67
|
+
user_id: undefined;
|
|
68
|
+
}, "">;
|
|
69
|
+
metadata: {
|
|
70
|
+
summary: string;
|
|
71
|
+
description: string;
|
|
72
|
+
tags: string[];
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
export declare const projectPermissionDefinitionsCrudAdminReadSchema: import("yup").ObjectSchema<{
|
|
76
|
+
id: string;
|
|
77
|
+
description: string | undefined;
|
|
78
|
+
contained_permission_ids: string[];
|
|
79
|
+
}, import("yup").AnyObject, {
|
|
80
|
+
id: undefined;
|
|
81
|
+
description: undefined;
|
|
82
|
+
contained_permission_ids: undefined;
|
|
83
|
+
}, "">;
|
|
84
|
+
export declare const projectPermissionDefinitionsCrudAdminCreateSchema: import("yup").ObjectSchema<{
|
|
85
|
+
id: string;
|
|
86
|
+
description: string | undefined;
|
|
87
|
+
contained_permission_ids: string[] | undefined;
|
|
88
|
+
}, import("yup").AnyObject, {
|
|
89
|
+
id: undefined;
|
|
90
|
+
description: undefined;
|
|
91
|
+
contained_permission_ids: undefined;
|
|
92
|
+
}, "">;
|
|
93
|
+
export declare const projectPermissionDefinitionsCrudAdminUpdateSchema: import("yup").ObjectSchema<{
|
|
94
|
+
id: string | undefined;
|
|
95
|
+
description: string | undefined;
|
|
96
|
+
contained_permission_ids: string[] | undefined;
|
|
97
|
+
}, import("yup").AnyObject, {
|
|
98
|
+
id: undefined;
|
|
99
|
+
description: undefined;
|
|
100
|
+
contained_permission_ids: undefined;
|
|
101
|
+
}, "">;
|
|
102
|
+
export declare const projectPermissionDefinitionsCrudAdminDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
103
|
+
export declare const projectPermissionDefinitionsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
104
|
+
adminReadSchema: import("yup").ObjectSchema<{
|
|
105
|
+
id: string;
|
|
106
|
+
description: string | undefined;
|
|
107
|
+
contained_permission_ids: string[];
|
|
108
|
+
}, import("yup").AnyObject, {
|
|
109
|
+
id: undefined;
|
|
110
|
+
description: undefined;
|
|
111
|
+
contained_permission_ids: undefined;
|
|
112
|
+
}, "">;
|
|
113
|
+
adminCreateSchema: import("yup").ObjectSchema<{
|
|
114
|
+
id: string;
|
|
115
|
+
description: string | undefined;
|
|
116
|
+
contained_permission_ids: string[] | undefined;
|
|
117
|
+
}, import("yup").AnyObject, {
|
|
118
|
+
id: undefined;
|
|
119
|
+
description: undefined;
|
|
120
|
+
contained_permission_ids: undefined;
|
|
121
|
+
}, "">;
|
|
122
|
+
adminUpdateSchema: import("yup").ObjectSchema<{
|
|
123
|
+
id: string | undefined;
|
|
124
|
+
description: string | undefined;
|
|
125
|
+
contained_permission_ids: string[] | undefined;
|
|
126
|
+
}, import("yup").AnyObject, {
|
|
127
|
+
id: undefined;
|
|
128
|
+
description: undefined;
|
|
129
|
+
contained_permission_ids: undefined;
|
|
130
|
+
}, "">;
|
|
131
|
+
adminDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
132
|
+
docs: {
|
|
133
|
+
adminList: {
|
|
134
|
+
summary: string;
|
|
135
|
+
description: string;
|
|
136
|
+
tags: string[];
|
|
137
|
+
};
|
|
138
|
+
adminCreate: {
|
|
139
|
+
summary: string;
|
|
140
|
+
description: string;
|
|
141
|
+
tags: string[];
|
|
142
|
+
};
|
|
143
|
+
adminUpdate: {
|
|
144
|
+
summary: string;
|
|
145
|
+
description: string;
|
|
146
|
+
tags: string[];
|
|
147
|
+
};
|
|
148
|
+
adminDelete: {
|
|
149
|
+
summary: string;
|
|
150
|
+
description: string;
|
|
151
|
+
tags: string[];
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
}>;
|
|
155
|
+
export type ProjectPermissionDefinitionsCrud = CrudTypeOf<typeof projectPermissionDefinitionsCrud>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createCrud } from "../../crud";
|
|
2
|
+
import * as schemaFields from "../../schema-fields";
|
|
3
|
+
import { yupMixed, yupObject } from "../../schema-fields";
|
|
4
|
+
// =============== Project permissions =================
|
|
5
|
+
export const projectPermissionsCrudClientReadSchema = yupObject({
|
|
6
|
+
id: schemaFields.permissionDefinitionIdSchema.defined(),
|
|
7
|
+
user_id: schemaFields.userIdSchema.defined(),
|
|
8
|
+
}).defined();
|
|
9
|
+
export const projectPermissionsCrudServerCreateSchema = yupObject({}).defined();
|
|
10
|
+
export const projectPermissionsCrudServerDeleteSchema = yupMixed();
|
|
11
|
+
export const projectPermissionsCrud = createCrud({
|
|
12
|
+
clientReadSchema: projectPermissionsCrudClientReadSchema,
|
|
13
|
+
serverCreateSchema: projectPermissionsCrudServerCreateSchema,
|
|
14
|
+
serverDeleteSchema: projectPermissionsCrudServerDeleteSchema,
|
|
15
|
+
docs: {
|
|
16
|
+
clientList: {
|
|
17
|
+
summary: "List project permissions",
|
|
18
|
+
description: "List global permissions of the current user. `user_id=me` must be set for client requests. `(user_id, permission_id)` together uniquely identify a permission.",
|
|
19
|
+
tags: ["Permissions"],
|
|
20
|
+
},
|
|
21
|
+
serverList: {
|
|
22
|
+
summary: "List project permissions",
|
|
23
|
+
description: "Query and filter the permission with `user_id` and `permission_id`. `(user_id, permission_id)` together uniquely identify a permission.",
|
|
24
|
+
tags: ["Permissions"],
|
|
25
|
+
},
|
|
26
|
+
serverCreate: {
|
|
27
|
+
summary: "Grant a global permission to a user",
|
|
28
|
+
description: "Grant a global permission to a user (the permission must be created first on the Stack dashboard)",
|
|
29
|
+
tags: ["Permissions"],
|
|
30
|
+
},
|
|
31
|
+
serverDelete: {
|
|
32
|
+
summary: "Revoke a global permission from a user",
|
|
33
|
+
description: "Revoke a global permission from a user",
|
|
34
|
+
tags: ["Permissions"],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
export const projectPermissionCreatedWebhookEvent = {
|
|
39
|
+
type: "project_permission.created",
|
|
40
|
+
schema: projectPermissionsCrud.server.readSchema,
|
|
41
|
+
metadata: {
|
|
42
|
+
summary: "Project Permission Created",
|
|
43
|
+
description: "This event is triggered when a project permission is created.",
|
|
44
|
+
tags: ["Users"],
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
export const projectPermissionDeletedWebhookEvent = {
|
|
48
|
+
type: "project_permission.deleted",
|
|
49
|
+
schema: projectPermissionsCrud.server.readSchema,
|
|
50
|
+
metadata: {
|
|
51
|
+
summary: "Project Permission Deleted",
|
|
52
|
+
description: "This event is triggered when a project permission is deleted.",
|
|
53
|
+
tags: ["Users"],
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
// =============== Project permission definitions =================
|
|
57
|
+
export const projectPermissionDefinitionsCrudAdminReadSchema = yupObject({
|
|
58
|
+
id: schemaFields.permissionDefinitionIdSchema.defined(),
|
|
59
|
+
description: schemaFields.teamPermissionDescriptionSchema.optional(),
|
|
60
|
+
contained_permission_ids: schemaFields.containedPermissionIdsSchema.defined(),
|
|
61
|
+
}).defined();
|
|
62
|
+
export const projectPermissionDefinitionsCrudAdminCreateSchema = yupObject({
|
|
63
|
+
id: schemaFields.customPermissionDefinitionIdSchema.defined(),
|
|
64
|
+
description: schemaFields.teamPermissionDescriptionSchema.optional(),
|
|
65
|
+
contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional(),
|
|
66
|
+
}).defined();
|
|
67
|
+
export const projectPermissionDefinitionsCrudAdminUpdateSchema = yupObject({
|
|
68
|
+
id: schemaFields.customPermissionDefinitionIdSchema.optional(),
|
|
69
|
+
description: schemaFields.teamPermissionDescriptionSchema.optional(),
|
|
70
|
+
contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional(),
|
|
71
|
+
}).defined();
|
|
72
|
+
export const projectPermissionDefinitionsCrudAdminDeleteSchema = yupMixed();
|
|
73
|
+
export const projectPermissionDefinitionsCrud = createCrud({
|
|
74
|
+
adminReadSchema: projectPermissionDefinitionsCrudAdminReadSchema,
|
|
75
|
+
adminCreateSchema: projectPermissionDefinitionsCrudAdminCreateSchema,
|
|
76
|
+
adminUpdateSchema: projectPermissionDefinitionsCrudAdminUpdateSchema,
|
|
77
|
+
adminDeleteSchema: projectPermissionDefinitionsCrudAdminDeleteSchema,
|
|
78
|
+
docs: {
|
|
79
|
+
adminList: {
|
|
80
|
+
summary: "List project permission definitions",
|
|
81
|
+
description: "Query and filter project permission definitions (the equivalent of listing permissions on the Stack dashboard)",
|
|
82
|
+
tags: ["Permissions"],
|
|
83
|
+
},
|
|
84
|
+
adminCreate: {
|
|
85
|
+
summary: "Create a new project permission definition",
|
|
86
|
+
description: "Create a new project permission definition (the equivalent of creating a new permission on the Stack dashboard)",
|
|
87
|
+
tags: ["Permissions"],
|
|
88
|
+
},
|
|
89
|
+
adminUpdate: {
|
|
90
|
+
summary: "Update a project permission definition",
|
|
91
|
+
description: "Update a project permission definition (the equivalent of updating a permission on the Stack dashboard)",
|
|
92
|
+
tags: ["Permissions"],
|
|
93
|
+
},
|
|
94
|
+
adminDelete: {
|
|
95
|
+
summary: "Delete a project permission definition",
|
|
96
|
+
description: "Delete a project permission definition (the equivalent of deleting a permission on the Stack dashboard)",
|
|
97
|
+
tags: ["Permissions"],
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
});
|
|
@@ -80,6 +80,9 @@ export declare const projectsCrudAdminReadSchema: import("yup").ObjectSchema<{
|
|
|
80
80
|
team_member_default_permissions: {
|
|
81
81
|
id: string;
|
|
82
82
|
}[];
|
|
83
|
+
user_default_permissions: {
|
|
84
|
+
id: string;
|
|
85
|
+
}[];
|
|
83
86
|
oauth_account_merge_strategy: "link_method" | "raise_error" | "allow_duplicates";
|
|
84
87
|
};
|
|
85
88
|
}, import("yup").AnyObject, {
|
|
@@ -113,6 +116,7 @@ export declare const projectsCrudAdminReadSchema: import("yup").ObjectSchema<{
|
|
|
113
116
|
create_team_on_sign_up: undefined;
|
|
114
117
|
team_creator_default_permissions: undefined;
|
|
115
118
|
team_member_default_permissions: undefined;
|
|
119
|
+
user_default_permissions: undefined;
|
|
116
120
|
oauth_account_merge_strategy: undefined;
|
|
117
121
|
};
|
|
118
122
|
}, "">;
|
|
@@ -184,6 +188,9 @@ export declare const projectsCrudAdminUpdateSchema: import("yup").ObjectSchema<{
|
|
|
184
188
|
team_member_default_permissions?: {
|
|
185
189
|
id: string;
|
|
186
190
|
}[] | undefined;
|
|
191
|
+
user_default_permissions?: {
|
|
192
|
+
id: string;
|
|
193
|
+
}[] | undefined;
|
|
187
194
|
oauth_account_merge_strategy?: "link_method" | "raise_error" | "allow_duplicates" | undefined;
|
|
188
195
|
} | undefined;
|
|
189
196
|
}, import("yup").AnyObject, {
|
|
@@ -233,6 +240,9 @@ export declare const projectsCrudAdminCreateSchema: import("yup").ObjectSchema<{
|
|
|
233
240
|
team_member_default_permissions?: {
|
|
234
241
|
id: string;
|
|
235
242
|
}[] | undefined;
|
|
243
|
+
user_default_permissions?: {
|
|
244
|
+
id: string;
|
|
245
|
+
}[] | undefined;
|
|
236
246
|
oauth_account_merge_strategy?: "link_method" | "raise_error" | "allow_duplicates" | undefined;
|
|
237
247
|
} | undefined;
|
|
238
248
|
} & {
|
|
@@ -320,6 +330,9 @@ export declare const projectsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
320
330
|
team_member_default_permissions: {
|
|
321
331
|
id: string;
|
|
322
332
|
}[];
|
|
333
|
+
user_default_permissions: {
|
|
334
|
+
id: string;
|
|
335
|
+
}[];
|
|
323
336
|
oauth_account_merge_strategy: "link_method" | "raise_error" | "allow_duplicates";
|
|
324
337
|
};
|
|
325
338
|
}, import("yup").AnyObject, {
|
|
@@ -353,6 +366,7 @@ export declare const projectsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
353
366
|
create_team_on_sign_up: undefined;
|
|
354
367
|
team_creator_default_permissions: undefined;
|
|
355
368
|
team_member_default_permissions: undefined;
|
|
369
|
+
user_default_permissions: undefined;
|
|
356
370
|
oauth_account_merge_strategy: undefined;
|
|
357
371
|
};
|
|
358
372
|
}, "">;
|
|
@@ -397,6 +411,9 @@ export declare const projectsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
397
411
|
team_member_default_permissions?: {
|
|
398
412
|
id: string;
|
|
399
413
|
}[] | undefined;
|
|
414
|
+
user_default_permissions?: {
|
|
415
|
+
id: string;
|
|
416
|
+
}[] | undefined;
|
|
400
417
|
oauth_account_merge_strategy?: "link_method" | "raise_error" | "allow_duplicates" | undefined;
|
|
401
418
|
} | undefined;
|
|
402
419
|
}, import("yup").AnyObject, {
|
|
@@ -479,6 +496,9 @@ export declare const internalProjectsCrud: import("../../crud").CrudSchemaFromOp
|
|
|
479
496
|
team_member_default_permissions: {
|
|
480
497
|
id: string;
|
|
481
498
|
}[];
|
|
499
|
+
user_default_permissions: {
|
|
500
|
+
id: string;
|
|
501
|
+
}[];
|
|
482
502
|
oauth_account_merge_strategy: "link_method" | "raise_error" | "allow_duplicates";
|
|
483
503
|
};
|
|
484
504
|
}, import("yup").AnyObject, {
|
|
@@ -512,6 +532,7 @@ export declare const internalProjectsCrud: import("../../crud").CrudSchemaFromOp
|
|
|
512
532
|
create_team_on_sign_up: undefined;
|
|
513
533
|
team_creator_default_permissions: undefined;
|
|
514
534
|
team_member_default_permissions: undefined;
|
|
535
|
+
user_default_permissions: undefined;
|
|
515
536
|
oauth_account_merge_strategy: undefined;
|
|
516
537
|
};
|
|
517
538
|
}, "">;
|
|
@@ -556,6 +577,9 @@ export declare const internalProjectsCrud: import("../../crud").CrudSchemaFromOp
|
|
|
556
577
|
team_member_default_permissions?: {
|
|
557
578
|
id: string;
|
|
558
579
|
}[] | undefined;
|
|
580
|
+
user_default_permissions?: {
|
|
581
|
+
id: string;
|
|
582
|
+
}[] | undefined;
|
|
559
583
|
oauth_account_merge_strategy?: "link_method" | "raise_error" | "allow_duplicates" | undefined;
|
|
560
584
|
} | undefined;
|
|
561
585
|
} & {
|
|
@@ -75,6 +75,7 @@ export const projectsCrudAdminReadSchema = yupObject({
|
|
|
75
75
|
create_team_on_sign_up: schemaFields.projectCreateTeamOnSignUpSchema.defined(),
|
|
76
76
|
team_creator_default_permissions: yupArray(teamPermissionSchema.defined()).defined(),
|
|
77
77
|
team_member_default_permissions: yupArray(teamPermissionSchema.defined()).defined(),
|
|
78
|
+
user_default_permissions: yupArray(teamPermissionSchema.defined()).defined(),
|
|
78
79
|
oauth_account_merge_strategy: schemaFields.oauthAccountMergeStrategySchema.defined(),
|
|
79
80
|
}).defined(),
|
|
80
81
|
}).defined();
|
|
@@ -109,6 +110,7 @@ export const projectsCrudAdminUpdateSchema = yupObject({
|
|
|
109
110
|
create_team_on_sign_up: schemaFields.projectCreateTeamOnSignUpSchema.optional(),
|
|
110
111
|
team_creator_default_permissions: yupArray(teamPermissionSchema.defined()).optional(),
|
|
111
112
|
team_member_default_permissions: yupArray(teamPermissionSchema.defined()).optional(),
|
|
113
|
+
user_default_permissions: yupArray(teamPermissionSchema.defined()).optional(),
|
|
112
114
|
oauth_account_merge_strategy: schemaFields.oauthAccountMergeStrategySchema.optional(),
|
|
113
115
|
}).optional().default(undefined),
|
|
114
116
|
}).defined();
|
|
@@ -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.
|
|
6
|
+
id: schemaFields.permissionDefinitionIdSchema.defined(),
|
|
7
7
|
user_id: schemaFields.userIdSchema.defined(),
|
|
8
8
|
team_id: schemaFields.teamIdSchema.defined(),
|
|
9
9
|
}).defined();
|
|
@@ -56,19 +56,19 @@ export const teamPermissionDeletedWebhookEvent = {
|
|
|
56
56
|
};
|
|
57
57
|
// =============== Team permission definitions =================
|
|
58
58
|
export const teamPermissionDefinitionsCrudAdminReadSchema = yupObject({
|
|
59
|
-
id: schemaFields.
|
|
59
|
+
id: schemaFields.permissionDefinitionIdSchema.defined(),
|
|
60
60
|
description: schemaFields.teamPermissionDescriptionSchema.optional(),
|
|
61
|
-
contained_permission_ids: schemaFields.containedPermissionIdsSchema.defined()
|
|
61
|
+
contained_permission_ids: schemaFields.containedPermissionIdsSchema.defined(),
|
|
62
62
|
}).defined();
|
|
63
63
|
export const teamPermissionDefinitionsCrudAdminCreateSchema = yupObject({
|
|
64
|
-
id: schemaFields.
|
|
64
|
+
id: schemaFields.customPermissionDefinitionIdSchema.defined(),
|
|
65
65
|
description: schemaFields.teamPermissionDescriptionSchema.optional(),
|
|
66
|
-
contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional()
|
|
66
|
+
contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional(),
|
|
67
67
|
}).defined();
|
|
68
68
|
export const teamPermissionDefinitionsCrudAdminUpdateSchema = yupObject({
|
|
69
|
-
id: schemaFields.
|
|
69
|
+
id: schemaFields.customPermissionDefinitionIdSchema.optional(),
|
|
70
70
|
description: schemaFields.teamPermissionDescriptionSchema.optional(),
|
|
71
|
-
contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional()
|
|
71
|
+
contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional(),
|
|
72
72
|
}).defined();
|
|
73
73
|
export const teamPermissionDefinitionsCrudAdminDeleteSchema = yupMixed();
|
|
74
74
|
export const teamPermissionDefinitionsCrud = createCrud({
|
|
@@ -9,6 +9,7 @@ import { SessionsCrud } from "./crud/sessions";
|
|
|
9
9
|
import { TeamInvitationCrud } from "./crud/team-invitation";
|
|
10
10
|
import { TeamMemberProfilesCrud } from "./crud/team-member-profiles";
|
|
11
11
|
import { TeamMembershipsCrud } from "./crud/team-memberships";
|
|
12
|
+
import { ProjectPermissionsCrud } from "./crud/project-permissions";
|
|
12
13
|
import { TeamPermissionsCrud } from "./crud/team-permissions";
|
|
13
14
|
import { TeamsCrud } from "./crud/teams";
|
|
14
15
|
import { UsersCrud } from "./crud/users";
|
|
@@ -51,6 +52,10 @@ export declare class StackServerInterface extends StackClientInterface {
|
|
|
51
52
|
teamId?: string;
|
|
52
53
|
recursive: boolean;
|
|
53
54
|
}, session: InternalSession | null): Promise<TeamPermissionsCrud['Server']['Read'][]>;
|
|
55
|
+
listServerProjectPermissions(options: {
|
|
56
|
+
userId?: string;
|
|
57
|
+
recursive: boolean;
|
|
58
|
+
}, session: InternalSession | null): Promise<ProjectPermissionsCrud['Server']['Read'][]>;
|
|
54
59
|
listServerUsers(options: {
|
|
55
60
|
cursor?: string;
|
|
56
61
|
limit?: number;
|
|
@@ -91,6 +91,14 @@ export class StackServerInterface extends StackClientInterface {
|
|
|
91
91
|
const result = await response.json();
|
|
92
92
|
return result.items;
|
|
93
93
|
}
|
|
94
|
+
async listServerProjectPermissions(options, session) {
|
|
95
|
+
const response = await this.sendServerRequest(`/project-permissions?${new URLSearchParams(filterUndefined({
|
|
96
|
+
user_id: options.userId,
|
|
97
|
+
recursive: options.recursive.toString(),
|
|
98
|
+
}))}`, {}, session);
|
|
99
|
+
const result = await response.json();
|
|
100
|
+
return result.items;
|
|
101
|
+
}
|
|
94
102
|
async listServerUsers(options) {
|
|
95
103
|
const searchParams = new URLSearchParams(filterUndefined({
|
|
96
104
|
cursor: options.cursor,
|
|
@@ -254,4 +254,36 @@ export declare const webhookEvents: readonly [{
|
|
|
254
254
|
description: string;
|
|
255
255
|
tags: string[];
|
|
256
256
|
};
|
|
257
|
+
}, {
|
|
258
|
+
type: string;
|
|
259
|
+
schema: yup.ObjectSchema<{
|
|
260
|
+
id: string;
|
|
261
|
+
user_id: string;
|
|
262
|
+
team_id: string;
|
|
263
|
+
}, yup.AnyObject, {
|
|
264
|
+
id: undefined;
|
|
265
|
+
user_id: undefined;
|
|
266
|
+
team_id: undefined;
|
|
267
|
+
}, "">;
|
|
268
|
+
metadata: {
|
|
269
|
+
summary: string;
|
|
270
|
+
description: string;
|
|
271
|
+
tags: string[];
|
|
272
|
+
};
|
|
273
|
+
}, {
|
|
274
|
+
type: string;
|
|
275
|
+
schema: yup.ObjectSchema<{
|
|
276
|
+
id: string;
|
|
277
|
+
user_id: string;
|
|
278
|
+
team_id: string;
|
|
279
|
+
}, yup.AnyObject, {
|
|
280
|
+
id: undefined;
|
|
281
|
+
user_id: undefined;
|
|
282
|
+
team_id: undefined;
|
|
283
|
+
}, "">;
|
|
284
|
+
metadata: {
|
|
285
|
+
summary: string;
|
|
286
|
+
description: string;
|
|
287
|
+
tags: string[];
|
|
288
|
+
};
|
|
257
289
|
}];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { teamMembershipCreatedWebhookEvent, teamMembershipDeletedWebhookEvent } from "./crud/team-memberships";
|
|
2
|
+
import { teamPermissionCreatedWebhookEvent, teamPermissionDeletedWebhookEvent } from "./crud/team-permissions";
|
|
2
3
|
import { teamCreatedWebhookEvent, teamDeletedWebhookEvent, teamUpdatedWebhookEvent } from "./crud/teams";
|
|
3
4
|
import { userCreatedWebhookEvent, userDeletedWebhookEvent, userUpdatedWebhookEvent } from "./crud/users";
|
|
4
5
|
export const webhookEvents = [
|
|
@@ -10,4 +11,6 @@ export const webhookEvents = [
|
|
|
10
11
|
teamDeletedWebhookEvent,
|
|
11
12
|
teamMembershipCreatedWebhookEvent,
|
|
12
13
|
teamMembershipDeletedWebhookEvent,
|
|
14
|
+
teamPermissionCreatedWebhookEvent,
|
|
15
|
+
teamPermissionDeletedWebhookEvent,
|
|
13
16
|
];
|
package/dist/known-errors.d.ts
CHANGED
|
@@ -66,6 +66,9 @@ export declare const KnownErrors: {
|
|
|
66
66
|
ProjectAuthenticationError: KnownErrorConstructor<KnownError & KnownErrorBrand<"PROJECT_AUTHENTICATION_ERROR">, [statusCode: number, humanReadableMessage: string, details?: Json | undefined]> & {
|
|
67
67
|
errorCode: "PROJECT_AUTHENTICATION_ERROR";
|
|
68
68
|
};
|
|
69
|
+
PermissionIdAlreadyExists: KnownErrorConstructor<KnownError & KnownErrorBrand<"PERMISSION_ID_ALREADY_EXISTS">, [permissionId: string]> & {
|
|
70
|
+
errorCode: "PERMISSION_ID_ALREADY_EXISTS";
|
|
71
|
+
};
|
|
69
72
|
InvalidProjectAuthentication: KnownErrorConstructor<KnownError & KnownErrorBrand<"PROJECT_AUTHENTICATION_ERROR"> & {
|
|
70
73
|
constructorArgs: [statusCode: number, humanReadableMessage: string, details?: Json | undefined];
|
|
71
74
|
} & KnownErrorBrand<"INVALID_PROJECT_AUTHENTICATION">, [statusCode: number, humanReadableMessage: string, details?: Json | undefined]> & {
|
|
@@ -373,6 +376,9 @@ export declare const KnownErrors: {
|
|
|
373
376
|
TeamMembershipAlreadyExists: KnownErrorConstructor<KnownError & KnownErrorBrand<"TEAM_MEMBERSHIP_ALREADY_EXISTS">, []> & {
|
|
374
377
|
errorCode: "TEAM_MEMBERSHIP_ALREADY_EXISTS";
|
|
375
378
|
};
|
|
379
|
+
ProjectPermissionRequired: KnownErrorConstructor<KnownError & KnownErrorBrand<"PROJECT_PERMISSION_REQUIRED">, [any, any]> & {
|
|
380
|
+
errorCode: "PROJECT_PERMISSION_REQUIRED";
|
|
381
|
+
};
|
|
376
382
|
TeamPermissionRequired: KnownErrorConstructor<KnownError & KnownErrorBrand<"TEAM_PERMISSION_REQUIRED">, [any, any, any]> & {
|
|
377
383
|
errorCode: "TEAM_PERMISSION_REQUIRED";
|
|
378
384
|
};
|
package/dist/known-errors.js
CHANGED
|
@@ -510,6 +510,14 @@ const TeamMembershipAlreadyExists = createKnownErrorConstructor(KnownError, "TEA
|
|
|
510
510
|
409,
|
|
511
511
|
"Team membership already exists.",
|
|
512
512
|
], () => []);
|
|
513
|
+
const ProjectPermissionRequired = createKnownErrorConstructor(KnownError, "PROJECT_PERMISSION_REQUIRED", (userId, permissionId) => [
|
|
514
|
+
401,
|
|
515
|
+
`User ${userId} does not have permission ${permissionId}.`,
|
|
516
|
+
{
|
|
517
|
+
user_id: userId,
|
|
518
|
+
permission_id: permissionId,
|
|
519
|
+
},
|
|
520
|
+
], (json) => [json.user_id, json.permission_id]);
|
|
513
521
|
const TeamPermissionRequired = createKnownErrorConstructor(KnownError, "TEAM_PERMISSION_REQUIRED", (teamId, userId, permissionId) => [
|
|
514
522
|
401,
|
|
515
523
|
`User ${userId} does not have permission ${permissionId} in team ${teamId}.`,
|
|
@@ -562,6 +570,13 @@ const InvalidPollingCodeError = createKnownErrorConstructor(KnownError, "INVALID
|
|
|
562
570
|
"The polling code is invalid or does not exist.",
|
|
563
571
|
details,
|
|
564
572
|
], (json) => [json]);
|
|
573
|
+
const PermissionIdAlreadyExists = createKnownErrorConstructor(KnownError, "PERMISSION_ID_ALREADY_EXISTS", (permissionId) => [
|
|
574
|
+
400,
|
|
575
|
+
`Permission with ID "${permissionId}" already exists. Choose a different ID.`,
|
|
576
|
+
{
|
|
577
|
+
permission_id: permissionId,
|
|
578
|
+
},
|
|
579
|
+
], (json) => [json.permission_id]);
|
|
565
580
|
export const KnownErrors = {
|
|
566
581
|
CannotDeleteCurrentSession,
|
|
567
582
|
UnsupportedError,
|
|
@@ -569,6 +584,7 @@ export const KnownErrors = {
|
|
|
569
584
|
SchemaError,
|
|
570
585
|
AllOverloadsFailed,
|
|
571
586
|
ProjectAuthenticationError,
|
|
587
|
+
PermissionIdAlreadyExists,
|
|
572
588
|
InvalidProjectAuthentication,
|
|
573
589
|
ProjectKeyWithoutAccessType,
|
|
574
590
|
InvalidAccessType,
|
|
@@ -648,6 +664,7 @@ export const KnownErrors = {
|
|
|
648
664
|
InvalidTotpCode,
|
|
649
665
|
UserAuthenticationRequired,
|
|
650
666
|
TeamMembershipAlreadyExists,
|
|
667
|
+
ProjectPermissionRequired,
|
|
651
668
|
TeamPermissionRequired,
|
|
652
669
|
InvalidSharedOAuthProviderId,
|
|
653
670
|
InvalidStandardOAuthProviderId,
|
package/dist/schema-fields.d.ts
CHANGED
|
@@ -131,8 +131,8 @@ export declare const signInResponseSchema: yup.ObjectSchema<{
|
|
|
131
131
|
user_id: undefined;
|
|
132
132
|
}, "">;
|
|
133
133
|
export declare const teamSystemPermissions: readonly ["$update_team", "$delete_team", "$read_members", "$remove_members", "$invite_members"];
|
|
134
|
-
export declare const
|
|
135
|
-
export declare const
|
|
134
|
+
export declare const permissionDefinitionIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
135
|
+
export declare const customPermissionDefinitionIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
136
136
|
export declare const teamPermissionDescriptionSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
137
137
|
export declare const containedPermissionIdsSchema: yup.ArraySchema<string[] | undefined, yup.AnyObject, undefined, "">;
|
|
138
138
|
export declare const teamIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
package/dist/schema-fields.js
CHANGED
|
@@ -327,7 +327,7 @@ export const teamSystemPermissions = [
|
|
|
327
327
|
'$remove_members',
|
|
328
328
|
'$invite_members',
|
|
329
329
|
];
|
|
330
|
-
export const
|
|
330
|
+
export const permissionDefinitionIdSchema = yupString()
|
|
331
331
|
.matches(/^\$?[a-z0-9_:]+$/, 'Only lowercase letters, numbers, ":", "_" and optional "$" at the beginning are allowed')
|
|
332
332
|
.test('is-system-permission', 'System permissions must start with a dollar sign', (value, ctx) => {
|
|
333
333
|
if (!value)
|
|
@@ -338,11 +338,11 @@ export const teamPermissionDefinitionIdSchema = yupString()
|
|
|
338
338
|
return true;
|
|
339
339
|
})
|
|
340
340
|
.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.map(x => `\`${x}\``).join(', ')}`, exampleValue: 'read_secret_info' } });
|
|
341
|
-
export const
|
|
341
|
+
export const customPermissionDefinitionIdSchema = yupString()
|
|
342
342
|
.matches(/^[a-z0-9_:]+$/, 'Only lowercase letters, numbers, ":", "_" are allowed')
|
|
343
343
|
.meta({ openapiField: { description: 'The permission ID used to uniquely identify a permission. Can only contain lowercase letters, numbers, ":", and "_" characters', exampleValue: 'read_secret_info' } });
|
|
344
344
|
export const teamPermissionDescriptionSchema = yupString().meta({ openapiField: { description: 'A human-readable description of the permission', exampleValue: 'Read secret information' } });
|
|
345
|
-
export const containedPermissionIdsSchema = yupArray(
|
|
345
|
+
export const containedPermissionIdsSchema = yupArray(permissionDefinitionIdSchema.defined()).meta({ openapiField: { description: 'The IDs of the permissions that are contained in this permission', exampleValue: ['read_public_info'] } });
|
|
346
346
|
// Teams
|
|
347
347
|
export const teamIdSchema = yupString().uuid().meta({ openapiField: { description: _idDescription('team'), exampleValue: 'ad962777-8244-496a-b6a2-e0c6a449c79e' } });
|
|
348
348
|
export const teamDisplayNameSchema = yupString().meta({ openapiField: { description: _displayNameDescription('team'), exampleValue: 'My Team' } });
|
package/dist/utils/errors.js
CHANGED
|
@@ -68,11 +68,7 @@ StackAssertionError.prototype.name = "StackAssertionError";
|
|
|
68
68
|
export function errorToNiceString(error) {
|
|
69
69
|
if (!(error instanceof Error))
|
|
70
70
|
return `${typeof error}<${nicify(error)}>`;
|
|
71
|
-
|
|
72
|
-
const toString = error.toString();
|
|
73
|
-
if (!stack.startsWith(toString))
|
|
74
|
-
stack = `${toString}\n${stack}`; // some browsers don't include the error message in the stack, some do
|
|
75
|
-
return `${stack} ${nicify(Object.fromEntries(Object.entries(error)), { maxDepth: 8 })}`;
|
|
71
|
+
return nicify(error, { maxDepth: 8 });
|
|
76
72
|
}
|
|
77
73
|
const errorSinks = new Set();
|
|
78
74
|
export function registerErrorSink(sink) {
|
package/dist/utils/results.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { wait } from "./promises";
|
|
2
|
-
import { deindent } from "./strings";
|
|
2
|
+
import { deindent, nicify } from "./strings";
|
|
3
3
|
export const Result = {
|
|
4
4
|
fromThrowing,
|
|
5
5
|
fromThrowingAsync,
|
|
@@ -255,17 +255,17 @@ import.meta.vitest?.test("mapResult", ({ expect }) => {
|
|
|
255
255
|
});
|
|
256
256
|
class RetryError extends AggregateError {
|
|
257
257
|
constructor(errors) {
|
|
258
|
-
const strings = errors.map(e =>
|
|
258
|
+
const strings = errors.map(e => nicify(e));
|
|
259
259
|
const isAllSame = strings.length > 1 && strings.every(s => s === strings[0]);
|
|
260
260
|
super(errors, deindent `
|
|
261
261
|
Error after ${errors.length} attempts.
|
|
262
262
|
|
|
263
263
|
${isAllSame ? deindent `
|
|
264
264
|
Attempts 1-${errors.length}:
|
|
265
|
-
${
|
|
266
|
-
` :
|
|
265
|
+
${strings[0]}
|
|
266
|
+
` : strings.map((s, i) => deindent `
|
|
267
267
|
Attempt ${i + 1}:
|
|
268
|
-
${
|
|
268
|
+
${s}
|
|
269
269
|
`).join("\n\n")}
|
|
270
270
|
`, { cause: errors[errors.length - 1] });
|
|
271
271
|
this.errors = errors;
|
package/dist/utils/strings.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export declare function trimLines(s: string): string;
|
|
|
43
43
|
export declare function templateIdentity(strings: TemplateStringsArray | readonly string[], ...values: string[]): string;
|
|
44
44
|
export declare function deindent(code: string): string;
|
|
45
45
|
export declare function deindent(strings: TemplateStringsArray | readonly string[], ...values: any[]): string;
|
|
46
|
+
export declare function deindentTemplate(strings: TemplateStringsArray | readonly string[], ...values: any[]): [string[], ...string[]];
|
|
46
47
|
export declare function extractScopes(scope: string, removeDuplicates?: boolean): string[];
|
|
47
48
|
export declare function mergeScopeStrings(...scopes: string[]): string;
|
|
48
49
|
export declare function escapeTemplateLiteral(s: string): string;
|
package/dist/utils/strings.js
CHANGED
|
@@ -207,8 +207,9 @@ Line2`).toBe("Line1\nLine2");
|
|
|
207
207
|
export function deindent(strings, ...values) {
|
|
208
208
|
if (typeof strings === "string")
|
|
209
209
|
return deindent([strings]);
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
return templateIdentity(...deindentTemplate(strings, ...values));
|
|
211
|
+
}
|
|
212
|
+
export function deindentTemplate(strings, ...values) {
|
|
212
213
|
if (values.length !== strings.length - 1)
|
|
213
214
|
throw new StackAssertionError("Invalid number of values; must be one less than strings", { strings, values });
|
|
214
215
|
const trimmedStrings = [...strings];
|
|
@@ -231,7 +232,7 @@ export function deindent(strings, ...values) {
|
|
|
231
232
|
const firstLineIndentation = getWhitespacePrefix(deindentedStrings[i].split("\n").at(-1));
|
|
232
233
|
return `${value}`.replaceAll("\n", `\n${firstLineIndentation}`);
|
|
233
234
|
});
|
|
234
|
-
return
|
|
235
|
+
return [deindentedStrings, ...indentedValues];
|
|
235
236
|
}
|
|
236
237
|
import.meta.vitest?.test("deindent", ({ expect }) => {
|
|
237
238
|
// Test with string input
|
|
@@ -241,7 +242,6 @@ import.meta.vitest?.test("deindent", ({ expect }) => {
|
|
|
241
242
|
expect(deindent("\n hello\n world\n")).toBe("hello\nworld");
|
|
242
243
|
// Test with empty input
|
|
243
244
|
expect(deindent("")).toBe("");
|
|
244
|
-
expect(deindent([])).toBe("");
|
|
245
245
|
// Test with template literal
|
|
246
246
|
expect(deindent `
|
|
247
247
|
hello
|
|
@@ -414,12 +414,13 @@ export function nicify(value, options = {}) {
|
|
|
414
414
|
keyInParent: null,
|
|
415
415
|
hideFields: [],
|
|
416
416
|
};
|
|
417
|
-
const nestedNicify = (newValue, newPath, keyInParent) => {
|
|
417
|
+
const nestedNicify = (newValue, newPath, keyInParent, options = {}) => {
|
|
418
418
|
return nicify(newValue, {
|
|
419
419
|
...newOptions,
|
|
420
420
|
path: newPath,
|
|
421
421
|
currentIndent: currentIndent + lineIndent,
|
|
422
422
|
keyInParent,
|
|
423
|
+
...options,
|
|
423
424
|
});
|
|
424
425
|
};
|
|
425
426
|
switch (typeof value) {
|
|
@@ -431,7 +432,7 @@ export function nicify(value, options = {}) {
|
|
|
431
432
|
const isDeindentable = (v) => deindent(v) === v && v.includes("\n");
|
|
432
433
|
const wrapInDeindent = (v) => deindent `
|
|
433
434
|
deindent\`
|
|
434
|
-
${currentIndent + lineIndent}${escapeTemplateLiteral(
|
|
435
|
+
${currentIndent + lineIndent}${escapeTemplateLiteral(v).replaceAll("\n", nl + lineIndent)}
|
|
435
436
|
${currentIndent}\`
|
|
436
437
|
`;
|
|
437
438
|
if (isDeindentable(value)) {
|
|
@@ -470,7 +471,7 @@ export function nicify(value, options = {}) {
|
|
|
470
471
|
resValues.push(...extraLines);
|
|
471
472
|
if (resValues.length !== resValueLength)
|
|
472
473
|
throw new StackAssertionError("nicify of object: resValues.length !== resValueLength", { value, resValues, resValueLength });
|
|
473
|
-
const shouldIndent = resValues.length >
|
|
474
|
+
const shouldIndent = resValues.length > 4 || resValues.some(x => (resValues.length > 1 && x.length > 4) || x.includes("\n"));
|
|
474
475
|
if (shouldIndent) {
|
|
475
476
|
return `[${nl}${resValues.map(x => `${lineIndent}${x},${nl}`).join("")}]`;
|
|
476
477
|
}
|
|
@@ -479,13 +480,30 @@ export function nicify(value, options = {}) {
|
|
|
479
480
|
}
|
|
480
481
|
}
|
|
481
482
|
if (value instanceof URL) {
|
|
482
|
-
return `URL(${
|
|
483
|
+
return `URL(${nestedNicify(value.toString(), `${path}.toString()`, null)})`;
|
|
483
484
|
}
|
|
484
485
|
if (ArrayBuffer.isView(value)) {
|
|
485
486
|
return `${value.constructor.name}([${value.toString()}])`;
|
|
486
487
|
}
|
|
488
|
+
if (value instanceof Error) {
|
|
489
|
+
let stack = value.stack ?? "";
|
|
490
|
+
const toString = value.toString();
|
|
491
|
+
if (!stack.startsWith(toString))
|
|
492
|
+
stack = `${toString}\n${stack}`; // some browsers don't include the error message in the stack, some do
|
|
493
|
+
stack = stack.trimEnd();
|
|
494
|
+
stack = stack.replace(/\n\s+/g, `\n${lineIndent}${lineIndent}`);
|
|
495
|
+
stack = stack.replace("\n", `\n${lineIndent}Stack:\n`);
|
|
496
|
+
if (Object.keys(value).length > 0) {
|
|
497
|
+
stack += `\n${lineIndent}Extra properties: ${nestedNicify(Object.fromEntries(Object.entries(value)), path, null)}`;
|
|
498
|
+
}
|
|
499
|
+
if (value.cause) {
|
|
500
|
+
stack += `\n${lineIndent}Cause:\n${lineIndent}${lineIndent}${nestedNicify(value.cause, path, null, { currentIndent: currentIndent + lineIndent + lineIndent })}`;
|
|
501
|
+
}
|
|
502
|
+
stack = stack.replaceAll("\n", `\n${currentIndent}`);
|
|
503
|
+
return stack;
|
|
504
|
+
}
|
|
487
505
|
const constructorName = [null, Object.prototype].includes(Object.getPrototypeOf(value)) ? null : (nicifiableClassNameOverrides.get(value.constructor) ?? value.constructor.name);
|
|
488
|
-
const constructorString = constructorName ? `${
|
|
506
|
+
const constructorString = constructorName ? `${constructorName} ` : "";
|
|
489
507
|
const entries = getNicifiableEntries(value).filter(([k]) => !hideFields.includes(k));
|
|
490
508
|
const extraLines = [
|
|
491
509
|
...getNicifiedObjectExtraLines(value),
|
|
@@ -498,7 +516,7 @@ export function nicify(value, options = {}) {
|
|
|
498
516
|
return `${constructorString}{ ... }`;
|
|
499
517
|
const resValues = entries.map(([k, v], keyIndex) => {
|
|
500
518
|
const keyNicified = nestedNicify(k, `Object.keys(${path})[${keyIndex}]`, null);
|
|
501
|
-
const keyInObjectLiteral = typeof k === "string" ?
|
|
519
|
+
const keyInObjectLiteral = typeof k === "string" ? nicifyPropertyString(k) : `[${keyNicified}]`;
|
|
502
520
|
if (typeof v === "function" && v.name === k) {
|
|
503
521
|
return `${keyInObjectLiteral}(...): { ... }`;
|
|
504
522
|
}
|
|
@@ -525,25 +543,63 @@ export function nicify(value, options = {}) {
|
|
|
525
543
|
}
|
|
526
544
|
}
|
|
527
545
|
export function replaceAll(input, searchValue, replaceValue) {
|
|
546
|
+
if (searchValue === "")
|
|
547
|
+
throw new StackAssertionError("replaceAll: searchValue is empty");
|
|
528
548
|
return input.split(searchValue).join(replaceValue);
|
|
529
549
|
}
|
|
550
|
+
import.meta.vitest?.test("replaceAll", ({ expect }) => {
|
|
551
|
+
expect(replaceAll("hello world", "o", "x")).toBe("hellx wxrld");
|
|
552
|
+
expect(replaceAll("aaa", "a", "b")).toBe("bbb");
|
|
553
|
+
expect(replaceAll("", "a", "b")).toBe("");
|
|
554
|
+
expect(replaceAll("abc", "b", "")).toBe("ac");
|
|
555
|
+
expect(replaceAll("test.test.test", ".", "_")).toBe("test_test_test");
|
|
556
|
+
expect(replaceAll("a.b*c", ".", "x")).toBe("axb*c");
|
|
557
|
+
expect(replaceAll("a*b*c", "*", "x")).toBe("axbxc");
|
|
558
|
+
expect(replaceAll("hello hello", "hello", "hi")).toBe("hi hi");
|
|
559
|
+
});
|
|
530
560
|
function nicifyPropertyString(str) {
|
|
531
|
-
if (/^[_a-zA-Z][_a-zA-Z0-9]*$/.test(str))
|
|
532
|
-
return str;
|
|
533
561
|
return JSON.stringify(str);
|
|
534
562
|
}
|
|
563
|
+
import.meta.vitest?.test("nicifyPropertyString", ({ expect }) => {
|
|
564
|
+
// Test valid identifiers
|
|
565
|
+
expect(nicifyPropertyString("validName")).toBe('"validName"');
|
|
566
|
+
expect(nicifyPropertyString("_validName")).toBe('"_validName"');
|
|
567
|
+
expect(nicifyPropertyString("valid123Name")).toBe('"valid123Name"');
|
|
568
|
+
// Test invalid identifiers
|
|
569
|
+
expect(nicifyPropertyString("123invalid")).toBe('"123invalid"');
|
|
570
|
+
expect(nicifyPropertyString("invalid-name")).toBe('"invalid-name"');
|
|
571
|
+
expect(nicifyPropertyString("invalid space")).toBe('"invalid space"');
|
|
572
|
+
expect(nicifyPropertyString("$invalid")).toBe('"$invalid"');
|
|
573
|
+
expect(nicifyPropertyString("")).toBe('""');
|
|
574
|
+
// Test with special characters
|
|
575
|
+
expect(nicifyPropertyString("property!")).toBe('"property!"');
|
|
576
|
+
expect(nicifyPropertyString("property.name")).toBe('"property.name"');
|
|
577
|
+
// Test with escaped characters
|
|
578
|
+
expect(nicifyPropertyString("\\")).toBe('"\\\\"');
|
|
579
|
+
expect(nicifyPropertyString('"')).toBe('"\\""');
|
|
580
|
+
});
|
|
535
581
|
function getNicifiableKeys(value) {
|
|
536
582
|
const overridden = ("getNicifiableKeys" in value ? value.getNicifiableKeys?.bind(value) : null)?.();
|
|
537
583
|
if (overridden != null)
|
|
538
584
|
return overridden;
|
|
539
585
|
const keys = Object.keys(value).sort();
|
|
540
|
-
if (value instanceof Error) {
|
|
541
|
-
if (value.cause)
|
|
542
|
-
keys.unshift("cause");
|
|
543
|
-
keys.unshift("message", "stack");
|
|
544
|
-
}
|
|
545
586
|
return unique(keys);
|
|
546
587
|
}
|
|
588
|
+
import.meta.vitest?.test("getNicifiableKeys", ({ expect }) => {
|
|
589
|
+
// Test regular object
|
|
590
|
+
expect(getNicifiableKeys({ b: 1, a: 2, c: 3 })).toEqual(["a", "b", "c"]);
|
|
591
|
+
// Test empty object
|
|
592
|
+
expect(getNicifiableKeys({})).toEqual([]);
|
|
593
|
+
// Test object with custom getNicifiableKeys
|
|
594
|
+
const customObject = {
|
|
595
|
+
a: 1,
|
|
596
|
+
b: 2,
|
|
597
|
+
getNicifiableKeys() {
|
|
598
|
+
return ["customKey1", "customKey2"];
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
expect(getNicifiableKeys(customObject)).toEqual(["customKey1", "customKey2"]);
|
|
602
|
+
});
|
|
547
603
|
function getNicifiableEntries(value) {
|
|
548
604
|
const recordLikes = [Headers];
|
|
549
605
|
function isRecordLike(value) {
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { deindent, nicify } from "./strings";
|
|
3
|
+
describe("nicify", () => {
|
|
4
|
+
describe("primitive values", () => {
|
|
5
|
+
test("numbers", () => {
|
|
6
|
+
expect(nicify(123)).toBe("123");
|
|
7
|
+
expect(nicify(123n)).toBe("123n");
|
|
8
|
+
});
|
|
9
|
+
test("strings", () => {
|
|
10
|
+
expect(nicify("hello")).toBe('"hello"');
|
|
11
|
+
});
|
|
12
|
+
test("booleans", () => {
|
|
13
|
+
expect(nicify(true)).toBe("true");
|
|
14
|
+
expect(nicify(false)).toBe("false");
|
|
15
|
+
});
|
|
16
|
+
test("null and undefined", () => {
|
|
17
|
+
expect(nicify(null)).toBe("null");
|
|
18
|
+
expect(nicify(undefined)).toBe("undefined");
|
|
19
|
+
});
|
|
20
|
+
test("symbols", () => {
|
|
21
|
+
expect(nicify(Symbol("test"))).toBe("Symbol(test)");
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe("arrays", () => {
|
|
25
|
+
test("empty array", () => {
|
|
26
|
+
expect(nicify([])).toBe("[]");
|
|
27
|
+
});
|
|
28
|
+
test("single-element array", () => {
|
|
29
|
+
expect(nicify([1])).toBe("[1]");
|
|
30
|
+
});
|
|
31
|
+
test("single-element array with long content", () => {
|
|
32
|
+
expect(nicify(["123123123123123"])).toBe('["123123123123123"]');
|
|
33
|
+
});
|
|
34
|
+
test("flat array", () => {
|
|
35
|
+
expect(nicify([1, 2, 3])).toBe("[1, 2, 3]");
|
|
36
|
+
});
|
|
37
|
+
test("longer array", () => {
|
|
38
|
+
expect(nicify([10000, 2, 3])).toBe(deindent `
|
|
39
|
+
[
|
|
40
|
+
10000,
|
|
41
|
+
2,
|
|
42
|
+
3,
|
|
43
|
+
]
|
|
44
|
+
`);
|
|
45
|
+
});
|
|
46
|
+
test("nested array", () => {
|
|
47
|
+
expect(nicify([1, [2, 3]])).toBe(deindent `
|
|
48
|
+
[
|
|
49
|
+
1,
|
|
50
|
+
[2, 3],
|
|
51
|
+
]
|
|
52
|
+
`);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe("objects", () => {
|
|
56
|
+
test("empty object", () => {
|
|
57
|
+
expect(nicify({})).toBe("{}");
|
|
58
|
+
});
|
|
59
|
+
test("simple object", () => {
|
|
60
|
+
expect(nicify({ a: 1 })).toBe('{ "a": 1 }');
|
|
61
|
+
});
|
|
62
|
+
test("multiline object", () => {
|
|
63
|
+
expect(nicify({ a: 1, b: 2 })).toBe(deindent `
|
|
64
|
+
{
|
|
65
|
+
"a": 1,
|
|
66
|
+
"b": 2,
|
|
67
|
+
}
|
|
68
|
+
`);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe("custom classes", () => {
|
|
72
|
+
test("class instance", () => {
|
|
73
|
+
class TestClass {
|
|
74
|
+
constructor(value) {
|
|
75
|
+
this.value = value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
expect(nicify(new TestClass(42))).toBe('TestClass { "value": 42 }');
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe("built-in objects", () => {
|
|
82
|
+
test("URL", () => {
|
|
83
|
+
expect(nicify(new URL("https://example.com"))).toBe('URL("https://example.com/")');
|
|
84
|
+
});
|
|
85
|
+
test("TypedArrays", () => {
|
|
86
|
+
expect(nicify(new Uint8Array([1, 2, 3]))).toBe("Uint8Array([1,2,3])");
|
|
87
|
+
expect(nicify(new Int32Array([1, 2, 3]))).toBe("Int32Array([1,2,3])");
|
|
88
|
+
});
|
|
89
|
+
test("Error objects", () => {
|
|
90
|
+
const error = new Error("test error");
|
|
91
|
+
const nicifiedError = nicify({ error });
|
|
92
|
+
expect(nicifiedError).toMatch(new RegExp(deindent `
|
|
93
|
+
^\{
|
|
94
|
+
"error": Error: test error
|
|
95
|
+
Stack:
|
|
96
|
+
at (.|\\n)*
|
|
97
|
+
\}$
|
|
98
|
+
`));
|
|
99
|
+
});
|
|
100
|
+
test("Error objects with cause and an extra property", () => {
|
|
101
|
+
const error = new Error("test error", { cause: new Error("cause") });
|
|
102
|
+
error.extra = "something";
|
|
103
|
+
const nicifiedError = nicify(error, { lineIndent: "--" });
|
|
104
|
+
expect(nicifiedError).toMatch(new RegExp(deindent `
|
|
105
|
+
^Error: test error
|
|
106
|
+
--Stack:
|
|
107
|
+
----at (.|\\n)+
|
|
108
|
+
--Extra properties: \{ "extra": "something" \}
|
|
109
|
+
--Cause:
|
|
110
|
+
----Error: cause
|
|
111
|
+
------Stack:
|
|
112
|
+
--------at (.|\\n)+$
|
|
113
|
+
`));
|
|
114
|
+
});
|
|
115
|
+
test("Headers", () => {
|
|
116
|
+
const headers = new Headers();
|
|
117
|
+
headers.append("Content-Type", "application/json");
|
|
118
|
+
headers.append("Accept", "text/plain");
|
|
119
|
+
expect(nicify(headers)).toBe(deindent `
|
|
120
|
+
Headers {
|
|
121
|
+
"accept": "text/plain",
|
|
122
|
+
"content-type": "application/json",
|
|
123
|
+
}`);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
describe("multiline strings", () => {
|
|
127
|
+
test("basic multiline", () => {
|
|
128
|
+
expect(nicify("line1\nline2")).toBe('deindent`\n line1\n line2\n`');
|
|
129
|
+
});
|
|
130
|
+
test("multiline with trailing newline", () => {
|
|
131
|
+
expect(nicify("line1\nline2\n")).toBe('deindent`\n line1\n line2\n` + "\\n"');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
describe("circular references", () => {
|
|
135
|
+
test("object with self reference", () => {
|
|
136
|
+
const circular = { a: 1 };
|
|
137
|
+
circular.self = circular;
|
|
138
|
+
expect(nicify(circular)).toBe(deindent `
|
|
139
|
+
{
|
|
140
|
+
"a": 1,
|
|
141
|
+
"self": Ref<value>,
|
|
142
|
+
}`);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe("configuration options", () => {
|
|
146
|
+
test("maxDepth", () => {
|
|
147
|
+
const deep = { a: { b: { c: { d: { e: 1 } } } } };
|
|
148
|
+
expect(nicify(deep, { maxDepth: 2 })).toBe('{ "a": { "b": { ... } } }');
|
|
149
|
+
});
|
|
150
|
+
test("lineIndent", () => {
|
|
151
|
+
expect(nicify({ a: 1, b: 2 }, { lineIndent: " " })).toBe(deindent `
|
|
152
|
+
{
|
|
153
|
+
"a": 1,
|
|
154
|
+
"b": 2,
|
|
155
|
+
}
|
|
156
|
+
`);
|
|
157
|
+
});
|
|
158
|
+
test("hideFields", () => {
|
|
159
|
+
expect(nicify({ a: 1, b: 2, secret: "hidden" }, { hideFields: ["secret"] })).toBe(deindent `
|
|
160
|
+
{
|
|
161
|
+
"a": 1,
|
|
162
|
+
"b": 2,
|
|
163
|
+
<some fields may have been hidden>,
|
|
164
|
+
}
|
|
165
|
+
`);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe("custom overrides", () => {
|
|
169
|
+
test("override with custom type", () => {
|
|
170
|
+
expect(nicify({ type: "special" }, {
|
|
171
|
+
overrides: ((value) => {
|
|
172
|
+
if (typeof value === "object" && value && "type" in value && value.type === "special") {
|
|
173
|
+
return "SPECIAL";
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
})
|
|
177
|
+
})).toBe("SPECIAL");
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
describe("functions", () => {
|
|
181
|
+
test("named function", () => {
|
|
182
|
+
expect(nicify(function namedFunction() { })).toBe("function namedFunction(...) { ... }");
|
|
183
|
+
});
|
|
184
|
+
test("arrow function", () => {
|
|
185
|
+
expect(nicify(() => { })).toBe("(...) => { ... }");
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
describe("Nicifiable interface", () => {
|
|
189
|
+
test("object implementing Nicifiable", () => {
|
|
190
|
+
const nicifiable = {
|
|
191
|
+
value: 42,
|
|
192
|
+
getNicifiableKeys() {
|
|
193
|
+
return ["value"];
|
|
194
|
+
},
|
|
195
|
+
getNicifiedObjectExtraLines() {
|
|
196
|
+
return ["// custom comment"];
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
expect(nicify(nicifiable)).toBe(deindent `
|
|
200
|
+
{
|
|
201
|
+
"value": 42,
|
|
202
|
+
// custom comment,
|
|
203
|
+
}
|
|
204
|
+
`);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe("unknown types", () => {
|
|
208
|
+
test("object without prototype", () => {
|
|
209
|
+
const unknownType = Object.create(null);
|
|
210
|
+
unknownType.value = "test";
|
|
211
|
+
expect(nicify(unknownType)).toBe('{ "value": "test" }');
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|
package/package.json
CHANGED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { templateIdentity } from "./strings";
|
|
3
|
-
describe("templateIdentity", () => {
|
|
4
|
-
it("should be equivalent to a regular template string", () => {
|
|
5
|
-
const adjective = "scientific";
|
|
6
|
-
const noun = "railgun";
|
|
7
|
-
expect(templateIdentity `a certain scientific railgun`).toBe("a certain scientific railgun");
|
|
8
|
-
expect(templateIdentity `a certain ${adjective} railgun`).toBe(`a certain scientific railgun`);
|
|
9
|
-
expect(templateIdentity `a certain ${adjective} ${noun}`).toBe(`a certain scientific railgun`);
|
|
10
|
-
expect(templateIdentity `${adjective}${noun}`).toBe(`scientificrailgun`);
|
|
11
|
-
});
|
|
12
|
-
it("should work with empty strings", () => {
|
|
13
|
-
expect(templateIdentity ``).toBe("");
|
|
14
|
-
expect(templateIdentity `${""}`).toBe("");
|
|
15
|
-
expect(templateIdentity `${""}${""}`).toBe("");
|
|
16
|
-
});
|
|
17
|
-
it("should work with normal arrays", () => {
|
|
18
|
-
expect(templateIdentity(["a ", " scientific ", "gun"], "certain", "rail")).toBe("a certain scientific railgun");
|
|
19
|
-
expect(templateIdentity(["a"])).toBe("a");
|
|
20
|
-
});
|
|
21
|
-
it("should throw an error with wrong number of value arguments", () => {
|
|
22
|
-
expect(() => templateIdentity([])).toThrow();
|
|
23
|
-
expect(() => templateIdentity(["a", "b"])).toThrow();
|
|
24
|
-
expect(() => templateIdentity(["a", "b", "c"], "a", "b", "c")).toThrow();
|
|
25
|
-
});
|
|
26
|
-
});
|
|
File without changes
|