@account-kit/signer 4.30.0 → 4.31.1

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.
@@ -320,6 +320,7 @@ export type AlchemySignerParams = z.input<typeof AlchemySignerParamsSchema>;
320
320
  * A SmartAccountSigner that can be used with any SmartContractAccount
321
321
  */
322
322
  export declare class AlchemyWebSigner extends BaseAlchemySigner<AlchemySignerWebClient> {
323
+ private static replaceStateFilterInstalled;
323
324
  /**
324
325
  * Initializes an instance with the provided Alchemy signer parameters after parsing them with a schema.
325
326
  *
@@ -47,7 +47,7 @@ export class AlchemyWebSigner extends BaseAlchemySigner {
47
47
  else {
48
48
  client = params_.client;
49
49
  }
50
- const { emailBundle, oauthBundle, oauthOrgId, oauthError, idToken, isSignup, } = getAndRemoveQueryParams({
50
+ const qpStructure = {
51
51
  emailBundle: "bundle",
52
52
  // We don't need this, but we still want to remove it from the URL.
53
53
  emailOrgId: "orgId",
@@ -56,7 +56,12 @@ export class AlchemyWebSigner extends BaseAlchemySigner {
56
56
  oauthError: "alchemy-error",
57
57
  idToken: "alchemy-id-token",
58
58
  isSignup: "aa-is-signup",
59
- });
59
+ };
60
+ const { emailBundle, oauthBundle, oauthOrgId, oauthError, idToken, isSignup, } = getAndRemoveQueryParams(qpStructure);
61
+ if (!AlchemyWebSigner.replaceStateFilterInstalled) {
62
+ installReplaceStateFilter(Object.values(qpStructure));
63
+ AlchemyWebSigner.replaceStateFilterInstalled = true;
64
+ }
60
65
  const initialError = oauthError != null
61
66
  ? { name: "OauthError", message: oauthError }
62
67
  : undefined;
@@ -81,6 +86,48 @@ export class AlchemyWebSigner extends BaseAlchemySigner {
81
86
  }
82
87
  }
83
88
  }
89
+ Object.defineProperty(AlchemyWebSigner, "replaceStateFilterInstalled", {
90
+ enumerable: true,
91
+ configurable: true,
92
+ writable: true,
93
+ value: false
94
+ });
95
+ /**
96
+ * Overrides `window.history.replaceState` to remove the specified query params from target URLs.
97
+ *
98
+ * @param {string[]} qpToRemove The query params to remove from target URLs.
99
+ */
100
+ function installReplaceStateFilter(qpToRemove) {
101
+ const originalReplaceState = window.history.replaceState;
102
+ const processUrl = (src) => {
103
+ if (!src) {
104
+ return src;
105
+ }
106
+ try {
107
+ const url = new URL(src, document.baseURI);
108
+ const originalSearch = url.search;
109
+ qpToRemove.forEach((qp) => url.searchParams.delete(qp));
110
+ if (originalSearch === url.search)
111
+ return src;
112
+ console.log("[Alchemy] filtered query params from URL");
113
+ return url;
114
+ }
115
+ catch (e) {
116
+ console.log("[Alchemy] failed to process URL in state filter", e);
117
+ return src;
118
+ }
119
+ };
120
+ window.history.replaceState = function (...args) {
121
+ const [state, unused, url] = args;
122
+ const result = originalReplaceState.apply(this, [
123
+ state,
124
+ unused,
125
+ processUrl(url),
126
+ ]);
127
+ return result;
128
+ };
129
+ console.log("[Alchemy] installed window.history.replaceState interceptor");
130
+ }
84
131
  /**
85
132
  * Reads and removes the specified query params from the URL.
86
133
  *
@@ -1 +1 @@
1
- {"version":3,"file":"signer.js","sourceRoot":"","sources":["../../src/signer.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport { BaseAlchemySigner } from \"./base.js\";\nimport {\n AlchemySignerClientParamsSchema,\n AlchemySignerWebClient,\n} from \"./client/index.js\";\nimport type {\n CredentialCreationOptionOverrides,\n VerifyMfaParams,\n} from \"./client/types.js\";\nimport { SessionManagerParamsSchema } from \"./session/manager.js\";\n\nexport type AuthParams =\n | {\n type: \"email\";\n email: string;\n /** @deprecated This option will be overriden by dashboard settings. Please use the dashboard settings instead. This option will be removed in a future release. */\n emailMode?: \"magicLink\" | \"otp\";\n redirectParams?: URLSearchParams;\n multiFactors?: VerifyMfaParams[];\n }\n | { type: \"email\"; bundle: string; orgId?: string; isNewUser?: boolean }\n | {\n type: \"passkey\";\n email: string;\n creationOpts?: CredentialCreationOptionOverrides;\n }\n | {\n type: \"passkey\";\n createNew: false;\n }\n | {\n type: \"passkey\";\n createNew: true;\n username: string;\n creationOpts?: CredentialCreationOptionOverrides;\n }\n | ({\n type: \"oauth\";\n scope?: string;\n claims?: string;\n otherParameters?: Record<string, string>;\n } & OauthProviderConfig &\n OauthRedirectConfig)\n | {\n type: \"oauthReturn\";\n bundle: string;\n orgId: string;\n idToken: string;\n isNewUser?: boolean;\n }\n | {\n type: \"otp\";\n otpCode: string;\n multiFactors?: VerifyMfaParams[];\n };\n\nexport type OauthProviderConfig =\n | {\n authProviderId: \"auth0\";\n isCustomProvider?: false;\n auth0Connection?: string;\n }\n | {\n authProviderId: KnownAuthProvider;\n isCustomProvider?: false;\n auth0Connection?: never;\n }\n | {\n authProviderId: string;\n isCustomProvider: true;\n auth0Connection?: never;\n };\n\nexport type OauthRedirectConfig =\n | { mode: \"redirect\"; redirectUrl: string }\n | { mode: \"popup\"; redirectUrl?: never };\n\nexport type KnownAuthProvider =\n | \"google\"\n | \"apple\"\n | \"facebook\"\n | \"twitch\"\n | \"auth0\";\n\nexport type OauthMode = \"redirect\" | \"popup\";\n\nexport const AlchemySignerParamsSchema = z\n .object({\n client: z\n .custom<AlchemySignerWebClient>()\n .or(AlchemySignerClientParamsSchema),\n })\n .extend({\n sessionConfig: SessionManagerParamsSchema.omit({\n client: true,\n }).optional(),\n });\n\nexport type AlchemySignerParams = z.input<typeof AlchemySignerParamsSchema>;\n\n/**\n * A SmartAccountSigner that can be used with any SmartContractAccount\n */\nexport class AlchemyWebSigner extends BaseAlchemySigner<AlchemySignerWebClient> {\n /**\n * Initializes an instance with the provided Alchemy signer parameters after parsing them with a schema.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n * ```\n *\n * @param {AlchemySignerParams} params The parameters for the Alchemy signer, including the client and session configuration\n */\n\n constructor(params: AlchemySignerParams) {\n const { sessionConfig, ...params_ } =\n AlchemySignerParamsSchema.parse(params);\n\n let client: AlchemySignerWebClient;\n if (\"connection\" in params_.client) {\n client = new AlchemySignerWebClient(params_.client);\n } else {\n client = params_.client;\n }\n const {\n emailBundle,\n oauthBundle,\n oauthOrgId,\n oauthError,\n idToken,\n isSignup,\n } = getAndRemoveQueryParams({\n emailBundle: \"bundle\",\n // We don't need this, but we still want to remove it from the URL.\n emailOrgId: \"orgId\",\n oauthBundle: \"alchemy-bundle\",\n oauthOrgId: \"alchemy-org-id\",\n oauthError: \"alchemy-error\",\n idToken: \"alchemy-id-token\",\n isSignup: \"aa-is-signup\",\n });\n\n const initialError =\n oauthError != null\n ? { name: \"OauthError\", message: oauthError }\n : undefined;\n\n super({ client, sessionConfig, initialError });\n\n const isNewUser = isSignup === \"true\";\n\n this.signerType = \"alchemy-signer\";\n\n if (emailBundle) {\n this.authenticate({\n type: \"email\",\n bundle: emailBundle,\n isNewUser,\n });\n } else if (oauthBundle && oauthOrgId && idToken) {\n this.authenticate({\n type: \"oauthReturn\",\n bundle: oauthBundle,\n orgId: oauthOrgId,\n idToken,\n isNewUser,\n });\n }\n }\n}\n\n/**\n * Reads and removes the specified query params from the URL.\n *\n * @param {T} keys object whose values are the query parameter keys to read and\n * remove\n * @returns {{ [K in keyof T]: string | undefined }} object with the same keys\n * as the input whose values are the values of the query params.\n */\nfunction getAndRemoveQueryParams<T extends Record<string, string>>(\n keys: T\n): { [K in keyof T]: string | undefined } {\n const url = new URL(window.location.href);\n const result: Record<string, string | undefined> = {};\n let foundQueryParam = false;\n for (const [key, param] of Object.entries(keys)) {\n const value = url.searchParams.get(param) ?? undefined;\n foundQueryParam ||= value != null;\n result[key] = value;\n url.searchParams.delete(param);\n }\n if (foundQueryParam) {\n window.history.replaceState(window.history.state, \"\", url.toString());\n }\n return result as { [K in keyof T]: string | undefined };\n}\n"]}
1
+ {"version":3,"file":"signer.js","sourceRoot":"","sources":["../../src/signer.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport { BaseAlchemySigner } from \"./base.js\";\nimport {\n AlchemySignerClientParamsSchema,\n AlchemySignerWebClient,\n} from \"./client/index.js\";\nimport type {\n CredentialCreationOptionOverrides,\n VerifyMfaParams,\n} from \"./client/types.js\";\nimport { SessionManagerParamsSchema } from \"./session/manager.js\";\n\nexport type AuthParams =\n | {\n type: \"email\";\n email: string;\n /** @deprecated This option will be overriden by dashboard settings. Please use the dashboard settings instead. This option will be removed in a future release. */\n emailMode?: \"magicLink\" | \"otp\";\n redirectParams?: URLSearchParams;\n multiFactors?: VerifyMfaParams[];\n }\n | { type: \"email\"; bundle: string; orgId?: string; isNewUser?: boolean }\n | {\n type: \"passkey\";\n email: string;\n creationOpts?: CredentialCreationOptionOverrides;\n }\n | {\n type: \"passkey\";\n createNew: false;\n }\n | {\n type: \"passkey\";\n createNew: true;\n username: string;\n creationOpts?: CredentialCreationOptionOverrides;\n }\n | ({\n type: \"oauth\";\n scope?: string;\n claims?: string;\n otherParameters?: Record<string, string>;\n } & OauthProviderConfig &\n OauthRedirectConfig)\n | {\n type: \"oauthReturn\";\n bundle: string;\n orgId: string;\n idToken: string;\n isNewUser?: boolean;\n }\n | {\n type: \"otp\";\n otpCode: string;\n multiFactors?: VerifyMfaParams[];\n };\n\nexport type OauthProviderConfig =\n | {\n authProviderId: \"auth0\";\n isCustomProvider?: false;\n auth0Connection?: string;\n }\n | {\n authProviderId: KnownAuthProvider;\n isCustomProvider?: false;\n auth0Connection?: never;\n }\n | {\n authProviderId: string;\n isCustomProvider: true;\n auth0Connection?: never;\n };\n\nexport type OauthRedirectConfig =\n | { mode: \"redirect\"; redirectUrl: string }\n | { mode: \"popup\"; redirectUrl?: never };\n\nexport type KnownAuthProvider =\n | \"google\"\n | \"apple\"\n | \"facebook\"\n | \"twitch\"\n | \"auth0\";\n\nexport type OauthMode = \"redirect\" | \"popup\";\n\nexport const AlchemySignerParamsSchema = z\n .object({\n client: z\n .custom<AlchemySignerWebClient>()\n .or(AlchemySignerClientParamsSchema),\n })\n .extend({\n sessionConfig: SessionManagerParamsSchema.omit({\n client: true,\n }).optional(),\n });\n\nexport type AlchemySignerParams = z.input<typeof AlchemySignerParamsSchema>;\n\n/**\n * A SmartAccountSigner that can be used with any SmartContractAccount\n */\nexport class AlchemyWebSigner extends BaseAlchemySigner<AlchemySignerWebClient> {\n private static replaceStateFilterInstalled = false;\n /**\n * Initializes an instance with the provided Alchemy signer parameters after parsing them with a schema.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n * ```\n *\n * @param {AlchemySignerParams} params The parameters for the Alchemy signer, including the client and session configuration\n */\n\n constructor(params: AlchemySignerParams) {\n const { sessionConfig, ...params_ } =\n AlchemySignerParamsSchema.parse(params);\n\n let client: AlchemySignerWebClient;\n if (\"connection\" in params_.client) {\n client = new AlchemySignerWebClient(params_.client);\n } else {\n client = params_.client;\n }\n\n const qpStructure = {\n emailBundle: \"bundle\",\n // We don't need this, but we still want to remove it from the URL.\n emailOrgId: \"orgId\",\n oauthBundle: \"alchemy-bundle\",\n oauthOrgId: \"alchemy-org-id\",\n oauthError: \"alchemy-error\",\n idToken: \"alchemy-id-token\",\n isSignup: \"aa-is-signup\",\n };\n\n const {\n emailBundle,\n oauthBundle,\n oauthOrgId,\n oauthError,\n idToken,\n isSignup,\n } = getAndRemoveQueryParams(qpStructure);\n\n if (!AlchemyWebSigner.replaceStateFilterInstalled) {\n installReplaceStateFilter(Object.values(qpStructure));\n AlchemyWebSigner.replaceStateFilterInstalled = true;\n }\n\n const initialError =\n oauthError != null\n ? { name: \"OauthError\", message: oauthError }\n : undefined;\n\n super({ client, sessionConfig, initialError });\n\n const isNewUser = isSignup === \"true\";\n\n this.signerType = \"alchemy-signer\";\n\n if (emailBundle) {\n this.authenticate({\n type: \"email\",\n bundle: emailBundle,\n isNewUser,\n });\n } else if (oauthBundle && oauthOrgId && idToken) {\n this.authenticate({\n type: \"oauthReturn\",\n bundle: oauthBundle,\n orgId: oauthOrgId,\n idToken,\n isNewUser,\n });\n }\n }\n}\n\n/**\n * Overrides `window.history.replaceState` to remove the specified query params from target URLs.\n *\n * @param {string[]} qpToRemove The query params to remove from target URLs.\n */\nfunction installReplaceStateFilter(qpToRemove: string[]) {\n const originalReplaceState = window.history.replaceState;\n\n const processUrl = (src: string | URL | undefined | null) => {\n if (!src) {\n return src;\n }\n\n try {\n const url = new URL(src, document.baseURI);\n const originalSearch = url.search;\n\n qpToRemove.forEach((qp) => url.searchParams.delete(qp));\n if (originalSearch === url.search) return src;\n\n console.log(\"[Alchemy] filtered query params from URL\");\n return url;\n } catch (e) {\n console.log(\"[Alchemy] failed to process URL in state filter\", e);\n return src;\n }\n };\n\n window.history.replaceState = function (...args) {\n const [state, unused, url] = args;\n\n const result = originalReplaceState.apply(this, [\n state,\n unused,\n processUrl(url),\n ]);\n\n return result;\n };\n\n console.log(\"[Alchemy] installed window.history.replaceState interceptor\");\n}\n\n/**\n * Reads and removes the specified query params from the URL.\n *\n * @param {T} keys object whose values are the query parameter keys to read and\n * remove\n * @returns {{ [K in keyof T]: string | undefined }} object with the same keys\n * as the input whose values are the values of the query params.\n */\nfunction getAndRemoveQueryParams<T extends Record<string, string>>(\n keys: T\n): { [K in keyof T]: string | undefined } {\n const url = new URL(window.location.href);\n const result: Record<string, string | undefined> = {};\n let foundQueryParam = false;\n for (const [key, param] of Object.entries(keys)) {\n const value = url.searchParams.get(param) ?? undefined;\n foundQueryParam ||= value != null;\n result[key] = value;\n url.searchParams.delete(param);\n }\n if (foundQueryParam) {\n window.history.replaceState(window.history.state, \"\", url.toString());\n }\n return result as { [K in keyof T]: string | undefined };\n}\n"]}
@@ -1 +1 @@
1
- export declare const VERSION = "4.30.0";
1
+ export declare const VERSION = "4.31.1";
@@ -1,4 +1,4 @@
1
1
  // This file is autogenerated by inject-version.ts. Any changes will be
