@jskit-ai/shell-web 0.1.4
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/package.descriptor.mjs +165 -0
- package/package.json +23 -0
- package/src/client/components/ShellErrorHost.vue +208 -0
- package/src/client/components/ShellLayout.vue +191 -0
- package/src/client/components/ShellOutlet.vue +95 -0
- package/src/client/components/useShellLayout.js +93 -0
- package/src/client/error/index.js +2 -0
- package/src/client/error/inject.js +142 -0
- package/src/client/error/normalize.js +75 -0
- package/src/client/error/policy.js +50 -0
- package/src/client/error/presenters.js +89 -0
- package/src/client/error/runtime.js +418 -0
- package/src/client/error/store.js +176 -0
- package/src/client/error/tokens.js +14 -0
- package/src/client/index.js +17 -0
- package/src/client/navigation/linkResolver.js +117 -0
- package/src/client/placement/debug.js +52 -0
- package/src/client/placement/index.js +26 -0
- package/src/client/placement/inject.js +104 -0
- package/src/client/placement/pathname.js +14 -0
- package/src/client/placement/registry.js +41 -0
- package/src/client/placement/runtime.js +435 -0
- package/src/client/placement/surfaceContext.js +290 -0
- package/src/client/placement/tokens.js +29 -0
- package/src/client/placement/validators.js +210 -0
- package/src/client/providers/ShellWebClientProvider.js +352 -0
- package/templates/src/App.vue +11 -0
- package/templates/src/components/ShellLayout.vue +247 -0
- package/templates/src/error.js +13 -0
- package/templates/src/pages/console/index.vue +24 -0
- package/templates/src/pages/console.vue +20 -0
- package/templates/src/pages/home/index.vue +54 -0
- package/templates/src/pages/home.vue +20 -0
- package/templates/src/placement.js +12 -0
- package/test/errorRuntime.test.js +191 -0
- package/test/errorStore.test.js +26 -0
- package/test/linkResolver.test.js +112 -0
- package/test/placementRegistry.test.js +45 -0
- package/test/placementRuntime.test.js +374 -0
- package/test/provider.test.js +163 -0
- package/test/surfaceContext.test.js +184 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import {
|
|
4
|
+
buildSurfaceConfigContext,
|
|
5
|
+
readPlacementSurfaceConfig,
|
|
6
|
+
joinSurfacePath,
|
|
7
|
+
resolveSurfaceIdFromPlacementPathname,
|
|
8
|
+
resolveSurfaceRootPathFromPlacementContext,
|
|
9
|
+
resolveSurfacePathFromPlacementContext,
|
|
10
|
+
resolveSurfaceNavigationTargetFromPlacementContext
|
|
11
|
+
} from "../src/client/placement/surfaceContext.js";
|
|
12
|
+
|
|
13
|
+
test("buildSurfaceConfigContext normalizes runtime definitions for placement context", () => {
|
|
14
|
+
const surfaceConfig = buildSurfaceConfigContext(
|
|
15
|
+
{
|
|
16
|
+
DEFAULT_SURFACE_ID: "APP",
|
|
17
|
+
listEnabledSurfaceIds() {
|
|
18
|
+
return [" APP ", "admin"];
|
|
19
|
+
},
|
|
20
|
+
listSurfaceDefinitions() {
|
|
21
|
+
return [
|
|
22
|
+
{ id: "app", pagesRoot: "", requiresWorkspace: false },
|
|
23
|
+
{ id: "admin", pagesRoot: "w/[workspaceSlug]/admin", requiresWorkspace: true },
|
|
24
|
+
{ id: "console", pagesRoot: "console", requiresWorkspace: false }
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
tenancyMode: "workspace"
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
assert.equal(surfaceConfig.defaultSurfaceId, "app");
|
|
34
|
+
assert.equal(surfaceConfig.tenancyMode, "workspace");
|
|
35
|
+
assert.deepEqual(surfaceConfig.enabledSurfaceIds, ["app", "admin"]);
|
|
36
|
+
assert.deepEqual(surfaceConfig.surfacesById.admin, {
|
|
37
|
+
id: "admin",
|
|
38
|
+
pagesRoot: "w/[workspaceSlug]/admin",
|
|
39
|
+
routeBase: "/w/:workspaceSlug/admin",
|
|
40
|
+
enabled: true,
|
|
41
|
+
requiresWorkspace: true
|
|
42
|
+
});
|
|
43
|
+
assert.deepEqual(surfaceConfig.surfacesById.console, {
|
|
44
|
+
id: "console",
|
|
45
|
+
pagesRoot: "console",
|
|
46
|
+
routeBase: "/console",
|
|
47
|
+
enabled: false,
|
|
48
|
+
requiresWorkspace: false
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("readPlacementSurfaceConfig normalizes malformed context data", () => {
|
|
53
|
+
const context = {
|
|
54
|
+
surfaceConfig: {
|
|
55
|
+
tenancyMode: "workspace",
|
|
56
|
+
defaultSurfaceId: " ADMIN ",
|
|
57
|
+
enabledSurfaceIds: ["admin", "app", "app"],
|
|
58
|
+
surfacesById: {
|
|
59
|
+
admin: {
|
|
60
|
+
id: "ADMIN",
|
|
61
|
+
pagesRoot: "w/[workspaceSlug]/admin/",
|
|
62
|
+
requiresWorkspace: true
|
|
63
|
+
},
|
|
64
|
+
app: {
|
|
65
|
+
id: "app",
|
|
66
|
+
pagesRoot: "",
|
|
67
|
+
requiresWorkspace: false
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const surfaceConfig = readPlacementSurfaceConfig(context);
|
|
74
|
+
assert.equal(surfaceConfig.defaultSurfaceId, "admin");
|
|
75
|
+
assert.deepEqual(surfaceConfig.enabledSurfaceIds, ["admin", "app"]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("surface path helpers compose root and prefixed surface routes", () => {
|
|
79
|
+
const context = {
|
|
80
|
+
surfaceConfig: {
|
|
81
|
+
tenancyMode: "workspace",
|
|
82
|
+
enabledSurfaceIds: ["app", "home", "console"],
|
|
83
|
+
surfacesById: {
|
|
84
|
+
app: {
|
|
85
|
+
id: "app",
|
|
86
|
+
pagesRoot: "app",
|
|
87
|
+
routeBase: "/app",
|
|
88
|
+
requiresWorkspace: true
|
|
89
|
+
},
|
|
90
|
+
home: {
|
|
91
|
+
id: "home",
|
|
92
|
+
pagesRoot: "",
|
|
93
|
+
routeBase: "/",
|
|
94
|
+
requiresWorkspace: false
|
|
95
|
+
},
|
|
96
|
+
console: {
|
|
97
|
+
id: "console",
|
|
98
|
+
pagesRoot: "console",
|
|
99
|
+
routeBase: "/console",
|
|
100
|
+
requiresWorkspace: false
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
assert.equal(joinSurfacePath("/admin/", "/members/"), "/admin/members");
|
|
107
|
+
assert.equal(resolveSurfaceIdFromPlacementPathname(context, "/console/settings"), "console");
|
|
108
|
+
assert.equal(resolveSurfaceIdFromPlacementPathname(context, "/unknown"), "home");
|
|
109
|
+
assert.equal(resolveSurfaceRootPathFromPlacementContext(context, "app"), "/app");
|
|
110
|
+
assert.equal(resolveSurfaceRootPathFromPlacementContext(context, "home"), "/");
|
|
111
|
+
assert.equal(resolveSurfacePathFromPlacementContext(context, "app", "/workspace/settings"), "/app/workspace/settings");
|
|
112
|
+
assert.equal(resolveSurfacePathFromPlacementContext(context, "home", "members"), "/members");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("resolveSurfaceIdFromPlacementPathname prefers most specific dynamic surface route base", () => {
|
|
116
|
+
const context = {
|
|
117
|
+
surfaceConfig: {
|
|
118
|
+
defaultSurfaceId: "home",
|
|
119
|
+
enabledSurfaceIds: ["home", "app", "admin", "console"],
|
|
120
|
+
surfacesById: {
|
|
121
|
+
home: { id: "home", pagesRoot: "", routeBase: "/" },
|
|
122
|
+
app: { id: "app", pagesRoot: "w/[workspaceSlug]", routeBase: "/w/:workspaceSlug" },
|
|
123
|
+
admin: { id: "admin", pagesRoot: "w/[workspaceSlug]/admin", routeBase: "/w/:workspaceSlug/admin" },
|
|
124
|
+
console: { id: "console", pagesRoot: "console", routeBase: "/console" }
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
assert.equal(resolveSurfaceIdFromPlacementPathname(context, "/"), "home");
|
|
130
|
+
assert.equal(resolveSurfaceIdFromPlacementPathname(context, "/w/acme"), "app");
|
|
131
|
+
assert.equal(resolveSurfaceIdFromPlacementPathname(context, "/w/acme/projects"), "app");
|
|
132
|
+
assert.equal(resolveSurfaceIdFromPlacementPathname(context, "/w/acme/admin"), "admin");
|
|
133
|
+
assert.equal(resolveSurfaceIdFromPlacementPathname(context, "/w/acme/admin/users"), "admin");
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("resolveSurfaceNavigationTargetFromPlacementContext resolves cross-origin targets from surface config", () => {
|
|
137
|
+
const context = {
|
|
138
|
+
surfaceConfig: {
|
|
139
|
+
defaultSurfaceId: "home",
|
|
140
|
+
enabledSurfaceIds: ["home", "auth", "account", "app", "admin"],
|
|
141
|
+
surfacesById: {
|
|
142
|
+
home: { id: "home", routeBase: "/home", origin: "https://www.example.com" },
|
|
143
|
+
auth: { id: "auth", routeBase: "/auth", origin: "https://auth.example.com" },
|
|
144
|
+
account: { id: "account", routeBase: "/account", origin: "https://www.example.com" },
|
|
145
|
+
app: { id: "app", routeBase: "/w/:workspaceSlug", origin: "https://app.example.com" },
|
|
146
|
+
admin: { id: "admin", routeBase: "/w/:workspaceSlug/admin", origin: "https://admin.example.com" }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const sameOriginTarget = resolveSurfaceNavigationTargetFromPlacementContext(context, {
|
|
152
|
+
path: "/account",
|
|
153
|
+
currentOrigin: "https://www.example.com"
|
|
154
|
+
});
|
|
155
|
+
assert.deepEqual(sameOriginTarget, {
|
|
156
|
+
href: "/account",
|
|
157
|
+
sameOrigin: true,
|
|
158
|
+
surfaceId: "account",
|
|
159
|
+
external: false
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const crossOriginTarget = resolveSurfaceNavigationTargetFromPlacementContext(context, {
|
|
163
|
+
path: "/auth/login",
|
|
164
|
+
currentOrigin: "https://www.example.com"
|
|
165
|
+
});
|
|
166
|
+
assert.deepEqual(crossOriginTarget, {
|
|
167
|
+
href: "https://auth.example.com/auth/login",
|
|
168
|
+
sameOrigin: false,
|
|
169
|
+
surfaceId: "auth",
|
|
170
|
+
external: false
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const explicitSurfaceTarget = resolveSurfaceNavigationTargetFromPlacementContext(context, {
|
|
174
|
+
path: "/w/acme/admin",
|
|
175
|
+
surfaceId: "admin",
|
|
176
|
+
currentOrigin: "https://app.example.com"
|
|
177
|
+
});
|
|
178
|
+
assert.deepEqual(explicitSurfaceTarget, {
|
|
179
|
+
href: "https://admin.example.com/w/acme/admin",
|
|
180
|
+
sameOrigin: false,
|
|
181
|
+
surfaceId: "admin",
|
|
182
|
+
external: false
|
|
183
|
+
});
|
|
184
|
+
});
|