@stackframe/stack-shared 2.8.43 → 2.8.45

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/apps/apps-config.d.mts +52 -31
  3. package/dist/apps/apps-config.d.ts +52 -31
  4. package/dist/apps/apps-config.js +54 -32
  5. package/dist/apps/apps-config.js.map +1 -1
  6. package/dist/config/schema.d.mts +159 -159
  7. package/dist/config/schema.d.ts +159 -159
  8. package/dist/config/schema.js +1 -1
  9. package/dist/config/schema.js.map +1 -1
  10. package/dist/esm/apps/apps-config.js +52 -31
  11. package/dist/esm/apps/apps-config.js.map +1 -1
  12. package/dist/esm/config/schema.js +1 -1
  13. package/dist/esm/config/schema.js.map +1 -1
  14. package/dist/esm/interface/client-interface.js +18 -16
  15. package/dist/esm/interface/client-interface.js.map +1 -1
  16. package/dist/esm/utils/caches.js +6 -2
  17. package/dist/esm/utils/caches.js.map +1 -1
  18. package/dist/esm/utils/globals.js +9 -1
  19. package/dist/esm/utils/globals.js.map +1 -1
  20. package/dist/esm/utils/react.js +12 -6
  21. package/dist/esm/utils/react.js.map +1 -1
  22. package/dist/esm/utils/regex.js +13 -0
  23. package/dist/esm/utils/regex.js.map +1 -0
  24. package/dist/esm/utils/strings.js +1 -1
  25. package/dist/esm/utils/strings.js.map +1 -1
  26. package/dist/esm/utils/strings.nicify.test.js +6 -0
  27. package/dist/esm/utils/strings.nicify.test.js.map +1 -1
  28. package/dist/esm/utils/urls.js +10 -0
  29. package/dist/esm/utils/urls.js.map +1 -1
  30. package/dist/index.d.mts +1 -1
  31. package/dist/index.d.ts +1 -1
  32. package/dist/interface/admin-interface.d.mts +1 -1
  33. package/dist/interface/admin-interface.d.ts +1 -1
  34. package/dist/interface/client-interface.d.mts +1 -1
  35. package/dist/interface/client-interface.d.ts +1 -1
  36. package/dist/interface/client-interface.js +18 -16
  37. package/dist/interface/client-interface.js.map +1 -1
  38. package/dist/interface/server-interface.d.mts +1 -1
  39. package/dist/interface/server-interface.d.ts +1 -1
  40. package/dist/utils/caches.d.mts +4 -2
  41. package/dist/utils/caches.d.ts +4 -2
  42. package/dist/utils/caches.js +6 -2
  43. package/dist/utils/caches.js.map +1 -1
  44. package/dist/utils/globals.d.mts +3 -1
  45. package/dist/utils/globals.d.ts +3 -1
  46. package/dist/utils/globals.js +12 -2
  47. package/dist/utils/globals.js.map +1 -1
  48. package/dist/utils/react.d.mts +2 -1
  49. package/dist/utils/react.d.ts +2 -1
  50. package/dist/utils/react.js +13 -6
  51. package/dist/utils/react.js.map +1 -1
  52. package/dist/utils/regex.d.mts +3 -0
  53. package/dist/utils/regex.d.ts +3 -0
  54. package/dist/utils/regex.js +38 -0
  55. package/dist/utils/regex.js.map +1 -0
  56. package/dist/utils/strings.js +1 -1
  57. package/dist/utils/strings.js.map +1 -1
  58. package/dist/utils/strings.nicify.test.js +6 -0
  59. package/dist/utils/strings.nicify.test.js.map +1 -1
  60. package/dist/utils/urls.d.mts +3 -1
  61. package/dist/utils/urls.d.ts +3 -1
  62. package/dist/utils/urls.js +12 -0
  63. package/dist/utils/urls.js.map +1 -1
  64. package/package.json +1 -1
@@ -135,6 +135,12 @@ var import_strings = require("./strings.js");
135
135
  (0, import_vitest.test)("multiline with trailing newline", () => {
136
136
  (0, import_vitest.expect)((0, import_strings.nicify)("line1\nline2\n")).toBe('deindent`\n line1\n line2\n` + "\\n"');
137
137
  });
138
+ (0, import_vitest.test)("multiline with dollar sign", () => {
139
+ (0, import_vitest.expect)((0, import_strings.nicify)("a\n$b\nc")).toBe("deindent`\n a\n $b\n c\n`");
140
+ });
141
+ (0, import_vitest.test)("multiline with dollar sign interpolation", () => {
142
+ (0, import_vitest.expect)((0, import_strings.nicify)("a\n${b\nc")).toBe("deindent`\n a\n \\${b\n c\n`");
143
+ });
138
144
  });
