@stackframe/stack-shared 2.7.19 → 2.7.21

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.
@@ -8,15 +8,47 @@ export function createUrlIfValid(...args) {
8
8
  return null;
9
9
  }
10
10
  }
11
+ import.meta.vitest?.test("createUrlIfValid", ({ expect }) => {
12
+ // Test with valid URLs
13
+ expect(createUrlIfValid("https://example.com")).toBeInstanceOf(URL);
14
+ expect(createUrlIfValid("https://example.com/path?query=value#hash")).toBeInstanceOf(URL);
15
+ expect(createUrlIfValid("/path", "https://example.com")).toBeInstanceOf(URL);
16
+ // Test with invalid URLs
17
+ expect(createUrlIfValid("")).toBeNull();
18
+ expect(createUrlIfValid("not a url")).toBeNull();
19
+ expect(createUrlIfValid("http://")).toBeNull();
20
+ });
11
21
  export function isValidUrl(url) {
12
22
  return !!createUrlIfValid(url);
13
23
  }
24
+ import.meta.vitest?.test("isValidUrl", ({ expect }) => {
25
+ // Test with valid URLs
26
+ expect(isValidUrl("https://example.com")).toBe(true);
27
+ expect(isValidUrl("http://localhost:3000")).toBe(true);
28
+ expect(isValidUrl("ftp://example.com")).toBe(true);
29
+ // Test with invalid URLs
30
+ expect(isValidUrl("")).toBe(false);
31
+ expect(isValidUrl("not a url")).toBe(false);
32
+ expect(isValidUrl("http://")).toBe(false);
33
+ });
14
34
  export function isValidHostname(hostname) {
15
35
  const url = createUrlIfValid(`https://${hostname}`);
16
36
  if (!url)
17
37
  return false;
18
38
  return url.hostname === hostname;
19
39
  }
