@jskit-ai/users-web 0.1.52 → 0.1.54

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 (73) hide show
  1. package/package.descriptor.mjs +14 -96
  2. package/package.json +16 -11
  3. package/src/client/account-settings/sections.js +74 -0
  4. package/src/client/composables/account-settings/accountSettingsRuntimeHelpers.js +2 -38
  5. package/src/client/composables/crud/crudLookupFieldRuntime.js +2 -2
  6. package/src/client/composables/internal/crudListParentTitleSupport.js +1 -1
  7. package/src/client/composables/internal/useOperationScope.js +12 -12
  8. package/src/client/composables/records/useAddEdit.js +2 -2
  9. package/src/client/composables/records/useList.js +3 -3
  10. package/src/client/composables/records/useView.js +2 -2
  11. package/src/client/composables/support/scopeHelpers.js +19 -19
  12. package/src/client/composables/useAccess.js +3 -3
  13. package/src/client/composables/useAccountSettingsRuntime.js +8 -156
  14. package/src/client/composables/useCommand.js +2 -2
  15. package/src/client/composables/useCrudListParentTitle.js +2 -2
  16. package/src/client/composables/usePaths.js +50 -38
  17. package/src/client/composables/useScopeRuntime.js +55 -27
  18. package/src/client/composables/useSurfaceRouteContext.js +1 -7
  19. package/src/client/index.js +0 -1
  20. package/src/client/lib/bootstrap.js +0 -63
  21. package/src/client/lib/httpClient.js +2 -59
  22. package/src/client/lib/theme.js +12 -189
  23. package/src/client/providers/UsersWebClientProvider.js +2 -25
  24. package/src/client/providers/bootUsersWebClientProvider.js +28 -0
  25. package/src/shared/toolsOutletContracts.js +1 -8
  26. package/templates/src/components/account/settings/AccountSettingsClientElement.vue +33 -21
  27. package/test/accountSettingsSections.test.js +79 -0
  28. package/test/exportsContract.test.js +2 -2
  29. package/test/scopeHelpers.test.js +6 -6
  30. package/test/settingsPlacementContract.test.js +4 -49
  31. package/test/theme.test.js +0 -56
  32. package/src/client/components/ConsoleSettingsClientElement.vue +0 -24
  33. package/src/client/components/MembersAdminClientElement.vue +0 -400
  34. package/src/client/components/UsersProfileSurfaceSwitchMenuItem.vue +0 -39
  35. package/src/client/components/UsersWorkspaceMembersMenuItem.vue +0 -36
  36. package/src/client/components/UsersWorkspacePermissionMenuItem.vue +0 -90
  37. package/src/client/components/UsersWorkspaceSelector.vue +0 -248
  38. package/src/client/components/UsersWorkspaceSettingsMenuItem.vue +0 -39
  39. package/src/client/components/UsersWorkspaceToolsWidget.vue +0 -12
  40. package/src/client/components/WorkspaceMembersClientElement.vue +0 -655
  41. package/src/client/components/WorkspaceProfileClientElement.vue +0 -116
  42. package/src/client/components/WorkspaceSettingsClientElement.vue +0 -102
  43. package/src/client/components/WorkspaceSettingsFieldsClientElement.vue +0 -265
  44. package/src/client/components/WorkspacesClientElement.vue +0 -509
  45. package/src/client/composables/account-settings/accountSettingsInvitesRuntime.js +0 -88
  46. package/src/client/composables/useBootstrapQuery.js +0 -52
  47. package/src/client/composables/useWorkspaceRouteContext.js +0 -28
  48. package/src/client/composables/useWorkspaceSurfaceId.js +0 -43
  49. package/src/client/lib/menuIcons.js +0 -210
  50. package/src/client/lib/profileSurfaceMenuLinks.js +0 -142
  51. package/src/client/lib/surfaceAccessPolicy.js +0 -350
  52. package/src/client/lib/workspaceLinkResolver.js +0 -207
  53. package/src/client/lib/workspaceSurfaceContext.js +0 -82
  54. package/src/client/lib/workspaceSurfacePaths.js +0 -163
  55. package/src/client/providers/UsersWorkspacesClientProvider.js +0 -24
  56. package/src/client/runtime/bootstrapPlacementRouteGuards.js +0 -371
  57. package/src/client/runtime/bootstrapPlacementRuntime.js +0 -463
  58. package/src/client/runtime/bootstrapPlacementRuntimeConstants.js +0 -28
  59. package/src/client/runtime/bootstrapPlacementRuntimeHelpers.js +0 -147
  60. package/src/client/support/menuLinkTarget.js +0 -93
  61. package/src/client/support/realtimeWorkspace.js +0 -21
  62. package/src/client/support/runtimeNormalization.js +0 -27
  63. package/src/client/support/workspaceQueryKeys.js +0 -15
  64. package/templates/src/components/account/settings/AccountSettingsInvitesSection.vue +0 -77
  65. package/templates/src/pages/console/settings/index.vue +0 -8
  66. package/templates/src/pages/console/settings.vue +0 -32
  67. package/test/bootstrapPlacementRuntime.test.js +0 -1095
  68. package/test/menuIcons.test.js +0 -35
  69. package/test/menuLinkTarget.test.js +0 -116
  70. package/test/profileSurfaceMenuLinks.test.js +0 -207
  71. package/test/surfaceAccessPolicy.test.js +0 -129
  72. package/test/workspaceLinkResolver.test.js +0 -61
  73. package/test/workspaceSurfacePaths.test.js +0 -39
