@stackframe/stack-shared 2.6.27 → 2.6.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @stackframe/stack-shared
2
2
 
3
+ ## 2.6.28
4
+
5
+ ### Patch Changes
6
+
7
+ - Bugfixes
8
+ - @stackframe/stack-sc@2.6.28
9
+
3
10
  ## 2.6.27
4
11
 
5
12
  ### Patch Changes
@@ -395,5 +395,8 @@ export declare const KnownErrors: {
395
395
  OAuthProviderAccessDenied: KnownErrorConstructor<KnownError & KnownErrorBrand<"OAUTH_PROVIDER_ACCESS_DENIED">, []> & {
396
396
  errorCode: "OAUTH_PROVIDER_ACCESS_DENIED";
397
397
  };
398
+ ContactChannelAlreadyUsedForAuthBySomeoneElse: KnownErrorConstructor<KnownError & KnownErrorBrand<"CONTACT_CHANNEL_ALREADY_USED_FOR_AUTH_BY_SOMEONE_ELSE">, [type: "email"]> & {
399
+ errorCode: "CONTACT_CHANNEL_ALREADY_USED_FOR_AUTH_BY_SOMEONE_ELSE";
400
+ };
398
401
  };
399
402
  export {};
@@ -558,6 +558,11 @@ const OAuthProviderAccessDenied = createKnownErrorConstructor(KnownError, "OAUTH
558
558
  400,
559
559
  "The OAuth provider denied access to the user.",
560
560
  ], () => []);
561
+ const ContactChannelAlreadyUsedForAuthBySomeoneElse = createKnownErrorConstructor(KnownError, "CONTACT_CHANNEL_ALREADY_USED_FOR_AUTH_BY_SOMEONE_ELSE", (type) => [
562
+ 400,
563
+ `This ${type} is already used for authentication by another account.`,
564
+ { type },
565
+ ], (json) => [json.type]);
561
566
  export const KnownErrors = {
562
567
  UnsupportedError,
563
568
  BodyParsingError,
@@ -650,6 +655,7 @@ export const KnownErrors = {
650
655
  InvalidAuthorizationCode,
651
656
  TeamPermissionNotFound,
652
657
  OAuthProviderAccessDenied,
658
+ ContactChannelAlreadyUsedForAuthBySomeoneElse,
653
659
  };
654
660
  // ensure that all known error codes are unique
655
661
  const knownErrorCodes = new Set();
@@ -296,7 +296,7 @@ export const userPasswordHashMutationSchema = yupString()
296
296
  .meta({ openapiField: { description: 'If `password` is not given, sets the user\'s password hash to the given string in Modular Crypt Format (ex.: `$2a$10$VIhIOofSMqGdGlL4wzE//e.77dAQGqNtF/1dT7bqCrVtQuInWy2qi`). Doing so revokes all current sessions.' } }); // we don't set an exampleValue here because it's exclusive with the password field and having both would break the generated example
297
297
  export const userTotpSecretMutationSchema = base64Schema.nullable().meta({ openapiField: { description: 'Enables 2FA and sets a TOTP secret for the user. Set to null to disable 2FA.', exampleValue: 'dG90cC1zZWNyZXQ=' } });
298
298
  // Auth
299
- export const signInEmailSchema = emailSchema.meta({ openapiField: { description: 'The email to sign in with.', exampleValue: 'johndoe@example.com' } });
299
+ export const signInEmailSchema = strictEmailSchema(undefined).meta({ openapiField: { description: 'The email to sign in with.', exampleValue: 'johndoe@example.com' } });
300
300
  export const emailOtpSignInCallbackUrlSchema = urlSchema.meta({ openapiField: { description: 'The base callback URL to construct the magic link from. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/auth/otp/sign-in` endpoint.', exampleValue: 'https://example.com/handler/magic-link-callback' } });
301
301
  export const emailVerificationCallbackUrlSchema = urlSchema.meta({ openapiField: { description: 'The base callback URL to construct a verification link for the verification e-mail. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/contact-channels/verify` endpoint.', exampleValue: 'https://example.com/handler/email-verification' } });
302
302
  export const accessTokenResponseSchema = yupString().meta({ openapiField: { description: 'Short-lived access token that can be used to authenticate the user', exampleValue: 'eyJhmMiJB2TO...diI4QT' } });
@@ -105,7 +105,7 @@ export function runAsynchronouslyWithAlert(...args) {
105
105
  return runAsynchronously(args[0], {
106
106
  ...args[1],
107
107
  onError: error => {
108
- alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === "development" ? `check the browser console for the full error. ${error}` : "report this to the developer."}\n\n${error}`);
108
+ alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === "development" ? `check the browser console for the full error.` : "report this to the developer."}\n\n${error}`);
109
109
  args[1]?.onError?.(error);
110
110
  },
111
111
  }, ...args.slice(2));
@@ -116,9 +116,9 @@ export function runAsynchronously(promiseOrFunc, options = {}) {
116
116
  }
117
117
  const duringError = new Error();
118
118
  promiseOrFunc?.catch(error => {
119
+ options.onError?.(error);
119
120
  const newError = new StackAssertionError("Uncaught error in asynchronous function: " + error.toString(), { cause: error });
120
121
  concatStacktraces(newError, duringError);
121
- options.onError?.(newError);
122
122
  if (!options.noErrorLogging) {
123
123
  captureError("runAsynchronously", newError);
124
124
  }
@@ -1,3 +1,4 @@
1
+ export declare function createUrlIfValid(...args: ConstructorParameters<typeof URL>): URL | null;
1
2
  export declare function isLocalhost(urlOrString: string | URL): boolean;
2
3
  export declare function isRelative(url: string): boolean;
3
4
  export declare function getRelativePart(url: URL): string;
@@ -1,6 +1,16 @@
1
1
  import { generateSecureRandomString } from "./crypto";
2
+ export function createUrlIfValid(...args) {
3
+ try {
4
+ return new URL(...args);
5
+ }
6
+ catch (e) {
7
+ return null;
8
+ }
9
+ }
2
10
  export function isLocalhost(urlOrString) {
3
- const url = new URL(urlOrString);
11
+ const url = createUrlIfValid(urlOrString);
12
+ if (!url)
13
+ return false;
4
14
  if (url.hostname === "localhost" || url.hostname.endsWith(".localhost"))
5
15
  return true;
6
16
  if (url.hostname.match(/^127\.\d+\.\d+\.\d+$/))
@@ -9,7 +19,9 @@ export function isLocalhost(urlOrString) {
9
19
  }
10
20
  export function isRelative(url) {
11
21
  const randomDomain = `${generateSecureRandomString()}.stack-auth.example.com`;
12
- const u = new URL(url, `https://${randomDomain}`);
22
+ const u = createUrlIfValid(url, `https://${randomDomain}`);
23
+ if (!u)
24
+ return false;
13
25
  if (u.host !== randomDomain)
14
26
  return false;
15
27
  if (u.protocol !== "https:")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.6.27",
3
+ "version": "2.6.28",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -50,7 +50,7 @@
50
50
  "oauth4webapi": "^2.10.3",
51
51
  "semver": "^7.6.3",
52
52
  "uuid": "^9.0.1",
53
- "@stackframe/stack-sc": "2.6.27"
53
+ "@stackframe/stack-sc": "2.6.28"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@simplewebauthn/types": "^11.0.0",