@strivacity/sdk-core 4.0.0-beta.0 → 4.0.0-beta.2

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 (97) hide show
  1. package/README.md +228 -86
  2. package/dist/assets/oidc.cjs +1 -1
  3. package/dist/assets/oidc.cjs.map +1 -1
  4. package/dist/assets/oidc.mjs +1 -1
  5. package/dist/assets/oidc.mjs.map +1 -1
  6. package/dist/assets/server.cjs +1 -1
  7. package/dist/assets/server.cjs.map +1 -1
  8. package/dist/assets/server.mjs +1 -1
  9. package/dist/assets/server.mjs.map +1 -1
  10. package/dist/flows/base.cjs +1 -1
  11. package/dist/flows/base.cjs.map +1 -1
  12. package/dist/flows/base.d.ts +4 -2
  13. package/dist/flows/base.mjs +1 -1
  14. package/dist/flows/base.mjs.map +1 -1
  15. package/dist/flows/popup.cjs +1 -1
  16. package/dist/flows/popup.cjs.map +1 -1
  17. package/dist/flows/popup.mjs +1 -1
  18. package/dist/flows/popup.mjs.map +1 -1
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.ts +6 -2
  22. package/dist/index.mjs +1 -1
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/server/base.cjs +1 -1
  25. package/dist/server/base.cjs.map +1 -1
  26. package/dist/server/base.d.ts +2 -4
  27. package/dist/server/base.mjs +1 -1
  28. package/dist/server/base.mjs.map +1 -1
  29. package/dist/server/index.cjs +1 -1
  30. package/dist/server/index.mjs +1 -1
  31. package/dist/storages/cache.cjs.map +1 -1
  32. package/dist/storages/cache.d.ts +1 -1
  33. package/dist/storages/cache.mjs.map +1 -1
  34. package/dist/storages/index.cjs +1 -1
  35. package/dist/storages/index.mjs +1 -1
  36. package/dist/storages/server.cjs +1 -1
  37. package/dist/storages/server.d.ts +29 -1
  38. package/dist/storages/server.mjs +1 -1
  39. package/dist/storages/worker.cjs.map +1 -1
  40. package/dist/storages/worker.d.ts +1 -1
  41. package/dist/storages/worker.mjs.map +1 -1
  42. package/dist/types/native.d.ts +67 -2
  43. package/dist/types/oidc.cjs.map +1 -1
  44. package/dist/types/oidc.d.ts +47 -6
  45. package/dist/types/oidc.mjs.map +1 -1
  46. package/dist/types/popup.d.ts +1 -1
  47. package/dist/types/server.d.ts +21 -9
  48. package/dist/utils/index.cjs +1 -1
  49. package/dist/utils/index.d.ts +1 -0
  50. package/dist/utils/index.mjs +1 -1
  51. package/dist/utils/native-login.cjs +2 -0
  52. package/dist/utils/native-login.cjs.map +1 -0
  53. package/dist/utils/native-login.d.ts +13 -0
  54. package/dist/utils/native-login.mjs +2 -0
  55. package/dist/utils/native-login.mjs.map +1 -0
  56. package/dist/utils/oidc.d.ts +3 -4
  57. package/dist/utils/path.cjs +2 -0
  58. package/dist/utils/path.cjs.map +1 -0
  59. package/dist/utils/path.d.ts +16 -0
  60. package/dist/utils/path.mjs +2 -0
  61. package/dist/utils/path.mjs.map +1 -0
  62. package/dist/utils/server.d.ts +5 -4
  63. package/dist/utils/session.cjs +1 -1
  64. package/dist/utils/session.cjs.map +1 -1
  65. package/dist/utils/session.d.ts +10 -1
  66. package/dist/utils/session.mjs +1 -1
  67. package/dist/utils/session.mjs.map +1 -1
  68. package/package.json +1 -1
  69. package/testing/tests/flows/base.spec.ts +0 -1030
  70. package/testing/tests/flows/embedded.spec.ts +0 -443
  71. package/testing/tests/flows/index.spec.ts +0 -8
  72. package/testing/tests/flows/native.spec.ts +0 -487
  73. package/testing/tests/flows/popup.spec.ts +0 -400
  74. package/testing/tests/flows/redirect.spec.ts +0 -369
  75. package/testing/tests/handlers/embedded.spec.ts +0 -199
  76. package/testing/tests/handlers/index.spec.ts +0 -8
  77. package/testing/tests/handlers/native.spec.ts +0 -283
  78. package/testing/tests/handlers/popup.spec.ts +0 -206
  79. package/testing/tests/handlers/redirect.spec.ts +0 -70
  80. package/testing/tests/index.spec.ts +0 -78
  81. package/testing/tests/server/base.spec.ts +0 -846
  82. package/testing/tests/server/index.spec.ts +0 -15
  83. package/testing/tests/storages/cache.spec.ts +0 -107
  84. package/testing/tests/storages/index.spec.ts +0 -22
  85. package/testing/tests/storages/indexeddb.spec.ts +0 -113
  86. package/testing/tests/storages/local.spec.ts +0 -46
  87. package/testing/tests/storages/memory.spec.ts +0 -51
  88. package/testing/tests/storages/server.spec.ts +0 -435
  89. package/testing/tests/storages/session.spec.ts +0 -46
  90. package/testing/tests/storages/worker.spec.ts +0 -106
  91. package/testing/tests/utils/common.spec.ts +0 -77
  92. package/testing/tests/utils/credentials.spec.ts +0 -195
  93. package/testing/tests/utils/dom.spec.ts +0 -37
  94. package/testing/tests/utils/index.spec.ts +0 -71
  95. package/testing/tests/utils/logging.spec.ts +0 -82
  96. package/testing/tests/utils/oidc.spec.ts +0 -744
  97. package/testing/tests/utils/server.spec.ts +0 -235
