@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.
Files changed (41) hide show
  1. package/package.descriptor.mjs +165 -0
  2. package/package.json +23 -0
  3. package/src/client/components/ShellErrorHost.vue +208 -0
  4. package/src/client/components/ShellLayout.vue +191 -0
  5. package/src/client/components/ShellOutlet.vue +95 -0
  6. package/src/client/components/useShellLayout.js +93 -0
  7. package/src/client/error/index.js +2 -0
  8. package/src/client/error/inject.js +142 -0
  9. package/src/client/error/normalize.js +75 -0
  10. package/src/client/error/policy.js +50 -0
  11. package/src/client/error/presenters.js +89 -0
  12. package/src/client/error/runtime.js +418 -0
  13. package/src/client/error/store.js +176 -0
  14. package/src/client/error/tokens.js +14 -0
  15. package/src/client/index.js +17 -0
  16. package/src/client/navigation/linkResolver.js +117 -0
  17. package/src/client/placement/debug.js +52 -0
  18. package/src/client/placement/index.js +26 -0
  19. package/src/client/placement/inject.js +104 -0
  20. package/src/client/placement/pathname.js +14 -0
  21. package/src/client/placement/registry.js +41 -0
  22. package/src/client/placement/runtime.js +435 -0
  23. package/src/client/placement/surfaceContext.js +290 -0
  24. package/src/client/placement/tokens.js +29 -0
  25. package/src/client/placement/validators.js +210 -0
  26. package/src/client/providers/ShellWebClientProvider.js +352 -0
  27. package/templates/src/App.vue +11 -0
  28. package/templates/src/components/ShellLayout.vue +247 -0
  29. package/templates/src/error.js +13 -0
  30. package/templates/src/pages/console/index.vue +24 -0
  31. package/templates/src/pages/console.vue +20 -0
  32. package/templates/src/pages/home/index.vue +54 -0
  33. package/templates/src/pages/home.vue +20 -0
  34. package/templates/src/placement.js +12 -0
  35. package/test/errorRuntime.test.js +191 -0
  36. package/test/errorStore.test.js +26 -0
  37. package/test/linkResolver.test.js +112 -0
  38. package/test/placementRegistry.test.js +45 -0
  39. package/test/placementRuntime.test.js +374 -0
  40. package/test/provider.test.js +163 -0
  41. 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
+ });