139
145
  (0, import_vitest.describe)("circular references", () => {
140
146
  (0, import_vitest.test)("object with self reference", () => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/strings.nicify.test.ts"],"sourcesContent":["import { describe, expect, test } from \"vitest\";\nimport { NicifyOptions, deindent, nicify } from \"./strings\";\n\ndescribe(\"nicify\", () => {\n describe(\"primitive values\", () => {\n test(\"numbers\", () => {\n expect(nicify(123)).toBe(\"123\");\n expect(nicify(123n)).toBe(\"123n\");\n });\n\n test(\"strings\", () => {\n expect(nicify(\"hello\")).toBe('\"hello\"');\n });\n\n test(\"booleans\", () => {\n expect(nicify(true)).toBe(\"true\");\n expect(nicify(false)).toBe(\"false\");\n });\n\n test(\"null and undefined\", () => {\n expect(nicify(null)).toBe(\"null\");\n expect(nicify(undefined)).toBe(\"undefined\");\n });\n\n test(\"symbols\", () => {\n expect(nicify(Symbol(\"test\"))).toBe(\"Symbol(test)\");\n });\n });\n\n describe(\"arrays\", () => {\n test(\"empty array\", () => {\n expect(nicify([])).toBe(\"[]\");\n });\n\n test(\"single-element array\", () => {\n expect(nicify([1])).toBe(\"[1]\");\n });\n\n test(\"single-element array with long content\", () => {\n expect(nicify([\"123123123123123\"])).toBe('[\"123123123123123\"]');\n });\n\n test(\"flat array\", () => {\n expect(nicify([1, 2, 3])).toBe(\"[1, 2, 3]\");\n });\n\n test(\"longer array\", () => {\n expect(nicify([10000, 2, 3])).toBe(deindent`\n [\n 10000,\n 2,\n 3,\n ]\n `);\n });\n\n test(\"nested array\", () => {\n expect(nicify([1, [2, 3]])).toBe(deindent`\n [\n 1,\n [2, 3],\n ]\n `);\n });\n });\n\n describe(\"objects\", () => {\n test(\"empty object\", () => {\n expect(nicify({})).toBe(\"{}\");\n });\n\n test(\"simple object\", () => {\n expect(nicify({ a: 1 })).toBe('{ \"a\": 1 }');\n });\n\n test(\"multiline object\", () => {\n expect(nicify({ a: 1, b: 2 })).toBe(deindent`\n {\n \"a\": 1,\n \"b\": 2,\n }\n `);\n });\n });\n\n describe(\"custom classes\", () => {\n test(\"class instance\", () => {\n class TestClass {\n constructor(public value: number) {}\n }\n expect(nicify(new TestClass(42))).toBe('TestClass { \"value\": 42 }');\n });\n });\n\n describe(\"built-in objects\", () => {\n test(\"URL\", () => {\n expect(nicify(new URL(\"https://example.com\"))).toBe('URL(\"https://example.com/\")');\n });\n\n test(\"TypedArrays\", () => {\n expect(nicify(new Uint8Array([1, 2, 3]))).toBe(\"Uint8Array([1,2,3])\");\n expect(nicify(new Int32Array([1, 2, 3]))).toBe(\"Int32Array([1,2,3])\");\n });\n\n test(\"Error objects\", () => {\n const error = new Error(\"test error\");\n const nicifiedError = nicify({ error });\n expect(nicifiedError).toMatch(new RegExp(deindent`\n ^\\{\n \"error\": Error: test error\n Stack:\n at (.|\\\\n)*\n \\}$\n `));\n });\n\n test(\"Error objects with cause and an extra property\", () => {\n const error = new Error(\"test error\", { cause: new Error(\"cause\") });\n (error as any).extra = \"something\";\n const nicifiedError = nicify(error, { lineIndent: \"--\" });\n expect(nicifiedError).toMatch(new RegExp(deindent`\n ^Error: test error\n --Stack:\n ----at (.|\\\\n)+\n --Extra properties: \\{ \"extra\": \"something\" \\}\n --Cause:\n ----Error: cause\n ------Stack:\n --------at (.|\\\\n)+$\n `));\n });\n\n test(\"Headers\", () => {\n const headers = new Headers();\n headers.append(\"Content-Type\", \"application/json\");\n headers.append(\"Accept\", \"text/plain\");\n expect(nicify(headers)).toBe(deindent`\n Headers {\n \"accept\": \"text/plain\",\n \"content-type\": \"application/json\",\n }`\n );\n });\n });\n\n describe(\"multiline strings\", () => {\n test(\"basic multiline\", () => {\n expect(nicify(\"line1\\nline2\")).toBe('deindent`\\n line1\\n line2\\n`');\n });\n\n test(\"multiline with trailing newline\", () => {\n expect(nicify(\"line1\\nline2\\n\")).toBe('deindent`\\n line1\\n line2\\n` + \"\\\\n\"');\n });\n });\n\n describe(\"circular references\", () => {\n test(\"object with self reference\", () => {\n const circular: any = { a: 1 };\n circular.self = circular;\n expect(nicify(circular)).toBe(deindent`\n {\n \"a\": 1,\n \"self\": Ref<value>,\n }`\n );\n });\n });\n\n describe(\"configuration options\", () => {\n test(\"maxDepth\", () => {\n const deep = { a: { b: { c: { d: { e: 1 } } } } };\n expect(nicify(deep, { maxDepth: 2 })).toBe('{ \"a\": { \"b\": { ... } } }');\n });\n\n test(\"lineIndent\", () => {\n expect(nicify({ a: 1, b: 2 }, { lineIndent: \" \" })).toBe(deindent`\n {\n \"a\": 1,\n \"b\": 2,\n }\n `);\n });\n\n test(\"hideFields\", () => {\n expect(nicify({ a: 1, b: 2, secret: \"hidden\" }, { hideFields: [\"secret\"] })).toBe(deindent`\n {\n \"a\": 1,\n \"b\": 2,\n <some fields may have been hidden>,\n }\n `);\n });\n });\n\n describe(\"custom overrides\", () => {\n test(\"override with custom type\", () => {\n expect(nicify({ type: \"special\" }, {\n overrides: ((value: unknown) => {\n if (typeof value === \"object\" && value && \"type\" in value && (value as any).type === \"special\") {\n return \"SPECIAL\";\n }\n return null;\n }) as NicifyOptions[\"overrides\"]\n })).toBe(\"SPECIAL\");\n });\n });\n\n describe(\"functions\", () => {\n test(\"named function\", () => {\n expect(nicify(function namedFunction() {})).toBe(\"function namedFunction(...) { ... }\");\n });\n\n test(\"arrow function\", () => {\n expect(nicify(() => {})).toBe(\"(...) => { ... }\");\n });\n });\n\n describe(\"Nicifiable interface\", () => {\n test(\"object implementing Nicifiable\", () => {\n const nicifiable = {\n value: 42,\n getNicifiableKeys() {\n return [\"value\"];\n },\n getNicifiedObjectExtraLines() {\n return [\"// custom comment\"];\n }\n };\n expect(nicify(nicifiable)).toBe(deindent`\n {\n \"value\": 42,\n // custom comment,\n }\n `);\n });\n });\n\n describe(\"unknown types\", () => {\n test(\"object without prototype\", () => {\n const unknownType = Object.create(null);\n unknownType.value = \"test\";\n expect(nicify(unknownType)).toBe('{ \"value\": \"test\" }');\n });\n });\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/utils/strings.nicify.test.ts"],"sourcesContent":["import { describe, expect, test } from \"vitest\";\nimport { NicifyOptions, deindent, nicify } from \"./strings\";\n\ndescribe(\"nicify\", () => {\n describe(\"primitive values\", () => {\n test(\"numbers\", () => {\n expect(nicify(123)).toBe(\"123\");\n expect(nicify(123n)).toBe(\"123n\");\n });\n\n test(\"strings\", () => {\n expect(nicify(\"hello\")).toBe('\"hello\"');\n });\n\n test(\"booleans\", () => {\n expect(nicify(true)).toBe(\"true\");\n expect(nicify(false)).toBe(\"false\");\n });\n\n test(\"null and undefined\", () => {\n expect(nicify(null)).toBe(\"null\");\n expect(nicify(undefined)).toBe(\"undefined\");\n });\n\n test(\"symbols\", () => {\n expect(nicify(Symbol(\"test\"))).toBe(\"Symbol(test)\");\n });\n });\n\n describe(\"arrays\", () => {\n test(\"empty array\", () => {\n expect(nicify([])).toBe(\"[]\");\n });\n\n test(\"single-element array\", () => {\n expect(nicify([1])).toBe(\"[1]\");\n });\n\n test(\"single-element array with long content\", () => {\n expect(nicify([\"123123123123123\"])).toBe('[\"123123123123123\"]');\n });\n\n test(\"flat array\", () => {\n expect(nicify([1, 2, 3])).toBe(\"[1, 2, 3]\");\n });\n\n test(\"longer array\", () => {\n expect(nicify([10000, 2, 3])).toBe(deindent`\n [\n 10000,\n 2,\n 3,\n ]\n `);\n });\n\n test(\"nested array\", () => {\n expect(nicify([1, [2, 3]])).toBe(deindent`\n [\n 1,\n [2, 3],\n ]\n `);\n });\n });\n\n describe(\"objects\", () => {\n test(\"empty object\", () => {\n expect(nicify({})).toBe(\"{}\");\n });\n\n test(\"simple object\", () => {\n expect(nicify({ a: 1 })).toBe('{ \"a\": 1 }');\n });\n\n test(\"multiline object\", () => {\n expect(nicify({ a: 1, b: 2 })).toBe(deindent`\n {\n \"a\": 1,\n \"b\": 2,\n }\n `);\n });\n });\n\n describe(\"custom classes\", () => {\n test(\"class instance\", () => {\n class TestClass {\n constructor(public value: number) {}\n }\n expect(nicify(new TestClass(42))).toBe('TestClass { \"value\": 42 }');\n });\n });\n\n describe(\"built-in objects\", () => {\n test(\"URL\", () => {\n expect(nicify(new URL(\"https://example.com\"))).toBe('URL(\"https://example.com/\")');\n });\n\n test(\"TypedArrays\", () => {\n expect(nicify(new Uint8Array([1, 2, 3]))).toBe(\"Uint8Array([1,2,3])\");\n expect(nicify(new Int32Array([1, 2, 3]))).toBe(\"Int32Array([1,2,3])\");\n });\n\n test(\"Error objects\", () => {\n const error = new Error(\"test error\");\n const nicifiedError = nicify({ error });\n expect(nicifiedError).toMatch(new RegExp(deindent`\n ^\\{\n \"error\": Error: test error\n Stack:\n at (.|\\\\n)*\n \\}$\n `));\n });\n\n test(\"Error objects with cause and an extra property\", () => {\n const error = new Error(\"test error\", { cause: new Error(\"cause\") });\n (error as any).extra = \"something\";\n const nicifiedError = nicify(error, { lineIndent: \"--\" });\n expect(nicifiedError).toMatch(new RegExp(deindent`\n ^Error: test error\n --Stack:\n ----at (.|\\\\n)+\n --Extra properties: \\{ \"extra\": \"something\" \\}\n --Cause:\n ----Error: cause\n ------Stack:\n --------at (.|\\\\n)+$\n `));\n });\n\n test(\"Headers\", () => {\n const headers = new Headers();\n headers.append(\"Content-Type\", \"application/json\");\n headers.append(\"Accept\", \"text/plain\");\n expect(nicify(headers)).toBe(deindent`\n Headers {\n \"accept\": \"text/plain\",\n \"content-type\": \"application/json\",\n }`\n );\n });\n });\n\n describe(\"multiline strings\", () => {\n test(\"basic multiline\", () => {\n expect(nicify(\"line1\\nline2\")).toBe('deindent`\\n line1\\n line2\\n`');\n });\n\n test(\"multiline with trailing newline\", () => {\n expect(nicify(\"line1\\nline2\\n\")).toBe('deindent`\\n line1\\n line2\\n` + \"\\\\n\"');\n });\n\n test(\"multiline with dollar sign\", () => {\n expect(nicify(\"a\\n$b\\nc\")).toBe('deindent`\\n a\\n $b\\n c\\n`');\n });\n\n test(\"multiline with dollar sign interpolation\", () => {\n expect(nicify(\"a\\n${b\\nc\")).toBe('deindent`\\n a\\n \\\\${b\\n c\\n`');\n });\n });\n\n describe(\"circular references\", () => {\n test(\"object with self reference\", () => {\n const circular: any = { a: 1 };\n circular.self = circular;\n expect(nicify(circular)).toBe(deindent`\n {\n \"a\": 1,\n \"self\": Ref<value>,\n }`\n );\n });\n });\n\n describe(\"configuration options\", () => {\n test(\"maxDepth\", () => {\n const deep = { a: { b: { c: { d: { e: 1 } } } } };\n expect(nicify(deep, { maxDepth: 2 })).toBe('{ \"a\": { \"b\": { ... } } }');\n });\n\n test(\"lineIndent\", () => {\n expect(nicify({ a: 1, b: 2 }, { lineIndent: \" \" })).toBe(deindent`\n {\n \"a\": 1,\n \"b\": 2,\n }\n `);\n });\n\n test(\"hideFields\", () => {\n expect(nicify({ a: 1, b: 2, secret: \"hidden\" }, { hideFields: [\"secret\"] })).toBe(deindent`\n {\n \"a\": 1,\n \"b\": 2,\n <some fields may have been hidden>,\n }\n `);\n });\n });\n\n describe(\"custom overrides\", () => {\n test(\"override with custom type\", () => {\n expect(nicify({ type: \"special\" }, {\n overrides: ((value: unknown) => {\n if (typeof value === \"object\" && value && \"type\" in value && (value as any).type === \"special\") {\n return \"SPECIAL\";\n }\n return null;\n }) as NicifyOptions[\"overrides\"]\n })).toBe(\"SPECIAL\");\n });\n });\n\n describe(\"functions\", () => {\n test(\"named function\", () => {\n expect(nicify(function namedFunction() {})).toBe(\"function namedFunction(...) { ... }\");\n });\n\n test(\"arrow function\", () => {\n expect(nicify(() => {})).toBe(\"(...) => { ... }\");\n });\n });\n\n describe(\"Nicifiable interface\", () => {\n test(\"object implementing Nicifiable\", () => {\n const nicifiable = {\n value: 42,\n getNicifiableKeys() {\n return [\"value\"];\n },\n getNicifiedObjectExtraLines() {\n return [\"// custom comment\"];\n }\n };\n expect(nicify(nicifiable)).toBe(deindent`\n {\n \"value\": 42,\n // custom comment,\n }\n `);\n });\n });\n\n describe(\"unknown types\", () => {\n test(\"object without prototype\", () => {\n const unknownType = Object.create(null);\n unknownType.value = \"test\";\n expect(nicify(unknownType)).toBe('{ \"value\": \"test\" }');\n });\n });\n});\n"],"mappings":"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","names":[]}
@@ -18,5 +18,7 @@ declare function url(strings: TemplateStringsArray | readonly string[], ...value
18
18
  * Any values passed are encoded.
19
19
  */
20
20
  declare function urlString(strings: TemplateStringsArray | readonly string[], ...values: (string | number | boolean)[]): string;
21
+ declare function isChildUrl(parentUrl: URL, maybeChildUrl: URL): boolean;
22
+ declare function isChildPath(parentPath: string, maybeChildPath: string): boolean;
21
23
 
22
- export { createUrlIfValid, getRelativePart, isLocalhost, isRelative, isValidHostname, isValidHostnameWithWildcards, isValidUrl, matchHostnamePattern, url, urlString };
24
+ export { createUrlIfValid, getRelativePart, isChildPath, isChildUrl, isLocalhost, isRelative, isValidHostname, isValidHostnameWithWildcards, isValidUrl, matchHostnamePattern, url, urlString };
@@ -18,5 +18,7 @@ declare function url(strings: TemplateStringsArray | readonly string[], ...value
18
18
  * Any values passed are encoded.
19
19
  */
20
20
  declare function urlString(strings: TemplateStringsArray | readonly string[], ...values: (string | number | boolean)[]): string;
21
+ declare function isChildUrl(parentUrl: URL, maybeChildUrl: URL): boolean;
22
+ declare function isChildPath(parentPath: string, maybeChildPath: string): boolean;
21
23
 
22
- export { createUrlIfValid, getRelativePart, isLocalhost, isRelative, isValidHostname, isValidHostnameWithWildcards, isValidUrl, matchHostnamePattern, url, urlString };
24
+ export { createUrlIfValid, getRelativePart, isChildPath, isChildUrl, isLocalhost, isRelative, isValidHostname, isValidHostnameWithWildcards, isValidUrl, matchHostnamePattern, url, urlString };
@@ -22,6 +22,8 @@ var urls_exports = {};
22
22
  __export(urls_exports, {
23
23
  createUrlIfValid: () => createUrlIfValid,
24
24
  getRelativePart: () => getRelativePart,
25
+ isChildPath: () => isChildPath,
26
+ isChildUrl: () => isChildUrl,
25
27
  isLocalhost: () => isLocalhost,
26
28
  isRelative: () => isRelative,
27
29
  isValidHostname: () => isValidHostname,
@@ -125,10 +127,20 @@ function url(strings, ...values) {
125
127
  function urlString(strings, ...values) {
126
128
  return (0, import_strings.templateIdentity)(strings, ...values.map(encodeURIComponent));
127
129
  }
130
+ function isChildUrl(parentUrl, maybeChildUrl) {
131
+ return parentUrl.origin === maybeChildUrl.origin && isChildPath(parentUrl.pathname, maybeChildUrl.pathname) && [...parentUrl.searchParams].every(([key, value]) => maybeChildUrl.searchParams.get(key) === value) && (!parentUrl.hash || parentUrl.hash === maybeChildUrl.hash);
132
+ }
133
+ function isChildPath(parentPath, maybeChildPath) {
134
+ parentPath = parentPath.endsWith("/") ? parentPath : parentPath + "/";
135
+ maybeChildPath = maybeChildPath.endsWith("/") ? maybeChildPath : maybeChildPath + "/";
136
+ return maybeChildPath.startsWith(parentPath);
137
+ }
128
138
  // Annotate the CommonJS export names for ESM import in node:
129
139
  0 && (module.exports = {
130
140
  createUrlIfValid,
131
141
  getRelativePart,
142
+ isChildPath,
143
+ isChildUrl,
132
144
  isLocalhost,
133
145
  isRelative,
134
146
  isValidHostname,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/urls.tsx"],"sourcesContent":["import { generateSecureRandomString } from \"./crypto\";\nimport { templateIdentity } from \"./strings\";\n\nexport function createUrlIfValid(...args: ConstructorParameters<typeof URL>) {\n try {\n return new URL(...args);\n } catch (e) {\n return null;\n }\n}\nundefined?.test(\"createUrlIfValid\", ({ expect }) => {\n // Test with valid URLs\n expect(createUrlIfValid(\"https://example.com\")).toBeInstanceOf(URL);\n expect(createUrlIfValid(\"https://example.com/path?query=value#hash\")).toBeInstanceOf(URL);\n expect(createUrlIfValid(\"/path\", \"https://example.com\")).toBeInstanceOf(URL);\n\n // Test with invalid URLs\n expect(createUrlIfValid(\"\")).toBeNull();\n expect(createUrlIfValid(\"not a url\")).toBeNull();\n expect(createUrlIfValid(\"http://\")).toBeNull();\n});\n\nexport function isValidUrl(url: string) {\n return !!createUrlIfValid(url);\n}\nundefined?.test(\"isValidUrl\", ({ expect }) => {\n // Test with valid URLs\n expect(isValidUrl(\"https://example.com\")).toBe(true);\n expect(isValidUrl(\"http://localhost:3000\")).toBe(true);\n expect(isValidUrl(\"ftp://example.com\")).toBe(true);\n\n // Test with invalid URLs\n expect(isValidUrl(\"\")).toBe(false);\n expect(isValidUrl(\"not a url\")).toBe(false);\n expect(isValidUrl(\"http://\")).toBe(false);\n});\n\nexport function isValidHostname(hostname: string) {\n // Basic validation\n if (!hostname || hostname.startsWith('.') || hostname.endsWith('.') || hostname.includes('..')) {\n return false;\n }\n\n const url = createUrlIfValid(`https://${hostname}`);\n if (!url) return false;\n return url.hostname === hostname;\n}\nundefined?.test(\"isValidHostname\", ({ expect }) => {\n // Test with valid hostnames\n expect(isValidHostname(\"example.com\")).toBe(true);\n expect(isValidHostname(\"localhost\")).toBe(true);\n expect(isValidHostname(\"sub.domain.example.com\")).toBe(true);\n expect(isValidHostname(\"127.0.0.1\")).toBe(true);\n\n // Test with invalid hostnames\n expect(isValidHostname(\"\")).toBe(false);\n expect(isValidHostname(\"example.com/path\")).toBe(false);\n expect(isValidHostname(\"https://example.com\")).toBe(false);\n expect(isValidHostname(\"example com\")).toBe(false);\n});\n\nexport function isValidHostnameWithWildcards(hostname: string) {\n // Empty hostnames are invalid\n if (!hostname) return false;\n\n // Check if it contains wildcards\n const hasWildcard = hostname.includes('*');\n\n if (!hasWildcard) {\n // If no wildcards, validate as a normal hostname\n return isValidHostname(hostname);\n }\n\n // Basic validation checks that apply even with wildcards\n // - Hostname cannot start or end with a dot\n if (hostname.startsWith('.') || hostname.endsWith('.')) {\n return false;\n }\n\n // - No consecutive dots\n if (hostname.includes('..')) {\n return false;\n }\n\n // For wildcard validation, check that non-wildcard parts contain valid characters\n // Replace wildcards with a valid placeholder to check the rest\n const testHostname = hostname.replace(/\\*+/g, 'wildcard');\n\n // Check if the resulting string would be a valid hostname\n if (!/^[a-zA-Z0-9.-]+$/.test(testHostname)) {\n return false;\n }\n\n // Additional check: ensure the pattern makes sense\n // Check each segment between wildcards\n const segments = hostname.split(/\\*+/);\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i];\n if (segment === '') continue; // Empty segments are OK (consecutive wildcards)\n\n // First segment can't start with dot\n if (i === 0 && segment.startsWith('.')) {\n return false;\n }\n\n // Last segment can't end with dot\n if (i === segments.length - 1 && segment.endsWith('.')) {\n return false;\n }\n\n // No segment should have consecutive dots\n if (segment.includes('..')) {\n return false;\n }\n }\n\n return true;\n}\nundefined?.test(\"isValidHostnameWithWildcards\", ({ expect }) => {\n // Test with valid regular hostnames\n expect(isValidHostnameWithWildcards(\"example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"localhost\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"sub.domain.example.com\")).toBe(true);\n\n // Test with valid wildcard hostnames\n expect(isValidHostnameWithWildcards(\"*.example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"a-*.example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"*.*.org\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"**.example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"sub.**.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"*-api.*.com\")).toBe(true);\n\n // Test with invalid hostnames\n expect(isValidHostnameWithWildcards(\"\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example.com/path\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"https://example.com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\".example.com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example.com.\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example..com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"*.example..com\")).toBe(false);\n});\n\nexport function matchHostnamePattern(pattern: string, hostname: string): boolean {\n // If no wildcards, it's an exact match\n if (!pattern.includes('*')) {\n return pattern === hostname;\n }\n\n // Convert the pattern to a regex\n // First, escape all regex special characters except *\n let regexPattern = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Use a placeholder for ** to handle it separately from single *\n const doubleWildcardPlaceholder = '\\x00DOUBLE_WILDCARD\\x00';\n regexPattern = regexPattern.replace(/\\*\\*/g, doubleWildcardPlaceholder);\n\n // Replace single * with a pattern that matches anything except dots\n regexPattern = regexPattern.replace(/\\*/g, '[^.]*');\n\n // Replace the double wildcard placeholder with a pattern that matches anything including dots\n regexPattern = regexPattern.replace(new RegExp(doubleWildcardPlaceholder, 'g'), '.*');\n\n // Anchor the pattern to match the entire hostname\n regexPattern = '^' + regexPattern + '$';\n\n try {\n const regex = new RegExp(regexPattern);\n return regex.test(hostname);\n } catch {\n return false;\n }\n}\nundefined?.test(\"matchHostnamePattern\", ({ expect }) => {\n // Test exact matches\n expect(matchHostnamePattern(\"example.com\", \"example.com\")).toBe(true);\n expect(matchHostnamePattern(\"example.com\", \"other.com\")).toBe(false);\n\n // Test single wildcard matches\n expect(matchHostnamePattern(\"*.example.com\", \"api.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"*.example.com\", \"www.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"*.example.com\", \"example.com\")).toBe(false);\n expect(matchHostnamePattern(\"*.example.com\", \"api.v2.example.com\")).toBe(false);\n\n // Test double wildcard matches\n expect(matchHostnamePattern(\"**.example.com\", \"api.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"**.example.com\", \"api.v2.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"**.example.com\", \"a.b.c.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"**.example.com\", \"example.com\")).toBe(false);\n\n // Test complex patterns\n expect(matchHostnamePattern(\"api-*.example.com\", \"api-v1.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"api-*.example.com\", \"api-v2.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"api-*.example.com\", \"api.example.com\")).toBe(false);\n expect(matchHostnamePattern(\"*.*.org\", \"mail.example.org\")).toBe(true);\n expect(matchHostnamePattern(\"*.*.org\", \"example.org\")).toBe(false);\n});\n\nexport function isLocalhost(urlOrString: string | URL) {\n const url = createUrlIfValid(urlOrString);\n if (!url) return false;\n if (url.hostname === \"localhost\" || url.hostname.endsWith(\".localhost\")) return true;\n if (url.hostname.match(/^127\\.\\d+\\.\\d+\\.\\d+$/)) return true;\n return false;\n}\nundefined?.test(\"isLocalhost\", ({ expect }) => {\n // Test with localhost URLs\n expect(isLocalhost(\"http://localhost\")).toBe(true);\n expect(isLocalhost(\"https://localhost:8080\")).toBe(true);\n expect(isLocalhost(\"http://sub.localhost\")).toBe(true);\n expect(isLocalhost(\"http://127.0.0.1\")).toBe(true);\n expect(isLocalhost(\"http://127.1.2.3\")).toBe(true);\n\n // Test with non-localhost URLs\n expect(isLocalhost(\"https://example.com\")).toBe(false);\n expect(isLocalhost(\"http://192.168.1.1\")).toBe(false);\n expect(isLocalhost(\"http://10.0.0.1\")).toBe(false);\n\n // Test with URL objects\n expect(isLocalhost(new URL(\"http://localhost\"))).toBe(true);\n expect(isLocalhost(new URL(\"https://example.com\"))).toBe(false);\n\n // Test with invalid URLs\n expect(isLocalhost(\"not a url\")).toBe(false);\n expect(isLocalhost(\"\")).toBe(false);\n});\n\nexport function isRelative(url: string) {\n const randomDomain = `${generateSecureRandomString()}.stack-auth.example.com`;\n const u = createUrlIfValid(url, `https://${randomDomain}`);\n if (!u) return false;\n if (u.host !== randomDomain) return false;\n if (u.protocol !== \"https:\") return false;\n return true;\n}\nundefined?.test(\"isRelative\", ({ expect }) => {\n // We can't easily mock generateSecureRandomString in this context\n // but we can still test the function's behavior\n\n // Test with relative URLs\n expect(isRelative(\"/\")).toBe(true);\n expect(isRelative(\"/path\")).toBe(true);\n expect(isRelative(\"/path?query=value#hash\")).toBe(true);\n\n // Test with absolute URLs\n expect(isRelative(\"https://example.com\")).toBe(false);\n expect(isRelative(\"http://example.com\")).toBe(false);\n expect(isRelative(\"//example.com\")).toBe(false);\n\n // Note: The implementation treats empty strings and invalid URLs as relative\n // This is because they can be resolved against a base URL\n expect(isRelative(\"\")).toBe(true);\n expect(isRelative(\"not a url\")).toBe(true);\n});\n\nexport function getRelativePart(url: URL) {\n return url.pathname + url.search + url.hash;\n}\nundefined?.test(\"getRelativePart\", ({ expect }) => {\n // Test with various URLs\n expect(getRelativePart(new URL(\"https://example.com\"))).toBe(\"/\");\n expect(getRelativePart(new URL(\"https://example.com/path\"))).toBe(\"/path\");\n expect(getRelativePart(new URL(\"https://example.com/path?query=value\"))).toBe(\"/path?query=value\");\n expect(getRelativePart(new URL(\"https://example.com/path#hash\"))).toBe(\"/path#hash\");\n expect(getRelativePart(new URL(\"https://example.com/path?query=value#hash\"))).toBe(\"/path?query=value#hash\");\n\n // Test with different domains but same paths\n const url1 = new URL(\"https://example.com/path?query=value#hash\");\n const url2 = new URL(\"https://different.com/path?query=value#hash\");\n expect(getRelativePart(url1)).toBe(getRelativePart(url2));\n});\n\n/**\n * A template literal tag that returns a URL.\n *\n * Any values passed are encoded.\n */\nexport function url(strings: TemplateStringsArray | readonly string[], ...values: (string|number|boolean)[]): URL {\n return new URL(urlString(strings, ...values));\n}\nundefined?.test(\"url\", ({ expect }) => {\n // Test with no interpolation\n expect(url`https://example.com`).toBeInstanceOf(URL);\n expect(url`https://example.com`.href).toBe(\"https://example.com/\");\n\n // Test with string interpolation\n expect(url`https://example.com/${\"path\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path\"}`.pathname).toBe(\"/path\");\n\n // Test with number interpolation\n expect(url`https://example.com/${42}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${42}`.pathname).toBe(\"/42\");\n\n // Test with boolean interpolation\n expect(url`https://example.com/${true}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${true}`.pathname).toBe(\"/true\");\n\n // Test with special characters in interpolation\n expect(url`https://example.com/${\"path with spaces\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path with spaces\"}`.pathname).toBe(\"/path%20with%20spaces\");\n\n // Test with multiple interpolations\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`.pathname).toBe(\"/path\");\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`.search).toBe(\"?query=value\");\n});\n\n\n/**\n * A template literal tag that returns a URL string.\n *\n * Any values passed are encoded.\n */\nexport function urlString(strings: TemplateStringsArray | readonly string[], ...values: (string|number|boolean)[]): string {\n return templateIdentity(strings, ...values.map(encodeURIComponent));\n}\nundefined?.test(\"urlString\", ({ expect }) => {\n // Test with no interpolation\n expect(urlString`https://example.com`).toBe(\"https://example.com\");\n\n // Test with string interpolation\n expect(urlString`https://example.com/${\"path\"}`).toBe(\"https://example.com/path\");\n\n // Test with number interpolation\n expect(urlString`https://example.com/${42}`).toBe(\"https://example.com/42\");\n\n // Test with boolean interpolation\n expect(urlString`https://example.com/${true}`).toBe(\"https://example.com/true\");\n\n // Test with special characters in interpolation\n expect(urlString`https://example.com/${\"path with spaces\"}`).toBe(\"https://example.com/path%20with%20spaces\");\n expect(urlString`https://example.com/${\"?&=\"}`).toBe(\"https://example.com/%3F%26%3D\");\n\n // Test with multiple interpolations\n expect(urlString`https://example.com/${\"path\"}?query=${\"value\"}`).toBe(\"https://example.com/path?query=value\");\n expect(urlString`https://example.com/${\"path\"}?query=${\"value with spaces\"}`).toBe(\"https://example.com/path?query=value%20with%20spaces\");\n});\n\n\n"],"mappings":"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","names":["url"]}
1
+ {"version":3,"sources":["../../src/utils/urls.tsx"],"sourcesContent":["import { generateSecureRandomString } from \"./crypto\";\nimport { templateIdentity } from \"./strings\";\n\nexport function createUrlIfValid(...args: ConstructorParameters<typeof URL>) {\n try {\n return new URL(...args);\n } catch (e) {\n return null;\n }\n}\nundefined?.test(\"createUrlIfValid\", ({ expect }) => {\n // Test with valid URLs\n expect(createUrlIfValid(\"https://example.com\")).toBeInstanceOf(URL);\n expect(createUrlIfValid(\"https://example.com/path?query=value#hash\")).toBeInstanceOf(URL);\n expect(createUrlIfValid(\"/path\", \"https://example.com\")).toBeInstanceOf(URL);\n\n // Test with invalid URLs\n expect(createUrlIfValid(\"\")).toBeNull();\n expect(createUrlIfValid(\"not a url\")).toBeNull();\n expect(createUrlIfValid(\"http://\")).toBeNull();\n});\n\nexport function isValidUrl(url: string) {\n return !!createUrlIfValid(url);\n}\nundefined?.test(\"isValidUrl\", ({ expect }) => {\n // Test with valid URLs\n expect(isValidUrl(\"https://example.com\")).toBe(true);\n expect(isValidUrl(\"http://localhost:3000\")).toBe(true);\n expect(isValidUrl(\"ftp://example.com\")).toBe(true);\n\n // Test with invalid URLs\n expect(isValidUrl(\"\")).toBe(false);\n expect(isValidUrl(\"not a url\")).toBe(false);\n expect(isValidUrl(\"http://\")).toBe(false);\n});\n\nexport function isValidHostname(hostname: string) {\n // Basic validation\n if (!hostname || hostname.startsWith('.') || hostname.endsWith('.') || hostname.includes('..')) {\n return false;\n }\n\n const url = createUrlIfValid(`https://${hostname}`);\n if (!url) return false;\n return url.hostname === hostname;\n}\nundefined?.test(\"isValidHostname\", ({ expect }) => {\n // Test with valid hostnames\n expect(isValidHostname(\"example.com\")).toBe(true);\n expect(isValidHostname(\"localhost\")).toBe(true);\n expect(isValidHostname(\"sub.domain.example.com\")).toBe(true);\n expect(isValidHostname(\"127.0.0.1\")).toBe(true);\n\n // Test with invalid hostnames\n expect(isValidHostname(\"\")).toBe(false);\n expect(isValidHostname(\"example.com/path\")).toBe(false);\n expect(isValidHostname(\"https://example.com\")).toBe(false);\n expect(isValidHostname(\"example com\")).toBe(false);\n});\n\nexport function isValidHostnameWithWildcards(hostname: string) {\n // Empty hostnames are invalid\n if (!hostname) return false;\n\n // Check if it contains wildcards\n const hasWildcard = hostname.includes('*');\n\n if (!hasWildcard) {\n // If no wildcards, validate as a normal hostname\n return isValidHostname(hostname);\n }\n\n // Basic validation checks that apply even with wildcards\n // - Hostname cannot start or end with a dot\n if (hostname.startsWith('.') || hostname.endsWith('.')) {\n return false;\n }\n\n // - No consecutive dots\n if (hostname.includes('..')) {\n return false;\n }\n\n // For wildcard validation, check that non-wildcard parts contain valid characters\n // Replace wildcards with a valid placeholder to check the rest\n const testHostname = hostname.replace(/\\*+/g, 'wildcard');\n\n // Check if the resulting string would be a valid hostname\n if (!/^[a-zA-Z0-9.-]+$/.test(testHostname)) {\n return false;\n }\n\n // Additional check: ensure the pattern makes sense\n // Check each segment between wildcards\n const segments = hostname.split(/\\*+/);\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i];\n if (segment === '') continue; // Empty segments are OK (consecutive wildcards)\n\n // First segment can't start with dot\n if (i === 0 && segment.startsWith('.')) {\n return false;\n }\n\n // Last segment can't end with dot\n if (i === segments.length - 1 && segment.endsWith('.')) {\n return false;\n }\n\n // No segment should have consecutive dots\n if (segment.includes('..')) {\n return false;\n }\n }\n\n return true;\n}\nundefined?.test(\"isValidHostnameWithWildcards\", ({ expect }) => {\n // Test with valid regular hostnames\n expect(isValidHostnameWithWildcards(\"example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"localhost\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"sub.domain.example.com\")).toBe(true);\n\n // Test with valid wildcard hostnames\n expect(isValidHostnameWithWildcards(\"*.example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"a-*.example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"*.*.org\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"**.example.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"sub.**.com\")).toBe(true);\n expect(isValidHostnameWithWildcards(\"*-api.*.com\")).toBe(true);\n\n // Test with invalid hostnames\n expect(isValidHostnameWithWildcards(\"\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example.com/path\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"https://example.com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\".example.com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example.com.\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"example..com\")).toBe(false);\n expect(isValidHostnameWithWildcards(\"*.example..com\")).toBe(false);\n});\n\nexport function matchHostnamePattern(pattern: string, hostname: string): boolean {\n // If no wildcards, it's an exact match\n if (!pattern.includes('*')) {\n return pattern === hostname;\n }\n\n // Convert the pattern to a regex\n // First, escape all regex special characters except *\n let regexPattern = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Use a placeholder for ** to handle it separately from single *\n const doubleWildcardPlaceholder = '\\x00DOUBLE_WILDCARD\\x00';\n regexPattern = regexPattern.replace(/\\*\\*/g, doubleWildcardPlaceholder);\n\n // Replace single * with a pattern that matches anything except dots\n regexPattern = regexPattern.replace(/\\*/g, '[^.]*');\n\n // Replace the double wildcard placeholder with a pattern that matches anything including dots\n regexPattern = regexPattern.replace(new RegExp(doubleWildcardPlaceholder, 'g'), '.*');\n\n // Anchor the pattern to match the entire hostname\n regexPattern = '^' + regexPattern + '$';\n\n try {\n const regex = new RegExp(regexPattern);\n return regex.test(hostname);\n } catch {\n return false;\n }\n}\nundefined?.test(\"matchHostnamePattern\", ({ expect }) => {\n // Test exact matches\n expect(matchHostnamePattern(\"example.com\", \"example.com\")).toBe(true);\n expect(matchHostnamePattern(\"example.com\", \"other.com\")).toBe(false);\n\n // Test single wildcard matches\n expect(matchHostnamePattern(\"*.example.com\", \"api.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"*.example.com\", \"www.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"*.example.com\", \"example.com\")).toBe(false);\n expect(matchHostnamePattern(\"*.example.com\", \"api.v2.example.com\")).toBe(false);\n\n // Test double wildcard matches\n expect(matchHostnamePattern(\"**.example.com\", \"api.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"**.example.com\", \"api.v2.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"**.example.com\", \"a.b.c.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"**.example.com\", \"example.com\")).toBe(false);\n\n // Test complex patterns\n expect(matchHostnamePattern(\"api-*.example.com\", \"api-v1.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"api-*.example.com\", \"api-v2.example.com\")).toBe(true);\n expect(matchHostnamePattern(\"api-*.example.com\", \"api.example.com\")).toBe(false);\n expect(matchHostnamePattern(\"*.*.org\", \"mail.example.org\")).toBe(true);\n expect(matchHostnamePattern(\"*.*.org\", \"example.org\")).toBe(false);\n});\n\nexport function isLocalhost(urlOrString: string | URL) {\n const url = createUrlIfValid(urlOrString);\n if (!url) return false;\n if (url.hostname === \"localhost\" || url.hostname.endsWith(\".localhost\")) return true;\n if (url.hostname.match(/^127\\.\\d+\\.\\d+\\.\\d+$/)) return true;\n return false;\n}\nundefined?.test(\"isLocalhost\", ({ expect }) => {\n // Test with localhost URLs\n expect(isLocalhost(\"http://localhost\")).toBe(true);\n expect(isLocalhost(\"https://localhost:8080\")).toBe(true);\n expect(isLocalhost(\"http://sub.localhost\")).toBe(true);\n expect(isLocalhost(\"http://127.0.0.1\")).toBe(true);\n expect(isLocalhost(\"http://127.1.2.3\")).toBe(true);\n\n // Test with non-localhost URLs\n expect(isLocalhost(\"https://example.com\")).toBe(false);\n expect(isLocalhost(\"http://192.168.1.1\")).toBe(false);\n expect(isLocalhost(\"http://10.0.0.1\")).toBe(false);\n\n // Test with URL objects\n expect(isLocalhost(new URL(\"http://localhost\"))).toBe(true);\n expect(isLocalhost(new URL(\"https://example.com\"))).toBe(false);\n\n // Test with invalid URLs\n expect(isLocalhost(\"not a url\")).toBe(false);\n expect(isLocalhost(\"\")).toBe(false);\n});\n\nexport function isRelative(url: string) {\n const randomDomain = `${generateSecureRandomString()}.stack-auth.example.com`;\n const u = createUrlIfValid(url, `https://${randomDomain}`);\n if (!u) return false;\n if (u.host !== randomDomain) return false;\n if (u.protocol !== \"https:\") return false;\n return true;\n}\nundefined?.test(\"isRelative\", ({ expect }) => {\n // We can't easily mock generateSecureRandomString in this context\n // but we can still test the function's behavior\n\n // Test with relative URLs\n expect(isRelative(\"/\")).toBe(true);\n expect(isRelative(\"/path\")).toBe(true);\n expect(isRelative(\"/path?query=value#hash\")).toBe(true);\n\n // Test with absolute URLs\n expect(isRelative(\"https://example.com\")).toBe(false);\n expect(isRelative(\"http://example.com\")).toBe(false);\n expect(isRelative(\"//example.com\")).toBe(false);\n\n // Note: The implementation treats empty strings and invalid URLs as relative\n // This is because they can be resolved against a base URL\n expect(isRelative(\"\")).toBe(true);\n expect(isRelative(\"not a url\")).toBe(true);\n});\n\nexport function getRelativePart(url: URL) {\n return url.pathname + url.search + url.hash;\n}\nundefined?.test(\"getRelativePart\", ({ expect }) => {\n // Test with various URLs\n expect(getRelativePart(new URL(\"https://example.com\"))).toBe(\"/\");\n expect(getRelativePart(new URL(\"https://example.com/path\"))).toBe(\"/path\");\n expect(getRelativePart(new URL(\"https://example.com/path?query=value\"))).toBe(\"/path?query=value\");\n expect(getRelativePart(new URL(\"https://example.com/path#hash\"))).toBe(\"/path#hash\");\n expect(getRelativePart(new URL(\"https://example.com/path?query=value#hash\"))).toBe(\"/path?query=value#hash\");\n\n // Test with different domains but same paths\n const url1 = new URL(\"https://example.com/path?query=value#hash\");\n const url2 = new URL(\"https://different.com/path?query=value#hash\");\n expect(getRelativePart(url1)).toBe(getRelativePart(url2));\n});\n\n/**\n * A template literal tag that returns a URL.\n *\n * Any values passed are encoded.\n */\nexport function url(strings: TemplateStringsArray | readonly string[], ...values: (string|number|boolean)[]): URL {\n return new URL(urlString(strings, ...values));\n}\nundefined?.test(\"url\", ({ expect }) => {\n // Test with no interpolation\n expect(url`https://example.com`).toBeInstanceOf(URL);\n expect(url`https://example.com`.href).toBe(\"https://example.com/\");\n\n // Test with string interpolation\n expect(url`https://example.com/${\"path\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path\"}`.pathname).toBe(\"/path\");\n\n // Test with number interpolation\n expect(url`https://example.com/${42}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${42}`.pathname).toBe(\"/42\");\n\n // Test with boolean interpolation\n expect(url`https://example.com/${true}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${true}`.pathname).toBe(\"/true\");\n\n // Test with special characters in interpolation\n expect(url`https://example.com/${\"path with spaces\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path with spaces\"}`.pathname).toBe(\"/path%20with%20spaces\");\n\n // Test with multiple interpolations\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`).toBeInstanceOf(URL);\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`.pathname).toBe(\"/path\");\n expect(url`https://example.com/${\"path\"}?query=${\"value\"}`.search).toBe(\"?query=value\");\n});\n\n\n/**\n * A template literal tag that returns a URL string.\n *\n * Any values passed are encoded.\n */\nexport function urlString(strings: TemplateStringsArray | readonly string[], ...values: (string|number|boolean)[]): string {\n return templateIdentity(strings, ...values.map(encodeURIComponent));\n}\nundefined?.test(\"urlString\", ({ expect }) => {\n // Test with no interpolation\n expect(urlString`https://example.com`).toBe(\"https://example.com\");\n\n // Test with string interpolation\n expect(urlString`https://example.com/${\"path\"}`).toBe(\"https://example.com/path\");\n\n // Test with number interpolation\n expect(urlString`https://example.com/${42}`).toBe(\"https://example.com/42\");\n\n // Test with boolean interpolation\n expect(urlString`https://example.com/${true}`).toBe(\"https://example.com/true\");\n\n // Test with special characters in interpolation\n expect(urlString`https://example.com/${\"path with spaces\"}`).toBe(\"https://example.com/path%20with%20spaces\");\n expect(urlString`https://example.com/${\"?&=\"}`).toBe(\"https://example.com/%3F%26%3D\");\n\n // Test with multiple interpolations\n expect(urlString`https://example.com/${\"path\"}?query=${\"value\"}`).toBe(\"https://example.com/path?query=value\");\n expect(urlString`https://example.com/${\"path\"}?query=${\"value with spaces\"}`).toBe(\"https://example.com/path?query=value%20with%20spaces\");\n});\n\nexport function isChildUrl(parentUrl: URL, maybeChildUrl: URL) {\n return parentUrl.origin === maybeChildUrl.origin\n && isChildPath(parentUrl.pathname, maybeChildUrl.pathname)\n && [...parentUrl.searchParams].every(([key, value]) => maybeChildUrl.searchParams.get(key) === value)\n && (!parentUrl.hash || parentUrl.hash === maybeChildUrl.hash);\n}\nundefined?.test(\"isChildUrl\", ({ expect }) => {\n // true\n expect(isChildUrl(new URL(\"https://abc.com/\"), new URL(\"https://abc.com/\"))).toBe(true);\n expect(isChildUrl(new URL(\"https://abc.com/\"), new URL(\"https://abc.com/path\"))).toBe(true);\n expect(isChildUrl(new URL(\"https://abc.com/\"), new URL(\"https://abc.com/path?query=value\"))).toBe(true);\n expect(isChildUrl(new URL(\"https://abc.com/\"), new URL(\"https://abc.com/path?query=value#hash\"))).toBe(true);\n\n // false\n expect(isChildUrl(new URL(\"https://abc.com\"), new URL(\"https://example.com\"))).toBe(false);\n expect(isChildUrl(new URL(\"https://abc.com/\"), new URL(\"https://example.com/path\"))).toBe(false);\n expect(isChildUrl(new URL(\"https://abc.com/\"), new URL(\"https://example.com/path?query=value\"))).toBe(false);\n expect(isChildUrl(new URL(\"https://abc.com/\"), new URL(\"https://example.com/path?query=value#hash\"))).toBe(false);\n expect(isChildUrl(new URL(\"https://example.com\"), new URL(\"https://abc.com/path?query=value#hash\"))).toBe(false);\n expect(isChildUrl(new URL(\"https://example.com?query=value123\"), new URL(\"https://example.com/path?query=value#hash\"))).toBe(false);\n});\n\nexport function isChildPath(parentPath: string, maybeChildPath: string) {\n parentPath = parentPath.endsWith(\"/\") ? parentPath : parentPath + \"/\";\n maybeChildPath = maybeChildPath.endsWith(\"/\") ? maybeChildPath : maybeChildPath + \"/\";\n return maybeChildPath.startsWith(parentPath);\n}\nundefined?.test(\"isSubPath\", ({ expect }) => {\n expect(isChildPath(\"/\", \"/\")).toBe(true);\n expect(isChildPath(\"/\", \"/path\")).toBe(true);\n expect(isChildPath(\"/path\", \"/\")).toBe(false);\n expect(isChildPath(\"/path\", \"/path\")).toBe(true);\n expect(isChildPath(\"/path/\", \"/path\")).toBe(true);\n expect(isChildPath(\"/path\", \"/path/\")).toBe(true);\n expect(isChildPath(\"/path/\", \"/path/\")).toBe(true);\n expect(isChildPath(\"/path\", \"/path/abc\")).toBe(true);\n expect(isChildPath(\"/path/\", \"/path/abc\")).toBe(true);\n expect(isChildPath(\"/path\", \"/path-abc\")).toBe(false);\n expect(isChildPath(\"/path\", \"/path-abc/\")).toBe(false);\n expect(isChildPath(\"/path/\", \"/path-abc\")).toBe(false);\n expect(isChildPath(\"/path/\", \"/path-abc/\")).toBe(false);\n});\n\n"],"mappings":"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","names":["url"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.8.43",
3
+ "version": "2.8.45",
4
4
  "files": [
5
5
  "README.md",
6
6
  "dist",