@bytescale/sdk 3.61.0 → 3.62.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.
@@ -0,0 +1,259 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import type { AuthSwConfigEntryDto } from "../src/index.browser";
4
+ import { AuthServiceWorkerHarness, authConfig, rewriteRule } from "./utils/AuthServiceWorkerHarness";
5
+
6
+ const mediaPrefix = "https://dashboard.example.com/media-auth/";
7
+ const downloadPrefix = "https://dashboard.example.com/download/";
8
+ const sourcePrefix = "https://app.example.com/private/";
9
+ const rules = [rewriteRule("media-auth/", ""), rewriteRule("download/", "")];
10
+ const oldWorkerSource = readFileSync(resolve(process.cwd(), "tests/fixtures/auth-sw-3.61.0.js"), "utf8");
11
+
12
+ describe("Auth service-worker original request URL restrictions", () => {
13
+ test.each([
14
+ { prefixes: undefined, directAuth: true, mediaAuth: true, downloadAuth: true },
15
+ { prefixes: [], directAuth: false, mediaAuth: false, downloadAuth: false },
16
+ { prefixes: [""], directAuth: true, mediaAuth: true, downloadAuth: true },
17
+ { prefixes: [mediaPrefix], directAuth: false, mediaAuth: true, downloadAuth: false },
18
+ { prefixes: [mediaPrefix, downloadPrefix], directAuth: false, mediaAuth: true, downloadAuth: true },
19
+ { prefixes: ["https://upcdn.io/account-a/"], directAuth: true, mediaAuth: false, downloadAuth: false }
20
+ ])("matches the original URL for $prefixes", async ({ prefixes, directAuth, mediaAuth, downloadAuth }) => {
21
+ const harness = new AuthServiceWorkerHarness();
22
+ await harness.setConfig([scopedConfig(prefixes)], rules);
23
+
24
+ const direct = await harness.dispatchFetch("https://upcdn.io/account-a/image/example.jpg");
25
+ expect(direct.responded).toBe(directAuth);
26
+ expect(direct.outboundRequest?.headers.get("Authorization")).toBe(directAuth ? "Bearer token-a" : undefined);
27
+
28
+ for (const [prefix, expectedAuth] of [
29
+ [mediaPrefix, mediaAuth],
30
+ [downloadPrefix, downloadAuth]
31
+ ] as const) {
32
+ const result = await harness.dispatchFetch(`${prefix}account-a/raw/example.jpg?download=true`, {
33
+ navigation: true
34
+ });
35
+ expect(result.outboundRequest?.url).toBe("https://upcdn.io/account-a/raw/example.jpg?download=true");
36
+ expect(result.outboundRequest?.headers.get("Authorization")).toBe(expectedAuth ? "Bearer token-a" : null);
37
+ }
38
+ });
39
+
40
+ test("still checks the final account and CDN for an allowed alias", async () => {
41
+ const harness = new AuthServiceWorkerHarness();
42
+ await harness.setConfig([scopedConfig([mediaPrefix])], rules);
43
+
44
+ const otherAccount = await harness.dispatchFetch(`${mediaPrefix}account-b/raw/example.jpg`);
45
+ const similarAccount = await harness.dispatchFetch(`${mediaPrefix}account-a-extra/raw/example.jpg`);
46
+ expect(otherAccount.outboundRequest?.headers.has("Authorization")).toBe(false);
47
+ expect(similarAccount.outboundRequest?.headers.has("Authorization")).toBe(false);
48
+
49
+ await harness.setConfig(
50
+ [scopedConfig([mediaPrefix])],
51
+ [{ fromUrlPrefix: mediaPrefix, toUrlPrefix: "https://other-cdn.example.com/" }]
52
+ );
53
+ const otherCdn = await harness.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`);
54
+ expect(otherCdn.outboundRequest?.url).toBe("https://other-cdn.example.com/account-a/raw/example.jpg");
55
+ expect(otherCdn.outboundRequest?.headers.has("Authorization")).toBe(false);
56
+ });
57
+
58
+ test.each([[], [downloadPrefix]].map((prefixes): { prefixes: typeof prefixes } => ({ prefixes })))(
59
+ "continues to another eligible config after rejecting $prefixes",
60
+ async ({ prefixes }) => {
61
+ const harness = new AuthServiceWorkerHarness();
62
+ await harness.setConfig(
63
+ [
64
+ { ...scopedConfig(prefixes), headers: [{ key: "X-Rejected", value: "must-not-leak" }] },
65
+ scopedConfig([mediaPrefix]),
66
+ { ...scopedConfig([mediaPrefix]), headers: [{ key: "Authorization", value: "Bearer later" }] }
67
+ ],
68
+ rules
69
+ );
70
+
71
+ const result = await harness.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`);
72
+ expect(result.outboundRequest?.headers.get("Authorization")).toBe("Bearer token-a");
73
+ expect(result.outboundRequest?.headers.has("X-Rejected")).toBe(false);
74
+ }
75
+ );
76
+
77
+ test("does not block an eligible destination config with a rejected original-prefix config", async () => {
78
+ const harness = new AuthServiceWorkerHarness();
79
+ await harness.setConfig(
80
+ [
81
+ scopedConfig([downloadPrefix]),
82
+ {
83
+ ...scopedConfig([mediaPrefix]),
84
+ headers: [{ key: "Authorization", value: "Bearer token-b" }],
85
+ urlPrefix: "!bytescale-request-scoped!https://upcdn.io/account-b/"
86
+ }
87
+ ],
88
+ rules
89
+ );
90
+
91
+ const result = await harness.dispatchFetch(`${mediaPrefix}account-b/raw/example.jpg`);
92
+ expect(result.outboundRequest?.headers.get("Authorization")).toBe("Bearer token-b");
93
+ });
94
+
95
+ test.each([
96
+ { requestPrefix: mediaPrefix, clientUrl: `${sourcePrefix}page`, authorized: true },
97
+ { requestPrefix: mediaPrefix, clientUrl: "https://app.example.com/public/", authorized: false },
98
+ { requestPrefix: downloadPrefix, clientUrl: `${sourcePrefix}page`, authorized: false },
99
+ { requestPrefix: mediaPrefix, clientUrl: undefined, authorized: false }
100
+ ])("combines resource and initiating-page restrictions: %j", async ({ requestPrefix, clientUrl, authorized }) => {
101
+ const harness = new AuthServiceWorkerHarness();
102
+ if (clientUrl !== undefined) {
103
+ harness.setWindowClient("client", clientUrl);
104
+ }
105
+ await harness.setConfig([scopedConfig([mediaPrefix], [sourcePrefix])], rules);
106
+
107
+ const result = await harness.dispatchFetch(`${requestPrefix}account-a/raw/example.jpg`, { clientId: "client" });
108
+ expect(result.outboundRequest?.url).toBe("https://upcdn.io/account-a/raw/example.jpg");
109
+ expect(result.outboundRequest?.headers.get("Authorization")).toBe(authorized ? "Bearer token-a" : null);
110
+ });
111
+
112
+ test("a rejected request restriction skips source lookup and permits a later config", async () => {
113
+ const harness = new AuthServiceWorkerHarness();
114
+ await harness.setConfig([scopedConfig([], [sourcePrefix]), scopedConfig([mediaPrefix])], rules);
115
+
116
+ const result = await harness.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`);
117
+ expect(result.outboundRequest?.headers.get("Authorization")).toBe("Bearer token-a");
118
+ });
119
+
120
+ test.each(["expired", "empty source", "HEAD"])("keeps rewriting when auth is excluded by %s", async reason => {
121
+ const harness = new AuthServiceWorkerHarness();
122
+ const config = scopedConfig([mediaPrefix], reason === "empty source" ? [] : undefined);
123
+ if (reason === "expired") {
124
+ config.expires = Date.now() - 1;
125
+ }
126
+ await harness.setConfig([config], rules);
127
+
128
+ const result = await harness.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg?download=true`, {
129
+ method: reason === "HEAD" ? "HEAD" : "GET"
130
+ });
131
+ expect(result.outboundRequest?.url).toBe("https://upcdn.io/account-a/raw/example.jpg?download=true");
132
+ expect(result.outboundRequest?.headers.has("Authorization")).toBe(false);
133
+ });
134
+
135
+ test("does not strip caller headers from requests excluded by the restriction", async () => {
136
+ const harness = new AuthServiceWorkerHarness();
137
+ await harness.setConfig([scopedConfig([])], rules);
138
+ const result = await harness.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`, {
139
+ headers: { "Authorization": "Caller token", "Authorization-Token": "Caller access token", "Range": "bytes=0-9" }
140
+ });
141
+ expect(result.outboundRequest?.headers.get("Authorization")).toBe("Caller token");
142
+ expect(result.outboundRequest?.headers.get("Authorization-Token")).toBe("Caller access token");
143
+ expect(result.outboundRequest?.headers.get("Range")).toBe("bytes=0-9");
144
+ });
145
+
146
+ test.each(
147
+ [undefined, [], [mediaPrefix, downloadPrefix]].map((prefixes): { prefixes: typeof prefixes } => ({ prefixes }))
148
+ )("recovers restrictions and rewrites after restart: $prefixes", async ({ prefixes }) => {
149
+ const harness = new AuthServiceWorkerHarness();
150
+ await harness.dispatchMessage({
151
+ type: "SET_BYTESCALE_AUTH_CONFIG",
152
+ config: [scopedConfig(prefixes)],
153
+ urlRewriteRules: rules
154
+ });
155
+
156
+ const direct = await harness.restart().dispatchFetch("https://upcdn.io/account-a/raw/example.jpg");
157
+ expect(direct.outboundRequest?.headers.get("Authorization")).toBe(prefixes === undefined ? "Bearer token-a" : null);
158
+ for (const prefix of [mediaPrefix, downloadPrefix]) {
159
+ const alias = await harness
160
+ .restart()
161
+ .dispatchFetch(`${prefix}account-a/raw/example.jpg?download=true`, { navigation: true });
162
+ expect(alias.outboundRequest?.url).toBe("https://upcdn.io/account-a/raw/example.jpg?download=true");
163
+ expect(alias.outboundRequest?.headers.get("Authorization")).toBe(
164
+ prefixes?.length === 0 ? null : "Bearer token-a"
165
+ );
166
+ }
167
+ });
168
+
169
+ test("recovers both restrictions after restart", async () => {
170
+ const harness = new AuthServiceWorkerHarness();
171
+ await harness.dispatchMessage({
172
+ type: "SET_BYTESCALE_AUTH_CONFIG",
173
+ config: [scopedConfig([mediaPrefix], [sourcePrefix])],
174
+ urlRewriteRules: rules
175
+ });
176
+ const restarted = harness.restart();
177
+ restarted.setWindowClient("client", `${sourcePrefix}page`);
178
+ const allowed = await restarted.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`, { clientId: "client" });
179
+ const rejected = await restarted.dispatchFetch(`${downloadPrefix}account-a/raw/example.jpg`, {
180
+ clientId: "client"
181
+ });
182
+ expect(allowed.outboundRequest?.headers.get("Authorization")).toBe("Bearer token-a");
183
+ expect(rejected.outboundRequest?.headers.has("Authorization")).toBe(false);
184
+ });
185
+
186
+ test.each([null, "https://", [42]].map((prefixes): { prefixes: typeof prefixes } => ({ prefixes })))(
187
+ "rejects malformed persisted request prefixes: $prefixes",
188
+ async ({ prefixes }) => {
189
+ const harness = new AuthServiceWorkerHarness();
190
+ await harness.setConfig([scopedConfig(prefixes as unknown as string[])], rules);
191
+ const result = await harness.restart().dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`);
192
+ expect(result.outboundRequest?.headers.has("Authorization")).toBe(false);
193
+ }
194
+ );
195
+
196
+ test("rejects restricted configs without the compatibility marker", async () => {
197
+ const harness = new AuthServiceWorkerHarness();
198
+ await harness.setConfig([{ ...authConfig("account-a/", "token-a"), requestUrlPrefixes: [mediaPrefix] }], rules);
199
+ const result = await harness.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`);
200
+ expect(result.outboundRequest?.headers.has("Authorization")).toBe(false);
201
+ });
202
+ });
203
+
204
+ describe("Auth service-worker version compatibility", () => {
205
+ test.each(
206
+ [undefined, [], [sourcePrefix]].map((sourcePrefixes): { sourcePrefixes: typeof sourcePrefixes } => ({
207
+ sourcePrefixes
208
+ }))
209
+ )("3.61.0 skips request-scoped auth with source prefixes $sourcePrefixes", async ({ sourcePrefixes }) => {
210
+ const oldWorker = new AuthServiceWorkerHarness(undefined, oldWorkerSource);
211
+ oldWorker.setWindowClient("client", `${sourcePrefix}page`);
212
+ await oldWorker.setConfig([scopedConfig([mediaPrefix, downloadPrefix], sourcePrefixes)], rules);
213
+ const direct = await oldWorker.dispatchFetch("https://upcdn.io/account-a/raw/example.jpg", {
214
+ clientId: "client"
215
+ });
216
+ expect(direct.responded).toBe(false);
217
+ const alias = await oldWorker.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`, { clientId: "client" });
218
+ expect(alias.outboundRequest?.url).toBe("https://upcdn.io/account-a/raw/example.jpg");
219
+ expect(alias.outboundRequest?.headers.has("Authorization")).toBe(false);
220
+
221
+ const recoveredOld = await oldWorker.restart().dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`);
222
+ expect(recoveredOld.outboundRequest?.headers.has("Authorization")).toBe(false);
223
+ const upgraded = oldWorker.restart(readFileSync(resolve(process.cwd(), "src/index.auth-sw.js"), "utf8"));
224
+ upgraded.setWindowClient("client", `${sourcePrefix}page`);
225
+ const recoveredNew = await upgraded.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`, {
226
+ clientId: "client"
227
+ });
228
+ expect(recoveredNew.outboundRequest?.headers.get("Authorization")).toBe(
229
+ sourcePrefixes?.length === 0 ? null : "Bearer token-a"
230
+ );
231
+ });
232
+
233
+ test("3.61.0 skips empty request prefixes before and after restart", async () => {
234
+ const oldWorker = new AuthServiceWorkerHarness(undefined, oldWorkerSource);
235
+ await oldWorker.setConfig([scopedConfig([])], rules);
236
+ const alias = await oldWorker.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`);
237
+ const direct = await oldWorker.restart().dispatchFetch("https://upcdn.io/account-a/raw/example.jpg");
238
+ expect(alias.outboundRequest?.headers.has("Authorization")).toBe(false);
239
+ expect(direct.outboundRequest?.headers.has("Authorization")).toBe(false);
240
+ });
241
+
242
+ test("3.61.0 still authenticates unrestricted configs from the new SDK", async () => {
243
+ const oldWorker = new AuthServiceWorkerHarness(undefined, oldWorkerSource);
244
+ await oldWorker.setConfig([scopedConfig(undefined)], rules);
245
+ const result = await oldWorker.dispatchFetch(`${mediaPrefix}account-a/raw/example.jpg`);
246
+ expect(result.outboundRequest?.headers.get("Authorization")).toBe("Bearer token-a");
247
+ });
248
+ });
249
+
250
+ function scopedConfig(requestUrlPrefixes: string[] | undefined, sourceUrlPrefixes?: string[]): AuthSwConfigEntryDto {
251
+ return {
252
+ ...authConfig("account-a/", "token-a"),
253
+ requestUrlPrefixes,
254
+ sourceUrlPrefixes,
255
+ urlPrefix: `${requestUrlPrefixes === undefined ? "" : "!bytescale-request-scoped!"}${
256
+ sourceUrlPrefixes === undefined ? "" : "!bytescale-source-scoped!"
257
+ }https://upcdn.io/account-a/`
258
+ };
259
+ }
@@ -1,12 +1,6 @@
1
1
  import { jest } from "@jest/globals";
