@bytescale/sdk 3.56.0 → 3.58.0
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/dist/browser/cjs/main.js +138 -56
- package/dist/browser/esm/main.mjs +138 -56
- package/dist/types/private/dtos/AuthSwSetConfigDto.d.ts +2 -0
- package/dist/types/private/model/AuthManagerInterface.d.ts +40 -26
- package/dist/types/private/model/AuthSession.d.ts +5 -1
- package/dist/types/public/browser/AuthManagerBrowser.d.ts +4 -2
- package/dist/types/public/node/AuthManagerNode.d.ts +1 -1
- package/package.json +1 -1
- package/tests/AuthManagerBrowser.test.ts +278 -114
- package/tests/AuthServiceWorkerRewrite.test.ts +276 -0
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import { jest } from "@jest/globals";
|
|
2
2
|
import { Response as NodeFetchResponse } from "node-fetch";
|
|
3
|
-
import
|
|
3
|
+
import { AuthSessionState } from "../src/private/AuthSessionState";
|
|
4
|
+
import type {
|
|
5
|
+
AuthManagerServiceWorkerConfig,
|
|
6
|
+
AuthSwConfigEntryDto,
|
|
7
|
+
BeginAuthSessionParams,
|
|
8
|
+
UrlRewriteRule
|
|
9
|
+
} from "../src/index.browser";
|
|
10
|
+
|
|
11
|
+
type FetchApi = NonNullable<NonNullable<BeginAuthSessionParams["options"]>["fetchApi"]>;
|
|
4
12
|
|
|
5
13
|
interface AuthManagerApi {
|
|
6
|
-
beginAuthSession: (params:
|
|
14
|
+
beginAuthSession: (params: BeginAuthSessionParams) => Promise<void>;
|
|
7
15
|
endAuthSession: () => Promise<void>;
|
|
8
16
|
isAuthSessionActive: () => boolean;
|
|
9
17
|
isAuthSessionReady: () => boolean;
|
|
10
18
|
}
|
|
11
19
|
|
|
20
|
+
interface AuthManagerInternals extends AuthManagerApi {
|
|
21
|
+
refreshAccessToken: (
|
|
22
|
+
session: NonNullable<ReturnType<typeof AuthSessionState.getSession>>,
|
|
23
|
+
params: BeginAuthSessionParams
|
|
24
|
+
) => Promise<void>;
|
|
25
|
+
scheduler: { unschedule: (handle: number) => void };
|
|
26
|
+
}
|
|
27
|
+
|
|
12
28
|
describe("AuthManager browser service-worker config", () => {
|
|
13
29
|
const originalNavigator = Object.getOwnPropertyDescriptor(globalThis, "navigator");
|
|
14
30
|
const originalFetch = Object.getOwnPropertyDescriptor(globalThis, "fetch");
|
|
@@ -67,168 +83,316 @@ describe("AuthManager browser service-worker config", () => {
|
|
|
67
83
|
jest.restoreAllMocks();
|
|
68
84
|
});
|
|
69
85
|
|
|
70
|
-
test("
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
test("retains the existing cookie fallback when no additional config is requested", async () => {
|
|
87
|
+
delete navigatorValue.serviceWorker;
|
|
88
|
+
const fetchApi = createPrimaryFetchApi();
|
|
89
|
+
|
|
90
|
+
await AuthManager.beginAuthSession(createParams(fetchApi));
|
|
91
|
+
|
|
92
|
+
expect((fetchApi.mock.calls[1][0] as string).endsWith("?set-cookie=true")).toBe(true);
|
|
93
|
+
expect(postMessage).not.toHaveBeenCalled();
|
|
94
|
+
expect(AuthManager.isAuthSessionReady()).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("retains the existing primary-only service-worker flow", async () => {
|
|
98
|
+
const fetchApi = createPrimaryFetchApi();
|
|
99
|
+
|
|
100
|
+
await AuthManager.beginAuthSession({
|
|
101
|
+
...createParams(fetchApi),
|
|
102
|
+
serviceWorkerScript: "/bytescale-auth-sw.js"
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expect(AuthManager.isAuthSessionReady()).toBe(true);
|
|
106
|
+
expect(postMessage.mock.calls[0][0]).toEqual({
|
|
107
|
+
config: [
|
|
108
|
+
{
|
|
109
|
+
expires: expect.any(Number),
|
|
110
|
+
headers: [{ key: "Authorization", value: "Bearer jwt-a" }],
|
|
111
|
+
urlPrefix: "https://upcdn.io/account-a/"
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
type: "SET_BYTESCALE_AUTH_CONFIG"
|
|
115
|
+
});
|
|
116
|
+
expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT"]);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("merges the primary API/download context with additional download-only contexts", async () => {
|
|
120
|
+
const fetchApi = createPrimaryFetchApi();
|
|
121
|
+
const additionalConfig: AuthSwConfigEntryDto[] = [
|
|
78
122
|
{
|
|
79
123
|
expires: Date.now() + 60_000,
|
|
80
|
-
headers: [{ key: "Authorization", value: "Bearer
|
|
124
|
+
headers: [{ key: "Authorization", value: "Bearer jwt-b" }],
|
|
125
|
+
sourceUrlPrefixes: ["https://app.example.com/account-b/"],
|
|
81
126
|
urlPrefix: "https://upcdn.io/account-b/"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
expires: undefined,
|
|
130
|
+
headers: [{ key: "Authorization", value: "Bearer jwt-c" }],
|
|
131
|
+
urlPrefix: "https://upcdn.io/account-c/"
|
|
82
132
|
}
|
|
83
133
|
];
|
|
84
|
-
const
|
|
134
|
+
const urlRewriteRules: UrlRewriteRule[] = [
|
|
85
135
|
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
urlPrefix: "https://upcdn.io/account-a/"
|
|
136
|
+
fromUrlPrefix: "https://app.example.com/__authenticated-download/",
|
|
137
|
+
toUrlPrefix: "https://upcdn.io/account-b/"
|
|
89
138
|
}
|
|
90
139
|
];
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
140
|
+
const serviceWorkerConfig = jest.fn(
|
|
141
|
+
async (): Promise<AuthManagerServiceWorkerConfig> => ({
|
|
142
|
+
additionalConfig,
|
|
143
|
+
sourceUrlPrefixes: ["https://app.example.com/"],
|
|
144
|
+
urlRewriteRules
|
|
145
|
+
})
|
|
146
|
+
);
|
|
95
147
|
|
|
96
148
|
await AuthManager.beginAuthSession({
|
|
97
|
-
|
|
149
|
+
...createParams(fetchApi),
|
|
150
|
+
serviceWorkerConfig,
|
|
98
151
|
serviceWorkerScript: "/bytescale-auth-sw.js"
|
|
99
152
|
});
|
|
100
153
|
|
|
101
|
-
expect(AuthManager.isAuthSessionActive()).toBe(true);
|
|
102
154
|
expect(AuthManager.isAuthSessionReady()).toBe(true);
|
|
155
|
+
expect(serviceWorkerConfig).toHaveBeenCalledTimes(1);
|
|
103
156
|
expect(postMessage.mock.calls[0][0]).toEqual({
|
|
104
157
|
config: [
|
|
105
158
|
{
|
|
106
|
-
|
|
159
|
+
expires: expect.any(Number),
|
|
160
|
+
headers: [{ key: "Authorization", value: "Bearer jwt-a" }],
|
|
161
|
+
sourceUrlPrefixes: ["https://app.example.com/"],
|
|
107
162
|
urlPrefix: "!bytescale-source-scoped!https://upcdn.io/account-a/"
|
|
108
163
|
},
|
|
109
|
-
|
|
164
|
+
{
|
|
165
|
+
...additionalConfig[0],
|
|
166
|
+
urlPrefix: "!bytescale-source-scoped!https://upcdn.io/account-b/"
|
|
167
|
+
},
|
|
168
|
+
additionalConfig[1]
|
|
110
169
|
],
|
|
111
|
-
type: "SET_BYTESCALE_AUTH_CONFIG"
|
|
170
|
+
type: "SET_BYTESCALE_AUTH_CONFIG",
|
|
171
|
+
urlRewriteRules
|
|
112
172
|
});
|
|
113
|
-
expect(
|
|
173
|
+
expect(additionalConfig[0].urlPrefix).toBe("https://upcdn.io/account-b/");
|
|
174
|
+
expect(AuthSessionState.getSession()?.accessToken).toBe("access-a");
|
|
175
|
+
expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT"]);
|
|
176
|
+
|
|
177
|
+
await AuthManager.endAuthSession();
|
|
114
178
|
|
|
179
|
+
expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT", "DELETE"]);
|
|
180
|
+
expect(postMessage.mock.calls[1][0]).toEqual({ config: [], type: "SET_BYTESCALE_AUTH_CONFIG" });
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("refreshes additional rules independently while retaining the primary context", async () => {
|
|
184
|
+
const fetchApi = createPrimaryFetchApi();
|
|
185
|
+
const initialAdditionalConfig: AuthSwConfigEntryDto[] = [
|
|
186
|
+
{
|
|
187
|
+
expires: Date.now() + 21_000,
|
|
188
|
+
headers: [{ key: "Authorization", value: "Bearer jwt-b" }],
|
|
189
|
+
urlPrefix: "https://upcdn.io/account-b/"
|
|
190
|
+
}
|
|
191
|
+
];
|
|
192
|
+
const serviceWorkerConfig = jest
|
|
193
|
+
.fn<() => Promise<AuthManagerServiceWorkerConfig>>()
|
|
194
|
+
.mockResolvedValueOnce({
|
|
195
|
+
additionalConfig: initialAdditionalConfig,
|
|
196
|
+
sourceUrlPrefixes: ["https://app.example.com/initial/"],
|
|
197
|
+
urlRewriteRules: [
|
|
198
|
+
{
|
|
199
|
+
fromUrlPrefix: "https://app.example.com/download/",
|
|
200
|
+
toUrlPrefix: "https://upcdn.io/account-b/"
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
})
|
|
204
|
+
.mockResolvedValueOnce({
|
|
205
|
+
additionalConfig: [],
|
|
206
|
+
sourceUrlPrefixes: ["https://app.example.com/refreshed/"],
|
|
207
|
+
urlRewriteRules: [
|
|
208
|
+
{
|
|
209
|
+
fromUrlPrefix: "https://app.example.com/download/",
|
|
210
|
+
toUrlPrefix: "https://upcdn.io/account-c/"
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
await AuthManager.beginAuthSession({
|
|
216
|
+
...createParams(fetchApi),
|
|
217
|
+
serviceWorkerConfig,
|
|
218
|
+
serviceWorkerScript: "/bytescale-auth-sw.js"
|
|
219
|
+
});
|
|
115
220
|
await new Promise(resolve => setTimeout(resolve, 1_500));
|
|
116
221
|
|
|
117
|
-
expect(
|
|
222
|
+
expect(serviceWorkerConfig).toHaveBeenCalledTimes(2);
|
|
118
223
|
expect(postMessage.mock.calls[1][0]).toEqual({
|
|
119
|
-
config:
|
|
120
|
-
|
|
224
|
+
config: [
|
|
225
|
+
{
|
|
226
|
+
expires: expect.any(Number),
|
|
227
|
+
headers: [{ key: "Authorization", value: "Bearer jwt-a" }],
|
|
228
|
+
sourceUrlPrefixes: ["https://app.example.com/refreshed/"],
|
|
229
|
+
urlPrefix: "!bytescale-source-scoped!https://upcdn.io/account-a/"
|
|
230
|
+
}
|
|
231
|
+
],
|
|
232
|
+
type: "SET_BYTESCALE_AUTH_CONFIG",
|
|
233
|
+
urlRewriteRules: [
|
|
234
|
+
{
|
|
235
|
+
fromUrlPrefix: "https://app.example.com/download/",
|
|
236
|
+
toUrlPrefix: "https://upcdn.io/account-c/"
|
|
237
|
+
}
|
|
238
|
+
]
|
|
121
239
|
});
|
|
240
|
+
expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT"]);
|
|
241
|
+
expect(AuthManager.isAuthSessionReady()).toBe(true);
|
|
122
242
|
});
|
|
123
243
|
|
|
124
|
-
test("
|
|
244
|
+
test("retains additional rules when the primary JWT refreshes", async () => {
|
|
245
|
+
const fetchApi = createPrimaryFetchApi();
|
|
246
|
+
const additionalConfig: AuthSwConfigEntryDto[] = [
|
|
247
|
+
{
|
|
248
|
+
expires: undefined,
|
|
249
|
+
headers: [{ key: "Authorization", value: "Bearer jwt-b" }],
|
|
250
|
+
urlPrefix: "https://upcdn.io/account-b/"
|
|
251
|
+
}
|
|
252
|
+
];
|
|
253
|
+
const serviceWorkerConfig = jest.fn(
|
|
254
|
+
async (): Promise<AuthManagerServiceWorkerConfig> => ({
|
|
255
|
+
additionalConfig,
|
|
256
|
+
urlRewriteRules: [
|
|
257
|
+
{
|
|
258
|
+
fromUrlPrefix: "https://app.example.com/download/",
|
|
259
|
+
toUrlPrefix: "https://upcdn.io/account-b/"
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
})
|
|
263
|
+
);
|
|
264
|
+
|
|
125
265
|
await AuthManager.beginAuthSession({
|
|
126
|
-
|
|
266
|
+
...createParams(fetchApi),
|
|
267
|
+
serviceWorkerConfig,
|
|
268
|
+
serviceWorkerScript: "/bytescale-auth-sw.js"
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const session = AuthSessionState.getSession();
|
|
272
|
+
if (session?.accessTokenRefreshHandle === undefined) {
|
|
273
|
+
throw new Error("Expected the primary access-token refresh to be scheduled.");
|
|
274
|
+
}
|
|
275
|
+
const authManagerInternals = AuthManager as AuthManagerInternals;
|
|
276
|
+
authManagerInternals.scheduler.unschedule(session.accessTokenRefreshHandle);
|
|
277
|
+
await authManagerInternals.refreshAccessToken(session, session.params);
|
|
278
|
+
|
|
279
|
+
expect(serviceWorkerConfig).toHaveBeenCalledTimes(1);
|
|
280
|
+
expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT", "GET", "PUT"]);
|
|
281
|
+
expect(postMessage.mock.calls[1][0]).toEqual({
|
|
282
|
+
config: [
|
|
127
283
|
{
|
|
128
|
-
expires:
|
|
129
|
-
headers: [{ key: "Authorization", value: "Bearer
|
|
284
|
+
expires: expect.any(Number),
|
|
285
|
+
headers: [{ key: "Authorization", value: "Bearer jwt-a" }],
|
|
130
286
|
urlPrefix: "https://upcdn.io/account-a/"
|
|
131
|
-
}
|
|
287
|
+
},
|
|
288
|
+
additionalConfig[0]
|
|
132
289
|
],
|
|
133
|
-
|
|
290
|
+
type: "SET_BYTESCALE_AUTH_CONFIG",
|
|
291
|
+
urlRewriteRules: [
|
|
292
|
+
{
|
|
293
|
+
fromUrlPrefix: "https://app.example.com/download/",
|
|
294
|
+
toUrlPrefix: "https://upcdn.io/account-b/"
|
|
295
|
+
}
|
|
296
|
+
]
|
|
134
297
|
});
|
|
135
|
-
await AuthManager.endAuthSession();
|
|
136
|
-
|
|
137
|
-
expect(globalFetch).not.toHaveBeenCalled();
|
|
138
|
-
expect(postMessage.mock.calls[1][0]).toEqual({ config: [], type: "SET_BYTESCALE_AUTH_CONFIG" });
|
|
139
|
-
expect(AuthManager.isAuthSessionActive()).toBe(false);
|
|
140
|
-
expect(AuthManager.isAuthSessionReady()).toBe(false);
|
|
141
298
|
});
|
|
142
299
|
|
|
143
|
-
test("
|
|
144
|
-
|
|
145
|
-
const
|
|
300
|
+
test("rejects malformed URL rewrite rules", async () => {
|
|
301
|
+
jest.spyOn(console, "warn").mockImplementation(() => {});
|
|
302
|
+
const fetchApi = createPrimaryFetchApi();
|
|
146
303
|
|
|
147
|
-
await
|
|
148
|
-
|
|
149
|
-
|
|
304
|
+
await AuthManager.beginAuthSession({
|
|
305
|
+
...createParams(fetchApi),
|
|
306
|
+
serviceWorkerConfig: async (): Promise<AuthManagerServiceWorkerConfig> => ({
|
|
307
|
+
additionalConfig: [],
|
|
308
|
+
urlRewriteRules: [{ fromUrlPrefix: "https://app.example.com/download/" }] as UrlRewriteRule[]
|
|
309
|
+
}),
|
|
310
|
+
serviceWorkerScript: "/bytescale-auth-sw.js"
|
|
311
|
+
});
|
|
150
312
|
|
|
151
|
-
expect(
|
|
152
|
-
expect(AuthManager.
|
|
313
|
+
expect(postMessage).not.toHaveBeenCalled();
|
|
314
|
+
expect(AuthManager.isAuthSessionReady()).toBe(false);
|
|
153
315
|
});
|
|
154
316
|
|
|
155
|
-
test("
|
|
156
|
-
|
|
157
|
-
const fetchApi =
|
|
158
|
-
switch (init?.method) {
|
|
159
|
-
case "GET":
|
|
160
|
-
return new NodeFetchResponse("jwt-a", {
|
|
161
|
-
headers: { "Content-Type": "text/plain" }
|
|
162
|
-
}) as unknown as Response;
|
|
163
|
-
case "PUT":
|
|
164
|
-
return new NodeFetchResponse(
|
|
165
|
-
JSON.stringify({ accessToken: "access-a", ttlSeconds: 3600 })
|
|
166
|
-
) as unknown as Response;
|
|
167
|
-
case "DELETE":
|
|
168
|
-
return new NodeFetchResponse(null, { status: 204 }) as unknown as Response;
|
|
169
|
-
default:
|
|
170
|
-
throw new Error(`Unexpected method: ${init?.method ?? "undefined"}`);
|
|
171
|
-
}
|
|
172
|
-
});
|
|
317
|
+
test("fails closed until the initial service-worker config callback succeeds", async () => {
|
|
318
|
+
jest.spyOn(console, "warn").mockImplementation(() => {});
|
|
319
|
+
const fetchApi = createPrimaryFetchApi();
|
|
173
320
|
|
|
174
321
|
await AuthManager.beginAuthSession({
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
authUrl: "https://app.example.com/auth",
|
|
178
|
-
options: { fetchApi },
|
|
322
|
+
...createParams(fetchApi),
|
|
323
|
+
serviceWorkerConfig: async () => null as unknown as AuthManagerServiceWorkerConfig,
|
|
179
324
|
serviceWorkerScript: "/bytescale-auth-sw.js"
|
|
180
325
|
});
|
|
181
326
|
|
|
182
|
-
expect(
|
|
327
|
+
expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT"]);
|
|
183
328
|
expect(postMessage).not.toHaveBeenCalled();
|
|
184
|
-
expect(AuthManager.isAuthSessionReady()).toBe(
|
|
329
|
+
expect(AuthManager.isAuthSessionReady()).toBe(false);
|
|
185
330
|
});
|
|
186
331
|
|
|
187
|
-
test("
|
|
188
|
-
const fetchApi =
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
case "PUT":
|
|
195
|
-
return new NodeFetchResponse(
|
|
196
|
-
JSON.stringify({ accessToken: "access-a", ttlSeconds: 3600 })
|
|
197
|
-
) as unknown as Response;
|
|
198
|
-
case "DELETE":
|
|
199
|
-
return new NodeFetchResponse(null, { status: 204 }) as unknown as Response;
|
|
200
|
-
default:
|
|
201
|
-
throw new Error(`Unexpected method: ${init?.method ?? "undefined"}`);
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
const params: BeginAuthSessionParamsV1 = {
|
|
205
|
-
accountId: "account-a",
|
|
206
|
-
authHeaders: async (): Promise<Record<string, string>> => ({ "X-App-Authorization": "app-token" }),
|
|
207
|
-
authUrl: "https://app.example.com/auth",
|
|
208
|
-
options: { fetchApi },
|
|
209
|
-
serviceWorkerScript: "/bytescale-auth-sw.js",
|
|
210
|
-
sourceUrlPrefixes: ["https://app.example.com/"]
|
|
211
|
-
};
|
|
332
|
+
test("requires a service-worker script for additional configuration", async () => {
|
|
333
|
+
const fetchApi = createPrimaryFetchApi();
|
|
334
|
+
const serviceWorkerConfig = jest.fn(
|
|
335
|
+
async (): Promise<AuthManagerServiceWorkerConfig> => ({
|
|
336
|
+
additionalConfig: []
|
|
337
|
+
})
|
|
338
|
+
);
|
|
212
339
|
|
|
213
|
-
await AuthManager.beginAuthSession(
|
|
340
|
+
await expect(AuthManager.beginAuthSession({ ...createParams(fetchApi), serviceWorkerConfig })).rejects.toThrow(
|
|
341
|
+
"'serviceWorkerScript' field is required"
|
|
342
|
+
);
|
|
214
343
|
|
|
215
|
-
expect(
|
|
216
|
-
expect(
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
expires: expect.any(Number),
|
|
220
|
-
headers: [{ key: "Authorization", value: "Bearer jwt-a" }],
|
|
221
|
-
sourceUrlPrefixes: params.sourceUrlPrefixes,
|
|
222
|
-
urlPrefix: "!bytescale-source-scoped!https://upcdn.io/account-a/"
|
|
223
|
-
}
|
|
224
|
-
],
|
|
225
|
-
type: "SET_BYTESCALE_AUTH_CONFIG"
|
|
226
|
-
});
|
|
227
|
-
expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT"]);
|
|
344
|
+
expect(serviceWorkerConfig).not.toHaveBeenCalled();
|
|
345
|
+
expect(fetchApi).not.toHaveBeenCalled();
|
|
346
|
+
expect(AuthManager.isAuthSessionActive()).toBe(false);
|
|
347
|
+
});
|
|
228
348
|
|
|
229
|
-
|
|
349
|
+
test("rejects additional configuration when service workers are unavailable", async () => {
|
|
350
|
+
delete navigatorValue.serviceWorker;
|
|
351
|
+
const fetchApi = createPrimaryFetchApi();
|
|
352
|
+
const serviceWorkerConfig = jest.fn(
|
|
353
|
+
async (): Promise<AuthManagerServiceWorkerConfig> => ({
|
|
354
|
+
additionalConfig: []
|
|
355
|
+
})
|
|
356
|
+
);
|
|
230
357
|
|
|
231
|
-
expect(
|
|
232
|
-
|
|
358
|
+
await expect(
|
|
359
|
+
AuthManager.beginAuthSession({
|
|
360
|
+
...createParams(fetchApi),
|
|
361
|
+
serviceWorkerConfig,
|
|
362
|
+
serviceWorkerScript: "/bytescale-auth-sw.js"
|
|
363
|
+
})
|
|
364
|
+
).rejects.toThrow("requires service workers");
|
|
365
|
+
|
|
366
|
+
expect(serviceWorkerConfig).not.toHaveBeenCalled();
|
|
367
|
+
expect(fetchApi).not.toHaveBeenCalled();
|
|
368
|
+
expect(AuthManager.isAuthSessionActive()).toBe(false);
|
|
233
369
|
});
|
|
234
370
|
});
|
|
371
|
+
|
|
372
|
+
function createParams(fetchApi: FetchApi): BeginAuthSessionParams {
|
|
373
|
+
return {
|
|
374
|
+
accountId: "account-a",
|
|
375
|
+
authHeaders: async (): Promise<Record<string, string>> => ({ "X-App-Authorization": "app-token" }),
|
|
376
|
+
authUrl: "https://app.example.com/auth",
|
|
377
|
+
options: { fetchApi }
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function createPrimaryFetchApi(): jest.MockedFunction<FetchApi> {
|
|
382
|
+
return jest.fn<FetchApi>(async (_input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
|
|
383
|
+
switch (init?.method) {
|
|
384
|
+
case "GET":
|
|
385
|
+
return new NodeFetchResponse("jwt-a", {
|
|
386
|
+
headers: { "Content-Type": "text/plain" }
|
|
387
|
+
}) as unknown as Response;
|
|
388
|
+
case "PUT":
|
|
389
|
+
return new NodeFetchResponse(
|
|
390
|
+
JSON.stringify({ accessToken: "access-a", ttlSeconds: 3600 })
|
|
391
|
+
) as unknown as Response;
|
|
392
|
+
case "DELETE":
|
|
393
|
+
return new NodeFetchResponse(null, { status: 204 }) as unknown as Response;
|
|
394
|
+
default:
|
|
395
|
+
throw new Error(`Unexpected method: ${init?.method ?? "undefined"}`);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
}
|