@stackframe/stack-shared 2.5.8 → 2.5.10
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/clientInterface.d.ts +10 -10
- package/dist/interface/clientInterface.js +73 -30
- package/dist/interface/crud/oauth.d.ts +4 -4
- package/dist/interface/crud/oauth.js +5 -5
- package/dist/interface/crud/projects.d.ts +7 -0
- package/dist/interface/crud/projects.js +2 -0
- package/dist/interface/crud/team-member-profiles.d.ts +72 -0
- package/dist/interface/crud/team-member-profiles.js +49 -0
- package/dist/interface/crud/team-memberships.d.ts +4 -4
- package/dist/interface/crud/team-memberships.js +6 -4
- package/dist/interface/crud/teams.d.ts +8 -0
- package/dist/interface/crud/teams.js +6 -4
- package/dist/interface/crud-deprecated/current-user.d.ts +2 -2
- package/dist/interface/crud-deprecated/users.d.ts +4 -4
- package/dist/interface/serverInterface.d.ts +4 -0
- package/dist/interface/serverInterface.js +17 -0
- package/dist/known-errors.d.ts +12 -0
- package/dist/known-errors.js +44 -2
- package/dist/schema-fields.d.ts +4 -0
- package/dist/schema-fields.js +19 -3
- package/dist/utils/errors.js +1 -1
- package/dist/utils/oauth.d.ts +6 -0
- package/dist/utils/oauth.js +3 -0
- package/dist/utils/results.js +9 -4
- package/dist/utils/urls.d.ts +2 -0
- package/dist/utils/urls.js +13 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @stackframe/stack-shared
|
|
2
2
|
|
|
3
|
+
## 2.5.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Facebook Business support
|
|
8
|
+
- @stackframe/stack-sc@2.5.10
|
|
9
|
+
|
|
10
|
+
## 2.5.9
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Impersonation
|
|
15
|
+
- @stackframe/stack-sc@2.5.9
|
|
16
|
+
|
|
3
17
|
## 2.5.8
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -3,6 +3,7 @@ import { AccessToken, InternalSession, RefreshToken } from '../sessions';
|
|
|
3
3
|
import { ReadonlyJson } from '../utils/json';
|
|
4
4
|
import { Result } from "../utils/results";
|
|
5
5
|
import { CurrentUserCrud } from './crud/current-user';
|
|
6
|
+
import { ProviderAccessTokenCrud } from './crud/oauth';
|
|
6
7
|
import { InternalProjectsCrud, ProjectsCrud } from './crud/projects';
|
|
7
8
|
import { TeamPermissionsCrud } from './crud/team-permissions';
|
|
8
9
|
import { TeamsCrud } from './crud/teams';
|
|
@@ -15,17 +16,18 @@ export type ClientInterfaceOptions = {
|
|
|
15
16
|
} | {
|
|
16
17
|
projectOwnerSession: InternalSession;
|
|
17
18
|
});
|
|
18
|
-
export type SharedProvider = "shared-github" | "shared-google" | "shared-facebook" | "shared-microsoft" | "shared-spotify";
|
|
19
|
-
export declare const sharedProviders: readonly ["shared-github", "shared-google", "shared-facebook", "shared-microsoft", "shared-spotify"];
|
|
20
|
-
export type StandardProvider = "github" | "facebook" | "google" | "microsoft" | "spotify";
|
|
21
|
-
export declare const standardProviders: readonly ["github", "facebook", "google", "microsoft", "spotify"];
|
|
22
|
-
export declare function toStandardProvider(provider: SharedProvider | StandardProvider): StandardProvider;
|
|
23
|
-
export declare function toSharedProvider(provider: SharedProvider | StandardProvider): SharedProvider;
|
|
24
19
|
export declare class StackClientInterface {
|
|
25
20
|
readonly options: ClientInterfaceOptions;
|
|
26
21
|
constructor(options: ClientInterfaceOptions);
|
|
27
22
|
get projectId(): string;
|
|
28
23
|
getApiUrl(): string;
|
|
24
|
+
runNetworkDiagnostics(session?: InternalSession | null, requestType?: "client" | "server" | "admin"): Promise<{
|
|
25
|
+
cfTrace: string;
|
|
26
|
+
apiRoot: string;
|
|
27
|
+
baseUrlBackend: string;
|
|
28
|
+
prodDashboard: string;
|
|
29
|
+
prodBackend: string;
|
|
30
|
+
}>;
|
|
29
31
|
fetchNewAccessToken(refreshToken: RefreshToken): Promise<AccessToken | null>;
|
|
30
32
|
protected sendClientRequest(path: string, requestOptions: RequestInit, session: InternalSession | null, requestType?: "client" | "server" | "admin"): Promise<Response & {
|
|
31
33
|
usedTokens: {
|
|
@@ -46,7 +48,7 @@ export declare class StackClientInterface {
|
|
|
46
48
|
featureName?: string;
|
|
47
49
|
} & ReadonlyJson): Promise<never>;
|
|
48
50
|
sendForgotPasswordEmail(email: string, callbackUrl: string): Promise<KnownErrors["UserNotFound"] | undefined>;
|
|
49
|
-
sendVerificationEmail(
|
|
51
|
+
sendVerificationEmail(email: string, callbackUrl: string, session: InternalSession): Promise<KnownErrors["EmailAlreadyVerified"] | undefined>;
|
|
50
52
|
sendMagicLinkEmail(email: string, callbackUrl: string): Promise<KnownErrors["RedirectUrlNotWhitelisted"] | undefined>;
|
|
51
53
|
resetPassword(options: {
|
|
52
54
|
code: string;
|
|
@@ -111,8 +113,6 @@ export declare class StackClientInterface {
|
|
|
111
113
|
updateClientUser(update: CurrentUserCrud["Client"]["Update"], session: InternalSession): Promise<void>;
|
|
112
114
|
listProjects(session: InternalSession): Promise<InternalProjectsCrud['Client']['Read'][]>;
|
|
113
115
|
createProject(project: InternalProjectsCrud['Client']['Create'], session: InternalSession): Promise<InternalProjectsCrud['Client']['Read']>;
|
|
114
|
-
|
|
115
|
-
accessToken: string;
|
|
116
|
-
}>;
|
|
116
|
+
createProviderAccessToken(provider: string, scope: string, session: InternalSession): Promise<ProviderAccessTokenCrud['Client']['Read']>;
|
|
117
117
|
createTeamForCurrentUser(data: TeamsCrud['Client']['Create'], session: InternalSession): Promise<TeamsCrud['Client']['Read']>;
|
|
118
118
|
}
|
|
@@ -6,26 +6,7 @@ import { generateSecureRandomString } from '../utils/crypto';
|
|
|
6
6
|
import { StackAssertionError, throwErr } from '../utils/errors';
|
|
7
7
|
import { globalVar } from '../utils/globals';
|
|
8
8
|
import { Result } from "../utils/results";
|
|
9
|
-
|
|
10
|
-
"shared-github",
|
|
11
|
-
"shared-google",
|
|
12
|
-
"shared-facebook",
|
|
13
|
-
"shared-microsoft",
|
|
14
|
-
"shared-spotify",
|
|
15
|
-
];
|
|
16
|
-
export const standardProviders = [
|
|
17
|
-
"github",
|
|
18
|
-
"facebook",
|
|
19
|
-
"google",
|
|
20
|
-
"microsoft",
|
|
21
|
-
"spotify",
|
|
22
|
-
];
|
|
23
|
-
export function toStandardProvider(provider) {
|
|
24
|
-
return provider.replace("shared-", "");
|
|
25
|
-
}
|
|
26
|
-
export function toSharedProvider(provider) {
|
|
27
|
-
return "shared-" + provider;
|
|
28
|
-
}
|
|
9
|
+
import { deindent } from '../utils/strings';
|
|
29
10
|
export class StackClientInterface {
|
|
30
11
|
constructor(options) {
|
|
31
12
|
this.options = options;
|
|
@@ -37,6 +18,54 @@ export class StackClientInterface {
|
|
|
37
18
|
getApiUrl() {
|
|
38
19
|
return this.options.baseUrl + "/api/v1";
|
|
39
20
|
}
|
|
21
|
+
async runNetworkDiagnostics(session, requestType) {
|
|
22
|
+
const tryRequest = async (cb) => {
|
|
23
|
+
try {
|
|
24
|
+
await cb();
|
|
25
|
+
return "OK";
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
return `${e}`;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const cfTrace = await tryRequest(async () => {
|
|
32
|
+
const res = await fetch("https://1.1.1.1/cdn-cgi/trace");
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
throw new Error(`${res.status} ${res.statusText}: ${await res.text()}`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const apiRoot = session !== undefined && requestType !== undefined ? await tryRequest(async () => {
|
|
38
|
+
const res = await this.sendClientRequestInner("/", {}, session, requestType);
|
|
39
|
+
if (res.status === "error") {
|
|
40
|
+
throw res.error;
|
|
41
|
+
}
|
|
42
|
+
}) : "Not tested";
|
|
43
|
+
const baseUrlBackend = await tryRequest(async () => {
|
|
44
|
+
const res = await fetch(new URL("/health", this.getApiUrl()));
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
throw new Error(`${res.status} ${res.statusText}: ${await res.text()}`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const prodDashboard = await tryRequest(async () => {
|
|
50
|
+
const res = await fetch("https://app.stackframe.com/health");
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
throw new Error(`${res.status} ${res.statusText}: ${await res.text()}`);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
const prodBackend = await tryRequest(async () => {
|
|
56
|
+
const res = await fetch("https://api.stackframe.com/health");
|
|
57
|
+
if (!res.ok) {
|
|
58
|
+
throw new Error(`${res.status} ${res.statusText}: ${await res.text()}`);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
cfTrace,
|
|
63
|
+
apiRoot,
|
|
64
|
+
baseUrlBackend,
|
|
65
|
+
prodDashboard,
|
|
66
|
+
prodBackend,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
40
69
|
async fetchNewAccessToken(refreshToken) {
|
|
41
70
|
if (!('publishableClientKey' in this.options)) {
|
|
42
71
|
// TODO support it
|
|
@@ -79,7 +108,23 @@ export class StackClientInterface {
|
|
|
79
108
|
session ??= this.createSession({
|
|
80
109
|
refreshToken: null,
|
|
81
110
|
});
|
|
82
|
-
|
|
111
|
+
const retriedResult = await Result.retry(() => this.sendClientRequestInner(path, requestOptions, session, requestType), 5, { exponentialDelayBase: 1000 });
|
|
112
|
+
// try to diagnose the error for the user
|
|
113
|
+
if (retriedResult.status === "error") {
|
|
114
|
+
if (!navigator.onLine) {
|
|
115
|
+
throw new Error("Failed to send Stack request. It seems like you are offline. (window.navigator.onLine is falsy)", { cause: retriedResult.error });
|
|
116
|
+
}
|
|
117
|
+
throw new Error(deindent `
|
|
118
|
+
Stack is unable to connect to the server. Please check your internet connection and try again.
|
|
119
|
+
|
|
120
|
+
If the problem persists, please contact Stack support and provide a screenshot of your entire browser console.
|
|
121
|
+
|
|
122
|
+
${retriedResult.error}
|
|
123
|
+
|
|
124
|
+
${JSON.stringify(await this.runNetworkDiagnostics(session, requestType), null, 2)}
|
|
125
|
+
`, { cause: retriedResult.error });
|
|
126
|
+
}
|
|
127
|
+
return retriedResult.data;
|
|
83
128
|
}
|
|
84
129
|
createSession(options) {
|
|
85
130
|
const session = new InternalSession({
|
|
@@ -254,14 +299,15 @@ export class StackClientInterface {
|
|
|
254
299
|
return res.error;
|
|
255
300
|
}
|
|
256
301
|
}
|
|
257
|
-
async sendVerificationEmail(
|
|
302
|
+
async sendVerificationEmail(email, callbackUrl, session) {
|
|
258
303
|
const res = await this.sendClientRequestAndCatchKnownError("/contact-channels/send-verification-code", {
|
|
259
304
|
method: "POST",
|
|
260
305
|
headers: {
|
|
261
306
|
"Content-Type": "application/json"
|
|
262
307
|
},
|
|
263
308
|
body: JSON.stringify({
|
|
264
|
-
|
|
309
|
+
email,
|
|
310
|
+
callback_url: callbackUrl,
|
|
265
311
|
}),
|
|
266
312
|
}, session, [KnownErrors.EmailAlreadyVerified]);
|
|
267
313
|
if (res.status === "error") {
|
|
@@ -417,7 +463,7 @@ export class StackClientInterface {
|
|
|
417
463
|
url.searchParams.set("type", options.type);
|
|
418
464
|
url.searchParams.set("error_redirect_url", options.errorRedirectUrl);
|
|
419
465
|
if (options.afterCallbackRedirectUrl) {
|
|
420
|
-
url.searchParams.set("
|
|
466
|
+
url.searchParams.set("after_callback_redirect_url", options.afterCallbackRedirectUrl);
|
|
421
467
|
}
|
|
422
468
|
if (options.type === "link") {
|
|
423
469
|
const tokens = await options.session.getPotentiallyExpiredTokens();
|
|
@@ -551,18 +597,15 @@ export class StackClientInterface {
|
|
|
551
597
|
const json = await fetchResponse.json();
|
|
552
598
|
return json;
|
|
553
599
|
}
|
|
554
|
-
async
|
|
555
|
-
const response = await this.sendClientRequest(`/auth/oauth/connected-
|
|
600
|
+
async createProviderAccessToken(provider, scope, session) {
|
|
601
|
+
const response = await this.sendClientRequest(`/auth/oauth/connected-accounts/${provider}/access-token`, {
|
|
556
602
|
method: "POST",
|
|
557
603
|
headers: {
|
|
558
604
|
"content-type": "application/json",
|
|
559
605
|
},
|
|
560
606
|
body: JSON.stringify({ scope }),
|
|
561
607
|
}, session);
|
|
562
|
-
|
|
563
|
-
return {
|
|
564
|
-
accessToken: json.accessToken,
|
|
565
|
-
};
|
|
608
|
+
return await response.json();
|
|
566
609
|
}
|
|
567
610
|
async createTeamForCurrentUser(data, session) {
|
|
568
611
|
const response = await this.sendClientRequest("/teams?add_current_user=true", {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { CrudTypeOf } from "../../crud";
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const providerAccessTokenReadSchema: import("yup").ObjectSchema<{
|
|
3
3
|
access_token: string;
|
|
4
4
|
}, import("yup").AnyObject, {
|
|
5
5
|
access_token: undefined;
|
|
6
6
|
}, "">;
|
|
7
|
-
export declare const
|
|
7
|
+
export declare const providerAccessTokenCreateSchema: import("yup").ObjectSchema<{
|
|
8
8
|
scope: string | undefined;
|
|
9
9
|
}, import("yup").AnyObject, {
|
|
10
10
|
scope: undefined;
|
|
11
11
|
}, "">;
|
|
12
|
-
export declare const
|
|
12
|
+
export declare const providerAccessTokenCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
13
13
|
clientReadSchema: import("yup").ObjectSchema<{
|
|
14
14
|
access_token: string;
|
|
15
15
|
}, import("yup").AnyObject, {
|
|
@@ -21,4 +21,4 @@ export declare const accessTokenCrud: import("../../crud").CrudSchemaFromOptions
|
|
|
21
21
|
scope: undefined;
|
|
22
22
|
}, "">;
|
|
23
23
|
}>;
|
|
24
|
-
export type
|
|
24
|
+
export type ProviderAccessTokenCrud = CrudTypeOf<typeof providerAccessTokenCrud>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createCrud } from "../../crud";
|
|
2
2
|
import { yupObject, yupString } from "../../schema-fields";
|
|
3
|
-
export const
|
|
3
|
+
export const providerAccessTokenReadSchema = yupObject({
|
|
4
4
|
access_token: yupString().required(),
|
|
5
5
|
}).required();
|
|
6
|
-
export const
|
|
6
|
+
export const providerAccessTokenCreateSchema = yupObject({
|
|
7
7
|
scope: yupString().optional(),
|
|
8
8
|
}).required();
|
|
9
|
-
export const
|
|
10
|
-
clientReadSchema:
|
|
11
|
-
clientCreateSchema:
|
|
9
|
+
export const providerAccessTokenCrud = createCrud({
|
|
10
|
+
clientReadSchema: providerAccessTokenReadSchema,
|
|
11
|
+
clientCreateSchema: providerAccessTokenCreateSchema,
|
|
12
12
|
});
|
|
@@ -14,6 +14,7 @@ export declare const projectsCrudServerReadSchema: import("yup").ObjectSchema<{
|
|
|
14
14
|
oauth_providers: {
|
|
15
15
|
client_id?: string | undefined;
|
|
16
16
|
client_secret?: string | undefined;
|
|
17
|
+
facebook_config_id?: string | undefined;
|
|
17
18
|
type: NonNullable<"shared" | "standard" | undefined>;
|
|
18
19
|
id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
|
|
19
20
|
enabled: NonNullable<boolean | undefined>;
|
|
@@ -101,6 +102,7 @@ export declare const projectsCrudServerUpdateSchema: import("yup").ObjectSchema<
|
|
|
101
102
|
oauth_providers?: {
|
|
102
103
|
client_id?: string | undefined;
|
|
103
104
|
client_secret?: string | undefined;
|
|
105
|
+
facebook_config_id?: string | undefined;
|
|
104
106
|
type: NonNullable<"shared" | "standard" | undefined>;
|
|
105
107
|
id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
|
|
106
108
|
enabled: NonNullable<boolean | undefined>;
|
|
@@ -143,6 +145,7 @@ export declare const projectsCrudServerCreateSchema: import("yup").ObjectSchema<
|
|
|
143
145
|
oauth_providers?: {
|
|
144
146
|
client_id?: string | undefined;
|
|
145
147
|
client_secret?: string | undefined;
|
|
148
|
+
facebook_config_id?: string | undefined;
|
|
146
149
|
type: NonNullable<"shared" | "standard" | undefined>;
|
|
147
150
|
id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
|
|
148
151
|
enabled: NonNullable<boolean | undefined>;
|
|
@@ -211,6 +214,7 @@ export declare const projectsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
211
214
|
oauth_providers: {
|
|
212
215
|
client_id?: string | undefined;
|
|
213
216
|
client_secret?: string | undefined;
|
|
217
|
+
facebook_config_id?: string | undefined;
|
|
214
218
|
type: NonNullable<"shared" | "standard" | undefined>;
|
|
215
219
|
id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
|
|
216
220
|
enabled: NonNullable<boolean | undefined>;
|
|
@@ -279,6 +283,7 @@ export declare const projectsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
279
283
|
oauth_providers?: {
|
|
280
284
|
client_id?: string | undefined;
|
|
281
285
|
client_secret?: string | undefined;
|
|
286
|
+
facebook_config_id?: string | undefined;
|
|
282
287
|
type: NonNullable<"shared" | "standard" | undefined>;
|
|
283
288
|
id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
|
|
284
289
|
enabled: NonNullable<boolean | undefined>;
|
|
@@ -345,6 +350,7 @@ export declare const internalProjectsCrud: import("../../crud").CrudSchemaFromOp
|
|
|
345
350
|
oauth_providers: {
|
|
346
351
|
client_id?: string | undefined;
|
|
347
352
|
client_secret?: string | undefined;
|
|
353
|
+
facebook_config_id?: string | undefined;
|
|
348
354
|
type: NonNullable<"shared" | "standard" | undefined>;
|
|
349
355
|
id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
|
|
350
356
|
enabled: NonNullable<boolean | undefined>;
|
|
@@ -413,6 +419,7 @@ export declare const internalProjectsCrud: import("../../crud").CrudSchemaFromOp
|
|
|
413
419
|
oauth_providers?: {
|
|
414
420
|
client_id?: string | undefined;
|
|
415
421
|
client_secret?: string | undefined;
|
|
422
|
+
facebook_config_id?: string | undefined;
|
|
416
423
|
type: NonNullable<"shared" | "standard" | undefined>;
|
|
417
424
|
id: NonNullable<"google" | "github" | "facebook" | "microsoft" | "spotify" | undefined>;
|
|
418
425
|
enabled: NonNullable<boolean | undefined>;
|
|
@@ -10,6 +10,8 @@ const oauthProviderSchema = yupObject({
|
|
|
10
10
|
type: schemaFields.oauthTypeSchema.required(),
|
|
11
11
|
client_id: yupRequiredWhen(schemaFields.oauthClientIdSchema, 'type', 'standard'),
|
|
12
12
|
client_secret: yupRequiredWhen(schemaFields.oauthClientSecretSchema, 'type', 'standard'),
|
|
13
|
+
// extra params
|
|
14
|
+
facebook_config_id: yupString().optional().meta({ openapiField: { description: 'This parameter is the configuration id for Facebook business login (for things like ads and marketing).' } }),
|
|
13
15
|
});
|
|
14
16
|
const enabledOAuthProviderSchema = yupObject({
|
|
15
17
|
id: schemaFields.oauthIdSchema.required(),
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { CrudTypeOf } from "../../crud";
|
|
2
|
+
export declare const teamMemberProfilesCrudClientReadSchema: import("yup").ObjectSchema<{
|
|
3
|
+
team_id: string;
|
|
4
|
+
user_id: string;
|
|
5
|
+
display_name: string | null;
|
|
6
|
+
profile_image_url: string | null;
|
|
7
|
+
}, import("yup").AnyObject, {
|
|
8
|
+
team_id: undefined;
|
|
9
|
+
user_id: undefined;
|
|
10
|
+
display_name: undefined;
|
|
11
|
+
profile_image_url: undefined;
|
|
12
|
+
}, "">;
|
|
13
|
+
export declare const teamMemberProfilesCrudClientUpdateSchema: import("yup").ObjectSchema<{
|
|
14
|
+
display_name: string | undefined;
|
|
15
|
+
profile_image_url: string | null | undefined;
|
|
16
|
+
}, import("yup").AnyObject, {
|
|
17
|
+
display_name: undefined;
|
|
18
|
+
profile_image_url: undefined;
|
|
19
|
+
}, "">;
|
|
20
|
+
export declare const teamMemberProfilesCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
21
|
+
clientReadSchema: import("yup").ObjectSchema<{
|
|
22
|
+
team_id: string;
|
|
23
|
+
user_id: string;
|
|
24
|
+
display_name: string | null;
|
|
25
|
+
profile_image_url: string | null;
|
|
26
|
+
}, import("yup").AnyObject, {
|
|
27
|
+
team_id: undefined;
|
|
28
|
+
user_id: undefined;
|
|
29
|
+
display_name: undefined;
|
|
30
|
+
profile_image_url: undefined;
|
|
31
|
+
}, "">;
|
|
32
|
+
clientUpdateSchema: import("yup").ObjectSchema<{
|
|
33
|
+
display_name: string | undefined;
|
|
34
|
+
profile_image_url: string | null | undefined;
|
|
35
|
+
}, import("yup").AnyObject, {
|
|
36
|
+
display_name: undefined;
|
|
37
|
+
profile_image_url: undefined;
|
|
38
|
+
}, "">;
|
|
39
|
+
docs: {
|
|
40
|
+
clientList: {
|
|
41
|
+
summary: string;
|
|
42
|
+
description: string;
|
|
43
|
+
tags: string[];
|
|
44
|
+
};
|
|
45
|
+
serverList: {
|
|
46
|
+
summary: string;
|
|
47
|
+
description: string;
|
|
48
|
+
tags: string[];
|
|
49
|
+
};
|
|
50
|
+
clientRead: {
|
|
51
|
+
summary: string;
|
|
52
|
+
description: string;
|
|
53
|
+
tags: string[];
|
|
54
|
+
};
|
|
55
|
+
serverRead: {
|
|
56
|
+
summary: string;
|
|
57
|
+
description: string;
|
|
58
|
+
tags: string[];
|
|
59
|
+
};
|
|
60
|
+
clientUpdate: {
|
|
61
|
+
summary: string;
|
|
62
|
+
description: string;
|
|
63
|
+
tags: string[];
|
|
64
|
+
};
|
|
65
|
+
serverUpdate: {
|
|
66
|
+
summary: string;
|
|
67
|
+
description: string;
|
|
68
|
+
tags: string[];
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
}>;
|
|
72
|
+
export type TeamMemberProfilesCrud = CrudTypeOf<typeof teamMemberProfilesCrud>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createCrud } from "../../crud";
|
|
2
|
+
import * as schemaFields from "../../schema-fields";
|
|
3
|
+
import { yupObject } from "../../schema-fields";
|
|
4
|
+
export const teamMemberProfilesCrudClientReadSchema = yupObject({
|
|
5
|
+
team_id: schemaFields.teamIdSchema.required(),
|
|
6
|
+
user_id: schemaFields.userIdSchema.required(),
|
|
7
|
+
display_name: schemaFields.teamMemberDisplayNameSchema.nullable().defined(),
|
|
8
|
+
profile_image_url: schemaFields.teamMemberProfileImageUrlSchema.nullable().defined(),
|
|
9
|
+
}).required();
|
|
10
|
+
export const teamMemberProfilesCrudClientUpdateSchema = yupObject({
|
|
11
|
+
display_name: schemaFields.teamMemberDisplayNameSchema.optional(),
|
|
12
|
+
profile_image_url: schemaFields.teamMemberProfileImageUrlSchema.nullable().optional(),
|
|
13
|
+
}).required();
|
|
14
|
+
export const teamMemberProfilesCrud = createCrud({
|
|
15
|
+
clientReadSchema: teamMemberProfilesCrudClientReadSchema,
|
|
16
|
+
clientUpdateSchema: teamMemberProfilesCrudClientUpdateSchema,
|
|
17
|
+
docs: {
|
|
18
|
+
clientList: {
|
|
19
|
+
summary: "List team members profiles",
|
|
20
|
+
description: "List team members profiles. You always need to specify a `team_id` that your are a member of on the client. You can always filter for your own profile by setting `me` as the `user_id` in the path parameters. If you want list all the profiles in a team, you need to have the `$read_members` permission in that team.",
|
|
21
|
+
tags: ["Teams"],
|
|
22
|
+
},
|
|
23
|
+
serverList: {
|
|
24
|
+
summary: "List team members profiles",
|
|
25
|
+
description: "List team members profiles and filter by team ID and user ID",
|
|
26
|
+
tags: ["Teams"],
|
|
27
|
+
},
|
|
28
|
+
clientRead: {
|
|
29
|
+
summary: "Get a team member profile",
|
|
30
|
+
description: "Get a team member profile. you can always get your own profile by setting `me` as the `user_id` in the path parameters on the client. If you want to get someone else's profile in a team, you need to have the `$read_members` permission in that team.",
|
|
31
|
+
tags: ["Teams"],
|
|
32
|
+
},
|
|
33
|
+
serverRead: {
|
|
34
|
+
summary: "Get a team member profile",
|
|
35
|
+
description: "Get a team member profile by user ID",
|
|
36
|
+
tags: ["Teams"],
|
|
37
|
+
},
|
|
38
|
+
clientUpdate: {
|
|
39
|
+
summary: "Update your team member profile",
|
|
40
|
+
description: "Update your own team member profile. `user_id` must be `me` in the path parameters on the client.",
|
|
41
|
+
tags: ["Teams"],
|
|
42
|
+
},
|
|
43
|
+
serverUpdate: {
|
|
44
|
+
summary: "Update a team member profile",
|
|
45
|
+
description: "Update a team member profile by user ID",
|
|
46
|
+
tags: ["Teams"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { CrudTypeOf } from "../../crud";
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const teamMembershipsCrudClientReadSchema: import("yup").ObjectSchema<{}, import("yup").AnyObject, {}, "">;
|
|
3
3
|
export declare const teamMembershipsCrudServerCreateSchema: import("yup").ObjectSchema<{}, import("yup").AnyObject, {}, "">;
|
|
4
|
-
export declare const
|
|
4
|
+
export declare const teamMembershipsCrudClientDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
5
5
|
export declare const teamMembershipsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
6
|
-
|
|
6
|
+
clientReadSchema: import("yup").ObjectSchema<{}, import("yup").AnyObject, {}, "">;
|
|
7
|
+
clientDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
7
8
|
serverCreateSchema: import("yup").ObjectSchema<{}, import("yup").AnyObject, {}, "">;
|
|
8
|
-
serverDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
9
9
|
docs: {
|
|
10
10
|
serverCreate: {
|
|
11
11
|
summary: string;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { createCrud } from "../../crud";
|
|
2
2
|
import { yupMixed, yupObject } from "../../schema-fields";
|
|
3
|
-
export const
|
|
3
|
+
export const teamMembershipsCrudClientReadSchema = yupObject({}).required();
|
|
4
4
|
export const teamMembershipsCrudServerCreateSchema = yupObject({}).required();
|
|
5
|
-
export const
|
|
5
|
+
export const teamMembershipsCrudClientDeleteSchema = yupMixed();
|
|
6
6
|
export const teamMembershipsCrud = createCrud({
|
|
7
|
-
|
|
7
|
+
// Client
|
|
8
|
+
clientReadSchema: teamMembershipsCrudClientReadSchema,
|
|
9
|
+
clientDeleteSchema: teamMembershipsCrudClientDeleteSchema,
|
|
10
|
+
// Server
|
|
8
11
|
serverCreateSchema: teamMembershipsCrudServerCreateSchema,
|
|
9
|
-
serverDeleteSchema: teamMembershipsCrudServerDeleteSchema,
|
|
10
12
|
docs: {
|
|
11
13
|
serverCreate: {
|
|
12
14
|
summary: "Add a user to a team",
|
|
@@ -64,6 +64,13 @@ export declare const teamsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
64
64
|
display_name: undefined;
|
|
65
65
|
profile_image_url: undefined;
|
|
66
66
|
}, "">;
|
|
67
|
+
clientUpdateSchema: import("yup").ObjectSchema<{
|
|
68
|
+
display_name: string | undefined;
|
|
69
|
+
profile_image_url: string | null | undefined;
|
|
70
|
+
}, import("yup").AnyObject, {
|
|
71
|
+
display_name: undefined;
|
|
72
|
+
profile_image_url: undefined;
|
|
73
|
+
}, "">;
|
|
67
74
|
clientCreateSchema: import("yup").ObjectSchema<{
|
|
68
75
|
display_name: string;
|
|
69
76
|
profile_image_url: string | null | undefined;
|
|
@@ -73,6 +80,7 @@ export declare const teamsCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
73
80
|
display_name: undefined;
|
|
74
81
|
profile_image_url: undefined;
|
|
75
82
|
}, "">;
|
|
83
|
+
clientDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
76
84
|
serverReadSchema: import("yup").ObjectSchema<{
|
|
77
85
|
id: string;
|
|
78
86
|
display_name: string;
|
|
@@ -5,7 +5,7 @@ import { yupMixed, yupObject } from "../../schema-fields";
|
|
|
5
5
|
export const teamsCrudClientReadSchema = yupObject({
|
|
6
6
|
id: fieldSchema.teamIdSchema.required(),
|
|
7
7
|
display_name: fieldSchema.teamDisplayNameSchema.required(),
|
|
8
|
-
profile_image_url: fieldSchema.
|
|
8
|
+
profile_image_url: fieldSchema.teamProfileImageUrlSchema.nullable().defined(),
|
|
9
9
|
}).required();
|
|
10
10
|
export const teamsCrudServerReadSchema = teamsCrudClientReadSchema.concat(yupObject({
|
|
11
11
|
created_at_millis: fieldSchema.teamCreatedAtMillisSchema.required(),
|
|
@@ -13,7 +13,7 @@ export const teamsCrudServerReadSchema = teamsCrudClientReadSchema.concat(yupObj
|
|
|
13
13
|
// Update
|
|
14
14
|
export const teamsCrudClientUpdateSchema = yupObject({
|
|
15
15
|
display_name: fieldSchema.teamDisplayNameSchema.optional(),
|
|
16
|
-
profile_image_url: fieldSchema.
|
|
16
|
+
profile_image_url: fieldSchema.teamProfileImageUrlSchema.nullable().optional(),
|
|
17
17
|
}).required();
|
|
18
18
|
export const teamsCrudServerUpdateSchema = teamsCrudClientUpdateSchema.concat(yupObject({}).required());
|
|
19
19
|
// Create
|
|
@@ -27,10 +27,12 @@ export const teamsCrudServerCreateSchema = teamsCrudServerUpdateSchema.concat(yu
|
|
|
27
27
|
export const teamsCrudClientDeleteSchema = yupMixed();
|
|
28
28
|
export const teamsCrudServerDeleteSchema = teamsCrudClientDeleteSchema;
|
|
29
29
|
export const teamsCrud = createCrud({
|
|
30
|
+
// Client
|
|
30
31
|
clientReadSchema: teamsCrudClientReadSchema,
|
|
31
|
-
|
|
32
|
+
clientUpdateSchema: teamsCrudClientUpdateSchema,
|
|
32
33
|
clientCreateSchema: teamsCrudClientCreateSchema,
|
|
33
|
-
|
|
34
|
+
clientDeleteSchema: teamsCrudClientDeleteSchema,
|
|
35
|
+
// Server
|
|
34
36
|
serverReadSchema: teamsCrudServerReadSchema,
|
|
35
37
|
serverUpdateSchema: teamsCrudServerUpdateSchema,
|
|
36
38
|
serverCreateSchema: teamsCrudServerCreateSchema,
|
|
@@ -5,8 +5,8 @@ export declare const currentUserCrud: import("../../crud").CrudSchemaFromOptions
|
|
|
5
5
|
display_name: string | null;
|
|
6
6
|
oauth_providers: {
|
|
7
7
|
email?: string | null | undefined;
|
|
8
|
-
account_id: string;
|
|
9
8
|
provider_id: string;
|
|
9
|
+
account_id: string;
|
|
10
10
|
}[];
|
|
11
11
|
project_id: string;
|
|
12
12
|
primary_email: string | null;
|
|
@@ -48,8 +48,8 @@ export declare const currentUserCrud: import("../../crud").CrudSchemaFromOptions
|
|
|
48
48
|
auth_with_email: NonNullable<boolean | undefined>;
|
|
49
49
|
oauth_providers: {
|
|
50
50
|
email?: string | null | undefined;
|
|
51
|
-
account_id: string;
|
|
52
51
|
provider_id: string;
|
|
52
|
+
account_id: string;
|
|
53
53
|
}[];
|
|
54
54
|
client_metadata: {} | null;
|
|
55
55
|
server_metadata: {} | null;
|
|
@@ -34,8 +34,8 @@ export declare const usersCrudServerReadSchema: import("yup").ObjectSchema<{
|
|
|
34
34
|
auth_with_email: NonNullable<boolean | undefined>;
|
|
35
35
|
oauth_providers: {
|
|
36
36
|
email?: string | null | undefined;
|
|
37
|
-
account_id: string;
|
|
38
37
|
provider_id: string;
|
|
38
|
+
account_id: string;
|
|
39
39
|
}[];
|
|
40
40
|
client_metadata: {} | null;
|
|
41
41
|
server_metadata: {} | null;
|
|
@@ -68,8 +68,8 @@ export declare const usersCrudServerCreateSchema: import("yup").ObjectSchema<{
|
|
|
68
68
|
} & {
|
|
69
69
|
oauth_providers: {
|
|
70
70
|
email: string | null;
|
|
71
|
-
account_id: string;
|
|
72
71
|
provider_id: string;
|
|
72
|
+
account_id: string;
|
|
73
73
|
}[] | undefined;
|
|
74
74
|
}, import("yup").AnyObject, {
|
|
75
75
|
display_name: undefined;
|
|
@@ -99,8 +99,8 @@ export declare const usersCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
99
99
|
auth_with_email: NonNullable<boolean | undefined>;
|
|
100
100
|
oauth_providers: {
|
|
101
101
|
email?: string | null | undefined;
|
|
102
|
-
account_id: string;
|
|
103
102
|
provider_id: string;
|
|
103
|
+
account_id: string;
|
|
104
104
|
}[];
|
|
105
105
|
client_metadata: {} | null;
|
|
106
106
|
server_metadata: {} | null;
|
|
@@ -154,8 +154,8 @@ export declare const usersCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
|
154
154
|
} & {
|
|
155
155
|
oauth_providers: {
|
|
156
156
|
email: string | null;
|
|
157
|
-
account_id: string;
|
|
158
157
|
provider_id: string;
|
|
158
|
+
account_id: string;
|
|
159
159
|
}[] | undefined;
|
|
160
160
|
}, import("yup").AnyObject, {
|
|
161
161
|
display_name: undefined;
|
|
@@ -49,6 +49,10 @@ export declare class StackServerInterface extends StackClientInterface {
|
|
|
49
49
|
teamId: string;
|
|
50
50
|
}): Promise<void>;
|
|
51
51
|
updateServerUser(userId: string, update: UsersCrud['Server']['Update']): Promise<UsersCrud['Server']['Read']>;
|
|
52
|
+
createServerUserSession(userId: string, expiresInMillis: number): Promise<{
|
|
53
|
+
accessToken: string;
|
|
54
|
+
refreshToken: string;
|
|
55
|
+
}>;
|
|
52
56
|
listServerTeamMemberPermissions(options: {
|
|
53
57
|
teamId: string;
|
|
54
58
|
userId: string;
|
|
@@ -130,6 +130,23 @@ export class StackServerInterface extends StackClientInterface {
|
|
|
130
130
|
}, null);
|
|
131
131
|
return await response.json();
|
|
132
132
|
}
|
|
133
|
+
async createServerUserSession(userId, expiresInMillis) {
|
|
134
|
+
const response = await this.sendServerRequest("/auth/sessions", {
|
|
135
|
+
method: "POST",
|
|
136
|
+
headers: {
|
|
137
|
+
"content-type": "application/json",
|
|
138
|
+
},
|
|
139
|
+
body: JSON.stringify({
|
|
140
|
+
user_id: userId,
|
|
141
|
+
expires_in_millis: expiresInMillis,
|
|
142
|
+
}),
|
|
143
|
+
}, null);
|
|
144
|
+
const result = await response.json();
|
|
145
|
+
return {
|
|
146
|
+
accessToken: result.access_token,
|
|
147
|
+
refreshToken: result.refresh_token,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
133
150
|
async listServerTeamMemberPermissions(options) {
|
|
134
151
|
const response = await this.sendServerRequest(`/team-permissions?team_id=${options.teamId}&user_id=${options.userId}&recursive=${options.recursive}`, {}, null);
|
|
135
152
|
const result = await response.json();
|
package/dist/known-errors.d.ts
CHANGED
|
@@ -233,6 +233,9 @@ export declare const KnownErrors: {
|
|
|
233
233
|
UserEmailAlreadyExists: KnownErrorConstructor<KnownError & KnownErrorBrand<"USER_EMAIL_ALREADY_EXISTS">, []> & {
|
|
234
234
|
errorCode: "USER_EMAIL_ALREADY_EXISTS";
|
|
235
235
|
};
|
|
236
|
+
UserIdDoesNotExist: KnownErrorConstructor<KnownError & KnownErrorBrand<"USER_ID_DOES_NOT_EXIST">, [userId: string]> & {
|
|
237
|
+
errorCode: "USER_ID_DOES_NOT_EXIST";
|
|
238
|
+
};
|
|
236
239
|
UserNotFound: KnownErrorConstructor<KnownError & KnownErrorBrand<"USER_NOT_FOUND">, []> & {
|
|
237
240
|
errorCode: "USER_NOT_FOUND";
|
|
238
241
|
};
|
|
@@ -348,5 +351,14 @@ export declare const KnownErrors: {
|
|
|
348
351
|
TeamMembershipAlreadyExists: KnownErrorConstructor<KnownError & KnownErrorBrand<"TEAM_MEMBERSHIP_ALREADY_EXISTS">, []> & {
|
|
349
352
|
errorCode: "TEAM_MEMBERSHIP_ALREADY_EXISTS";
|
|
350
353
|
};
|
|
354
|
+
TeamPermissionRequired: KnownErrorConstructor<KnownError & KnownErrorBrand<"TEAM_PERMISSION_REQUIRED">, [any, any, any]> & {
|
|
355
|
+
errorCode: "TEAM_PERMISSION_REQUIRED";
|
|
356
|
+
};
|
|
357
|
+
InvalidSharedOAuthProviderId: KnownErrorConstructor<KnownError & KnownErrorBrand<"INVALID_SHARED_OAUTH_PROVIDER_ID">, [any]> & {
|
|
358
|
+
errorCode: "INVALID_SHARED_OAUTH_PROVIDER_ID";
|
|
359
|
+
};
|
|
360
|
+
InvalidStandardOAuthProviderId: KnownErrorConstructor<KnownError & KnownErrorBrand<"INVALID_STANDARD_OAUTH_PROVIDER_ID">, [any]> & {
|
|
361
|
+
errorCode: "INVALID_STANDARD_OAUTH_PROVIDER_ID";
|
|
362
|
+
};
|
|
351
363
|
};
|
|
352
364
|
export {};
|
package/dist/known-errors.js
CHANGED
|
@@ -146,14 +146,22 @@ const InvalidAccessType = createKnownErrorConstructor(InvalidProjectAuthenticati
|
|
|
146
146
|
]);
|
|
147
147
|
const AccessTypeWithoutProjectId = createKnownErrorConstructor(InvalidProjectAuthentication, "ACCESS_TYPE_WITHOUT_PROJECT_ID", (accessType) => [
|
|
148
148
|
400,
|
|
149
|
-
`
|
|
149
|
+
deindent `
|
|
150
|
+
The x-stack-access-type header was '${accessType}', but the x-stack-project-id header was not provided.
|
|
151
|
+
|
|
152
|
+
For more information, see the docs on REST API authentication: https://docs.stack-auth.com/rest-api/auth#authentication
|
|
153
|
+
`,
|
|
150
154
|
{
|
|
151
155
|
request_type: accessType,
|
|
152
156
|
},
|
|
153
157
|
], (json) => [json.request_type]);
|
|
154
158
|
const AccessTypeRequired = createKnownErrorConstructor(InvalidProjectAuthentication, "ACCESS_TYPE_REQUIRED", () => [
|
|
155
159
|
400,
|
|
156
|
-
`
|
|
160
|
+
deindent `
|
|
161
|
+
You must specify an access level for this Stack project. Make sure project API keys are provided (eg. x-stack-publishable-client-key) and you set the x-stack-access-type header to 'client', 'server', or 'admin'.
|
|
162
|
+
|
|
163
|
+
For more information, see the docs on REST API authentication: https://docs.stack-auth.com/rest-api/auth#authentication
|
|
164
|
+
`,
|
|
157
165
|
], () => []);
|
|
158
166
|
const InsufficientAccessType = createKnownErrorConstructor(InvalidProjectAuthentication, "INSUFFICIENT_ACCESS_TYPE", (actualAccessType, allowedAccessTypes) => [
|
|
159
167
|
401,
|
|
@@ -286,6 +294,13 @@ const CannotGetOwnUserWithoutUser = createKnownErrorConstructor(KnownError, "CAN
|
|
|
286
294
|
400,
|
|
287
295
|
"You have specified 'me' as a userId, but did not provide authentication for a user.",
|
|
288
296
|
], () => []);
|
|
297
|
+
const UserIdDoesNotExist = createKnownErrorConstructor(KnownError, "USER_ID_DOES_NOT_EXIST", (userId) => [
|
|
298
|
+
400,
|
|
299
|
+
`The given user with the ID ${userId} does not exist.`,
|
|
300
|
+
{
|
|
301
|
+
user_id: userId,
|
|
302
|
+
},
|
|
303
|
+
], (json) => [json.user_id]);
|
|
289
304
|
const UserNotFound = createKnownErrorConstructor(KnownError, "USER_NOT_FOUND", () => [
|
|
290
305
|
404,
|
|
291
306
|
"User not found.",
|
|
@@ -464,6 +479,29 @@ const TeamMembershipAlreadyExists = createKnownErrorConstructor(KnownError, "TEA
|
|
|
464
479
|
400,
|
|
465
480
|
"Team membership already exists.",
|
|
466
481
|
], () => []);
|
|
482
|
+
const TeamPermissionRequired = createKnownErrorConstructor(KnownError, "TEAM_PERMISSION_REQUIRED", (teamId, userId, permissionId) => [
|
|
483
|
+
401,
|
|
484
|
+
`User ${userId} does not have permission ${permissionId} in team ${teamId}.`,
|
|
485
|
+
{
|
|
486
|
+
team_id: teamId,
|
|
487
|
+
user_id: userId,
|
|
488
|
+
permission_id: permissionId,
|
|
489
|
+
},
|
|
490
|
+
], (json) => [json.team_id, json.user_id, json.permission_id]);
|
|
491
|
+
const InvalidSharedOAuthProviderId = createKnownErrorConstructor(KnownError, "INVALID_SHARED_OAUTH_PROVIDER_ID", (providerId) => [
|
|
492
|
+
400,
|
|
493
|
+
`The shared OAuth provider with ID ${providerId} is not valid.`,
|
|
494
|
+
{
|
|
495
|
+
provider_id: providerId,
|
|
496
|
+
},
|
|
497
|
+
], (json) => [json.provider_id]);
|
|
498
|
+
const InvalidStandardOAuthProviderId = createKnownErrorConstructor(KnownError, "INVALID_STANDARD_OAUTH_PROVIDER_ID", (providerId) => [
|
|
499
|
+
400,
|
|
500
|
+
`The standard OAuth provider with ID ${providerId} is not valid.`,
|
|
501
|
+
{
|
|
502
|
+
provider_id: providerId,
|
|
503
|
+
},
|
|
504
|
+
], (json) => [json.provider_id]);
|
|
467
505
|
export const KnownErrors = {
|
|
468
506
|
UnsupportedError,
|
|
469
507
|
BodyParsingError,
|
|
@@ -506,6 +544,7 @@ export const KnownErrors = {
|
|
|
506
544
|
ProviderRejected,
|
|
507
545
|
RefreshTokenNotFoundOrExpired,
|
|
508
546
|
UserEmailAlreadyExists,
|
|
547
|
+
UserIdDoesNotExist,
|
|
509
548
|
UserNotFound,
|
|
510
549
|
ApiKeyNotFound,
|
|
511
550
|
ProjectNotFound,
|
|
@@ -541,6 +580,9 @@ export const KnownErrors = {
|
|
|
541
580
|
OAuthProviderNotFoundOrNotEnabled,
|
|
542
581
|
UserAuthenticationRequired,
|
|
543
582
|
TeamMembershipAlreadyExists,
|
|
583
|
+
TeamPermissionRequired,
|
|
584
|
+
InvalidSharedOAuthProviderId,
|
|
585
|
+
InvalidStandardOAuthProviderId,
|
|
544
586
|
};
|
|
545
587
|
// ensure that all known error codes are unique
|
|
546
588
|
const knownErrorCodes = new Set();
|
package/dist/schema-fields.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare const adaptSchema: yup.MixedSchema<typeof StackAdaptSentinel | un
|
|
|
19
19
|
export declare const urlSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
20
20
|
export declare const jsonSchema: yup.MixedSchema<{} | null, yup.AnyObject, undefined, "">;
|
|
21
21
|
export declare const jsonStringSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
22
|
+
export declare const jsonStringOrEmptySchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
22
23
|
export declare const emailSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
23
24
|
export declare const clientOrHigherAuthTypeSchema: yup.StringSchema<"client" | "server" | "admin" | undefined, yup.AnyObject, undefined, "">;
|
|
24
25
|
export declare const serverOrHigherAuthTypeSchema: yup.StringSchema<"server" | "admin" | undefined, yup.AnyObject, undefined, "">;
|
|
@@ -85,8 +86,11 @@ export declare const teamPermissionDescriptionSchema: yup.StringSchema<string |
|
|
|
85
86
|
export declare const containedPermissionIdsSchema: yup.ArraySchema<string[] | undefined, yup.AnyObject, undefined, "">;
|
|
86
87
|
export declare const teamIdSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
87
88
|
export declare const teamDisplayNameSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
89
|
+
export declare const teamProfileImageUrlSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
88
90
|
export declare const teamClientMetadataSchema: yup.MixedSchema<{} | null, yup.AnyObject, undefined, "">;
|
|
89
91
|
export declare const teamServerMetadataSchema: yup.MixedSchema<{} | null, yup.AnyObject, undefined, "">;
|
|
90
92
|
export declare const teamCreatedAtMillisSchema: yup.NumberSchema<number | undefined, yup.AnyObject, undefined, "">;
|
|
93
|
+
export declare const teamMemberDisplayNameSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
94
|
+
export declare const teamMemberProfileImageUrlSchema: yup.StringSchema<string | undefined, yup.AnyObject, undefined, "">;
|
|
91
95
|
export declare function yupRequiredWhen<S extends yup.AnyObject>(schema: S, triggerName: string, isValue: any): S;
|
|
92
96
|
export {};
|
package/dist/schema-fields.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as yup from "yup";
|
|
2
|
+
import { allProviders } from "./utils/oauth";
|
|
2
3
|
import { isUuid } from "./utils/uuids";
|
|
3
4
|
const _idDescription = (identify) => `The unique identifier of this ${identify}`;
|
|
4
5
|
const _displayNameDescription = (identify) => `Human-readable ${identify} display name. This is not a unique identifier.`;
|
|
5
6
|
const _clientMetaDataDescription = (identify) => `Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client.`;
|
|
7
|
+
const _profileImageUrlDescription = (identify) => `URL of the profile image for ${identify}. Can be a Base64 encoded image. Please compress and crop to a square before passing in.`;
|
|
6
8
|
const _serverMetaDataDescription = (identify) => `Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the ${identify} here.`;
|
|
7
9
|
const _atMillisDescription = (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`;
|
|
8
10
|
const _createdAtMillisDescription = (identify) => `The time the ${identify} was created ${_atMillisDescription(identify)}`;
|
|
9
|
-
const _updatedAtMillisDescription = (identify) => `The time the ${identify} was last updated ${_atMillisDescription(identify)}`;
|
|
10
11
|
const _signedUpAtMillisDescription = `The time the user signed up ${_atMillisDescription}`;
|
|
11
12
|
// Built-in replacements
|
|
12
13
|
/* eslint-disable no-restricted-syntax */
|
|
@@ -86,6 +87,17 @@ export const jsonStringSchema = yupString().test("json", "Invalid JSON format",
|
|
|
86
87
|
return false;
|
|
87
88
|
}
|
|
88
89
|
});
|
|
90
|
+
export const jsonStringOrEmptySchema = yupString().test("json", "Invalid JSON format", (value) => {
|
|
91
|
+
if (!value)
|
|
92
|
+
return true;
|
|
93
|
+
try {
|
|
94
|
+
JSON.parse(value);
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
89
101
|
export const emailSchema = yupString().email();
|
|
90
102
|
// Request auth
|
|
91
103
|
export const clientOrHigherAuthTypeSchema = yupString().oneOf(['client', 'server', 'admin']);
|
|
@@ -105,7 +117,7 @@ export const projectCreateTeamOnSignUpSchema = yupBoolean().meta({ openapiField:
|
|
|
105
117
|
export const projectMagicLinkEnabledSchema = yupBoolean().meta({ openapiField: { description: 'Whether magic link authentication is enabled for this project', exampleValue: true } });
|
|
106
118
|
export const projectCredentialEnabledSchema = yupBoolean().meta({ openapiField: { description: 'Whether email password authentication is enabled for this project', exampleValue: true } });
|
|
107
119
|
// Project OAuth config
|
|
108
|
-
export const oauthIdSchema = yupString().oneOf(
|
|
120
|
+
export const oauthIdSchema = yupString().oneOf(allProviders).meta({ openapiField: { description: `OAuth provider ID, one of ${allProviders.map(x => `\`${x}\``).join(', ')}`, exampleValue: 'google' } });
|
|
109
121
|
export const oauthEnabledSchema = yupBoolean().meta({ openapiField: { description: 'Whether the OAuth provider is enabled. If an provider is first enabled, then disabled, it will be shown in the list but with enabled=false', exampleValue: true } });
|
|
110
122
|
export const oauthTypeSchema = yupString().oneOf(['shared', 'standard']).meta({ openapiField: { description: 'OAuth provider type, one of shared, standard. "shared" uses Stack shared OAuth keys and it is only meant for development. "standard" uses your own OAuth keys and will show your logo and company name when signing in with the provider.', exampleValue: 'standard' } });
|
|
111
123
|
export const oauthClientIdSchema = yupString().meta({ openapiField: { description: 'OAuth client ID. Needs to be specified when using type="standard"', exampleValue: 'google-oauth-client-id' } });
|
|
@@ -144,7 +156,7 @@ export const primaryEmailSchema = emailSchema.meta({ openapiField: { description
|
|
|
144
156
|
export const primaryEmailVerifiedSchema = yupBoolean().meta({ openapiField: { description: 'Whether the primary email has been verified to belong to this user', exampleValue: true } });
|
|
145
157
|
export const userDisplayNameSchema = yupString().nullable().meta({ openapiField: { description: _displayNameDescription('user'), exampleValue: 'John Doe' } });
|
|
146
158
|
export const selectedTeamIdSchema = yupString().meta({ openapiField: { description: 'ID of the team currently selected by the user', exampleValue: 'team-id' } });
|
|
147
|
-
export const profileImageUrlSchema = yupString().meta({ openapiField: { description: '
|
|
159
|
+
export const profileImageUrlSchema = yupString().meta({ openapiField: { description: _profileImageUrlDescription('user'), exampleValue: 'https://example.com/image.jpg' } });
|
|
148
160
|
export const signedUpAtMillisSchema = yupNumber().meta({ openapiField: { description: _signedUpAtMillisDescription, exampleValue: 1630000000000 } });
|
|
149
161
|
export const userClientMetadataSchema = jsonSchema.meta({ openapiField: { description: _clientMetaDataDescription('user'), exampleValue: { key: 'value' } } });
|
|
150
162
|
export const userServerMetadataSchema = jsonSchema.meta({ openapiField: { description: _serverMetaDataDescription('user'), exampleValue: { key: 'value' } } });
|
|
@@ -187,9 +199,13 @@ export const containedPermissionIdsSchema = yupArray(teamPermissionDefinitionIdS
|
|
|
187
199
|
// Teams
|
|
188
200
|
export const teamIdSchema = yupString().uuid().meta({ openapiField: { description: _idDescription('team'), exampleValue: 'ad962777-8244-496a-b6a2-e0c6a449c79e' } });
|
|
189
201
|
export const teamDisplayNameSchema = yupString().meta({ openapiField: { description: _displayNameDescription('team'), exampleValue: 'My Team' } });
|
|
202
|
+
export const teamProfileImageUrlSchema = yupString().meta({ openapiField: { description: _profileImageUrlDescription('team'), exampleValue: 'https://example.com/image.jpg' } });
|
|
190
203
|
export const teamClientMetadataSchema = jsonSchema.meta({ openapiField: { description: _clientMetaDataDescription('team'), exampleValue: { key: 'value' } } });
|
|
191
204
|
export const teamServerMetadataSchema = jsonSchema.meta({ openapiField: { description: _serverMetaDataDescription('team'), exampleValue: { key: 'value' } } });
|
|
192
205
|
export const teamCreatedAtMillisSchema = yupNumber().meta({ openapiField: { description: _createdAtMillisDescription('team'), exampleValue: 1630000000000 } });
|
|
206
|
+
// Team member profiles
|
|
207
|
+
export const teamMemberDisplayNameSchema = yupString().meta({ openapiField: { description: _displayNameDescription('team member') + ' Note that this is separate from the display_name of the user.', exampleValue: 'John Doe' } });
|
|
208
|
+
export const teamMemberProfileImageUrlSchema = yupString().meta({ openapiField: { description: _profileImageUrlDescription('team member'), exampleValue: 'https://example.com/image.jpg' } });
|
|
193
209
|
// Utils
|
|
194
210
|
export function yupRequiredWhen(schema, triggerName, isValue) {
|
|
195
211
|
return schema.when(triggerName, {
|
package/dist/utils/errors.js
CHANGED
|
@@ -13,7 +13,7 @@ export function throwErr(...args) {
|
|
|
13
13
|
}
|
|
14
14
|
export class StackAssertionError extends Error {
|
|
15
15
|
constructor(message, extraData, options) {
|
|
16
|
-
const disclaimer = `\n\nThis is likely an error in Stack. Please report it.`;
|
|
16
|
+
const disclaimer = `\n\nThis is likely an error in Stack. Please make sure you are running the newest version and report it.`;
|
|
17
17
|
super(`${message}${message.endsWith(disclaimer) ? "" : disclaimer}`, options);
|
|
18
18
|
this.extraData = extraData;
|
|
19
19
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const standardProviders: readonly ["google", "github", "facebook", "microsoft", "spotify"];
|
|
2
|
+
export declare const sharedProviders: readonly ["google", "github", "facebook", "microsoft", "spotify"];
|
|
3
|
+
export declare const allProviders: readonly ["google", "github", "facebook", "microsoft", "spotify"];
|
|
4
|
+
export type ProviderType = typeof allProviders[number];
|
|
5
|
+
export type StandardProviderType = typeof standardProviders[number];
|
|
6
|
+
export type SharedProviderType = typeof sharedProviders[number];
|
package/dist/utils/results.js
CHANGED
|
@@ -86,13 +86,18 @@ function mapResult(result, fn) {
|
|
|
86
86
|
}
|
|
87
87
|
class RetryError extends AggregateError {
|
|
88
88
|
constructor(errors) {
|
|
89
|
+
const strings = errors.map(e => String(e));
|
|
90
|
+
const isAllSame = strings.length > 1 && strings.every(s => s === strings[0]);
|
|
89
91
|
super(errors, deindent `
|
|
90
92
|
Error after retrying ${errors.length} times.
|
|
91
93
|
|
|
92
|
-
${
|
|
93
|
-
|
|
94
|
-
${
|
|
95
|
-
`
|
|
94
|
+
${isAllSame ? deindent `
|
|
95
|
+
Attempts 1-${errors.length}:
|
|
96
|
+
${errors[0]}
|
|
97
|
+
` : errors.map((e, i) => deindent `
|
|
98
|
+
Attempt ${i + 1}:
|
|
99
|
+
${e}
|
|
100
|
+
`).join("\n\n")}
|
|
96
101
|
`, { cause: errors[errors.length - 1] });
|
|
97
102
|
this.errors = errors;
|
|
98
103
|
this.name = "RetryError";
|
package/dist/utils/urls.d.ts
CHANGED
package/dist/utils/urls.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { generateSecureRandomString } from "./crypto";
|
|
1
2
|
export function isLocalhost(urlOrString) {
|
|
2
3
|
const url = new URL(urlOrString);
|
|
3
4
|
if (url.hostname === "localhost" || url.hostname.endsWith(".localhost"))
|
|
@@ -6,3 +7,15 @@ export function isLocalhost(urlOrString) {
|
|
|
6
7
|
return true;
|
|
7
8
|
return false;
|
|
8
9
|
}
|
|
10
|
+
export function isRelative(url) {
|
|
11
|
+
const randomDomain = `${generateSecureRandomString()}.stack-auth.example.com`;
|
|
12
|
+
const u = new URL(url, `https://${randomDomain}`);
|
|
13
|
+
if (u.host !== randomDomain)
|
|
14
|
+
return false;
|
|
15
|
+
if (u.protocol !== "https:")
|
|
16
|
+
return false;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
export function getRelativePart(url) {
|
|
20
|
+
return url.pathname + url.search + url.hash;
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackframe/stack-shared",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.10",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"jose": "^5.2.2",
|
|
37
37
|
"oauth4webapi": "^2.10.3",
|
|
38
38
|
"uuid": "^9.0.1",
|
|
39
|
-
"@stackframe/stack-sc": "2.5.
|
|
39
|
+
"@stackframe/stack-sc": "2.5.10"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"rimraf": "^5.0.5",
|