@strivacity/sdk-core 4.0.0-beta.1 → 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.
- package/README.md +228 -87
- package/dist/assets/oidc.cjs +1 -1
- package/dist/assets/oidc.cjs.map +1 -1
- package/dist/assets/oidc.mjs +1 -1
- package/dist/assets/oidc.mjs.map +1 -1
- package/dist/assets/server.cjs +1 -1
- package/dist/assets/server.cjs.map +1 -1
- package/dist/assets/server.mjs +1 -1
- package/dist/assets/server.mjs.map +1 -1
- package/dist/flows/base.cjs +1 -1
- package/dist/flows/base.cjs.map +1 -1
- package/dist/flows/base.d.ts +4 -2
- package/dist/flows/base.mjs +1 -1
- package/dist/flows/base.mjs.map +1 -1
- package/dist/flows/popup.cjs +1 -1
- package/dist/flows/popup.cjs.map +1 -1
- package/dist/flows/popup.mjs +1 -1
- package/dist/flows/popup.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/server/base.cjs +1 -1
- package/dist/server/base.cjs.map +1 -1
- package/dist/server/base.d.ts +2 -4
- package/dist/server/base.mjs +1 -1
- package/dist/server/base.mjs.map +1 -1
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.mjs +1 -1
- package/dist/storages/cache.cjs.map +1 -1
- package/dist/storages/cache.d.ts +1 -1
- package/dist/storages/cache.mjs.map +1 -1
- package/dist/storages/index.cjs +1 -1
- package/dist/storages/index.mjs +1 -1
- package/dist/storages/server.cjs +1 -1
- package/dist/storages/server.d.ts +29 -1
- package/dist/storages/server.mjs +1 -1
- package/dist/storages/worker.cjs.map +1 -1
- package/dist/storages/worker.d.ts +1 -1
- package/dist/storages/worker.mjs.map +1 -1
- package/dist/types/native.d.ts +67 -2
- package/dist/types/oidc.cjs.map +1 -1
- package/dist/types/oidc.d.ts +41 -6
- package/dist/types/oidc.mjs.map +1 -1
- package/dist/types/popup.d.ts +1 -1
- package/dist/types/server.d.ts +21 -9
- package/dist/utils/index.cjs +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/native-login.cjs +2 -0
- package/dist/utils/native-login.cjs.map +1 -0
- package/dist/utils/native-login.d.ts +13 -0
- package/dist/utils/native-login.mjs +2 -0
- package/dist/utils/native-login.mjs.map +1 -0
- package/dist/utils/oidc.d.ts +3 -4
- package/dist/utils/path.cjs +2 -0
- package/dist/utils/path.cjs.map +1 -0
- package/dist/utils/path.d.ts +16 -0
- package/dist/utils/path.mjs +2 -0
- package/dist/utils/path.mjs.map +1 -0
- package/dist/utils/server.d.ts +5 -4
- package/dist/utils/session.cjs +1 -1
- package/dist/utils/session.cjs.map +1 -1
- package/dist/utils/session.d.ts +9 -1
- package/dist/utils/session.mjs +1 -1
- package/dist/utils/session.mjs.map +1 -1
- package/package.json +1 -1
- package/testing/tests/flows/base.spec.ts +0 -1030
- package/testing/tests/flows/embedded.spec.ts +0 -443
- package/testing/tests/flows/index.spec.ts +0 -8
- package/testing/tests/flows/native.spec.ts +0 -487
- package/testing/tests/flows/popup.spec.ts +0 -400
- package/testing/tests/flows/redirect.spec.ts +0 -369
- package/testing/tests/handlers/embedded.spec.ts +0 -199
- package/testing/tests/handlers/index.spec.ts +0 -8
- package/testing/tests/handlers/native.spec.ts +0 -283
- package/testing/tests/handlers/popup.spec.ts +0 -206
- package/testing/tests/handlers/redirect.spec.ts +0 -70
- package/testing/tests/index.spec.ts +0 -78
- package/testing/tests/server/base.spec.ts +0 -846
- package/testing/tests/server/index.spec.ts +0 -15
- package/testing/tests/storages/cache.spec.ts +0 -107
- package/testing/tests/storages/index.spec.ts +0 -22
- package/testing/tests/storages/indexeddb.spec.ts +0 -113
- package/testing/tests/storages/local.spec.ts +0 -46
- package/testing/tests/storages/memory.spec.ts +0 -51
- package/testing/tests/storages/server.spec.ts +0 -435
- package/testing/tests/storages/session.spec.ts +0 -46
- package/testing/tests/storages/worker.spec.ts +0 -106
- package/testing/tests/utils/common.spec.ts +0 -77
- package/testing/tests/utils/credentials.spec.ts +0 -195
- package/testing/tests/utils/dom.spec.ts +0 -37
- package/testing/tests/utils/index.spec.ts +0 -71
- package/testing/tests/utils/logging.spec.ts +0 -82
- package/testing/tests/utils/oidc.spec.ts +0 -745
- package/testing/tests/utils/server.spec.ts +0 -235
- package/testing/tests/utils/session.spec.ts +0 -87
|
@@ -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
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, vi, afterEach } from 'vitest';
|
|
2
|
-
import { isSessionExpired } from '../../../src/utils/session';
|
|
3
|
-
|
|
4
|
-
describe('isSessionExpired', () => {
|
|
5
|
-
afterEach(() => {
|
|
6
|
-
vi.useRealTimers();
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
test('returns true for a null session', () => {
|
|
10
|
-
expect(isSessionExpired(null)).toBe(true);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test('returns true for an undefined session', () => {
|
|
14
|
-
expect(isSessionExpired(undefined)).toBe(true);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('returns true when access_token is missing', () => {
|
|
18
|
-
expect(isSessionExpired({ expires_at: Math.floor(Date.now() / 1000) + 3600 })).toBe(true);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test('returns true when expires_at is missing', () => {
|
|
22
|
-
expect(isSessionExpired({ access_token: 'token' })).toBe(true);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('returns true when expires_at is in the past', () => {
|
|
26
|
-
vi.useFakeTimers();
|
|
27
|
-
vi.setSystemTime(new Date('2030-01-01T00:00:00.000Z'));
|
|
28
|
-
|
|
29
|
-
const now = Math.floor(Date.now() / 1000);
|
|
30
|
-
|
|
31
|
-
expect(isSessionExpired({ access_token: 'token', expires_at: now - 1 })).toBe(true);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test('returns true when expires_at equals the current time', () => {
|
|
35
|
-
vi.useFakeTimers();
|
|
36
|
-
vi.setSystemTime(new Date('2030-01-01T00:00:00.000Z'));
|
|
37
|
-
|
|
38
|
-
const now = Math.floor(Date.now() / 1000);
|
|
39
|
-
|
|
40
|
-
expect(isSessionExpired({ access_token: 'token', expires_at: now })).toBe(true);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('returns false when expires_at is in the future and no skew is given', () => {
|
|
44
|
-
vi.useFakeTimers();
|
|
45
|
-
vi.setSystemTime(new Date('2030-01-01T00:00:00.000Z'));
|
|
46
|
-
|
|
47
|
-
const now = Math.floor(Date.now() / 1000);
|
|
48
|
-
|
|
49
|
-
expect(isSessionExpired({ access_token: 'token', expires_at: now + 3600 })).toBe(false);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('treats the session as expired once inside the skew window before actual expiration', () => {
|
|
53
|
-
vi.useFakeTimers();
|
|
54
|
-
vi.setSystemTime(new Date('2030-01-01T00:00:00.000Z'));
|
|
55
|
-
|
|
56
|
-
const now = Math.floor(Date.now() / 1000);
|
|
57
|
-
|
|
58
|
-
expect(isSessionExpired({ access_token: 'token', expires_at: now + 30 }, 60)).toBe(true);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('does not treat the session as expired outside the skew window', () => {
|
|
62
|
-
vi.useFakeTimers();
|
|
63
|
-
vi.setSystemTime(new Date('2030-01-01T00:00:00.000Z'));
|
|
64
|
-
|
|
65
|
-
const now = Math.floor(Date.now() / 1000);
|
|
66
|
-
|
|
67
|
-
expect(isSessionExpired({ access_token: 'token', expires_at: now + 120 }, 60)).toBe(false);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test('treats the session as expired exactly at the skew boundary', () => {
|
|
71
|
-
vi.useFakeTimers();
|
|
72
|
-
vi.setSystemTime(new Date('2030-01-01T00:00:00.000Z'));
|
|
73
|
-
|
|
74
|
-
const now = Math.floor(Date.now() / 1000);
|
|
75
|
-
|
|
76
|
-
expect(isSessionExpired({ access_token: 'token', expires_at: now + 60 }, 60)).toBe(true);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test('ignores a negative skew, only treating the session as expired after actual expiration', () => {
|
|
80
|
-
vi.useFakeTimers();
|
|
81
|
-
vi.setSystemTime(new Date('2030-01-01T00:00:00.000Z'));
|
|
82
|
-
|
|
83
|
-
const now = Math.floor(Date.now() / 1000);
|
|
84
|
-
|
|
85
|
-
expect(isSessionExpired({ access_token: 'token', expires_at: now + 30 }, -60)).toBe(false);
|
|
86
|
-
});
|
|
87
|
-
});
|