2
- import { readFileSync } from "node:fs";
3
- import { resolve } from "node:path";
4
- import { runInNewContext } from "node:vm";
5
- import { Headers as NodeFetchHeaders, Request as NodeFetchRequest, Response as NodeFetchResponse } from "node-fetch";
6
- import type { RequestInit as NodeFetchRequestInit } from "node-fetch";
7
- import type { AuthSwConfigEntryDto, UrlRewriteRule } from "../src/index.browser";
8
-
9
- const workerSource = readFileSync(resolve(process.cwd(), "src/index.auth-sw.js"), "utf8");
2
+ import { Response as NodeFetchResponse } from "node-fetch";
3
+ import { AuthServiceWorkerHarness, authConfig, authConfigForUrl, rewriteRule } from "./utils/AuthServiceWorkerHarness";
10
4
 
11
5
  describe("Auth service-worker URL rewriting", () => {
12
6
  test("preserves the remaining path, query string, and fragment", async () => {
@@ -24,7 +18,11 @@ describe("Auth service-worker URL rewriting", () => {
24
18
  );
25
19
  });
26
20
 
27
- test("matches authentication against the rewritten URL and supports navigation requests", async () => {
21
+ test.each(
22
+ [undefined, ["https://dashboard.example.com/download/"]].map((prefixes): { prefixes: typeof prefixes } => ({
23
+ prefixes
24
+ }))
25
+ )("preserves streaming, range, and navigation behavior with request prefixes $prefixes", async ({ prefixes }) => {
28
26
  const upstreamResponse = new NodeFetchResponse("streamed-body", {
29
27
  headers: {
30
28
  "Accept-Ranges": "bytes",
@@ -38,7 +36,16 @@ describe("Auth service-worker URL rewriting", () => {
38
36
  const blob = jest.spyOn(upstreamResponse, "blob");
39
37
  const arrayBuffer = jest.spyOn(upstreamResponse, "arrayBuffer");
40
38
  const harness = new AuthServiceWorkerHarness(upstreamResponse);
41
- await harness.setConfig([authConfig("account-a/", "token-a")], [rewriteRule("download/", "account-a/")]);
39
+ await harness.setConfig(
40
+ [
41
+ {
42
+ ...authConfig("account-a/", "token-a"),
43
+ requestUrlPrefixes: prefixes,
44
+ urlPrefix: `${prefixes === undefined ? "" : "!bytescale-request-scoped!"}https://upcdn.io/account-a/`
45
+ }
46
+ ],
47
+ [rewriteRule("download/", "account-a/")]
48
+ );
42
49
 
43
50
  const result = await harness.dispatchFetch("https://dashboard.example.com/download/file.pdf", {
44
51
  headers: {
@@ -213,145 +220,3 @@ describe("Auth service-worker URL rewriting", () => {
213
220
  expect(result.outboundRequest?.headers.get("X-Trace-Id")).toBe("trace");
214
221
  });
215
222
  });
216
-
217
- interface FetchOptions {
218
- clientId?: string;
219
- headers?: HeadersInit;
220
- navigation?: boolean;
221
- }
222
-
223
- interface FetchResult {
224
- outboundRequest: TestRequest | undefined;
225
- responded: boolean;
226
- response: NodeFetchResponse | undefined;
227
- }
228
-
229
- type WorkerEventListener = (event: unknown) => void;
230
-
231
- class AuthServiceWorkerHarness {
232
- private readonly clientsById = new Map<string, { type: "window"; url: string }>();
233
- private readonly cacheEntries = new Map<string, NodeFetchResponse>();
234
- private cacheReadDelayMilliseconds = 0;
235
- private readonly context: {
236
- getRewrittenUrl: (url: string, rules: UrlRewriteRule[]) => string | undefined;
237
- setConfig: (config: AuthSwConfigEntryDto[], rules?: UrlRewriteRule[]) => Promise<void>;
238
- };
239
-
240
- private readonly fetchListener: WorkerEventListener;
241
- private readonly fetchMock: jest.MockedFunction<(request: TestRequest) => Promise<NodeFetchResponse>>;
242
-
243
- constructor(private readonly upstreamResponse: NodeFetchResponse = new NodeFetchResponse("ok")) {
244
- const listeners = new Map<string, WorkerEventListener>();
245
- this.fetchMock = jest.fn(async (_request: TestRequest): Promise<NodeFetchResponse> => this.upstreamResponse);
246
-
247
- const self = {
248
- addEventListener: (type: string, listener: WorkerEventListener): void => {
249
- listeners.set(type, listener);
250
- },
251
- clients: {
252
- claim: async (): Promise<void> => {},
253
- get: async (clientId: string): Promise<{ type: "window"; url: string } | undefined> =>
254
- this.clientsById.get(clientId)
255
- },
256
- skipWaiting: async (): Promise<void> => {}
257
- };
258
- const cache = {
259
- match: async (key: string): Promise<NodeFetchResponse | undefined> => {
260
- if (this.cacheReadDelayMilliseconds > 0) {
261
- await new Promise(resolve => setTimeout(resolve, this.cacheReadDelayMilliseconds));
262
- }
263
- return this.cacheEntries.get(key)?.clone();
264
- },
265
- put: async (key: string, value: NodeFetchResponse): Promise<void> => {
266
- this.cacheEntries.set(key, value.clone());
267
- }
268
- };
269
- const sandbox = {
270
- caches: { open: async (): Promise<typeof cache> => cache },
271
- console: { error: jest.fn(), log: jest.fn() },
272
- fetch: this.fetchMock,
273
- Headers: NodeFetchHeaders,
274
- Promise,
275
- Request: TestRequest,
276
- Response: NodeFetchResponse,
277
- self,
278
- setTimeout
279
- };
280
- runInNewContext(workerSource, sandbox);
281
-
282
- this.context = sandbox as typeof sandbox & AuthServiceWorkerHarness["context"];
283
- const fetchListener = listeners.get("fetch");
284
- if (fetchListener === undefined) {
285
- throw new Error("Auth service worker did not register a fetch listener.");
286
- }
287
- this.fetchListener = fetchListener;
288
- }
289
-
290
- async setConfig(config: AuthSwConfigEntryDto[], rules?: UrlRewriteRule[]): Promise<void> {
291
- await this.context.setConfig(config, rules);
292
- }
293
-
294
- getRewrittenUrl(url: string, rules: UrlRewriteRule[]): string | undefined {
295
- return this.context.getRewrittenUrl(url, rules);
296
- }
297
-
298
- setWindowClient(clientId: string, url: string): void {
299
- this.clientsById.set(clientId, { type: "window", url });
300
- }
301
-
302
- setPersistentConfig(config: AuthSwConfigEntryDto[], cacheReadDelayMilliseconds: number): void {
303
- this.cacheEntries.set("config", new NodeFetchResponse(JSON.stringify(config)));
304
- this.cacheReadDelayMilliseconds = cacheReadDelayMilliseconds;
305
- }
306
-
307
- async dispatchFetch(url: string, options: FetchOptions = {}): Promise<FetchResult> {
308
- const request = new TestRequest(url, { headers: options.headers as NodeFetchRequestInit["headers"] });
309
- if (options.navigation === true) {
310
- Object.defineProperty(request, "mode", { configurable: true, value: "navigate" });
311
- }
312
-
313
- let responsePromise: Promise<NodeFetchResponse> | undefined;
314
- this.fetchListener({
315
- clientId: options.clientId ?? "",
316
- request,
317
- respondWith: (response: NodeFetchResponse | Promise<NodeFetchResponse>): void => {
318
- responsePromise = Promise.resolve(response);
319
- }
320
- });
321
-
322
- const response = await responsePromise;
323
- return {
324
- outboundRequest: this.fetchMock.mock.calls.at(-1)?.[0],
325
- responded: responsePromise !== undefined,
326
- response
327
- };
328
- }
329
- }
330
-
331
- class TestRequest extends NodeFetchRequest {
332
- readonly mode: RequestMode;
333
-
334
- constructor(input: string | NodeFetchRequest, init: NodeFetchRequestInit & { mode?: RequestMode } = {}) {
335
- super(input, init);
336
- this.mode = init.mode ?? (input instanceof TestRequest ? input.mode : "cors");
337
- }
338
- }
339
-
340
- function authConfig(accountPath: string, token: string): AuthSwConfigEntryDto {
341
- return authConfigForUrl(`https://upcdn.io/${accountPath}`, token);
342
- }
343
-
344
- function authConfigForUrl(urlPrefix: string, token: string): AuthSwConfigEntryDto {
345
- return {
346
- expires: undefined,
347
- headers: [{ key: "Authorization", value: `Bearer ${token}` }],
348
- urlPrefix
349
- };
350
- }
351
-
352
- function rewriteRule(fromPath: string, toPath: string): UrlRewriteRule {
353
- return {
354
- fromUrlPrefix: `https://dashboard.example.com/${fromPath}`,
355
- toUrlPrefix: `https://upcdn.io/${toPath}`
356
- };
357
- }