@agent-native/dispatch 0.15.22 → 0.15.24
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/actions/provider-api-register.d.ts +11 -11
- package/dist/actions/sync-vault-to-app.d.ts +4 -4
- package/dist/server/lib/app-creation-store.js +1 -1
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/vault-store.d.ts +4 -4
- package/dist/server/lib/vault-store.d.ts.map +1 -1
- package/dist/server/lib/vault-store.js +53 -28
- package/dist/server/lib/vault-store.js.map +1 -1
- package/package.json +3 -5
- package/src/server/lib/app-creation-store.ts +1 -1
- package/src/server/lib/vault-store.spec.ts +159 -0
- package/src/server/lib/vault-store.ts +61 -28
- package/dist/server/lib/pre-auth-routing.d.ts +0 -2
- package/dist/server/lib/pre-auth-routing.d.ts.map +0 -1
- package/dist/server/lib/pre-auth-routing.js +0 -136
- package/dist/server/lib/pre-auth-routing.js.map +0 -1
- package/src/server/lib/pre-auth-routing.ts +0 -159
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
const mocks = vi.hoisted(() => ({
|
|
4
|
+
currentOrgId: vi.fn(),
|
|
5
|
+
currentOwnerEmail: vi.fn(),
|
|
4
6
|
deleteAppSecret: vi.fn(),
|
|
7
|
+
discoverAgents: vi.fn(),
|
|
5
8
|
getDb: vi.fn(),
|
|
9
|
+
getOrgSetting: vi.fn(),
|
|
10
|
+
getUserSetting: vi.fn(),
|
|
6
11
|
listAppSecretsForScope: vi.fn(),
|
|
7
12
|
readAppSecret: vi.fn(),
|
|
13
|
+
recordAudit: vi.fn(),
|
|
8
14
|
writeAppSecret: vi.fn(),
|
|
9
15
|
}));
|
|
10
16
|
|
|
@@ -15,6 +21,23 @@ vi.mock("@agent-native/core/secrets", () => ({
|
|
|
15
21
|
writeAppSecret: mocks.writeAppSecret,
|
|
16
22
|
}));
|
|
17
23
|
|
|
24
|
+
vi.mock("@agent-native/core/server/agent-discovery", () => ({
|
|
25
|
+
discoverAgents: mocks.discoverAgents,
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
vi.mock("@agent-native/core/settings", () => ({
|
|
29
|
+
getOrgSetting: mocks.getOrgSetting,
|
|
30
|
+
getUserSetting: mocks.getUserSetting,
|
|
31
|
+
putOrgSetting: vi.fn(),
|
|
32
|
+
putUserSetting: vi.fn(),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
vi.mock("./dispatch-store.js", () => ({
|
|
36
|
+
currentOrgId: mocks.currentOrgId,
|
|
37
|
+
currentOwnerEmail: mocks.currentOwnerEmail,
|
|
38
|
+
recordAudit: mocks.recordAudit,
|
|
39
|
+
}));
|
|
40
|
+
|
|
18
41
|
vi.mock("../../db/index.js", async (importOriginal) => {
|
|
19
42
|
const actual = await importOriginal<typeof import("../../db/index.js")>();
|
|
20
43
|
return {
|
|
@@ -30,6 +53,7 @@ import {
|
|
|
30
53
|
credentialStoreScopeForVaultCtx,
|
|
31
54
|
isTrustedEnvVarSyncAgentUrl,
|
|
32
55
|
resyncAllVaultSecretsToCredentialStore,
|
|
56
|
+
syncGrantsToApp,
|
|
33
57
|
syncSecretsToCredentialStore,
|
|
34
58
|
} from "./vault-store.js";
|
|
35
59
|
|
|
@@ -319,3 +343,138 @@ describe("resyncAllVaultSecretsToCredentialStore", () => {
|
|
|
319
343
|
warnSpy.mockRestore();
|
|
320
344
|
});
|
|
321
345
|
});
|
|
346
|
+
|
|
347
|
+
describe("syncGrantsToApp", () => {
|
|
348
|
+
/** In-memory stand-in for app_secrets, keyed scope + scopeId + key. */
|
|
349
|
+
function fakeCredentialStore() {
|
|
350
|
+
const store = new Map<string, string>();
|
|
351
|
+
mocks.writeAppSecret.mockImplementation(async (args: any) => {
|
|
352
|
+
store.set(`${args.scope}:${args.scopeId}:${args.key}`, args.value);
|
|
353
|
+
return "app-secret-id";
|
|
354
|
+
});
|
|
355
|
+
return store;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* `all-apps` vault access, one discovered app, and a caller whose active org
|
|
360
|
+
* is deliberately NOT the org that owns the secrets. The app URL is remote so
|
|
361
|
+
* the best-effort env-var push is skipped and no network call is attempted.
|
|
362
|
+
*/
|
|
363
|
+
function mockWorkspace(
|
|
364
|
+
caller: { ownerEmail: string; orgId: string | null },
|
|
365
|
+
secretRows: Array<Record<string, unknown>>,
|
|
366
|
+
) {
|
|
367
|
+
mocks.currentOwnerEmail.mockReturnValue(caller.ownerEmail);
|
|
368
|
+
mocks.currentOrgId.mockReturnValue(caller.orgId);
|
|
369
|
+
mocks.getOrgSetting.mockResolvedValue(null);
|
|
370
|
+
mocks.getUserSetting.mockResolvedValue(null);
|
|
371
|
+
mocks.discoverAgents.mockResolvedValue([
|
|
372
|
+
{ id: "coach", url: "https://coach.example.test" },
|
|
373
|
+
]);
|
|
374
|
+
mocks.getDb.mockReturnValue({
|
|
375
|
+
select: () => ({
|
|
376
|
+
from: () => ({
|
|
377
|
+
where: () => ({ orderBy: async () => secretRows }),
|
|
378
|
+
}),
|
|
379
|
+
}),
|
|
380
|
+
insert: () => ({ values: async () => undefined }),
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
afterEach(() => {
|
|
385
|
+
mocks.writeAppSecret.mockReset();
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
// The regression: `all-apps` mode lists secrets across orgs, and syncing them
|
|
389
|
+
// under the caller's ctx upserts copies of another org's credentials into
|
|
390
|
+
// whichever org the person clicking Sync happened to be in. Because
|
|
391
|
+
// writeAppSecret upserts, that copies rather than moves, so credential
|
|
392
|
+
// material accumulates permanently in the wrong org.
|
|
393
|
+
it("writes each secret under its own org, not the caller's active org", async () => {
|
|
394
|
+
const store = fakeCredentialStore();
|
|
395
|
+
mockWorkspace({ ownerEmail: "clicker@example.test", orgId: "org_caller" }, [
|
|
396
|
+
{
|
|
397
|
+
id: "secret_builder",
|
|
398
|
+
ownerEmail: "admin@example.test",
|
|
399
|
+
orgId: "org_owner",
|
|
400
|
+
name: "Academy Site URL",
|
|
401
|
+
credentialKey: "ACADEMY_CONVEX_SITE_URL",
|
|
402
|
+
value: "https://academy.example.test",
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
id: "secret_solo",
|
|
406
|
+
ownerEmail: "owner@example.test",
|
|
407
|
+
orgId: null,
|
|
408
|
+
name: "Personal API Key",
|
|
409
|
+
credentialKey: "PERSONAL_API_KEY",
|
|
410
|
+
value: "sk-test-personal",
|
|
411
|
+
},
|
|
412
|
+
]);
|
|
413
|
+
|
|
414
|
+
const result = await syncGrantsToApp("coach");
|
|
415
|
+
|
|
416
|
+
expect(store.get("org:org_owner:ACADEMY_CONVEX_SITE_URL")).toBe(
|
|
417
|
+
"https://academy.example.test",
|
|
418
|
+
);
|
|
419
|
+
expect(
|
|
420
|
+
store.get("workspace:solo:owner@example.test:PERSONAL_API_KEY"),
|
|
421
|
+
).toBe("sk-test-personal");
|
|
422
|
+
|
|
423
|
+
// Nothing may be written under the caller's org.
|
|
424
|
+
const callerScoped = [...store.keys()].filter((key) =>
|
|
425
|
+
key.startsWith("org:org_caller:"),
|
|
426
|
+
);
|
|
427
|
+
expect(callerScoped).toEqual([]);
|
|
428
|
+
|
|
429
|
+
expect(result.credentialStores).toEqual([
|
|
430
|
+
{ scope: "org", scopeId: "org_owner", synced: 1 },
|
|
431
|
+
{
|
|
432
|
+
scope: "workspace",
|
|
433
|
+
scopeId: "solo:owner@example.test",
|
|
434
|
+
synced: 1,
|
|
435
|
+
},
|
|
436
|
+
]);
|
|
437
|
+
expect(result.synced).toBe(2);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it("still syncs the caller's own org secrets into that org", async () => {
|
|
441
|
+
const store = fakeCredentialStore();
|
|
442
|
+
mockWorkspace({ ownerEmail: "clicker@example.test", orgId: "org_caller" }, [
|
|
443
|
+
{
|
|
444
|
+
id: "secret_own",
|
|
445
|
+
ownerEmail: "clicker@example.test",
|
|
446
|
+
orgId: "org_caller",
|
|
447
|
+
name: "Shared API Key",
|
|
448
|
+
credentialKey: "SHARED_API_KEY",
|
|
449
|
+
value: "sk-test-shared",
|
|
450
|
+
},
|
|
451
|
+
]);
|
|
452
|
+
|
|
453
|
+
const result = await syncGrantsToApp("coach");
|
|
454
|
+
|
|
455
|
+
expect(store.get("org:org_caller:SHARED_API_KEY")).toBe("sk-test-shared");
|
|
456
|
+
expect(result.credentialStores).toEqual([
|
|
457
|
+
{ scope: "org", scopeId: "org_caller", synced: 1 },
|
|
458
|
+
]);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
// A row with no ownerEmail cannot name its own tenant, so the caller's ctx is
|
|
462
|
+
// the only scope available — the pre-existing ctxForSecretRow fallback.
|
|
463
|
+
it("falls back to the caller ctx for a secret row with no owner", async () => {
|
|
464
|
+
const store = fakeCredentialStore();
|
|
465
|
+
mockWorkspace({ ownerEmail: "clicker@example.test", orgId: "org_caller" }, [
|
|
466
|
+
{
|
|
467
|
+
id: "secret_ownerless",
|
|
468
|
+
ownerEmail: "",
|
|
469
|
+
orgId: null,
|
|
470
|
+
name: "Legacy Key",
|
|
471
|
+
credentialKey: "LEGACY_KEY",
|
|
472
|
+
value: "sk-test-legacy",
|
|
473
|
+
},
|
|
474
|
+
]);
|
|
475
|
+
|
|
476
|
+
await syncGrantsToApp("coach");
|
|
477
|
+
|
|
478
|
+
expect(store.get("org:org_caller:LEGACY_KEY")).toBe("sk-test-legacy");
|
|
479
|
+
});
|
|
480
|
+
});
|
|
@@ -763,6 +763,33 @@ export async function syncSecretsToCredentialStore(
|
|
|
763
763
|
return { ...target, keys: syncedKeys };
|
|
764
764
|
}
|
|
765
765
|
|
|
766
|
+
/**
|
|
767
|
+
* Group secrets by the tenant their credential-store rows must land in.
|
|
768
|
+
*
|
|
769
|
+
* Every sync path must write a secret under the org that *owns the row*, not
|
|
770
|
+
* under whoever happens to be syncing: `writeAppSecret` upserts, so syncing
|
|
771
|
+
* with the caller's ctx copies credential material into the caller's org
|
|
772
|
+
* instead of moving it, and it accumulates there permanently.
|
|
773
|
+
*/
|
|
774
|
+
function groupSecretsByTenant(
|
|
775
|
+
rows: VaultSecretRow[],
|
|
776
|
+
resolveCtx: (row: VaultSecretRow) => VaultCtx,
|
|
777
|
+
): { ctx: VaultCtx; rows: VaultSecretRow[] }[] {
|
|
778
|
+
const groups = new Map<string, { ctx: VaultCtx; rows: VaultSecretRow[] }>();
|
|
779
|
+
for (const row of rows) {
|
|
780
|
+
if (!row.credentialKey || !row.value) continue;
|
|
781
|
+
const ctx = resolveCtx(row);
|
|
782
|
+
const groupKey = `${ctx.orgId ?? ""}\u0000${ctx.ownerEmail}`;
|
|
783
|
+
const group = groups.get(groupKey);
|
|
784
|
+
if (group) {
|
|
785
|
+
group.rows.push(row);
|
|
786
|
+
} else {
|
|
787
|
+
groups.set(groupKey, { ctx, rows: [row] });
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return [...groups.values()];
|
|
791
|
+
}
|
|
792
|
+
|
|
766
793
|
/**
|
|
767
794
|
* Re-sync every vault secret across every tenant into the shared credential
|
|
768
795
|
* store, regardless of which request/ctx is currently active.
|
|
@@ -788,23 +815,12 @@ export async function resyncAllVaultSecretsToCredentialStore(): Promise<{
|
|
|
788
815
|
const db = getDb();
|
|
789
816
|
const rows = await db.select().from(schema.vaultSecrets);
|
|
790
817
|
|
|
791
|
-
const groups =
|
|
792
|
-
for (const row of rows) {
|
|
793
|
-
if (!row.credentialKey || !row.value) continue;
|
|
794
|
-
const ctx: VaultCtx = { ownerEmail: row.ownerEmail, orgId: row.orgId };
|
|
795
|
-
const groupKey = `${ctx.orgId ?? ""}${ctx.ownerEmail}`;
|
|
796
|
-
const group = groups.get(groupKey);
|
|
797
|
-
if (group) {
|
|
798
|
-
group.rows.push(row);
|
|
799
|
-
} else {
|
|
800
|
-
groups.set(groupKey, { ctx, rows: [row] });
|
|
801
|
-
}
|
|
802
|
-
}
|
|
818
|
+
const groups = groupSecretsByTenant(rows, ctxForRow);
|
|
803
819
|
|
|
804
820
|
let failedGroups = 0;
|
|
805
821
|
let syncedKeys = 0;
|
|
806
822
|
|
|
807
|
-
for (const { ctx, rows: groupRows } of groups
|
|
823
|
+
for (const { ctx, rows: groupRows } of groups) {
|
|
808
824
|
try {
|
|
809
825
|
const result = await syncSecretsToCredentialStore(groupRows, ctx);
|
|
810
826
|
syncedKeys += result.keys.length;
|
|
@@ -818,7 +834,7 @@ export async function resyncAllVaultSecretsToCredentialStore(): Promise<{
|
|
|
818
834
|
}
|
|
819
835
|
}
|
|
820
836
|
|
|
821
|
-
return { groups: groups.
|
|
837
|
+
return { groups: groups.length, failedGroups, syncedKeys };
|
|
822
838
|
}
|
|
823
839
|
|
|
824
840
|
export async function cleanupSyncedCredentialKeysIfUnused(
|
|
@@ -889,13 +905,37 @@ export async function syncGrantsToApp(
|
|
|
889
905
|
}
|
|
890
906
|
|
|
891
907
|
if (secretsToSync.length === 0) {
|
|
892
|
-
return {
|
|
908
|
+
return {
|
|
909
|
+
appId,
|
|
910
|
+
accessMode: access.mode,
|
|
911
|
+
synced: 0,
|
|
912
|
+
keys: [],
|
|
913
|
+
credentialStores: [],
|
|
914
|
+
};
|
|
893
915
|
}
|
|
894
916
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
917
|
+
// `all-apps` mode lists secrets across every org the caller can see, so each
|
|
918
|
+
// row must be written back under its own org. Syncing them all under `ctx`
|
|
919
|
+
// upserts copies of other orgs' credentials into the caller's org.
|
|
920
|
+
const credentialStoreGroups = groupSecretsByTenant(secretsToSync, (row) =>
|
|
921
|
+
ctxForSecretRow(row, ctx),
|
|
898
922
|
);
|
|
923
|
+
const credentialStores: {
|
|
924
|
+
scope: ReturnType<typeof credentialStoreScopeForVaultCtx>["scope"];
|
|
925
|
+
scopeId: string;
|
|
926
|
+
synced: number;
|
|
927
|
+
}[] = [];
|
|
928
|
+
const credentialStoreKeys: string[] = [];
|
|
929
|
+
for (const group of credentialStoreGroups) {
|
|
930
|
+
const result = await syncSecretsToCredentialStore(group.rows, group.ctx);
|
|
931
|
+
credentialStores.push({
|
|
932
|
+
scope: result.scope,
|
|
933
|
+
scopeId: result.scopeId,
|
|
934
|
+
synced: result.keys.length,
|
|
935
|
+
});
|
|
936
|
+
credentialStoreKeys.push(...result.keys);
|
|
937
|
+
}
|
|
938
|
+
|
|
899
939
|
const vars = secretsToSync.map((secret) => ({
|
|
900
940
|
key: secret.credentialKey,
|
|
901
941
|
value: secret.value,
|
|
@@ -942,7 +982,7 @@ export async function syncGrantsToApp(
|
|
|
942
982
|
}
|
|
943
983
|
}
|
|
944
984
|
|
|
945
|
-
const syncedKeys =
|
|
985
|
+
const syncedKeys = credentialStoreKeys;
|
|
946
986
|
const timestamp = now();
|
|
947
987
|
|
|
948
988
|
// Update syncedAt on grants that were successfully pushed to the shared
|
|
@@ -964,10 +1004,7 @@ export async function syncGrantsToApp(
|
|
|
964
1004
|
metadata: {
|
|
965
1005
|
syncedKeys,
|
|
966
1006
|
accessMode: access.mode,
|
|
967
|
-
|
|
968
|
-
scope: credentialStoreSync.scope,
|
|
969
|
-
scopeId: credentialStoreSync.scopeId,
|
|
970
|
-
},
|
|
1007
|
+
credentialStores,
|
|
971
1008
|
envVars: envVarSync,
|
|
972
1009
|
},
|
|
973
1010
|
});
|
|
@@ -977,11 +1014,7 @@ export async function syncGrantsToApp(
|
|
|
977
1014
|
accessMode: access.mode,
|
|
978
1015
|
synced: syncedKeys.length,
|
|
979
1016
|
keys: syncedKeys,
|
|
980
|
-
|
|
981
|
-
scope: credentialStoreSync.scope,
|
|
982
|
-
scopeId: credentialStoreSync.scopeId,
|
|
983
|
-
synced: credentialStoreSync.keys.length,
|
|
984
|
-
},
|
|
1017
|
+
credentialStores,
|
|
985
1018
|
envVars: envVarSync,
|
|
986
1019
|
};
|
|
987
1020
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pre-auth-routing.d.ts","sourceRoot":"","sources":["../../../src/server/lib/pre-auth-routing.ts"],"names":[],"mappings":"AAoFA,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,QAAQ,GAAG,IAAI,CAuEjB"}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
function normalizeBasePath(value) {
|
|
2
|
-
if (!value || value === "/")
|
|
3
|
-
return "";
|
|
4
|
-
const trimmed = value.trim();
|
|
5
|
-
if (!trimmed || trimmed === "/")
|
|
6
|
-
return "";
|
|
7
|
-
return `/${trimmed.replace(/^\/+/, "").replace(/\/+$/, "")}`;
|
|
8
|
-
}
|
|
9
|
-
function normalizePathname(value) {
|
|
10
|
-
if (value === "/")
|
|
11
|
-
return "/";
|
|
12
|
-
return value.replace(/\/+$/, "") || "/";
|
|
13
|
-
}
|
|
14
|
-
const DISPATCH_PAGE_PATHS = new Set([
|
|
15
|
-
"/overview",
|
|
16
|
-
"/metrics",
|
|
17
|
-
"/login",
|
|
18
|
-
"/signup",
|
|
19
|
-
"/apps",
|
|
20
|
-
"/new-app",
|
|
21
|
-
"/vault",
|
|
22
|
-
"/integrations",
|
|
23
|
-
"/agents",
|
|
24
|
-
"/workspace",
|
|
25
|
-
"/tools",
|
|
26
|
-
"/messaging",
|
|
27
|
-
"/destinations",
|
|
28
|
-
"/identities",
|
|
29
|
-
"/approvals",
|
|
30
|
-
"/automations",
|
|
31
|
-
"/audit",
|
|
32
|
-
"/team",
|
|
33
|
-
]);
|
|
34
|
-
const DISPATCH_ROOT_ALIASES = new Map([
|
|
35
|
-
...Array.from(DISPATCH_PAGE_PATHS, (path) => [path, path]),
|
|
36
|
-
["/approval", "/approval"],
|
|
37
|
-
["/extensions", "/extensions"],
|
|
38
|
-
["/tools", "/tools"],
|
|
39
|
-
["/apps/new-app", "/new-app"],
|
|
40
|
-
]);
|
|
41
|
-
const MOUNTED_DISPATCH_ALIASES = new Map([
|
|
42
|
-
["/apps/new-app", "/new-app"],
|
|
43
|
-
]);
|
|
44
|
-
function isDispatchPagePath(pathname) {
|
|
45
|
-
if (DISPATCH_PAGE_PATHS.has(pathname))
|
|
46
|
-
return true;
|
|
47
|
-
if (pathname === "/approval" || pathname === "/extensions")
|
|
48
|
-
return true;
|
|
49
|
-
if (pathname === "/tools")
|
|
50
|
-
return true;
|
|
51
|
-
return (/^\/extensions\/[^/]+$/.test(pathname) ||
|
|
52
|
-
/^\/tools\/[^/]+$/.test(pathname) ||
|
|
53
|
-
/^\/apps\/[^/]+$/.test(pathname));
|
|
54
|
-
}
|
|
55
|
-
function isDispatchAssetOrFrameworkPath(pathname) {
|
|
56
|
-
return (pathname === "/__manifest" ||
|
|
57
|
-
pathname.startsWith("/__manifest/") ||
|
|
58
|
-
pathname === "/_agent-native" ||
|
|
59
|
-
pathname.startsWith("/_agent-native/") ||
|
|
60
|
-
pathname === "/.well-known" ||
|
|
61
|
-
pathname.startsWith("/.well-known/") ||
|
|
62
|
-
pathname.startsWith("/assets/") ||
|
|
63
|
-
pathname.startsWith("/_build/") ||
|
|
64
|
-
pathname.endsWith(".js") ||
|
|
65
|
-
pathname.endsWith(".css") ||
|
|
66
|
-
pathname.endsWith(".map") ||
|
|
67
|
-
pathname.endsWith(".ico") ||
|
|
68
|
-
pathname.endsWith(".png") ||
|
|
69
|
-
pathname.endsWith(".svg") ||
|
|
70
|
-
pathname.endsWith(".woff2") ||
|
|
71
|
-
pathname.endsWith(".woff"));
|
|
72
|
-
}
|
|
73
|
-
function dispatchNotFoundResponse() {
|
|
74
|
-
return new Response("Dispatch route not found", {
|
|
75
|
-
status: 404,
|
|
76
|
-
headers: { "content-type": "text/plain; charset=utf-8" },
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
export function rootDispatchRedirect(pathname, search) {
|
|
80
|
-
const normalizedPathname = normalizePathname(pathname);
|
|
81
|
-
const basePath = normalizeBasePath(process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH);
|
|
82
|
-
if (!basePath)
|
|
83
|
-
return null;
|
|
84
|
-
if (normalizedPathname === "/__manifest" ||
|
|
85
|
-
normalizedPathname.startsWith("/__manifest/") ||
|
|
86
|
-
normalizedPathname === "/_agent-native" ||
|
|
87
|
-
normalizedPathname.startsWith("/_agent-native/")) {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
if (normalizedPathname === "/.well-known" ||
|
|
91
|
-
normalizedPathname.startsWith("/.well-known/")) {
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
if (normalizedPathname === "/") {
|
|
95
|
-
return new Response(null, {
|
|
96
|
-
status: 302,
|
|
97
|
-
headers: { Location: `${basePath}/overview${search}` },
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
if (normalizedPathname === basePath) {
|
|
101
|
-
return new Response(null, {
|
|
102
|
-
status: 302,
|
|
103
|
-
headers: { Location: `${basePath}/overview${search}` },
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
if (normalizedPathname.startsWith(`${basePath}/`)) {
|
|
107
|
-
const dispatchPath = normalizedPathname.slice(basePath.length);
|
|
108
|
-
const mountedAlias = MOUNTED_DISPATCH_ALIASES.get(dispatchPath);
|
|
109
|
-
if (mountedAlias) {
|
|
110
|
-
return new Response(null, {
|
|
111
|
-
status: 302,
|
|
112
|
-
headers: { Location: `${basePath}${mountedAlias}${search}` },
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
if (isDispatchPagePath(dispatchPath) ||
|
|
116
|
-
isDispatchAssetOrFrameworkPath(dispatchPath)) {
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
return dispatchNotFoundResponse();
|
|
120
|
-
}
|
|
121
|
-
const rootAlias = DISPATCH_ROOT_ALIASES.get(normalizedPathname);
|
|
122
|
-
if (rootAlias) {
|
|
123
|
-
return new Response(null, {
|
|
124
|
-
status: 302,
|
|
125
|
-
headers: { Location: `${basePath}${rootAlias}${search}` },
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
if (/^\/apps\/[^/]+$/.test(normalizedPathname)) {
|
|
129
|
-
return new Response(null, {
|
|
130
|
-
status: 302,
|
|
131
|
-
headers: { Location: `${basePath}${normalizedPathname}${search}` },
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
return dispatchNotFoundResponse();
|
|
135
|
-
}
|
|
136
|
-
//# sourceMappingURL=pre-auth-routing.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pre-auth-routing.js","sourceRoot":"","sources":["../../../src/server/lib/pre-auth-routing.ts"],"names":[],"mappings":"AAAA,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,GAAG;QAAE,OAAO,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,EAAE,CAAC;IAC3C,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa;IACtC,IAAI,KAAK,KAAK,GAAG;QAAE,OAAO,GAAG,CAAC;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;AAC1C,CAAC;AAED,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,WAAW;IACX,UAAU;IACV,QAAQ;IACR,SAAS;IACT,OAAO;IACP,UAAU;IACV,QAAQ;IACR,eAAe;IACf,SAAS;IACT,YAAY;IACZ,QAAQ;IACR,YAAY;IACZ,eAAe;IACf,aAAa;IACb,YAAY;IACZ,cAAc;IACd,QAAQ;IACR,OAAO;CACR,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAiB;IACpD,GAAG,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAU,CAAC;IACnE,CAAC,WAAW,EAAE,WAAW,CAAC;IAC1B,CAAC,aAAa,EAAE,aAAa,CAAC;IAC9B,CAAC,QAAQ,EAAE,QAAQ,CAAC;IACpB,CAAC,eAAe,EAAE,UAAU,CAAC;CAC9B,CAAC,CAAC;AAEH,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAiB;IACvD,CAAC,eAAe,EAAE,UAAU,CAAC;CAC9B,CAAC,CAAC;AAEH,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,IAAI,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC;IACxE,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,CACL,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC;QACtC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC;QACjC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CACjC,CAAC;AACJ,CAAC;AAED,SAAS,8BAA8B,CAAC,QAAgB;IACtD,OAAO,CACL,QAAQ,KAAK,aAAa;QAC1B,QAAQ,CAAC,UAAU,CAAC,cAAc,CAAC;QACnC,QAAQ,KAAK,gBAAgB;QAC7B,QAAQ,CAAC,UAAU,CAAC,iBAAiB,CAAC;QACtC,QAAQ,KAAK,cAAc;QAC3B,QAAQ,CAAC,UAAU,CAAC,eAAe,CAAC;QACpC,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC;QAC/B,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC;QAC/B,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;QACxB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC3B,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAC3B,CAAC;AACJ,CAAC;AAED,SAAS,wBAAwB;IAC/B,OAAO,IAAI,QAAQ,CAAC,0BAA0B,EAAE;QAC9C,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE;KACzD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,MAAc;IAEd,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,iBAAiB,CAChC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAC5D,CAAC;IACF,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE3B,IACE,kBAAkB,KAAK,aAAa;QACpC,kBAAkB,CAAC,UAAU,CAAC,cAAc,CAAC;QAC7C,kBAAkB,KAAK,gBAAgB;QACvC,kBAAkB,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAChD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IACE,kBAAkB,KAAK,cAAc;QACrC,kBAAkB,CAAC,UAAU,CAAC,eAAe,CAAC,EAC9C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,kBAAkB,KAAK,GAAG,EAAE,CAAC;QAC/B,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;YACxB,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,QAAQ,YAAY,MAAM,EAAE,EAAE;SACvD,CAAC,CAAC;IACL,CAAC;IAED,IAAI,kBAAkB,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;YACxB,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,QAAQ,YAAY,MAAM,EAAE,EAAE;SACvD,CAAC,CAAC;IACL,CAAC;IAED,IAAI,kBAAkB,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/D,MAAM,YAAY,GAAG,wBAAwB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAChE,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;gBACxB,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,EAAE,EAAE;aAC7D,CAAC,CAAC;QACL,CAAC;QACD,IACE,kBAAkB,CAAC,YAAY,CAAC;YAChC,8BAA8B,CAAC,YAAY,CAAC,EAC5C,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,wBAAwB,EAAE,CAAC;IACpC,CAAC;IAED,MAAM,SAAS,GAAG,qBAAqB,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChE,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;YACxB,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,EAAE,EAAE;SAC1D,CAAC,CAAC;IACL,CAAC;IAED,IAAI,iBAAiB,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC/C,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;YACxB,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,QAAQ,GAAG,kBAAkB,GAAG,MAAM,EAAE,EAAE;SACnE,CAAC,CAAC;IACL,CAAC;IAED,OAAO,wBAAwB,EAAE,CAAC;AACpC,CAAC","sourcesContent":["function normalizeBasePath(value?: string): string {\n if (!value || value === \"/\") return \"\";\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"/\") return \"\";\n return `/${trimmed.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\")}`;\n}\n\nfunction normalizePathname(value: string): string {\n if (value === \"/\") return \"/\";\n return value.replace(/\\/+$/, \"\") || \"/\";\n}\n\nconst DISPATCH_PAGE_PATHS = new Set([\n \"/overview\",\n \"/metrics\",\n \"/login\",\n \"/signup\",\n \"/apps\",\n \"/new-app\",\n \"/vault\",\n \"/integrations\",\n \"/agents\",\n \"/workspace\",\n \"/tools\",\n \"/messaging\",\n \"/destinations\",\n \"/identities\",\n \"/approvals\",\n \"/automations\",\n \"/audit\",\n \"/team\",\n]);\n\nconst DISPATCH_ROOT_ALIASES = new Map<string, string>([\n ...Array.from(DISPATCH_PAGE_PATHS, (path) => [path, path] as const),\n [\"/approval\", \"/approval\"],\n [\"/extensions\", \"/extensions\"],\n [\"/tools\", \"/tools\"],\n [\"/apps/new-app\", \"/new-app\"],\n]);\n\nconst MOUNTED_DISPATCH_ALIASES = new Map<string, string>([\n [\"/apps/new-app\", \"/new-app\"],\n]);\n\nfunction isDispatchPagePath(pathname: string): boolean {\n if (DISPATCH_PAGE_PATHS.has(pathname)) return true;\n if (pathname === \"/approval\" || pathname === \"/extensions\") return true;\n if (pathname === \"/tools\") return true;\n return (\n /^\\/extensions\\/[^/]+$/.test(pathname) ||\n /^\\/tools\\/[^/]+$/.test(pathname) ||\n /^\\/apps\\/[^/]+$/.test(pathname)\n );\n}\n\nfunction isDispatchAssetOrFrameworkPath(pathname: string): boolean {\n return (\n pathname === \"/__manifest\" ||\n pathname.startsWith(\"/__manifest/\") ||\n pathname === \"/_agent-native\" ||\n pathname.startsWith(\"/_agent-native/\") ||\n pathname === \"/.well-known\" ||\n pathname.startsWith(\"/.well-known/\") ||\n pathname.startsWith(\"/assets/\") ||\n pathname.startsWith(\"/_build/\") ||\n pathname.endsWith(\".js\") ||\n pathname.endsWith(\".css\") ||\n pathname.endsWith(\".map\") ||\n pathname.endsWith(\".ico\") ||\n pathname.endsWith(\".png\") ||\n pathname.endsWith(\".svg\") ||\n pathname.endsWith(\".woff2\") ||\n pathname.endsWith(\".woff\")\n );\n}\n\nfunction dispatchNotFoundResponse(): Response {\n return new Response(\"Dispatch route not found\", {\n status: 404,\n headers: { \"content-type\": \"text/plain; charset=utf-8\" },\n });\n}\n\nexport function rootDispatchRedirect(\n pathname: string,\n search: string,\n): Response | null {\n const normalizedPathname = normalizePathname(pathname);\n const basePath = normalizeBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n if (!basePath) return null;\n\n if (\n normalizedPathname === \"/__manifest\" ||\n normalizedPathname.startsWith(\"/__manifest/\") ||\n normalizedPathname === \"/_agent-native\" ||\n normalizedPathname.startsWith(\"/_agent-native/\")\n ) {\n return null;\n }\n\n if (\n normalizedPathname === \"/.well-known\" ||\n normalizedPathname.startsWith(\"/.well-known/\")\n ) {\n return null;\n }\n\n if (normalizedPathname === \"/\") {\n return new Response(null, {\n status: 302,\n headers: { Location: `${basePath}/overview${search}` },\n });\n }\n\n if (normalizedPathname === basePath) {\n return new Response(null, {\n status: 302,\n headers: { Location: `${basePath}/overview${search}` },\n });\n }\n\n if (normalizedPathname.startsWith(`${basePath}/`)) {\n const dispatchPath = normalizedPathname.slice(basePath.length);\n const mountedAlias = MOUNTED_DISPATCH_ALIASES.get(dispatchPath);\n if (mountedAlias) {\n return new Response(null, {\n status: 302,\n headers: { Location: `${basePath}${mountedAlias}${search}` },\n });\n }\n if (\n isDispatchPagePath(dispatchPath) ||\n isDispatchAssetOrFrameworkPath(dispatchPath)\n ) {\n return null;\n }\n return dispatchNotFoundResponse();\n }\n\n const rootAlias = DISPATCH_ROOT_ALIASES.get(normalizedPathname);\n if (rootAlias) {\n return new Response(null, {\n status: 302,\n headers: { Location: `${basePath}${rootAlias}${search}` },\n });\n }\n\n if (/^\\/apps\\/[^/]+$/.test(normalizedPathname)) {\n return new Response(null, {\n status: 302,\n headers: { Location: `${basePath}${normalizedPathname}${search}` },\n });\n }\n\n return dispatchNotFoundResponse();\n}\n"]}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
function normalizeBasePath(value?: string): string {
|
|
2
|
-
if (!value || value === "/") return "";
|
|
3
|
-
const trimmed = value.trim();
|
|
4
|
-
if (!trimmed || trimmed === "/") return "";
|
|
5
|
-
return `/${trimmed.replace(/^\/+/, "").replace(/\/+$/, "")}`;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
function normalizePathname(value: string): string {
|
|
9
|
-
if (value === "/") return "/";
|
|
10
|
-
return value.replace(/\/+$/, "") || "/";
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const DISPATCH_PAGE_PATHS = new Set([
|
|
14
|
-
"/overview",
|
|
15
|
-
"/metrics",
|
|
16
|
-
"/login",
|
|
17
|
-
"/signup",
|
|
18
|
-
"/apps",
|
|
19
|
-
"/new-app",
|
|
20
|
-
"/vault",
|
|
21
|
-
"/integrations",
|
|
22
|
-
"/agents",
|
|
23
|
-
"/workspace",
|
|
24
|
-
"/tools",
|
|
25
|
-
"/messaging",
|
|
26
|
-
"/destinations",
|
|
27
|
-
"/identities",
|
|
28
|
-
"/approvals",
|
|
29
|
-
"/automations",
|
|
30
|
-
"/audit",
|
|
31
|
-
"/team",
|
|
32
|
-
]);
|
|
33
|
-
|
|
34
|
-
const DISPATCH_ROOT_ALIASES = new Map<string, string>([
|
|
35
|
-
...Array.from(DISPATCH_PAGE_PATHS, (path) => [path, path] as const),
|
|
36
|
-
["/approval", "/approval"],
|
|
37
|
-
["/extensions", "/extensions"],
|
|
38
|
-
["/tools", "/tools"],
|
|
39
|
-
["/apps/new-app", "/new-app"],
|
|
40
|
-
]);
|
|
41
|
-
|
|
42
|
-
const MOUNTED_DISPATCH_ALIASES = new Map<string, string>([
|
|
43
|
-
["/apps/new-app", "/new-app"],
|
|
44
|
-
]);
|
|
45
|
-
|
|
46
|
-
function isDispatchPagePath(pathname: string): boolean {
|
|
47
|
-
if (DISPATCH_PAGE_PATHS.has(pathname)) return true;
|
|
48
|
-
if (pathname === "/approval" || pathname === "/extensions") return true;
|
|
49
|
-
if (pathname === "/tools") return true;
|
|
50
|
-
return (
|
|
51
|
-
/^\/extensions\/[^/]+$/.test(pathname) ||
|
|
52
|
-
/^\/tools\/[^/]+$/.test(pathname) ||
|
|
53
|
-
/^\/apps\/[^/]+$/.test(pathname)
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function isDispatchAssetOrFrameworkPath(pathname: string): boolean {
|
|
58
|
-
return (
|
|
59
|
-
pathname === "/__manifest" ||
|
|
60
|
-
pathname.startsWith("/__manifest/") ||
|
|
61
|
-
pathname === "/_agent-native" ||
|
|
62
|
-
pathname.startsWith("/_agent-native/") ||
|
|
63
|
-
pathname === "/.well-known" ||
|
|
64
|
-
pathname.startsWith("/.well-known/") ||
|
|
65
|
-
pathname.startsWith("/assets/") ||
|
|
66
|
-
pathname.startsWith("/_build/") ||
|
|
67
|
-
pathname.endsWith(".js") ||
|
|
68
|
-
pathname.endsWith(".css") ||
|
|
69
|
-
pathname.endsWith(".map") ||
|
|
70
|
-
pathname.endsWith(".ico") ||
|
|
71
|
-
pathname.endsWith(".png") ||
|
|
72
|
-
pathname.endsWith(".svg") ||
|
|
73
|
-
pathname.endsWith(".woff2") ||
|
|
74
|
-
pathname.endsWith(".woff")
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function dispatchNotFoundResponse(): Response {
|
|
79
|
-
return new Response("Dispatch route not found", {
|
|
80
|
-
status: 404,
|
|
81
|
-
headers: { "content-type": "text/plain; charset=utf-8" },
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function rootDispatchRedirect(
|
|
86
|
-
pathname: string,
|
|
87
|
-
search: string,
|
|
88
|
-
): Response | null {
|
|
89
|
-
const normalizedPathname = normalizePathname(pathname);
|
|
90
|
-
const basePath = normalizeBasePath(
|
|
91
|
-
process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,
|
|
92
|
-
);
|
|
93
|
-
if (!basePath) return null;
|
|
94
|
-
|
|
95
|
-
if (
|
|
96
|
-
normalizedPathname === "/__manifest" ||
|
|
97
|
-
normalizedPathname.startsWith("/__manifest/") ||
|
|
98
|
-
normalizedPathname === "/_agent-native" ||
|
|
99
|
-
normalizedPathname.startsWith("/_agent-native/")
|
|
100
|
-
) {
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
normalizedPathname === "/.well-known" ||
|
|
106
|
-
normalizedPathname.startsWith("/.well-known/")
|
|
107
|
-
) {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (normalizedPathname === "/") {
|
|
112
|
-
return new Response(null, {
|
|
113
|
-
status: 302,
|
|
114
|
-
headers: { Location: `${basePath}/overview${search}` },
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (normalizedPathname === basePath) {
|
|
119
|
-
return new Response(null, {
|
|
120
|
-
status: 302,
|
|
121
|
-
headers: { Location: `${basePath}/overview${search}` },
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (normalizedPathname.startsWith(`${basePath}/`)) {
|
|
126
|
-
const dispatchPath = normalizedPathname.slice(basePath.length);
|
|
127
|
-
const mountedAlias = MOUNTED_DISPATCH_ALIASES.get(dispatchPath);
|
|
128
|
-
if (mountedAlias) {
|
|
129
|
-
return new Response(null, {
|
|
130
|
-
status: 302,
|
|
131
|
-
headers: { Location: `${basePath}${mountedAlias}${search}` },
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
if (
|
|
135
|
-
isDispatchPagePath(dispatchPath) ||
|
|
136
|
-
isDispatchAssetOrFrameworkPath(dispatchPath)
|
|
137
|
-
) {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
return dispatchNotFoundResponse();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const rootAlias = DISPATCH_ROOT_ALIASES.get(normalizedPathname);
|
|
144
|
-
if (rootAlias) {
|
|
145
|
-
return new Response(null, {
|
|
146
|
-
status: 302,
|
|
147
|
-
headers: { Location: `${basePath}${rootAlias}${search}` },
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (/^\/apps\/[^/]+$/.test(normalizedPathname)) {
|
|
152
|
-
return new Response(null, {
|
|
153
|
-
status: 302,
|
|
154
|
-
headers: { Location: `${basePath}${normalizedPathname}${search}` },
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return dispatchNotFoundResponse();
|
|
159
|
-
}
|