2
2
  // overwritten on commit!
3
- export const VERSION = "4.30.0";
3
+ export const VERSION = "4.31.1";
4
4
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,yBAAyB;AACzB,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC","sourcesContent":["// This file is autogenerated by inject-version.ts. Any changes will be\n// overwritten on commit!\nexport const VERSION = \"4.30.0\";\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,yBAAyB;AACzB,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC","sourcesContent":["// This file is autogenerated by inject-version.ts. Any changes will be\n// overwritten on commit!\nexport const VERSION = \"4.31.1\";\n"]}
@@ -320,6 +320,7 @@ export type AlchemySignerParams = z.input<typeof AlchemySignerParamsSchema>;
320
320
  * A SmartAccountSigner that can be used with any SmartContractAccount
321
321
  */
322
322
  export declare class AlchemyWebSigner extends BaseAlchemySigner<AlchemySignerWebClient> {
323
+ private static replaceStateFilterInstalled;
323
324
  /**
324
325
  * Initializes an instance with the provided Alchemy signer parameters after parsing them with a schema.
325
326
  *
@@ -1 +1 @@
1
- {"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../../src/signer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../../src/signer.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "4.30.0";
1
+ export declare const VERSION = "4.31.1";
2
2
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@account-kit/signer",
3
- "version": "4.30.0",
3
+ "version": "4.31.1",
4
4
  "description": "Core interfaces and clients for interfacing with the Alchemy Signer API",
5
5
  "author": "Alchemy",
6
6
  "license": "MIT",
@@ -51,8 +51,8 @@
51
51
  "vitest": "^2.0.4"
52
52
  },
53
53
  "dependencies": {
54
- "@aa-sdk/core": "^4.30.0",
55
- "@account-kit/logging": "^4.30.0",
54
+ "@aa-sdk/core": "^4.31.1",
55
+ "@account-kit/logging": "^4.31.1",
56
56
  "@solana/web3.js": "^1.98.0",
57
57
  "@turnkey/http": "^2.6.2",
58
58
  "@turnkey/iframe-stamper": "^1.0.0",
@@ -78,5 +78,5 @@
78
78
  "url": "https://github.com/alchemyplatform/aa-sdk/issues"
79
79
  },
80
80
  "homepage": "https://github.com/alchemyplatform/aa-sdk#readme",
81
- "gitHead": "e58090cc00df11f6c6ccfd140088b28a67629fee"
81
+ "gitHead": "0b89a300a2ab7170e99769599000e2e22bcb2b7c"
82
82
  }
package/src/signer.ts CHANGED
@@ -103,6 +103,7 @@ export type AlchemySignerParams = z.input<typeof AlchemySignerParamsSchema>;
103
103
  * A SmartAccountSigner that can be used with any SmartContractAccount
104
104
  */
105
105
  export class AlchemyWebSigner extends BaseAlchemySigner<AlchemySignerWebClient> {
106
+ private static replaceStateFilterInstalled = false;
106
107
  /**
107
108
  * Initializes an instance with the provided Alchemy signer parameters after parsing them with a schema.
108
109
  *
@@ -135,14 +136,8 @@ export class AlchemyWebSigner extends BaseAlchemySigner<AlchemySignerWebClient>
135
136
  } else {
136
137
  client = params_.client;
137
138
  }
138
- const {
139
- emailBundle,
140
- oauthBundle,
141
- oauthOrgId,
142
- oauthError,
143
- idToken,
144
- isSignup,
145
- } = getAndRemoveQueryParams({
139
+
140
+ const qpStructure = {
146
141
  emailBundle: "bundle",
147
142
  // We don't need this, but we still want to remove it from the URL.
148
143
  emailOrgId: "orgId",
@@ -151,7 +146,21 @@ export class AlchemyWebSigner extends BaseAlchemySigner<AlchemySignerWebClient>
151
146
  oauthError: "alchemy-error",
152
147
  idToken: "alchemy-id-token",
153
148
  isSignup: "aa-is-signup",
154
- });
149
+ };
150
+
151
+ const {
152
+ emailBundle,
153
+ oauthBundle,
154
+ oauthOrgId,
155
+ oauthError,
156
+ idToken,
157
+ isSignup,
158
+ } = getAndRemoveQueryParams(qpStructure);
159
+
160
+ if (!AlchemyWebSigner.replaceStateFilterInstalled) {
161
+ installReplaceStateFilter(Object.values(qpStructure));
162
+ AlchemyWebSigner.replaceStateFilterInstalled = true;
163
+ }
155
164
 
156
165
  const initialError =
157
166
  oauthError != null
@@ -182,6 +191,49 @@ export class AlchemyWebSigner extends BaseAlchemySigner<AlchemySignerWebClient>
182
191
  }
183
192
  }
184
193
 
194
+ /**
195
+ * Overrides `window.history.replaceState` to remove the specified query params from target URLs.
196
+ *
197
+ * @param {string[]} qpToRemove The query params to remove from target URLs.
198
+ */
199
+ function installReplaceStateFilter(qpToRemove: string[]) {
200
+ const originalReplaceState = window.history.replaceState;
201
+
202
+ const processUrl = (src: string | URL | undefined | null) => {
203
+ if (!src) {
204
+ return src;
205
+ }
206
+
207
+ try {
208
+ const url = new URL(src, document.baseURI);
209
+ const originalSearch = url.search;
210
+
211
+ qpToRemove.forEach((qp) => url.searchParams.delete(qp));
212
+ if (originalSearch === url.search) return src;
213
+
214
+ console.log("[Alchemy] filtered query params from URL");
215
+ return url;
216
+ } catch (e) {
217
+ console.log("[Alchemy] failed to process URL in state filter", e);
218
+ return src;
219
+ }
220
+ };
221
+
222
+ window.history.replaceState = function (...args) {
223
+ const [state, unused, url] = args;
224
+
225
+ const result = originalReplaceState.apply(this, [
226
+ state,
227
+ unused,
228
+ processUrl(url),
229
+ ]);
230
+
231
+ return result;
232
+ };
233
+
234
+ console.log("[Alchemy] installed window.history.replaceState interceptor");
235
+ }
236
+
185
237
  /**
186
238
  * Reads and removes the specified query params from the URL.
187
239
  *
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file is autogenerated by inject-version.ts. Any changes will be
2
2
  // overwritten on commit!
3
- export const VERSION = "4.30.0";
3
+ export const VERSION = "4.31.1";