40
+ import.meta.vitest?.test("isValidHostname", ({ expect }) => {
41
+ // Test with valid hostnames
42
+ expect(isValidHostname("example.com")).toBe(true);
43
+ expect(isValidHostname("localhost")).toBe(true);
44
+ expect(isValidHostname("sub.domain.example.com")).toBe(true);
45
+ expect(isValidHostname("127.0.0.1")).toBe(true);
46
+ // Test with invalid hostnames
47
+ expect(isValidHostname("")).toBe(false);
48
+ expect(isValidHostname("example.com/path")).toBe(false);
49
+ expect(isValidHostname("https://example.com")).toBe(false);
50
+ expect(isValidHostname("example com")).toBe(false);
51
+ });
20
52
  export function isLocalhost(urlOrString) {
21
53
  const url = createUrlIfValid(urlOrString);
22
54
  if (!url)
@@ -27,6 +59,24 @@ export function isLocalhost(urlOrString) {
27
59
  return true;
28
60
  return false;
29
61
  }
62
+ import.meta.vitest?.test("isLocalhost", ({ expect }) => {
63
+ // Test with localhost URLs
64
+ expect(isLocalhost("http://localhost")).toBe(true);
65
+ expect(isLocalhost("https://localhost:8080")).toBe(true);
66
+ expect(isLocalhost("http://sub.localhost")).toBe(true);
67
+ expect(isLocalhost("http://127.0.0.1")).toBe(true);
68
+ expect(isLocalhost("http://127.1.2.3")).toBe(true);
69
+ // Test with non-localhost URLs
70
+ expect(isLocalhost("https://example.com")).toBe(false);
71
+ expect(isLocalhost("http://192.168.1.1")).toBe(false);
72
+ expect(isLocalhost("http://10.0.0.1")).toBe(false);
73
+ // Test with URL objects
74
+ expect(isLocalhost(new URL("http://localhost"))).toBe(true);
75
+ expect(isLocalhost(new URL("https://example.com"))).toBe(false);
76
+ // Test with invalid URLs
77
+ expect(isLocalhost("not a url")).toBe(false);
78
+ expect(isLocalhost("")).toBe(false);
79
+ });
30
80
  export function isRelative(url) {
31
81
  const randomDomain = `${generateSecureRandomString()}.stack-auth.example.com`;
32
82
  const u = createUrlIfValid(url, `https://${randomDomain}`);
@@ -38,9 +88,37 @@ export function isRelative(url) {
38
88
  return false;
39
89
  return true;
40
90
  }
91
+ import.meta.vitest?.test("isRelative", ({ expect }) => {
92
+ // We can't easily mock generateSecureRandomString in this context
93
+ // but we can still test the function's behavior
94
+ // Test with relative URLs
95
+ expect(isRelative("/")).toBe(true);
96
+ expect(isRelative("/path")).toBe(true);
97
+ expect(isRelative("/path?query=value#hash")).toBe(true);
98
+ // Test with absolute URLs
99
+ expect(isRelative("https://example.com")).toBe(false);
100
+ expect(isRelative("http://example.com")).toBe(false);
101
+ expect(isRelative("//example.com")).toBe(false);
102
+ // Note: The implementation treats empty strings and invalid URLs as relative
103
+ // This is because they can be resolved against a base URL
104
+ expect(isRelative("")).toBe(true);
105
+ expect(isRelative("not a url")).toBe(true);
106
+ });
41
107
  export function getRelativePart(url) {
42
108
  return url.pathname + url.search + url.hash;
43
109
  }
110
+ import.meta.vitest?.test("getRelativePart", ({ expect }) => {
111
+ // Test with various URLs
112
+ expect(getRelativePart(new URL("https://example.com"))).toBe("/");
113
+ expect(getRelativePart(new URL("https://example.com/path"))).toBe("/path");
114
+ expect(getRelativePart(new URL("https://example.com/path?query=value"))).toBe("/path?query=value");
115
+ expect(getRelativePart(new URL("https://example.com/path#hash"))).toBe("/path#hash");
116
+ expect(getRelativePart(new URL("https://example.com/path?query=value#hash"))).toBe("/path?query=value#hash");
117
+ // Test with different domains but same paths
118
+ const url1 = new URL("https://example.com/path?query=value#hash");
119
+ const url2 = new URL("https://different.com/path?query=value#hash");
120
+ expect(getRelativePart(url1)).toBe(getRelativePart(url2));
121
+ });
44
122
  /**
45
123
  * A template literal tag that returns a URL.
46
124
  *
@@ -49,6 +127,27 @@ export function getRelativePart(url) {
49
127
  export function url(strings, ...values) {
50
128
  return new URL(urlString(strings, ...values));
51
129
  }
130
+ import.meta.vitest?.test("url", ({ expect }) => {
131
+ // Test with no interpolation
132
+ expect(url `https://example.com`).toBeInstanceOf(URL);
133
+ expect(url `https://example.com`.href).toBe("https://example.com/");
134
+ // Test with string interpolation
135
+ expect(url `https://example.com/${"path"}`).toBeInstanceOf(URL);
136
+ expect(url `https://example.com/${"path"}`.pathname).toBe("/path");
137
+ // Test with number interpolation
138
+ expect(url `https://example.com/${42}`).toBeInstanceOf(URL);
139
+ expect(url `https://example.com/${42}`.pathname).toBe("/42");
140
+ // Test with boolean interpolation
141
+ expect(url `https://example.com/${true}`).toBeInstanceOf(URL);
142
+ expect(url `https://example.com/${true}`.pathname).toBe("/true");
143
+ // Test with special characters in interpolation
144
+ expect(url `https://example.com/${"path with spaces"}`).toBeInstanceOf(URL);
145
+ expect(url `https://example.com/${"path with spaces"}`.pathname).toBe("/path%20with%20spaces");
146
+ // Test with multiple interpolations
147
+ expect(url `https://example.com/${"path"}?query=${"value"}`).toBeInstanceOf(URL);
148
+ expect(url `https://example.com/${"path"}?query=${"value"}`.pathname).toBe("/path");
149
+ expect(url `https://example.com/${"path"}?query=${"value"}`.search).toBe("?query=value");
150
+ });
52
151
  /**
53
152
  * A template literal tag that returns a URL string.
54
153
  *
@@ -57,3 +156,19 @@ export function url(strings, ...values) {
57
156
  export function urlString(strings, ...values) {
58
157
  return templateIdentity(strings, ...values.map(encodeURIComponent));
59
158
  }
159
+ import.meta.vitest?.test("urlString", ({ expect }) => {
160
+ // Test with no interpolation
161
+ expect(urlString `https://example.com`).toBe("https://example.com");
162
+ // Test with string interpolation
163
+ expect(urlString `https://example.com/${"path"}`).toBe("https://example.com/path");
164
+ // Test with number interpolation
165
+ expect(urlString `https://example.com/${42}`).toBe("https://example.com/42");
166
+ // Test with boolean interpolation
167
+ expect(urlString `https://example.com/${true}`).toBe("https://example.com/true");
168
+ // Test with special characters in interpolation
169
+ expect(urlString `https://example.com/${"path with spaces"}`).toBe("https://example.com/path%20with%20spaces");
170
+ expect(urlString `https://example.com/${"?&="}`).toBe("https://example.com/%3F%26%3D");
171
+ // Test with multiple interpolations
172
+ expect(urlString `https://example.com/${"path"}?query=${"value"}`).toBe("https://example.com/path?query=value");
173
+ expect(urlString `https://example.com/${"path"}?query=${"value with spaces"}`).toBe("https://example.com/path?query=value%20with%20spaces");
174
+ });
@@ -3,6 +3,36 @@ export function generateUuid() {
3
3
  // crypto.randomUuid is not supported in all browsers, so this is a polyfill
4
4
  return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c => (+c ^ generateRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16));
5
5
  }
6
+ import.meta.vitest?.test("generateUuid", ({ expect }) => {
7
+ // Test that the function returns a valid UUID
8
+ const uuid = generateUuid();
9
+ expect(uuid).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
10
+ // Test that multiple calls generate different UUIDs
11
+ const uuid2 = generateUuid();
12
+ expect(uuid).not.toBe(uuid2);
13
+ // Test that the UUID is version 4 (random)
14
+ expect(uuid.charAt(14)).toBe('4');
15
+ // Test that the UUID has the correct variant (8, 9, a, or b in position 19)
16
+ expect('89ab').toContain(uuid.charAt(19));
17
+ });
6
18
  export function isUuid(str) {
7
19
  return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(str);
8
20
  }
21
+ import.meta.vitest?.test("isUuid", ({ expect }) => {
22
+ // Test with valid UUIDs
23
+ expect(isUuid("123e4567-e89b-42d3-a456-426614174000")).toBe(true);
24
+ expect(isUuid("123e4567-e89b-42d3-8456-426614174000")).toBe(true);
25
+ expect(isUuid("123e4567-e89b-42d3-9456-426614174000")).toBe(true);
26
+ expect(isUuid("123e4567-e89b-42d3-a456-426614174000")).toBe(true);
27
+ expect(isUuid("123e4567-e89b-42d3-b456-426614174000")).toBe(true);
28
+ // Test with invalid UUIDs
29
+ expect(isUuid("")).toBe(false);
30
+ expect(isUuid("not-a-uuid")).toBe(false);
31
+ expect(isUuid("123e4567-e89b-12d3-a456-426614174000")).toBe(false); // Wrong version (not 4)
32
+ expect(isUuid("123e4567-e89b-42d3-c456-426614174000")).toBe(false); // Wrong variant (not 8, 9, a, or b)
33
+ expect(isUuid("123e4567-e89b-42d3-a456-42661417400")).toBe(false); // Too short
34
+ expect(isUuid("123e4567-e89b-42d3-a456-4266141740000")).toBe(false); // Too long
35
+ expect(isUuid("123e4567-e89b-42d3-a456_426614174000")).toBe(false); // Wrong format (underscore instead of dash)
36
+ // Test with uppercase letters (should fail as UUID should be lowercase)
37
+ expect(isUuid("123E4567-E89B-42D3-A456-426614174000")).toBe(false);
38
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.7.19",
3
+ "version": "2.7.21",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",
@@ -23,7 +23,6 @@
23
23
  "peerDependencies": {
24
24
  "@types/react": ">=18.2 || >=19.0.0-rc.0",
25
25
  "@types/react-dom": ">=18.2 || >=19.0.0-rc.0",
26
- "next": ">=14.1.0 || >=15.0.0-rc.0",
27
26
  "react": ">=18.2 || >=19.0.0-rc.0",
28
27
  "react-dom": ">=18.2 || >=19.0.0-rc.0",
29
28
  "yup": "^1.4.0"
@@ -51,8 +50,7 @@
51
50
  "jose": "^5.2.2",
52
51
  "oauth4webapi": "^2.10.3",
53
52
  "semver": "^7.6.3",
54
- "uuid": "^9.0.1",
55
- "@stackframe/stack-sc": "2.7.19"
53
+ "uuid": "^9.0.1"
56
54
  },
57
55
  "devDependencies": {
58
56
  "@sentry/nextjs": "^8.40.0",
@@ -61,7 +59,6 @@
61
59
  "@types/elliptic": "^6.4.18",
62
60
  "@types/semver": "^7.5.8",
63
61
  "@types/uuid": "^9.0.8",
64
- "next": "^14.1.0",
65
62
  "react": "^18.2",
66
63
  "react-dom": "^18.2",
67
64
  "rimraf": "^5.0.5"