@@ -1,235 +0,0 @@
1
- import { describe, test, expect } from 'vitest';
2
- import { serverAdapter, createHttpResponse, createMockStorage, createServerOptions } from '@strivacity/testing/mocks/sdk';
3
- import {
4
- getServerSDKOptions,
5
- parseCookieHeader,
6
- serializeCookie,
7
- pushSetCookie,
8
- flushSetCookies,
9
- proxyResponse,
10
- toSafeRedirect,
11
- DEFAULT_COOKIE_MAX_AGE,
12
- ConfigurationError,
13
- InternalError,
14
- } from '../../../src/utils';
15
-
16
- describe('getServerSDKOptions', () => {
17
- test('w/o options', async () => {
18
- const options = getServerSDKOptions(serverAdapter, createServerOptions({ secret: 'secret' }));
19
-
20
- expect(options.storage.get).toBeInstanceOf(Function);
21
- expect(options.storage.set).toBeInstanceOf(Function);
22
- expect(options.storage.delete).toBeInstanceOf(Function);
23
- expect(options.postLoginRedirectUri).toBe('https://brandtegrity.io');
24
- expect(options.postLogoutRedirectUri).toBe('https://brandtegrity.io');
25
- expect(options.cookieMaxAge).toBe(DEFAULT_COOKIE_MAX_AGE);
26
- expect(options.authUrlPrefix).toBe('/auth');
27
- expect(options.loginUri).toBe('/login');
28
- expect(options.serverSessionUri).toBe('/auth/login');
29
- await expect(options.urlHandler(new URL('https://brandtegrity.io'))).resolves.toBeUndefined();
30
- });
31
-
32
- test('w/ options', () => {
33
- const storage = createMockStorage();
34
- const options = getServerSDKOptions(
35
- serverAdapter,
36
- createServerOptions({
37
- storage,
38
- cookieMaxAge: 60,
39
- postLoginRedirectUri: 'https://brandtegrity.io/home',
40
- postLogoutRedirectUri: 'https://brandtegrity.io/bye',
41
- authUrlPrefix: '/custom-auth',
42
- }),
43
- );
44
-
45
- expect(options.storage).toBe(storage);
46
- expect(options.postLoginRedirectUri).toBe('https://brandtegrity.io/home');
47
- expect(options.postLogoutRedirectUri).toBe('https://brandtegrity.io/bye');
48
- expect(options.cookieMaxAge).toBe(60);
49
- expect(options.serverSessionUri).toBe('/custom-auth/login');
50
- });
51
-
52
- test('throws a ConfigurationError when neither storage nor secret is provided', () => {
53
- expect(() => getServerSDKOptions(serverAdapter, createServerOptions({ secret: undefined }))).toThrow(new ConfigurationError('Missing SDK option: secret'));
54
- });
55
- });
56
-
57
- describe('parseCookieHeader', () => {
58
- test('returns an empty object when the header is missing', () => {
59
- expect(parseCookieHeader(null)).toEqual({});
60
- expect(parseCookieHeader(undefined)).toEqual({});
61
- expect(parseCookieHeader('')).toEqual({});
62
- });
63
-
64
- test('parses a single cookie', () => {
65
- expect(parseCookieHeader('foo=bar')).toEqual({ foo: 'bar' });
66
- });
67
-
68
- test('parses multiple cookies separated by "; "', () => {
69
- expect(parseCookieHeader('foo=bar; baz=qux')).toEqual({ foo: 'bar', baz: 'qux' });
70
- });
71
-
72
- test('decodes URI-encoded cookie values', () => {
73
- expect(parseCookieHeader('foo=hello%20world')).toEqual({ foo: 'hello world' });
74
- });
75
-
76
- test('falls back to the raw value when it cannot be URI-decoded', () => {
77
- expect(parseCookieHeader('foo=100%')).toEqual({ foo: '100%' });
78
- });
79
-
80
- test('ignores segments without an "=" separator', () => {
81
- expect(parseCookieHeader('foo=bar; malformed')).toEqual({ foo: 'bar' });
82
- });
83
-
84
- test('ignores segments with an empty name', () => {
85
- expect(parseCookieHeader('=value; foo=bar')).toEqual({ foo: 'bar' });
86
- });
87
- });
88
-
89
- describe('serializeCookie', () => {
90
- test('serializes name/value with the default path', () => {
91
- expect(serializeCookie('foo', 'bar')).toBe('foo=bar; Path=/');
92
- });
93
-
94
- test('URI-encodes the cookie value', () => {
95
- expect(serializeCookie('foo', 'hello world')).toBe('foo=hello%20world; Path=/');
96
- });
97
-
98
- test('includes Max-Age when provided', () => {
99
- expect(serializeCookie('foo', 'bar', { maxAge: 3600.9 })).toBe('foo=bar; Max-Age=3600; Path=/');
100
- });
101
-
102
- test('includes Expires when provided', () => {
103
- const expires = new Date('2030-01-01T00:00:00.000Z');
104
-
105
- expect(serializeCookie('foo', 'bar', { expires })).toBe(`foo=bar; Expires=${expires.toUTCString()}; Path=/`);
106
- });
107
-
108
- test('includes a custom path', () => {
109
- expect(serializeCookie('foo', 'bar', { path: '/auth' })).toBe('foo=bar; Path=/auth');
110
- });
111
-
112
- test('includes Domain when provided', () => {
113
- expect(serializeCookie('foo', 'bar', { domain: 'brandtegrity.io' })).toBe('foo=bar; Path=/; Domain=brandtegrity.io');
114
- });
115
-
116
- test('capitalizes the SameSite attribute', () => {
117
- expect(serializeCookie('foo', 'bar', { sameSite: 'strict' })).toBe('foo=bar; Path=/; SameSite=Strict');
118
- });
119
-
120
- test('includes Secure when true', () => {
121
- expect(serializeCookie('foo', 'bar', { secure: true })).toBe('foo=bar; Path=/; Secure');
122
- });
123
-
124
- test('includes HttpOnly when true', () => {
125
- expect(serializeCookie('foo', 'bar', { httpOnly: true })).toBe('foo=bar; Path=/; HttpOnly');
126
- });
127
-
128
- test('combines all attributes in the expected order', () => {
129
- const expires = new Date('2030-01-01T00:00:00.000Z');
130
-
131
- expect(
132
- serializeCookie('foo', 'bar', { maxAge: 60, expires, path: '/auth', domain: 'brandtegrity.io', sameSite: 'lax', secure: true, httpOnly: true }),
133
- ).toBe(`foo=bar; Max-Age=60; Expires=${expires.toUTCString()}; Path=/auth; Domain=brandtegrity.io; SameSite=Lax; Secure; HttpOnly`);
134
- });
135
- });
136
-
137
- describe('pushSetCookie / flushSetCookies', () => {
138
- test('pushSetCookie throws an InternalError when the event is null', () => {
139
- expect(() => pushSetCookie(null, 'foo=bar')).toThrow(new InternalError('Server adapter events must be objects to track outgoing cookies'));
140
- });
141
-
142
- test('pushSetCookie throws an InternalError when the event is not an object', () => {
143
- expect(() => pushSetCookie('not-an-object', 'foo=bar')).toThrow(InternalError);
144
- });
145
-
146
- test('flushSetCookies throws an InternalError when the event is null', () => {
147
- expect(() => flushSetCookies(null, new Response())).toThrow(new InternalError('Server adapter events must be objects to track outgoing cookies'));
148
- });
149
-
150
- test('flushSetCookies throws an InternalError when the event is not an object', () => {
151
- expect(() => flushSetCookies(42, new Response())).toThrow(InternalError);
152
- });
153
-
154
- test('returns the response unchanged when nothing was pushed', () => {
155
- const response = flushSetCookies({}, new Response());
156
-
157
- expect(response.headers.getSetCookie()).toEqual([]);
158
- });
159
-
160
- test('appends all pushed Set-Cookie headers to the response', () => {
161
- const event = {};
162
- pushSetCookie(event, 'foo=bar; Path=/');
163
- pushSetCookie(event, 'baz=qux; Path=/');
164
-
165
- const response = flushSetCookies(event, new Response());
166
-
167
- expect(response.headers.getSetCookie()).toEqual(['foo=bar; Path=/', 'baz=qux; Path=/']);
168
- });
169
-
170
- test('clears the cookie jar after flushing', () => {
171
- const event = {};
172
- pushSetCookie(event, 'foo=bar; Path=/');
173
-
174
- flushSetCookies(event, new Response());
175
- const response = flushSetCookies(event, new Response());
176
-
177
- expect(response.headers.getSetCookie()).toEqual([]);
178
- });
179
- });
180
-
181
- describe('proxyResponse', () => {
182
- test('preserves the status and statusText', () => {
183
- const response = proxyResponse(createHttpResponse({ status: 201, statusText: 'Created' }));
184
-
185
- expect(response.status).toBe(201);
186
- expect(response.statusText).toBe('Created');
187
- });
188
-
189
- test('copies allowed headers', () => {
190
- const response = proxyResponse(createHttpResponse({ headers: new Headers({ 'content-type': 'application/json' }) }));
191
-
192
- expect(response.headers.get('content-type')).toBe('application/json');
193
- });
194
-
195
- test.each(['transfer-encoding', 'connection', 'keep-alive', 'content-encoding'])('excludes the disallowed "%s" header', (header) => {
196
- const response = proxyResponse(createHttpResponse({ headers: new Headers({ [header]: 'value', 'content-type': 'application/json' }) }));
197
-
198
- expect(response.headers.has(header)).toBe(false);
199
- expect(response.headers.get('content-type')).toBe('application/json');
200
- });
201
-
202
- test('omits the set-cookie header when the source response has none', () => {
203
- const response = proxyResponse(createHttpResponse());
204
-
205
- expect(response.headers.has('set-cookie')).toBe(false);
206
- });
207
-
208
- test('normalizes a comma-separated set-cookie header without throwing', () => {
209
- expect(() => proxyResponse(createHttpResponse({ headers: new Headers({ 'set-cookie': 'foo=bar,baz=qux' }) }))).not.toThrow();
210
- });
211
- });
212
-
213
- describe('toSafeRedirect', () => {
214
- test('returns null when the redirect is missing', () => {
215
- expect(toSafeRedirect(undefined, 'https://brandtegrity.io')).toBeNull();
216
- expect(toSafeRedirect(null, 'https://brandtegrity.io')).toBeNull();
217
- expect(toSafeRedirect('', 'https://brandtegrity.io')).toBeNull();
218
- });
219
-
220
- test('resolves a relative path against the safe base URL', () => {
221
- expect(toSafeRedirect('/dashboard', 'https://brandtegrity.io')).toBe('https://brandtegrity.io/dashboard');
222
- });
223
-
224
- test('resolves correctly when the safe base URL has no trailing slash', () => {
225
- expect(toSafeRedirect('/dashboard?tab=1', 'https://brandtegrity.io/app')).toBe('https://brandtegrity.io/app/dashboard?tab=1');
226
- });
227
-
228
- test('returns null when the redirect points to a different origin', () => {
229
- expect(toSafeRedirect('https://evil.example.com/phish', 'https://brandtegrity.io')).toBeNull();
230
- });
231
-
232
- test('returns null when the redirect cannot be parsed as a URL', () => {
233
- expect(toSafeRedirect('http://', 'https://brandtegrity.io')).toBeNull();
234
- });
235
- });