@stackframe/stack-shared 2.5.2 → 2.5.4
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 +16 -0
- package/dist/crud.d.ts +10 -3
- package/dist/helpers/production-mode.d.ts +6 -0
- package/dist/helpers/production-mode.js +43 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/interface/adminInterface.d.ts +28 -67
- package/dist/interface/adminInterface.js +63 -22
- package/dist/interface/clientInterface.d.ts +21 -133
- package/dist/interface/clientInterface.js +92 -119
- package/dist/interface/crud/api-keys.d.ts +134 -0
- package/dist/interface/crud/api-keys.js +61 -0
- package/dist/interface/crud/current-user.d.ts +47 -11
- package/dist/interface/crud/current-user.js +7 -3
- package/dist/interface/crud/email-templates.d.ts +53 -34
- package/dist/interface/crud/email-templates.js +37 -24
- package/dist/interface/crud/oauth.d.ts +8 -9
- package/dist/interface/crud/oauth.js +5 -5
- package/dist/interface/crud/projects.d.ts +446 -0
- package/dist/interface/crud/projects.js +110 -0
- package/dist/interface/crud/team-memberships.d.ts +22 -0
- package/dist/interface/crud/team-memberships.js +22 -0
- package/dist/interface/crud/team-permissions.d.ts +129 -0
- package/dist/interface/crud/team-permissions.js +83 -0
- package/dist/interface/crud/teams.d.ts +148 -0
- package/dist/interface/crud/teams.js +80 -0
- package/dist/interface/crud/users.d.ts +88 -33
- package/dist/interface/crud/users.js +22 -14
- package/dist/interface/crud-deprecated/api-keys.d.ts +134 -0
- package/dist/interface/crud-deprecated/api-keys.js +61 -0
- package/dist/interface/crud-deprecated/current-user.d.ts +127 -0
- package/dist/interface/crud-deprecated/current-user.js +49 -0
- package/dist/interface/crud-deprecated/email-templates.d.ts +75 -0
- package/dist/interface/crud-deprecated/email-templates.js +41 -0
- package/dist/interface/crud-deprecated/oauth.d.ts +24 -0
- package/dist/interface/crud-deprecated/oauth.js +12 -0
- package/dist/interface/crud-deprecated/projects.d.ts +440 -0
- package/dist/interface/crud-deprecated/projects.js +109 -0
- package/dist/interface/crud-deprecated/team-memberships.d.ts +22 -0
- package/dist/interface/crud-deprecated/team-memberships.js +22 -0
- package/dist/interface/crud-deprecated/team-permissions.d.ts +129 -0
- package/dist/interface/crud-deprecated/team-permissions.js +83 -0
- package/dist/interface/crud-deprecated/teams.d.ts +126 -0
- package/dist/interface/crud-deprecated/teams.js +78 -0
- package/dist/interface/crud-deprecated/users.d.ts +201 -0
- package/dist/interface/crud-deprecated/users.js +75 -0
- package/dist/interface/serverInterface.d.ts +33 -60
- package/dist/interface/serverInterface.js +74 -102
- package/dist/known-errors.d.ts +43 -26
- package/dist/known-errors.js +135 -92
- package/dist/schema-fields.d.ts +53 -4
- package/dist/schema-fields.js +156 -26
- package/dist/sessions.d.ts +1 -0
- package/dist/sessions.js +20 -26
- package/dist/utils/arrays.d.ts +4 -0
- package/dist/utils/arrays.js +10 -0
- package/dist/utils/caches.js +11 -18
- package/dist/utils/compile-time.d.ts +3 -1
- package/dist/utils/compile-time.js +3 -1
- package/dist/utils/errors.d.ts +8 -1
- package/dist/utils/errors.js +58 -47
- package/dist/utils/globals.js +3 -0
- package/dist/utils/maps.js +8 -5
- package/dist/utils/numbers.js +5 -5
- package/dist/utils/objects.d.ts +4 -1
- package/dist/utils/objects.js +16 -8
- package/dist/utils/promises.js +6 -2
- package/dist/utils/proxies.d.ts +1 -0
- package/dist/utils/proxies.js +65 -0
- package/dist/utils/react.d.ts +1 -1
- package/dist/utils/react.js +2 -2
- package/dist/utils/results.js +0 -1
- package/dist/utils/stores.js +7 -10
- package/dist/utils/strings.js +7 -2
- package/dist/utils/urls.d.ts +1 -0
- package/dist/utils/urls.js +8 -0
- package/dist/utils/uuids.d.ts +1 -1
- package/dist/utils/uuids.js +2 -1
- package/package.json +2 -2
- package/dist/utils/yup.d.ts +0 -3
- package/dist/utils/yup.js +0 -13
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as oauth from 'oauth4webapi';
|
|
2
|
-
import { Result } from "../utils/results";
|
|
3
|
-
import { KnownError, KnownErrors } from '../known-errors';
|
|
4
|
-
import { StackAssertionError, captureError, throwErr } from '../utils/errors';
|
|
5
2
|
import { cookies } from '@stackframe/stack-sc';
|
|
6
|
-
import {
|
|
3
|
+
import { KnownError, KnownErrors } from '../known-errors';
|
|
7
4
|
import { AccessToken, InternalSession } from '../sessions';
|
|
5
|
+
import { generateSecureRandomString } from '../utils/crypto';
|
|
6
|
+
import { StackAssertionError, throwErr } from '../utils/errors';
|
|
8
7
|
import { globalVar } from '../utils/globals';
|
|
8
|
+
import { Result } from "../utils/results";
|
|
9
9
|
export const sharedProviders = [
|
|
10
10
|
"shared-github",
|
|
11
11
|
"shared-google",
|
|
@@ -27,7 +27,6 @@ export function toSharedProvider(provider) {
|
|
|
27
27
|
return "shared-" + provider;
|
|
28
28
|
}
|
|
29
29
|
export class StackClientInterface {
|
|
30
|
-
options;
|
|
31
30
|
constructor(options) {
|
|
32
31
|
this.options = options;
|
|
33
32
|
// nothing here
|
|
@@ -46,12 +45,12 @@ export class StackClientInterface {
|
|
|
46
45
|
const as = {
|
|
47
46
|
issuer: this.options.baseUrl,
|
|
48
47
|
algorithm: 'oauth2',
|
|
49
|
-
token_endpoint: this.getApiUrl() + '/auth/token',
|
|
48
|
+
token_endpoint: this.getApiUrl() + '/auth/oauth/token',
|
|
50
49
|
};
|
|
51
50
|
const client = {
|
|
52
51
|
client_id: this.projectId,
|
|
53
52
|
client_secret: this.options.publishableClientKey,
|
|
54
|
-
token_endpoint_auth_method: '
|
|
53
|
+
token_endpoint_auth_method: 'client_secret_post',
|
|
55
54
|
};
|
|
56
55
|
const rawResponse = await oauth.refreshTokenGrantRequest(as, client, refreshToken.token);
|
|
57
56
|
const response = await this._processResponse(rawResponse);
|
|
@@ -115,7 +114,7 @@ export class StackClientInterface {
|
|
|
115
114
|
const params = {
|
|
116
115
|
/**
|
|
117
116
|
* This fetch may be cross-origin, in which case we don't want to send cookies of the
|
|
118
|
-
* original origin (this is the default
|
|
117
|
+
* original origin (this is the default behavior of `credentials`).
|
|
119
118
|
*
|
|
120
119
|
* To help debugging, also omit cookies on same-origin, so we don't accidentally
|
|
121
120
|
* implement reliance on cookies anywhere.
|
|
@@ -130,10 +129,9 @@ export class StackClientInterface {
|
|
|
130
129
|
headers: {
|
|
131
130
|
"X-Stack-Override-Error-Status": "true",
|
|
132
131
|
"X-Stack-Project-Id": this.projectId,
|
|
133
|
-
"X-Stack-
|
|
132
|
+
"X-Stack-Access-Type": requestType,
|
|
134
133
|
"X-Stack-Client-Version": this.options.clientVersion,
|
|
135
134
|
...(tokenObj ? {
|
|
136
|
-
"Authorization": "StackSession " + tokenObj.accessToken.token,
|
|
137
135
|
"X-Stack-Access-Token": tokenObj.accessToken.token,
|
|
138
136
|
} : {}),
|
|
139
137
|
...(tokenObj?.refreshToken ? {
|
|
@@ -241,15 +239,15 @@ export class StackClientInterface {
|
|
|
241
239
|
}, null);
|
|
242
240
|
throw new StackAssertionError(await res.text());
|
|
243
241
|
}
|
|
244
|
-
async sendForgotPasswordEmail(email,
|
|
245
|
-
const res = await this.sendClientRequestAndCatchKnownError("/auth/
|
|
242
|
+
async sendForgotPasswordEmail(email, callbackUrl) {
|
|
243
|
+
const res = await this.sendClientRequestAndCatchKnownError("/auth/password/send-reset-code", {
|
|
246
244
|
method: "POST",
|
|
247
245
|
headers: {
|
|
248
246
|
"Content-Type": "application/json"
|
|
249
247
|
},
|
|
250
248
|
body: JSON.stringify({
|
|
251
249
|
email,
|
|
252
|
-
|
|
250
|
+
callback_url: callbackUrl,
|
|
253
251
|
}),
|
|
254
252
|
}, null, [KnownErrors.UserNotFound]);
|
|
255
253
|
if (res.status === "error") {
|
|
@@ -257,7 +255,7 @@ export class StackClientInterface {
|
|
|
257
255
|
}
|
|
258
256
|
}
|
|
259
257
|
async sendVerificationEmail(emailVerificationRedirectUrl, session) {
|
|
260
|
-
const res = await this.sendClientRequestAndCatchKnownError("/
|
|
258
|
+
const res = await this.sendClientRequestAndCatchKnownError("/contact-channels/send-verification-code", {
|
|
261
259
|
method: "POST",
|
|
262
260
|
headers: {
|
|
263
261
|
"Content-Type": "application/json"
|
|
@@ -270,15 +268,15 @@ export class StackClientInterface {
|
|
|
270
268
|
return res.error;
|
|
271
269
|
}
|
|
272
270
|
}
|
|
273
|
-
async sendMagicLinkEmail(email,
|
|
274
|
-
const res = await this.sendClientRequestAndCatchKnownError("/auth/send-
|
|
271
|
+
async sendMagicLinkEmail(email, callbackUrl) {
|
|
272
|
+
const res = await this.sendClientRequestAndCatchKnownError("/auth/otp/send-sign-in-code", {
|
|
275
273
|
method: "POST",
|
|
276
274
|
headers: {
|
|
277
275
|
"Content-Type": "application/json"
|
|
278
276
|
},
|
|
279
277
|
body: JSON.stringify({
|
|
280
278
|
email,
|
|
281
|
-
|
|
279
|
+
callback_url: callbackUrl,
|
|
282
280
|
}),
|
|
283
281
|
}, null, [KnownErrors.RedirectUrlNotWhitelisted]);
|
|
284
282
|
if (res.status === "error") {
|
|
@@ -286,7 +284,7 @@ export class StackClientInterface {
|
|
|
286
284
|
}
|
|
287
285
|
}
|
|
288
286
|
async resetPassword(options) {
|
|
289
|
-
const res = await this.sendClientRequestAndCatchKnownError("/auth/password
|
|
287
|
+
const res = await this.sendClientRequestAndCatchKnownError("/auth/password/reset", {
|
|
290
288
|
method: "POST",
|
|
291
289
|
headers: {
|
|
292
290
|
"Content-Type": "application/json"
|
|
@@ -298,13 +296,16 @@ export class StackClientInterface {
|
|
|
298
296
|
}
|
|
299
297
|
}
|
|
300
298
|
async updatePassword(options, session) {
|
|
301
|
-
const res = await this.sendClientRequestAndCatchKnownError("/auth/update
|
|
299
|
+
const res = await this.sendClientRequestAndCatchKnownError("/auth/password/update", {
|
|
302
300
|
method: "POST",
|
|
303
301
|
headers: {
|
|
304
302
|
"Content-Type": "application/json"
|
|
305
303
|
},
|
|
306
|
-
body: JSON.stringify(
|
|
307
|
-
|
|
304
|
+
body: JSON.stringify({
|
|
305
|
+
old_password: options.oldPassword,
|
|
306
|
+
new_password: options.newPassword,
|
|
307
|
+
}),
|
|
308
|
+
}, session, [KnownErrors.PasswordConfirmationMismatch, KnownErrors.PasswordRequirementsNotMet]);
|
|
308
309
|
if (res.status === "error") {
|
|
309
310
|
return res.error;
|
|
310
311
|
}
|
|
@@ -317,7 +318,7 @@ export class StackClientInterface {
|
|
|
317
318
|
return res;
|
|
318
319
|
}
|
|
319
320
|
async verifyEmail(code) {
|
|
320
|
-
const res = await this.sendClientRequestAndCatchKnownError("/
|
|
321
|
+
const res = await this.sendClientRequestAndCatchKnownError("/contact-channels/verify", {
|
|
321
322
|
method: "POST",
|
|
322
323
|
headers: {
|
|
323
324
|
"Content-Type": "application/json"
|
|
@@ -331,7 +332,7 @@ export class StackClientInterface {
|
|
|
331
332
|
}
|
|
332
333
|
}
|
|
333
334
|
async signInWithCredential(email, password, session) {
|
|
334
|
-
const res = await this.sendClientRequestAndCatchKnownError("/auth/
|
|
335
|
+
const res = await this.sendClientRequestAndCatchKnownError("/auth/password/sign-in", {
|
|
335
336
|
method: "POST",
|
|
336
337
|
headers: {
|
|
337
338
|
"Content-Type": "application/json"
|
|
@@ -346,12 +347,12 @@ export class StackClientInterface {
|
|
|
346
347
|
}
|
|
347
348
|
const result = await res.data.json();
|
|
348
349
|
return {
|
|
349
|
-
accessToken: result.
|
|
350
|
-
refreshToken: result.
|
|
350
|
+
accessToken: result.access_token,
|
|
351
|
+
refreshToken: result.refresh_token,
|
|
351
352
|
};
|
|
352
353
|
}
|
|
353
354
|
async signUpWithCredential(email, password, emailVerificationRedirectUrl, session) {
|
|
354
|
-
const res = await this.sendClientRequestAndCatchKnownError("/auth/
|
|
355
|
+
const res = await this.sendClientRequestAndCatchKnownError("/auth/password/sign-up", {
|
|
355
356
|
headers: {
|
|
356
357
|
"Content-Type": "application/json"
|
|
357
358
|
},
|
|
@@ -359,7 +360,7 @@ export class StackClientInterface {
|
|
|
359
360
|
body: JSON.stringify({
|
|
360
361
|
email,
|
|
361
362
|
password,
|
|
362
|
-
emailVerificationRedirectUrl,
|
|
363
|
+
verification_callback_url: emailVerificationRedirectUrl,
|
|
363
364
|
}),
|
|
364
365
|
}, session, [KnownErrors.UserEmailAlreadyExists, KnownErrors.PasswordRequirementsNotMet]);
|
|
365
366
|
if (res.status === "error") {
|
|
@@ -367,12 +368,12 @@ export class StackClientInterface {
|
|
|
367
368
|
}
|
|
368
369
|
const result = await res.data.json();
|
|
369
370
|
return {
|
|
370
|
-
accessToken: result.
|
|
371
|
-
refreshToken: result.
|
|
371
|
+
accessToken: result.access_token,
|
|
372
|
+
refreshToken: result.refresh_token,
|
|
372
373
|
};
|
|
373
374
|
}
|
|
374
|
-
async signInWithMagicLink(code
|
|
375
|
-
const res = await this.sendClientRequestAndCatchKnownError("/auth/
|
|
375
|
+
async signInWithMagicLink(code) {
|
|
376
|
+
const res = await this.sendClientRequestAndCatchKnownError("/auth/otp/sign-in", {
|
|
376
377
|
method: "POST",
|
|
377
378
|
headers: {
|
|
378
379
|
"Content-Type": "application/json"
|
|
@@ -386,9 +387,9 @@ export class StackClientInterface {
|
|
|
386
387
|
}
|
|
387
388
|
const result = await res.data.json();
|
|
388
389
|
return {
|
|
389
|
-
accessToken: result.
|
|
390
|
-
refreshToken: result.
|
|
391
|
-
newUser: result.
|
|
390
|
+
accessToken: result.access_token,
|
|
391
|
+
refreshToken: result.refresh_token,
|
|
392
|
+
newUser: result.new_user,
|
|
392
393
|
};
|
|
393
394
|
}
|
|
394
395
|
async getOAuthUrl(options) {
|
|
@@ -403,26 +404,26 @@ export class StackClientInterface {
|
|
|
403
404
|
// TODO fix
|
|
404
405
|
throw new Error("Admin session token is currently not supported for OAuth");
|
|
405
406
|
}
|
|
406
|
-
const url = new URL(this.getApiUrl() + "/auth/authorize/" + options.provider.toLowerCase());
|
|
407
|
+
const url = new URL(this.getApiUrl() + "/auth/oauth/authorize/" + options.provider.toLowerCase());
|
|
407
408
|
url.searchParams.set("client_id", this.projectId);
|
|
408
409
|
url.searchParams.set("client_secret", this.options.publishableClientKey);
|
|
409
410
|
url.searchParams.set("redirect_uri", updatedRedirectUrl.toString());
|
|
410
|
-
url.searchParams.set("scope", "
|
|
411
|
+
url.searchParams.set("scope", "legacy");
|
|
411
412
|
url.searchParams.set("state", options.state);
|
|
412
413
|
url.searchParams.set("grant_type", "authorization_code");
|
|
413
414
|
url.searchParams.set("code_challenge", options.codeChallenge);
|
|
414
415
|
url.searchParams.set("code_challenge_method", "S256");
|
|
415
416
|
url.searchParams.set("response_type", "code");
|
|
416
417
|
url.searchParams.set("type", options.type);
|
|
417
|
-
url.searchParams.set("
|
|
418
|
+
url.searchParams.set("error_redirect_url", options.errorRedirectUrl);
|
|
418
419
|
if (options.afterCallbackRedirectUrl) {
|
|
419
|
-
url.searchParams.set("
|
|
420
|
+
url.searchParams.set("after_callback_redirect_rrl", options.afterCallbackRedirectUrl);
|
|
420
421
|
}
|
|
421
422
|
if (options.type === "link") {
|
|
422
423
|
const tokens = await options.session.getPotentiallyExpiredTokens();
|
|
423
424
|
url.searchParams.set("token", tokens?.accessToken.token || "");
|
|
424
425
|
if (options.providerScope) {
|
|
425
|
-
url.searchParams.set("
|
|
426
|
+
url.searchParams.set("provider_scope", options.providerScope);
|
|
426
427
|
}
|
|
427
428
|
}
|
|
428
429
|
return url.toString();
|
|
@@ -435,12 +436,12 @@ export class StackClientInterface {
|
|
|
435
436
|
const as = {
|
|
436
437
|
issuer: this.options.baseUrl,
|
|
437
438
|
algorithm: 'oauth2',
|
|
438
|
-
token_endpoint: this.getApiUrl() + '/auth/token',
|
|
439
|
+
token_endpoint: this.getApiUrl() + '/auth/oauth/token',
|
|
439
440
|
};
|
|
440
441
|
const client = {
|
|
441
442
|
client_id: this.projectId,
|
|
442
443
|
client_secret: this.options.publishableClientKey,
|
|
443
|
-
token_endpoint_auth_method: '
|
|
444
|
+
token_endpoint_auth_method: 'client_secret_post',
|
|
444
445
|
};
|
|
445
446
|
const params = oauth.validateAuthResponse(as, client, options.oauthParams, options.state);
|
|
446
447
|
if (oauth.isOAuth2Error(params)) {
|
|
@@ -462,52 +463,66 @@ export class StackClientInterface {
|
|
|
462
463
|
async signOut(session) {
|
|
463
464
|
const tokenObj = await session.getPotentiallyExpiredTokens();
|
|
464
465
|
if (tokenObj) {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
466
|
+
const resOrError = await this.sendClientRequestAndCatchKnownError("/auth/sessions/current", {
|
|
467
|
+
method: "DELETE",
|
|
468
|
+
headers: {
|
|
469
|
+
"Content-Type": "application/json"
|
|
470
|
+
},
|
|
471
|
+
body: JSON.stringify({}),
|
|
472
|
+
}, session, [KnownErrors.RefreshTokenError]);
|
|
473
|
+
if (resOrError.status === "error") {
|
|
474
|
+
if (resOrError.error instanceof KnownErrors.RefreshTokenError) {
|
|
475
|
+
// refresh token was already invalid, just continue like nothing happened
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
// this should never happen
|
|
479
|
+
throw new StackAssertionError("Unexpected error", { error: resOrError.error });
|
|
480
|
+
}
|
|
468
481
|
}
|
|
469
482
|
else {
|
|
470
|
-
|
|
471
|
-
method: "POST",
|
|
472
|
-
headers: {
|
|
473
|
-
"Content-Type": "application/json"
|
|
474
|
-
},
|
|
475
|
-
body: JSON.stringify({
|
|
476
|
-
refreshToken: tokenObj.refreshToken.token,
|
|
477
|
-
}),
|
|
478
|
-
}, session);
|
|
479
|
-
await res.json();
|
|
483
|
+
// user was signed out successfully, all good
|
|
480
484
|
}
|
|
481
485
|
}
|
|
482
486
|
session.markInvalid();
|
|
483
487
|
}
|
|
484
|
-
async getClientUserByToken(
|
|
485
|
-
const
|
|
488
|
+
async getClientUserByToken(session) {
|
|
489
|
+
const responseOrError = await this.sendClientRequestAndCatchKnownError("/users/me", {}, session, [KnownErrors.CannotGetOwnUserWithoutUser]);
|
|
490
|
+
if (responseOrError.status === "error") {
|
|
491
|
+
if (responseOrError.error instanceof KnownErrors.CannotGetOwnUserWithoutUser) {
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
throw new StackAssertionError("Unexpected uncaught error", { cause: responseOrError.error });
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
const response = responseOrError.data;
|
|
486
499
|
const user = await response.json();
|
|
487
500
|
if (!user)
|
|
488
|
-
|
|
489
|
-
return
|
|
501
|
+
throw new StackAssertionError("User endpoint returned null; this should never happen");
|
|
502
|
+
return user;
|
|
490
503
|
}
|
|
491
|
-
async
|
|
492
|
-
const response = await this.sendClientRequest(`/
|
|
493
|
-
const
|
|
494
|
-
return
|
|
504
|
+
async listCurrentUserTeamPermissions(options, session) {
|
|
505
|
+
const response = await this.sendClientRequest(`/team-permissions?team_id=${options.teamId}?user_id=me&recursive=${options.recursive}`, {}, session);
|
|
506
|
+
const result = await response.json();
|
|
507
|
+
return result.items;
|
|
495
508
|
}
|
|
496
|
-
async
|
|
497
|
-
const response = await this.sendClientRequest("/
|
|
498
|
-
const
|
|
499
|
-
return
|
|
509
|
+
async listCurrentUserTeams(session) {
|
|
510
|
+
const response = await this.sendClientRequest("/teams?user_id=me", {}, session);
|
|
511
|
+
const result = await response.json();
|
|
512
|
+
return result.items;
|
|
500
513
|
}
|
|
501
514
|
async getClientProject() {
|
|
502
|
-
const
|
|
515
|
+
const responseOrError = await this.sendClientRequestAndCatchKnownError("/projects/current", {}, null, [KnownErrors.ProjectNotFound]);
|
|
516
|
+
if (responseOrError.status === "error") {
|
|
517
|
+
return Result.error(responseOrError.error);
|
|
518
|
+
}
|
|
519
|
+
const response = responseOrError.data;
|
|
503
520
|
const project = await response.json();
|
|
504
|
-
if (!project)
|
|
505
|
-
return Result.error(new Error("Failed to get project"));
|
|
506
521
|
return Result.ok(project);
|
|
507
522
|
}
|
|
508
|
-
async
|
|
509
|
-
await this.sendClientRequest("/
|
|
510
|
-
method: "
|
|
523
|
+
async updateClientUser(update, session) {
|
|
524
|
+
await this.sendClientRequest("/users/me", {
|
|
525
|
+
method: "PATCH",
|
|
511
526
|
headers: {
|
|
512
527
|
"content-type": "application/json",
|
|
513
528
|
},
|
|
@@ -515,15 +530,15 @@ export class StackClientInterface {
|
|
|
515
530
|
}, session);
|
|
516
531
|
}
|
|
517
532
|
async listProjects(session) {
|
|
518
|
-
const response = await this.sendClientRequest("/projects", {}, session);
|
|
533
|
+
const response = await this.sendClientRequest("/internal/projects", {}, session);
|
|
519
534
|
if (!response.ok) {
|
|
520
535
|
throw new Error("Failed to list projects: " + response.status + " " + (await response.text()));
|
|
521
536
|
}
|
|
522
537
|
const json = await response.json();
|
|
523
|
-
return json;
|
|
538
|
+
return json.items;
|
|
524
539
|
}
|
|
525
540
|
async createProject(project, session) {
|
|
526
|
-
const fetchResponse = await this.sendClientRequest("/projects", {
|
|
541
|
+
const fetchResponse = await this.sendClientRequest("/internal/projects", {
|
|
527
542
|
method: "POST",
|
|
528
543
|
headers: {
|
|
529
544
|
"content-type": "application/json",
|
|
@@ -537,7 +552,7 @@ export class StackClientInterface {
|
|
|
537
552
|
return json;
|
|
538
553
|
}
|
|
539
554
|
async getAccessToken(provider, scope, session) {
|
|
540
|
-
const response = await this.sendClientRequest(`/auth/
|
|
555
|
+
const response = await this.sendClientRequest(`/auth/oauth/connected-account/${provider}/access-token`, {
|
|
541
556
|
method: "POST",
|
|
542
557
|
headers: {
|
|
543
558
|
"content-type": "application/json",
|
|
@@ -550,7 +565,7 @@ export class StackClientInterface {
|
|
|
550
565
|
};
|
|
551
566
|
}
|
|
552
567
|
async createTeamForCurrentUser(data, session) {
|
|
553
|
-
const response = await this.sendClientRequest("/
|
|
568
|
+
const response = await this.sendClientRequest("/teams?add_current_user=true", {
|
|
554
569
|
method: "POST",
|
|
555
570
|
headers: {
|
|
556
571
|
"content-type": "application/json",
|
|
@@ -560,45 +575,3 @@ export class StackClientInterface {
|
|
|
560
575
|
return await response.json();
|
|
561
576
|
}
|
|
562
577
|
}
|
|
563
|
-
export function getProductionModeErrors(project) {
|
|
564
|
-
const errors = [];
|
|
565
|
-
const fixUrlRelative = `/projects/${project.id}/domains`;
|
|
566
|
-
if (project.evaluatedConfig.allowLocalhost) {
|
|
567
|
-
errors.push({
|
|
568
|
-
errorMessage: "Localhost is not allowed in production mode, turn off 'Allow localhost' in project settings",
|
|
569
|
-
fixUrlRelative,
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
for (const { domain } of project.evaluatedConfig.domains) {
|
|
573
|
-
let url;
|
|
574
|
-
try {
|
|
575
|
-
url = new URL(domain);
|
|
576
|
-
}
|
|
577
|
-
catch (e) {
|
|
578
|
-
errors.push({
|
|
579
|
-
errorMessage: "Domain should be a valid URL: " + domain,
|
|
580
|
-
fixUrlRelative,
|
|
581
|
-
});
|
|
582
|
-
continue;
|
|
583
|
-
}
|
|
584
|
-
if (url.hostname === "localhost") {
|
|
585
|
-
errors.push({
|
|
586
|
-
errorMessage: "Domain should not be localhost: " + domain,
|
|
587
|
-
fixUrlRelative,
|
|
588
|
-
});
|
|
589
|
-
}
|
|
590
|
-
else if (!url.hostname.includes(".") || url.hostname.match(/\d+(\.\d+)*/)) {
|
|
591
|
-
errors.push({
|
|
592
|
-
errorMessage: "Not a valid domain" + domain,
|
|
593
|
-
fixUrlRelative,
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
else if (url.protocol !== "https:") {
|
|
597
|
-
errors.push({
|
|
598
|
-
errorMessage: "Domain should be HTTPS: " + domain,
|
|
599
|
-
fixUrlRelative,
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
return errors;
|
|
604
|
-
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { CrudTypeOf } from "../../crud";
|
|
2
|
+
export declare const apiKeysCreateInputSchema: import("yup").ObjectSchema<{
|
|
3
|
+
description: string;
|
|
4
|
+
expires_at_millis: number;
|
|
5
|
+
has_publishable_client_key: NonNullable<boolean | undefined>;
|
|
6
|
+
has_secret_server_key: NonNullable<boolean | undefined>;
|
|
7
|
+
has_super_secret_admin_key: NonNullable<boolean | undefined>;
|
|
8
|
+
}, import("yup").AnyObject, {
|
|
9
|
+
description: undefined;
|
|
10
|
+
expires_at_millis: undefined;
|
|
11
|
+
has_publishable_client_key: undefined;
|
|
12
|
+
has_secret_server_key: undefined;
|
|
13
|
+
has_super_secret_admin_key: undefined;
|
|
14
|
+
}, "">;
|
|
15
|
+
export declare const apiKeysCreateOutputSchema: import("yup").ObjectSchema<{
|
|
16
|
+
id: string;
|
|
17
|
+
description: string;
|
|
18
|
+
expires_at_millis: number;
|
|
19
|
+
manually_revoked_at_millis: number | undefined;
|
|
20
|
+
created_at_millis: number;
|
|
21
|
+
} & {
|
|
22
|
+
publishable_client_key: string | undefined;
|
|
23
|
+
secret_server_key: string | undefined;
|
|
24
|
+
super_secret_admin_key: string | undefined;
|
|
25
|
+
}, import("yup").AnyObject, {
|
|
26
|
+
id: undefined;
|
|
27
|
+
description: undefined;
|
|
28
|
+
expires_at_millis: undefined;
|
|
29
|
+
manually_revoked_at_millis: undefined;
|
|
30
|
+
created_at_millis: undefined;
|
|
31
|
+
publishable_client_key: undefined;
|
|
32
|
+
secret_server_key: undefined;
|
|
33
|
+
super_secret_admin_key: undefined;
|
|
34
|
+
}, "">;
|
|
35
|
+
export declare const apiKeysCrudAdminObfuscatedReadSchema: import("yup").ObjectSchema<{
|
|
36
|
+
id: string;
|
|
37
|
+
description: string;
|
|
38
|
+
expires_at_millis: number;
|
|
39
|
+
manually_revoked_at_millis: number | undefined;
|
|
40
|
+
created_at_millis: number;
|
|
41
|
+
} & {
|
|
42
|
+
publishable_client_key: {
|
|
43
|
+
last_four: string;
|
|
44
|
+
} | undefined;
|
|
45
|
+
secret_server_key: {
|
|
46
|
+
last_four: string;
|
|
47
|
+
} | undefined;
|
|
48
|
+
super_secret_admin_key: {
|
|
49
|
+
last_four: string;
|
|
50
|
+
} | undefined;
|
|
51
|
+
}, import("yup").AnyObject, {
|
|
52
|
+
id: undefined;
|
|
53
|
+
description: undefined;
|
|
54
|
+
expires_at_millis: undefined;
|
|
55
|
+
manually_revoked_at_millis: undefined;
|
|
56
|
+
created_at_millis: undefined;
|
|
57
|
+
publishable_client_key: {
|
|
58
|
+
last_four: undefined;
|
|
59
|
+
};
|
|
60
|
+
secret_server_key: {
|
|
61
|
+
last_four: undefined;
|
|
62
|
+
};
|
|
63
|
+
super_secret_admin_key: {
|
|
64
|
+
last_four: undefined;
|
|
65
|
+
};
|
|
66
|
+
}, "">;
|
|
67
|
+
export declare const apiKeysCrudAdminUpdateSchema: import("yup").ObjectSchema<{
|
|
68
|
+
description: string | undefined;
|
|
69
|
+
revoked: boolean | undefined;
|
|
70
|
+
}, import("yup").AnyObject, {
|
|
71
|
+
description: undefined;
|
|
72
|
+
revoked: undefined;
|
|
73
|
+
}, "">;
|
|
74
|
+
export declare const apiKeysCrudAdminDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
75
|
+
export declare const apiKeysCrud: import("../../crud").CrudSchemaFromOptions<{
|
|
76
|
+
adminReadSchema: import("yup").ObjectSchema<{
|
|
77
|
+
id: string;
|
|
78
|
+
description: string;
|
|
79
|
+
expires_at_millis: number;
|
|
80
|
+
manually_revoked_at_millis: number | undefined;
|
|
81
|
+
created_at_millis: number;
|
|
82
|
+
} & {
|
|
83
|
+
publishable_client_key: {
|
|
84
|
+
last_four: string;
|
|
85
|
+
} | undefined;
|
|
86
|
+
secret_server_key: {
|
|
87
|
+
last_four: string;
|
|
88
|
+
} | undefined;
|
|
89
|
+
super_secret_admin_key: {
|
|
90
|
+
last_four: string;
|
|
91
|
+
} | undefined;
|
|
92
|
+
}, import("yup").AnyObject, {
|
|
93
|
+
id: undefined;
|
|
94
|
+
description: undefined;
|
|
95
|
+
expires_at_millis: undefined;
|
|
96
|
+
manually_revoked_at_millis: undefined;
|
|
97
|
+
created_at_millis: undefined;
|
|
98
|
+
publishable_client_key: {
|
|
99
|
+
last_four: undefined;
|
|
100
|
+
};
|
|
101
|
+
secret_server_key: {
|
|
102
|
+
last_four: undefined;
|
|
103
|
+
};
|
|
104
|
+
super_secret_admin_key: {
|
|
105
|
+
last_four: undefined;
|
|
106
|
+
};
|
|
107
|
+
}, "">;
|
|
108
|
+
adminUpdateSchema: import("yup").ObjectSchema<{
|
|
109
|
+
description: string | undefined;
|
|
110
|
+
revoked: boolean | undefined;
|
|
111
|
+
}, import("yup").AnyObject, {
|
|
112
|
+
description: undefined;
|
|
113
|
+
revoked: undefined;
|
|
114
|
+
}, "">;
|
|
115
|
+
adminDeleteSchema: import("yup").MixedSchema<{} | undefined, import("yup").AnyObject, undefined, "">;
|
|
116
|
+
docs: {
|
|
117
|
+
adminList: {
|
|
118
|
+
hidden: true;
|
|
119
|
+
};
|
|
120
|
+
adminRead: {
|
|
121
|
+
hidden: true;
|
|
122
|
+
};
|
|
123
|
+
adminCreate: {
|
|
124
|
+
hidden: true;
|
|
125
|
+
};
|
|
126
|
+
adminUpdate: {
|
|
127
|
+
hidden: true;
|
|
128
|
+
};
|
|
129
|
+
adminDelete: {
|
|
130
|
+
hidden: true;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
}>;
|
|
134
|
+
export type ApiKeysCrud = CrudTypeOf<typeof apiKeysCrud>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createCrud } from "../../crud";
|
|
2
|
+
import { yupBoolean, yupMixed, yupNumber, yupObject, yupString } from "../../schema-fields";
|
|
3
|
+
const baseApiKeysReadSchema = yupObject({
|
|
4
|
+
id: yupString().required(),
|
|
5
|
+
description: yupString().required(),
|
|
6
|
+
expires_at_millis: yupNumber().required(),
|
|
7
|
+
manually_revoked_at_millis: yupNumber().optional(),
|
|
8
|
+
created_at_millis: yupNumber().required(),
|
|
9
|
+
});
|
|
10
|
+
// Used for the result of the create endpoint
|
|
11
|
+
export const apiKeysCreateInputSchema = yupObject({
|
|
12
|
+
description: yupString().required(),
|
|
13
|
+
expires_at_millis: yupNumber().required(),
|
|
14
|
+
has_publishable_client_key: yupBoolean().required(),
|
|
15
|
+
has_secret_server_key: yupBoolean().required(),
|
|
16
|
+
has_super_secret_admin_key: yupBoolean().required(),
|
|
17
|
+
});
|
|
18
|
+
export const apiKeysCreateOutputSchema = baseApiKeysReadSchema.concat(yupObject({
|
|
19
|
+
publishable_client_key: yupString().optional(),
|
|
20
|
+
secret_server_key: yupString().optional(),
|
|
21
|
+
super_secret_admin_key: yupString().optional(),
|
|
22
|
+
}).required());
|
|
23
|
+
// Used for list, read and update endpoints after the initial creation
|
|
24
|
+
export const apiKeysCrudAdminObfuscatedReadSchema = baseApiKeysReadSchema.concat(yupObject({
|
|
25
|
+
publishable_client_key: yupObject({
|
|
26
|
+
last_four: yupString().required(),
|
|
27
|
+
}).optional(),
|
|
28
|
+
secret_server_key: yupObject({
|
|
29
|
+
last_four: yupString().required(),
|
|
30
|
+
}).optional(),
|
|
31
|
+
super_secret_admin_key: yupObject({
|
|
32
|
+
last_four: yupString().required(),
|
|
33
|
+
}).optional(),
|
|
34
|
+
}));
|
|
35
|
+
export const apiKeysCrudAdminUpdateSchema = yupObject({
|
|
36
|
+
description: yupString().optional(),
|
|
37
|
+
revoked: yupBoolean().oneOf([true]).optional(),
|
|
38
|
+
}).required();
|
|
39
|
+
export const apiKeysCrudAdminDeleteSchema = yupMixed();
|
|
40
|
+
export const apiKeysCrud = createCrud({
|
|
41
|
+
adminReadSchema: apiKeysCrudAdminObfuscatedReadSchema,
|
|
42
|
+
adminUpdateSchema: apiKeysCrudAdminUpdateSchema,
|
|
43
|
+
adminDeleteSchema: apiKeysCrudAdminDeleteSchema,
|
|
44
|
+
docs: {
|
|
45
|
+
adminList: {
|
|
46
|
+
hidden: true,
|
|
47
|
+
},
|
|
48
|
+
adminRead: {
|
|
49
|
+
hidden: true,
|
|
50
|
+
},
|
|
51
|
+
adminCreate: {
|
|
52
|
+
hidden: true,
|
|
53
|
+
},
|
|
54
|
+
adminUpdate: {
|
|
55
|
+
hidden: true,
|
|
56
|
+
},
|
|
57
|
+
adminDelete: {
|
|
58
|
+
hidden: true,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|