@@ -1,163 +0,0 @@
1
- import {
2
- normalizeSurfaceId
3
- } from "@jskit-ai/kernel/shared/surface";
4
- import {
5
- normalizePathname,
6
- normalizeSurfaceSegmentFromRouteBase,
7
- parseWorkspacePathname,
8
- resolveDefaultWorkspaceSurfaceId,
9
- resolveWorkspaceSurfaceIdFromSuffixSegments
10
- } from "@jskit-ai/users-core/shared/support/workspacePathModel";
11
- import {
12
- readPlacementSurfaceConfig,
13
- resolveSurfaceDefinitionFromPlacementContext,
14
- resolveSurfacePathFromPlacementContext,
15
- resolveSurfaceRootPathFromPlacementContext
16
- } from "@jskit-ai/shell-web/client/placement";
17
- import {
18
- listWorkspaceSurfaceIdsFromSurfaceConfig,
19
- surfaceRequiresWorkspaceFromPlacementContext
20
- } from "./workspaceSurfaceContext.js";
21
-
22
- const ACCOUNT_SURFACE_ID = "account";
23
- const ACCOUNT_SETTINGS_SUFFIX = "/";
24
- const ACCOUNT_SETTINGS_FALLBACK_PATH = "/account";
25
-
26
- function normalizeWorkspaceSuffix(suffix) {
27
- const rawSuffix = String(suffix || "/").trim();
28
- if (!rawSuffix || rawSuffix === "/") {
29
- return "/";
30
- }
31
- return rawSuffix.startsWith("/") ? rawSuffix : `/${rawSuffix}`;
32
- }
33
-
34
- function resolveWorkspaceSurfaceIdFromSurfaceConfig(surfaceConfig, pathname = "") {
35
- const parsedWorkspacePath = parseWorkspacePathname(pathname, {
36
- workspaceBasePath: "/w"
37
- });
38
- if (!parsedWorkspacePath) {
39
- return "";
40
- }
41
-
42
- const workspaceSurfaceIds = listWorkspaceSurfaceIdsFromSurfaceConfig(surfaceConfig);
43
- const defaultWorkspaceSurfaceId = resolveDefaultWorkspaceSurfaceId({
44
- defaultSurfaceId: surfaceConfig?.defaultSurfaceId,
45
- workspaceSurfaceIds,
46
- surfaceRequiresWorkspace: (surfaceId) => Boolean(surfaceConfig?.surfacesById?.[surfaceId]?.requiresWorkspace)
47
- });
48
- if (parsedWorkspacePath.suffixSegments.length < 1) {
49
- return defaultWorkspaceSurfaceId || normalizeSurfaceId(surfaceConfig?.defaultSurfaceId);
50
- }
51
-
52
- const workspaceSurfaces = workspaceSurfaceIds
53
- .map((surfaceId) => normalizeSurfaceId(surfaceId))
54
- .map((surfaceId) => {
55
- if (!surfaceId) {
56
- return null;
57
- }
58
- const definition = surfaceConfig.surfacesById?.[surfaceId];
59
- return {
60
- id: surfaceId,
61
- routeBase: definition?.routeBase
62
- };
63
- })
64
- .filter(Boolean);
65
-
66
- return (
67
- resolveWorkspaceSurfaceIdFromSuffixSegments({
68
- suffixSegments: parsedWorkspacePath.suffixSegments,
69
- defaultWorkspaceSurfaceId,
70
- workspaceSurfaces
71
- }) ||
72
- defaultWorkspaceSurfaceId ||
73
- normalizeSurfaceId(surfaceConfig?.defaultSurfaceId)
74
- );
75
- }
76
-
77
- function resolveWorkspaceSurfaceIdFromPlacementPathname(contextValue = null, pathname = "") {
78
- const surfaceConfig = readPlacementSurfaceConfig(contextValue);
79
- const normalizedPathname =
80
- normalizePathname(pathname) ||
81
- (typeof window === "object" && window?.location?.pathname ? normalizePathname(window.location.pathname) : "/");
82
-
83
- return resolveWorkspaceSurfaceIdFromSurfaceConfig(surfaceConfig, normalizedPathname);
84
- }
85
-
86
- function resolveAccountSettingsPathFromPlacementContext(contextValue = null) {
87
- const accountSurfaceDefinition = resolveSurfaceDefinitionFromPlacementContext(contextValue, ACCOUNT_SURFACE_ID);
88
- if (!accountSurfaceDefinition) {
89
- return ACCOUNT_SETTINGS_FALLBACK_PATH;
90
- }
91
-
92
- return resolveSurfacePathFromPlacementContext(contextValue, ACCOUNT_SURFACE_ID, ACCOUNT_SETTINGS_SUFFIX);
93
- }
94
-
95
- function resolveSurfaceWorkspacePathFromPlacementContext(contextValue = null, surfaceId = "", workspaceSlug = "", suffix = "/") {
96
- const normalizedWorkspaceSlug = String(workspaceSlug || "").trim();
97
- const normalizedSurfaceId = normalizeSurfaceId(surfaceId);
98
- if (!normalizedWorkspaceSlug) {
99
- return "";
100
- }
101
-
102
- const surfaceConfig = readPlacementSurfaceConfig(contextValue);
103
- const surfaceDefinition = surfaceConfig.surfacesById[normalizedSurfaceId] || null;
104
- const normalizedSuffix = normalizeWorkspaceSuffix(suffix);
105
-
106
- if (surfaceDefinition && !surfaceDefinition.requiresWorkspace) {
107
- if (normalizedSuffix === "/") {
108
- return resolveSurfaceRootPathFromPlacementContext(contextValue, normalizedSurfaceId);
109
- }
110
- return resolveSurfacePathFromPlacementContext(contextValue, normalizedSurfaceId, normalizedSuffix);
111
- }
112
-
113
- let workspaceRootPath = `/w/${normalizedWorkspaceSlug}`;
114
- const workspaceSurfaceIds = listWorkspaceSurfaceIdsFromSurfaceConfig(surfaceConfig);
115
- const defaultWorkspaceSurfaceId = resolveDefaultWorkspaceSurfaceId({
116
- defaultSurfaceId: surfaceConfig?.defaultSurfaceId,
117
- workspaceSurfaceIds,
118
- surfaceRequiresWorkspace: (candidateSurfaceId) => Boolean(surfaceConfig?.surfacesById?.[candidateSurfaceId]?.requiresWorkspace)
119
- });
120
- if (normalizedSurfaceId && normalizedSurfaceId !== defaultWorkspaceSurfaceId) {
121
- const surfaceSegment = normalizeSurfaceSegmentFromRouteBase(surfaceDefinition?.routeBase) || normalizedSurfaceId;
122
- if (surfaceSegment) {
123
- workspaceRootPath = `${workspaceRootPath}/${surfaceSegment}`;
124
- }
125
- }
126
-
127
- if (normalizedSuffix === "/") {
128
- return normalizePathname(workspaceRootPath);
129
- }
130
- return normalizePathname(`${workspaceRootPath}${normalizedSuffix}`);
131
- }
132
-
133
- function extractWorkspaceSlugFromSurfacePathname(contextValue = null, surfaceId = "", pathname = "") {
134
- const normalizedPathname = normalizePathname(
135
- pathname || (typeof window === "object" && window?.location?.pathname ? window.location.pathname : "/")
136
- );
137
- const normalizedSurfaceId = normalizeSurfaceId(surfaceId);
138
- if (!normalizedSurfaceId) {
139
- return "";
140
- }
141
- if (!surfaceRequiresWorkspaceFromPlacementContext(contextValue, normalizedSurfaceId)) {
142
- return "";
143
- }
144
-
145
- const parsedWorkspacePath = parseWorkspacePathname(normalizedPathname);
146
- if (!parsedWorkspacePath) {
147
- return "";
148
- }
149
-
150
- const resolvedSurfaceId = resolveWorkspaceSurfaceIdFromPlacementPathname(contextValue, normalizedPathname);
151
- if (resolvedSurfaceId !== normalizedSurfaceId) {
152
- return "";
153
- }
154
-
155
- return parsedWorkspacePath.workspaceSlug;
156
- }
157
-
158
- export {
159
- resolveAccountSettingsPathFromPlacementContext,
160
- resolveWorkspaceSurfaceIdFromPlacementPathname,
161
- resolveSurfaceWorkspacePathFromPlacementContext,
162
- extractWorkspaceSlugFromSurfacePathname
163
- };
@@ -1,24 +0,0 @@
1
- import UsersWorkspaceSelector from "../components/UsersWorkspaceSelector.vue";
2
- import UsersWorkspaceToolsWidget from "../components/UsersWorkspaceToolsWidget.vue";
3
- import UsersWorkspaceSettingsMenuItem from "../components/UsersWorkspaceSettingsMenuItem.vue";
4
- import UsersWorkspaceMembersMenuItem from "../components/UsersWorkspaceMembersMenuItem.vue";
5
- import MembersAdminClientElement from "../components/MembersAdminClientElement.vue";
6
-
7
- class UsersWorkspacesClientProvider {
8
- static id = "workspaces.web.client";
9
- static dependsOn = ["users.web.client"];
10
-
11
- register(app) {
12
- if (!app || typeof app.singleton !== "function") {
13
- throw new Error("UsersWorkspacesClientProvider requires application singleton().");
14
- }
15
-
16
- app.singleton("users.web.workspace.selector", () => UsersWorkspaceSelector);
17
- app.singleton("users.web.workspace.tools.widget", () => UsersWorkspaceToolsWidget);
18
- app.singleton("users.web.workspace-settings.menu-item", () => UsersWorkspaceSettingsMenuItem);
19
- app.singleton("users.web.workspace-members.menu-item", () => UsersWorkspaceMembersMenuItem);
20
- app.singleton("users.web.members-admin.element", () => MembersAdminClientElement);
21
- }
22
- }
23
-
24
- export { UsersWorkspacesClientProvider };
@@ -1,371 +0,0 @@
1
- import {
2
- resolveSurfaceDefinitionFromPlacementContext,
3
- resolveSurfaceIdFromPlacementPathname,
4
- resolveSurfaceRootPathFromPlacementContext,
5
- resolveRuntimePathname
6
- } from "@jskit-ai/shell-web/client/placement";
7
- import {
8
- extractWorkspaceSlugFromSurfacePathname,
9
- resolveSurfaceWorkspacePathFromPlacementContext
10
- } from "../lib/workspaceSurfacePaths.js";
11
- import { evaluateSurfaceAccess } from "../lib/surfaceAccessPolicy.js";
12
- import {
13
- SHELL_GUARD_EVALUATOR_KEY,
14
- WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN,
15
- WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND,
16
- WORKSPACE_FORBIDDEN_GUARD_REASON,
17
- WORKSPACE_NOT_FOUND_GUARD_REASON
18
- } from "./bootstrapPlacementRuntimeConstants.js";
19
- import {
20
- isGuardDenied,
21
- normalizeSearch,
22
- normalizeWorkspaceBootstrapStatus,
23
- normalizeWorkspaceSlugKey,
24
- resolveSearchFromFullPath
25
- } from "./bootstrapPlacementRuntimeHelpers.js";
26
-
27
- function createBootstrapPlacementRouteGuards({
28
- placementRuntime,
29
- router = null,
30
- root = null,
31
- getWorkspaceBootstrapStatus = () => ""
32
- } = {}) {
33
- const cleanup = [];
34
- let delegatedGuardEvaluator = null;
35
- let workspaceGuardEvaluatorInstalled = false;
36
-
37
- function resolveNormalizedSurfaceState(pathname = "/", search = "") {
38
- const context = placementRuntime.getContext();
39
- const normalizedPathname = resolveRuntimePathname(pathname);
40
- const normalizedSearch = normalizeSearch(search);
41
- const surfaceId = String(resolveSurfaceIdFromPlacementPathname(context, normalizedPathname) || "")
42
- .trim()
43
- .toLowerCase();
44
- if (!surfaceId) {
45
- return null;
46
- }
47
-
48
- const surfaceDefinition = resolveSurfaceDefinitionFromPlacementContext(context, surfaceId);
49
- if (!surfaceDefinition) {
50
- return null;
51
- }
52
-
53
- return Object.freeze({
54
- context,
55
- normalizedPathname,
56
- normalizedSearch,
57
- surfaceId,
58
- surfaceDefinition
59
- });
60
- }
61
-
62
- function resolveWorkspaceRouteState(pathname = "/", search = "") {
63
- const surfaceState = resolveNormalizedSurfaceState(pathname, search);
64
- if (!surfaceState || surfaceState.surfaceDefinition.requiresWorkspace !== true) {
65
- return null;
66
- }
67
-
68
- const workspaceSlug = normalizeWorkspaceSlugKey(
69
- extractWorkspaceSlugFromSurfacePathname(surfaceState.context, surfaceState.surfaceId, surfaceState.normalizedPathname)
70
- );
71
- if (!workspaceSlug) {
72
- return null;
73
- }
74
-
75
- return Object.freeze({
76
- pathname: surfaceState.normalizedPathname,
77
- search: surfaceState.normalizedSearch,
78
- surfaceId: surfaceState.surfaceId,
79
- workspaceSlug,
80
- workspaceRootPath: resolveRuntimePathname(
81
- resolveSurfaceWorkspacePathFromPlacementContext(surfaceState.context, surfaceState.surfaceId, workspaceSlug, "/")
82
- ),
83
- workspaceBootstrapStatus: String(getWorkspaceBootstrapStatus(workspaceSlug) || "")
84
- });
85
- }
86
-
87
- function resolveSurfaceRouteState(pathname = "/", search = "") {
88
- const surfaceState = resolveNormalizedSurfaceState(pathname, search);
89
- if (!surfaceState || surfaceState.surfaceDefinition.enabled === false) {
90
- return null;
91
- }
92
-
93
- const workspaceSlug =
94
- surfaceState.surfaceDefinition.requiresWorkspace === true
95
- ? normalizeWorkspaceSlugKey(
96
- extractWorkspaceSlugFromSurfacePathname(
97
- surfaceState.context,
98
- surfaceState.surfaceId,
99
- surfaceState.normalizedPathname
100
- )
101
- )
102
- : "";
103
- return Object.freeze({
104
- pathname: surfaceState.normalizedPathname,
105
- search: surfaceState.normalizedSearch,
106
- surfaceId: surfaceState.surfaceId,
107
- workspaceSlug,
108
- workspaceBootstrapStatus: workspaceSlug ? String(getWorkspaceBootstrapStatus(workspaceSlug) || "") : ""
109
- });
110
- }
111
-
112
- function resolveDefaultSurfaceFallbackPath(surfaceState = null) {
113
- const context = placementRuntime.getContext();
114
- const defaultSurfaceId = String(context?.surfaceConfig?.defaultSurfaceId || "")
115
- .trim()
116
- .toLowerCase();
117
- const fallbackSurfaceId = defaultSurfaceId || surfaceState?.surfaceId || "";
118
- if (!fallbackSurfaceId) {
119
- return "/";
120
- }
121
-
122
- const fallbackSurfaceDefinition = resolveSurfaceDefinitionFromPlacementContext(context, fallbackSurfaceId);
123
- if (fallbackSurfaceDefinition?.requiresWorkspace === true) {
124
- const fallbackWorkspaceSlug =
125
- normalizeWorkspaceSlugKey(surfaceState?.workspaceSlug) || normalizeWorkspaceSlugKey(context?.workspace?.slug);
126
- if (!fallbackWorkspaceSlug) {
127
- return "/";
128
- }
129
- return resolveRuntimePathname(
130
- resolveSurfaceWorkspacePathFromPlacementContext(context, fallbackSurfaceId, fallbackWorkspaceSlug, "/")
131
- );
132
- }
133
-
134
- const fallbackPath = resolveRuntimePathname(resolveSurfaceRootPathFromPlacementContext(context, fallbackSurfaceId));
135
- if (fallbackPath.includes(":")) {
136
- return "/";
137
- }
138
- return fallbackPath || "/";
139
- }
140
-
141
- function resolveWorkspaceGuardDecision(pathname = "/", search = "") {
142
- const workspaceState = resolveWorkspaceRouteState(pathname, search);
143
- if (!workspaceState) {
144
- return null;
145
- }
146
-
147
- if (workspaceState.workspaceBootstrapStatus === WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND) {
148
- if (workspaceState.workspaceRootPath && workspaceState.workspaceRootPath !== workspaceState.pathname) {
149
- return {
150
- allow: false,
151
- redirectTo: workspaceState.workspaceRootPath,
152
- reason: WORKSPACE_NOT_FOUND_GUARD_REASON
153
- };
154
- }
155
- return null;
156
- }
157
-
158
- if (workspaceState.workspaceBootstrapStatus === WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN) {
159
- if (workspaceState.workspaceRootPath && workspaceState.workspaceRootPath !== workspaceState.pathname) {
160
- return {
161
- allow: false,
162
- redirectTo: workspaceState.workspaceRootPath,
163
- reason: WORKSPACE_FORBIDDEN_GUARD_REASON
164
- };
165
- }
166
- return null;
167
- }
168
-
169
- return null;
170
- }
171
-
172
- function resolveSurfaceAccessGuardDecision(pathname = "/", search = "", { allowOnUnknown = true } = {}) {
173
- const surfaceState = resolveSurfaceRouteState(pathname, search);
174
- if (!surfaceState) {
175
- return null;
176
- }
177
-
178
- if (
179
- surfaceState.workspaceBootstrapStatus === WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND ||
180
- surfaceState.workspaceBootstrapStatus === WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN
181
- ) {
182
- return null;
183
- }
184
-
185
- const accessDecision = evaluateSurfaceAccess({
186
- context: placementRuntime.getContext(),
187
- surfaceId: surfaceState.surfaceId,
188
- workspaceSlug: surfaceState.workspaceSlug,
189
- allowOnUnknown
190
- });
191
- if (accessDecision.allowed || accessDecision.pending) {
192
- return null;
193
- }
194
-
195
- const redirectTarget = resolveDefaultSurfaceFallbackPath(surfaceState);
196
- const redirectTo = redirectTarget && redirectTarget !== surfaceState.pathname ? redirectTarget : "";
197
-
198
- return {
199
- allow: false,
200
- redirectTo,
201
- reason: accessDecision.reason || "surface-access-denied"
202
- };
203
- }
204
-
205
- async function replaceRouteIfNeeded(targetPath = "") {
206
- if (!router || typeof router.replace !== "function") {
207
- return;
208
- }
209
-
210
- const normalizedTargetPath = String(targetPath || "").trim();
211
- if (!normalizedTargetPath) {
212
- return;
213
- }
214
-
215
- const currentRoute = router.currentRoute?.value || {};
216
- const currentFullPath = String(currentRoute.fullPath || "").trim();
217
- const currentPath = resolveRuntimePathname(currentRoute.path || "/");
218
- const currentComparablePath = currentFullPath || currentPath;
219
- if (currentComparablePath === normalizedTargetPath) {
220
- return;
221
- }
222
-
223
- try {
224
- await router.replace(normalizedTargetPath);
225
- } catch {}
226
- }
227
-
228
- function enforceWorkspaceRouteForStatusUpdate({ workspaceSlug = "", status = "" } = {}) {
229
- const normalizedWorkspaceSlug = normalizeWorkspaceSlugKey(workspaceSlug);
230
- const normalizedStatus = normalizeWorkspaceBootstrapStatus(status);
231
- if (!normalizedWorkspaceSlug || !normalizedStatus || !router) {
232
- return;
233
- }
234
-
235
- const currentRoute = router.currentRoute?.value || {};
236
- const currentPath = resolveRuntimePathname(currentRoute.path || "/");
237
- const currentSearch = resolveSearchFromFullPath(currentRoute.fullPath || "");
238
- const workspaceState = resolveWorkspaceRouteState(currentPath, currentSearch);
239
- if (!workspaceState || workspaceState.workspaceSlug !== normalizedWorkspaceSlug) {
240
- return;
241
- }
242
-
243
- if (normalizedStatus === WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND) {
244
- if (workspaceState.workspaceRootPath && workspaceState.workspaceRootPath !== workspaceState.pathname) {
245
- void replaceRouteIfNeeded(workspaceState.workspaceRootPath);
246
- }
247
- return;
248
- }
249
-
250
- if (normalizedStatus === WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN) {
251
- if (workspaceState.workspaceRootPath && workspaceState.workspaceRootPath !== workspaceState.pathname) {
252
- void replaceRouteIfNeeded(workspaceState.workspaceRootPath);
253
- }
254
- }
255
- }
256
-
257
- function enforceSurfaceAccessForCurrentRoute() {
258
- if (!router) {
259
- return;
260
- }
261
-
262
- const currentRoute = router.currentRoute?.value || {};
263
- const currentPath = resolveRuntimePathname(currentRoute.path || "/");
264
- const currentSearch = resolveSearchFromFullPath(currentRoute.fullPath || "");
265
- const surfaceDecision = resolveSurfaceAccessGuardDecision(currentPath, currentSearch, {
266
- allowOnUnknown: false
267
- });
268
- if (!surfaceDecision || !surfaceDecision.redirectTo) {
269
- return;
270
- }
271
-
272
- void replaceRouteIfNeeded(surfaceDecision.redirectTo);
273
- }
274
-
275
- function installWorkspaceGuardEvaluator() {
276
- if (!root || workspaceGuardEvaluatorInstalled) {
277
- return;
278
- }
279
-
280
- if (typeof delegatedGuardEvaluator !== "function") {
281
- const currentEvaluator = root[SHELL_GUARD_EVALUATOR_KEY];
282
- delegatedGuardEvaluator = typeof currentEvaluator === "function" ? currentEvaluator : null;
283
- }
284
-
285
- const previousDescriptor = Object.getOwnPropertyDescriptor(root, SHELL_GUARD_EVALUATOR_KEY);
286
- const previousOwnProperty = previousDescriptor || null;
287
- let released = false;
288
-
289
- const workspaceGuardEvaluator = ({ guard, phase, context } = {}) => {
290
- const baseOutcome =
291
- typeof delegatedGuardEvaluator === "function"
292
- ? delegatedGuardEvaluator({
293
- guard,
294
- phase,
295
- context
296
- })
297
- : true;
298
- if (isGuardDenied(baseOutcome)) {
299
- return baseOutcome;
300
- }
301
-
302
- const pathname = resolveRuntimePathname(context?.location?.pathname || context?.to?.path || "/");
303
- const search = normalizeSearch(context?.location?.search || resolveSearchFromFullPath(context?.to?.fullPath || ""));
304
- const workspaceDecision = resolveWorkspaceGuardDecision(pathname, search);
305
- if (workspaceDecision) {
306
- return workspaceDecision;
307
- }
308
-
309
- const surfaceDecision = resolveSurfaceAccessGuardDecision(pathname, search, {
310
- allowOnUnknown: true
311
- });
312
- if (surfaceDecision) {
313
- return surfaceDecision;
314
- }
315
-
316
- return baseOutcome;
317
- };
318
-
319
- Object.defineProperty(root, SHELL_GUARD_EVALUATOR_KEY, {
320
- configurable: true,
321
- enumerable: true,
322
- get() {
323
- return workspaceGuardEvaluator;
324
- },
325
- set(nextEvaluator) {
326
- if (nextEvaluator === workspaceGuardEvaluator) {
327
- return;
328
- }
329
- delegatedGuardEvaluator = typeof nextEvaluator === "function" ? nextEvaluator : null;
330
- }
331
- });
332
- workspaceGuardEvaluatorInstalled = true;
333
-
334
- cleanup.push(() => {
335
- if (released || !root) {
336
- return;
337
- }
338
- released = true;
339
-
340
- try {
341
- if (previousOwnProperty) {
342
- Object.defineProperty(root, SHELL_GUARD_EVALUATOR_KEY, previousOwnProperty);
343
- } else {
344
- delete root[SHELL_GUARD_EVALUATOR_KEY];
345
- }
346
- } catch {}
347
- delegatedGuardEvaluator = null;
348
- workspaceGuardEvaluatorInstalled = false;
349
- });
350
- }
351
-
352
- function shutdown() {
353
- for (const release of cleanup.splice(0, cleanup.length)) {
354
- if (typeof release !== "function") {
355
- continue;
356
- }
357
- try {
358
- release();
359
- } catch {}
360
- }
361
- }
362
-
363
- return Object.freeze({
364
- enforceSurfaceAccessForCurrentRoute,
365
- enforceWorkspaceRouteForStatusUpdate,
366
- installWorkspaceGuardEvaluator,
367
- shutdown
368
- });
369
- }
370
-
371
- export { createBootstrapPlacementRouteGuards };