@jskit-ai/workspaces-web 0.1.139-oldline.2 → 0.1.139

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 (40) hide show
  1. package/package.json +247 -9
  2. package/patterns/workspace-surfaces/PATTERN.md +63 -0
  3. package/src/client/account-settings/accountSettingsInvitesRuntime.js +2 -2
  4. package/src/client/account-settings/useAccountSettingsInvitesSectionRuntime.js +3 -3
  5. package/src/client/components/MembersAdminClientElement.vue +1 -1
  6. package/src/client/components/WorkspaceInviteLanding.vue +4 -4
  7. package/src/client/components/WorkspaceMembersClientElement.vue +6 -6
  8. package/src/client/components/{UsersWorkspaceMembersMenuItem.vue → WorkspaceMembersMenuItem.vue} +2 -2
  9. package/src/client/components/{UsersWorkspacePermissionMenuItem.vue → WorkspacePermissionMenuItem.vue} +3 -3
  10. package/src/client/components/{UsersProfileSurfaceSwitchMenuItem.vue → WorkspaceProfileSurfaceSwitchMenuItem.vue} +1 -1
  11. package/src/client/components/{UsersWorkspaceSelector.vue → WorkspaceSelector.vue} +1 -1
  12. package/src/client/components/{UsersWorkspaceSettingsMenuItem.vue → WorkspaceSettingsMenuItem.vue} +2 -2
  13. package/src/client/components/WorkspacesClientElement.vue +13 -13
  14. package/src/client/composables/useWorkspaceRouteContext.js +1 -1
  15. package/src/client/index.js +0 -5
  16. package/src/client/lib/surfaceAccessPolicy.js +4 -1
  17. package/src/client/providers/WorkspacesWebClientProvider.js +54 -50
  18. package/src/client/runtime/bootstrapPlacementRuntime.js +18 -32
  19. package/src/client/runtime/bootstrapPlacementRuntimeHelpers.js +4 -4
  20. package/test/bootstrapPlacementRuntime.test.js +40 -125
  21. package/test/packageMetadataOwnership.test.js +19 -0
  22. package/test/settingsPlacementContract.test.js +87 -389
  23. package/test/{usersWorkspaceSelectorContract.test.js → workspaceSelectorContract.test.js} +3 -3
  24. package/package.descriptor.mjs +0 -492
  25. package/src/client/lib/httpClient.js +0 -10
  26. package/src/client/lib/permissions.js +0 -27
  27. package/test/packageDescriptorOwnership.test.js +0 -16
  28. /package/{templates → patterns/workspace-surfaces/example}/packages/main/src/client/components/AccountPendingInvitesCue.vue +0 -0
  29. /package/{templates → patterns/workspace-surfaces/example}/packages/main/src/client/components/AccountSettingsInvitesSection.vue +0 -0
  30. /package/{templates → patterns/workspace-surfaces/example}/src/components/WorkspaceNotFoundCard.vue +0 -0
  31. /package/{templates → patterns/workspace-surfaces/example}/src/composables/useWorkspaceNotFoundState.js +0 -0
  32. /package/{templates → patterns/workspace-surfaces/example}/src/pages/admin/members/index.vue +0 -0
  33. /package/{templates → patterns/workspace-surfaces/example}/src/pages/admin/workspace/settings/index.vue +0 -0
  34. /package/{templates → patterns/workspace-surfaces/example}/src/pages/admin/workspace/settings.vue +0 -0
  35. /package/{templates → patterns/workspace-surfaces/example}/src/pages/invite/[token].vue +0 -0
  36. /package/{templates → patterns/workspace-surfaces/example}/src/surfaces/admin/index.vue +0 -0
  37. /package/{templates → patterns/workspace-surfaces/example}/src/surfaces/admin/root.vue +0 -0
  38. /package/{templates → patterns/workspace-surfaces/example}/src/surfaces/app/index.vue +0 -0
  39. /package/{templates → patterns/workspace-surfaces/example}/src/surfaces/app/root.vue +0 -0
  40. /package/src/client/components/{UsersWorkspaceToolsWidget.vue → WorkspaceToolsWidget.vue} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/workspaces-web",
3
- "version": "0.1.139-oldline.2",
3
+ "version": "0.1.139",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -14,19 +14,257 @@
14
14
  "./client/composables/useWorkspaceRouteContext": "./src/client/composables/useWorkspaceRouteContext.js"
15
15
  },
16
16
  "dependencies": {
17
- "@mdi/js": "^7.4.47",
18
- "@jskit-ai/auth-web": "0.1.148",
19
- "@jskit-ai/http-runtime": "0.1.146",
20
- "@jskit-ai/kernel": "0.1.147",
21
- "@jskit-ai/shell-web": "0.1.148",
22
- "@jskit-ai/users-core": "0.1.161",
23
- "@jskit-ai/users-web": "0.1.178-oldline.3",
24
- "@jskit-ai/workspaces-core": "0.1.138-oldline.1"
17
+ "@jskit-ai/auth-web": "0.1.160",
18
+ "@jskit-ai/http-web": "0.1.5",
19
+ "@jskit-ai/kernel": "0.1.160",
20
+ "@jskit-ai/shell-web": "0.1.164",
21
+ "@jskit-ai/users-core": "0.1.173",
22
+ "@jskit-ai/users-web": "0.1.178",
23
+ "@jskit-ai/workspaces-core": "0.1.138",
24
+ "@mdi/js": "^7.4.47"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@tanstack/vue-query": "^5.90.5",
28
28
  "vue": "^3.5.13",
29
29
  "vue-router": "^5.0.4",
30
30
  "vuetify": "^4.0.0"
31
+ },
32
+ "description": "Workspace web module: workspace selector, tools widget, workspace surfaces, members UI, and settings hosts.",
33
+ "jskit": {
34
+ "kind": "runtime",
35
+ "capabilities": {
36
+ "provides": [
37
+ "workspaces.web"
38
+ ],
39
+ "requires": [
40
+ "runtime.http-web",
41
+ "users.web",
42
+ "workspaces.core"
43
+ ]
44
+ },
45
+ "runtime": {
46
+ "server": {
47
+ "providers": []
48
+ },
49
+ "client": {
50
+ "providers": [
51
+ {
52
+ "entrypoint": "src/client/providers/WorkspacesWebClientProvider.js",
53
+ "export": "WorkspacesWebClientProvider"
54
+ }
55
+ ]
56
+ }
57
+ },
58
+ "metadata": {
59
+ "apiSummary": {
60
+ "surfaces": [
61
+ {
62
+ "subpath": "./client",
63
+ "summary": "Exports workspaces-web client provider registration surface."
64
+ },
65
+ {
66
+ "subpath": "./client/components/AccountSettingsInvitesSection",
67
+ "summary": "Exports the default account invites section component used by multihoming installs."
68
+ },
69
+ {
70
+ "subpath": "./client/components/WorkspaceInviteLanding",
71
+ "summary": "Exports the default public workspace invite landing component."
72
+ },
73
+ {
74
+ "subpath": "./client/providers/WorkspacesWebClientProvider",
75
+ "summary": "Exports workspaces-web client provider class."
76
+ },
77
+ {
78
+ "subpath": "./client/composables/useWorkspaceRouteContext",
79
+ "summary": "Exports workspace route context composable."
80
+ }
81
+ ]
82
+ },
83
+ "ui": {
84
+ "placements": {
85
+ "outlets": [
86
+ {
87
+ "target": "admin-settings:primary-menu",
88
+ "surfaces": [
89
+ "admin"
90
+ ],
91
+ "source": "patterns/workspace-surfaces/example/src/pages/admin/workspace/settings.vue"
92
+ },
93
+ {
94
+ "target": "admin-cog:primary-menu",
95
+ "surfaces": [
96
+ "admin"
97
+ ],
98
+ "source": "src/client/components/WorkspaceToolsWidget.vue"
99
+ }
100
+ ],
101
+ "topology": {
102
+ "placements": [
103
+ {
104
+ "id": "page.section-nav",
105
+ "owner": "admin-settings",
106
+ "description": "Navigation between workspace admin settings child pages.",
107
+ "surfaces": [
108
+ "admin"
109
+ ],
110
+ "variants": {
111
+ "compact": {
112
+ "outlet": "admin-settings:primary-menu",
113
+ "renderers": {
114
+ "link": "local.main.ui.surface-aware-menu-link-item"
115
+ }
116
+ },
117
+ "medium": {
118
+ "outlet": "admin-settings:primary-menu",
119
+ "renderers": {
120
+ "link": "local.main.ui.surface-aware-menu-link-item"
121
+ }
122
+ },
123
+ "expanded": {
124
+ "outlet": "admin-settings:primary-menu",
125
+ "renderers": {
126
+ "link": "local.main.ui.surface-aware-menu-link-item"
127
+ }
128
+ }
129
+ }
130
+ },
131
+ {
132
+ "id": "admin.tools-menu",
133
+ "description": "Admin surface tools menu actions.",
134
+ "surfaces": [
135
+ "admin"
136
+ ],
137
+ "variants": {
138
+ "compact": {
139
+ "outlet": "admin-cog:primary-menu",
140
+ "renderers": {
141
+ "link": "local.main.ui.surface-aware-menu-link-item"
142
+ }
143
+ },
144
+ "medium": {
145
+ "outlet": "admin-cog:primary-menu",
146
+ "renderers": {
147
+ "link": "local.main.ui.surface-aware-menu-link-item"
148
+ }
149
+ },
150
+ "expanded": {
151
+ "outlet": "admin-cog:primary-menu",
152
+ "renderers": {
153
+ "link": "local.main.ui.surface-aware-menu-link-item"
154
+ }
155
+ }
156
+ }
157
+ }
158
+ ]
159
+ },
160
+ "contributions": [
161
+ {
162
+ "id": "workspaces.workspace.menu.app",
163
+ "target": "shell.primary-nav",
164
+ "kind": "link",
165
+ "surfaces": [
166
+ "app"
167
+ ],
168
+ "order": 50,
169
+ "when": "auth.authenticated === true",
170
+ "source": "patterns/workspace-surfaces/example/src/surfaces/app/index.vue"
171
+ },
172
+ {
173
+ "id": "workspaces.workspace.menu.admin",
174
+ "target": "shell.primary-nav",
175
+ "kind": "link",
176
+ "surfaces": [
177
+ "admin"
178
+ ],
179
+ "order": 60,
180
+ "when": "auth.authenticated === true",
181
+ "source": "patterns/workspace-surfaces/example/src/surfaces/admin/index.vue"
182
+ },
183
+ {
184
+ "id": "workspaces.profile.menu.surface-switch",
185
+ "target": "auth.profile-menu",
186
+ "kind": "component",
187
+ "surfaces": [
188
+ "*"
189
+ ],
190
+ "order": 100,
191
+ "componentToken": "workspaces.web.profile.menu.surface-switch-item",
192
+ "when": "auth.authenticated === true",
193
+ "source": "src/client/components/WorkspaceProfileSurfaceSwitchMenuItem.vue"
194
+ },
195
+ {
196
+ "id": "workspaces.workspace.selector",
197
+ "target": "shell.identity",
198
+ "kind": "component",
199
+ "surfaces": [
200
+ "*"
201
+ ],
202
+ "order": 200,
203
+ "componentToken": "workspaces.web.workspace.selector",
204
+ "when": "auth.authenticated === true",
205
+ "source": "src/client/components/WorkspaceSelector.vue"
206
+ },
207
+ {
208
+ "id": "workspaces.account.invites.cue",
209
+ "target": "shell.status",
210
+ "kind": "component",
211
+ "surfaces": [
212
+ "*"
213
+ ],
214
+ "order": 850,
215
+ "componentToken": "local.main.account.pending-invites.cue",
216
+ "when": "auth.authenticated === true",
217
+ "source": "patterns/workspace-surfaces/example/packages/main/src/client/components/AccountPendingInvitesCue.vue"
218
+ },
219
+ {
220
+ "id": "workspaces.account.settings.invites",
221
+ "target": "settings.sections",
222
+ "owner": "account-settings",
223
+ "kind": "component",
224
+ "surfaces": [
225
+ "account"
226
+ ],
227
+ "order": 400,
228
+ "componentToken": "local.main.account-settings.section.invites",
229
+ "when": "auth.authenticated === true && workspaceInvitesEnabled === true",
230
+ "source": "patterns/workspace-surfaces/example/packages/main/src/client/components/AccountSettingsInvitesSection.vue"
231
+ },
232
+ {
233
+ "id": "workspaces.workspace.tools.widget",
234
+ "target": "shell.status",
235
+ "kind": "component",
236
+ "surfaces": [
237
+ "admin"
238
+ ],
239
+ "order": 900,
240
+ "componentToken": "workspaces.web.workspace.tools.widget",
241
+ "source": "src/client/components/WorkspaceToolsWidget.vue"
242
+ },
243
+ {
244
+ "id": "workspaces.workspace.menu.workspace-settings",
245
+ "target": "admin.tools-menu",
246
+ "kind": "component",
247
+ "surfaces": [
248
+ "admin"
249
+ ],
250
+ "order": 100,
251
+ "componentToken": "workspaces.web.workspace-settings.menu-item",
252
+ "source": "src/client/components/WorkspaceSettingsMenuItem.vue"
253
+ },
254
+ {
255
+ "id": "workspaces.workspace.menu.members",
256
+ "target": "admin.tools-menu",
257
+ "kind": "component",
258
+ "surfaces": [
259
+ "admin"
260
+ ],
261
+ "order": 200,
262
+ "componentToken": "workspaces.web.workspace-members.menu-item",
263
+ "source": "src/client/components/WorkspaceMembersMenuItem.vue"
264
+ }
265
+ ]
266
+ }
267
+ }
268
+ }
31
269
  }
32
270
  }
@@ -0,0 +1,63 @@
1
+ ---
2
+ id: workspaces/workspace-surfaces
3
+ title: Workspace application and administration surfaces
4
+ summary: Compose workspace selection, invitation, member administration, settings, and responsive navigation using JSKIT workspace web APIs.
5
+ keywords: admin, invite, member, navigation, settings, surface, switcher, workspace
6
+ requires: @jskit-ai/workspaces-core, @jskit-ai/workspaces-web, @jskit-ai/shell-web
7
+ ---
8
+
9
+ # Workspace application and administration surfaces
10
+
11
+ ## Use when
12
+
13
+ Use this pattern when the product has workspace-scoped app and administration
14
+ surfaces, invitations, member management, or workspace switching.
15
+
16
+ ## Do not use when
17
+
18
+ Do not use this pattern for a single-owner application, or copy its whole
19
+ surface tree when only one workspace widget is needed.
20
+
21
+ ## Product decisions
22
+
23
+ Choose public invitation routes, application/admin surface ids, workspace
24
+ selector behavior, member-management permissions, settings sections, and the
25
+ empty or not-found experience.
26
+
27
+ ## Framework APIs
28
+
29
+ Use the workspace client provider, components, and composables exported by
30
+ `@jskit-ai/workspaces-web` together with JSKIT shell placements and routes.
31
+
32
+ ## Invariants
33
+
34
+ - Route workspace slug, selected workspace, and server scope stay synchronized.
35
+ - Invitation acceptance is public only where the server contract permits it.
36
+ - Administrative UI visibility never substitutes for server authorization.
37
+ - Query and route state hydrate immediately on warm-cache navigation.
38
+ - Loading uses skeletons; mutation failures use toasts without layout movement.
39
+ - Navigation is composed through semantic placements and registered tokens.
40
+
41
+ ## Example files
42
+
43
+ `example/` contains workspace app/admin roots, starter pages, invitation route,
44
+ member and settings routes, not-found state, app-owned invitation widgets, and
45
+ the components that an application's client provider registers.
46
+
47
+ ## Variation points
48
+
49
+ Change surfaces, routes, section owners, labels, icons, placement order,
50
+ workspace-not-found copy, member operations, and invitation presentation.
51
+
52
+ ## Verification
53
+
54
+ Exercise direct workspace URLs, selection and switching, invitations, members,
55
+ settings, not-found state, browser back/forward, forbidden access, and all
56
+ responsive navigation variants.
57
+
58
+ ## Avoid
59
+
60
+ - defaulting silently to another workspace after an invalid route
61
+ - unscoped queries
62
+ - inline mutation error banners
63
+ - generated placement or source mutation machinery
@@ -50,7 +50,7 @@ function createAccountSettingsInvitesRuntime({
50
50
  message: normalizedDecision === "accept" ? "Invitation accepted." : "Invitation refused.",
51
51
  severity: "success",
52
52
  channel: "snackbar",
53
- dedupeKey: `users-web.account-settings-runtime:invite-${normalizedDecision}:${token}`
53
+ dedupeKey: `workspaces-web.account-settings-runtime:invite-${normalizedDecision}:${token}`
54
54
  });
55
55
  } catch (error) {
56
56
  const statusCode = resolveErrorStatusCode(error);
@@ -63,7 +63,7 @@ function createAccountSettingsInvitesRuntime({
63
63
  : String(error?.message || fallbackMessage),
64
64
  severity: "error",
65
65
  channel: "banner",
66
- dedupeKey: `users-web.account-settings-runtime:invite-${normalizedDecision}-error:${token}`
66
+ dedupeKey: `workspaces-web.account-settings-runtime:invite-${normalizedDecision}-error:${token}`
67
67
  });
68
68
  } finally {
69
69
  inviteAction.value = {
@@ -6,9 +6,9 @@ import {
6
6
  } from "@jskit-ai/shell-web/client/placement";
7
7
  import { useShellWebErrorRuntime } from "@jskit-ai/shell-web/client/error";
8
8
  import { ROUTE_VISIBILITY_PUBLIC } from "@jskit-ai/kernel/shared/support/visibility";
9
- import { useCommand } from "@jskit-ai/users-web/client/composables/useCommand";
10
- import { usePaths } from "@jskit-ai/users-web/client/composables/usePaths";
11
- import { useView } from "@jskit-ai/users-web/client/composables/useView";
9
+ import { useCommand } from "@jskit-ai/http-web/client/composables/useCommand";
10
+ import { usePaths } from "@jskit-ai/shell-web/client/navigation/usePaths";
11
+ import { useView } from "@jskit-ai/http-web/client/composables/useView";
12
12
  import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
13
13
  import { WORKSPACE_INVITE_REDEEM_TRANSPORT } from "@jskit-ai/workspaces-core/shared/jsonApiTransports";
14
14
  import { useWorkspaceSurfaceId } from "../composables/useWorkspaceSurfaceId.js";
@@ -195,7 +195,7 @@ import { computed, toRefs, unref } from "vue";
195
195
  import { mdiContentCopy } from "@mdi/js";
196
196
  import { formatDateTime as formatKernelDateTime } from "@jskit-ai/kernel/shared/support";
197
197
  import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
198
- import { requireBoolean, requireFunction, requireRecord } from "@jskit-ai/users-web/client/support/contractGuards";
198
+ import { requireBoolean, requireFunction, requireRecord } from "@jskit-ai/http-web/client/support/contractGuards";
199
199
 
200
200
  const props = defineProps({
201
201
  forms: {
@@ -62,12 +62,12 @@
62
62
  import { computed, onMounted } from "vue";
63
63
  import { useRoute, useRouter } from "vue-router";
64
64
  import { useAuthStore } from "@jskit-ai/auth-web/client";
65
- import { useEndpointResource } from "@jskit-ai/users-web/client/composables/useEndpointResource";
65
+ import { useEndpointResource } from "@jskit-ai/http-web/client/composables/useEndpointResource";
66
66
  import {
67
67
  WORKSPACE_INVITATION_RESOLVE_TRANSPORT,
68
68
  WORKSPACE_INVITE_REDEEM_TRANSPORT
69
69
  } from "@jskit-ai/workspaces-core/shared/jsonApiTransports";
70
- import { workspacesWebHttpClient } from "../lib/httpClient.js";
70
+ import { httpWebClient } from "@jskit-ai/http-web/client/lib/httpClient";
71
71
 
72
72
  const route = useRoute();
73
73
  const router = useRouter();
@@ -84,7 +84,7 @@ const inviteResource = useEndpointResource({
84
84
  queryKey: computed(() => ["workspaces-web", "invite-landing", token.value]),
85
85
  path: "/api/workspace/invitations/resolve",
86
86
  enabled: computed(() => Boolean(token.value)),
87
- client: workspacesWebHttpClient,
87
+ client: httpWebClient,
88
88
  readQuery: inviteQuery,
89
89
  transport: WORKSPACE_INVITATION_RESOLVE_TRANSPORT,
90
90
  fallbackLoadError: "Unable to load invitation."
@@ -94,7 +94,7 @@ const redeemResource = useEndpointResource({
94
94
  queryKey: computed(() => ["workspaces-web", "invite-landing", "redeem", token.value]),
95
95
  path: "/api/workspace/invitations/redeem",
96
96
  enabled: false,
97
- client: workspacesWebHttpClient,
97
+ client: httpWebClient,
98
98
  writeMethod: "POST",
99
99
  transport: WORKSPACE_INVITE_REDEEM_TRANSPORT,
100
100
  fallbackSaveError: "Unable to accept invitation."
@@ -41,12 +41,12 @@ import {
41
41
  WORKSPACE_SETTINGS_TRANSPORT
42
42
  } from "@jskit-ai/workspaces-core/shared/jsonApiTransports";
43
43
  import MembersAdminClientElement from "./MembersAdminClientElement.vue";
44
- import { useCommand } from "@jskit-ai/users-web/client/composables/useCommand";
45
- import { useList } from "@jskit-ai/users-web/client/composables/useList";
46
- import { useView } from "@jskit-ai/users-web/client/composables/useView";
47
- import { usePaths } from "@jskit-ai/users-web/client/composables/usePaths";
48
- import { useAccess } from "@jskit-ai/users-web/client/composables/useAccess";
49
- import { useUiFeedback } from "@jskit-ai/users-web/client/composables/runtime/useUiFeedback";
44
+ import { useCommand } from "@jskit-ai/http-web/client/composables/useCommand";
45
+ import { useList } from "@jskit-ai/http-web/client/composables/useList";
46
+ import { useView } from "@jskit-ai/http-web/client/composables/useView";
47
+ import { usePaths } from "@jskit-ai/shell-web/client/navigation/usePaths";
48
+ import { useAccess } from "@jskit-ai/http-web/client/composables/useAccess";
49
+ import { useUiFeedback } from "@jskit-ai/http-web/client/composables/useUiFeedback";
50
50
  import { useWorkspaceRouteContext } from "../composables/useWorkspaceRouteContext.js";
51
51
  import { createWorkspaceRealtimeMatcher } from "../support/realtimeWorkspace.js";
52
52
  import { buildWorkspaceQueryKey } from "../support/workspaceQueryKeys.js";
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import { mdiAccountGroupOutline } from "@mdi/js";
3
- import UsersWorkspacePermissionMenuItem from "./UsersWorkspacePermissionMenuItem.vue";
3
+ import WorkspacePermissionMenuItem from "./WorkspacePermissionMenuItem.vue";
4
4
 
5
5
  const props = defineProps({
6
6
  label: {
@@ -25,7 +25,7 @@ const MEMBERS_MENU_PERMISSIONS = Object.freeze(["workspace.members.view", "works
25
25
  </script>
26
26
 
27
27
  <template>
28
- <UsersWorkspacePermissionMenuItem
28
+ <WorkspacePermissionMenuItem
29
29
  :label="props.label"
30
30
  :to="props.to"
31
31
  :icon="props.icon"
@@ -1,8 +1,8 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
- import { useSurfaceRouteContext } from "@jskit-ai/users-web/client/composables/useSurfaceRouteContext";
4
- import { hasPermission, normalizePermissionList } from "@jskit-ai/users-web/client/lib/permissions";
5
- import { usePaths } from "@jskit-ai/users-web/client/composables/usePaths";
3
+ import { useSurfaceRouteContext } from "@jskit-ai/shell-web/client/navigation/useSurfaceRouteContext";
4
+ import { hasPermission, normalizePermissionList } from "@jskit-ai/http-web/client/lib/permissions";
5
+ import { usePaths } from "@jskit-ai/shell-web/client/navigation/usePaths";
6
6
 
7
7
  const props = defineProps({
8
8
  label: {
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
- import { useSurfaceRouteContext } from "@jskit-ai/users-web/client/composables/useSurfaceRouteContext";
3
+ import { useSurfaceRouteContext } from "@jskit-ai/shell-web/client/navigation/useSurfaceRouteContext";
4
4
  import { resolveProfileSurfaceMenuLinks } from "../lib/profileSurfaceMenuLinks.js";
5
5
 
6
6
  const props = defineProps({
@@ -9,7 +9,7 @@ import {
9
9
  import { TENANCY_MODE_NONE } from "@jskit-ai/workspaces-core/shared/tenancyProfile";
10
10
  import { mdiBriefcaseOutline } from "@mdi/js";
11
11
  import { findWorkspaceBySlug, normalizeWorkspaceEntry, normalizeWorkspaceList } from "../lib/bootstrap.js";
12
- import { usePaths } from "@jskit-ai/users-web/client/composables/usePaths";
12
+ import { usePaths } from "@jskit-ai/shell-web/client/navigation/usePaths";
13
13
  import { resolveSurfaceSwitchTargetsFromPlacementContext, surfaceRequiresWorkspaceFromPlacementContext } from "../lib/workspaceSurfaceContext.js";
14
14
  import { resolveWorkspaceSurfaceIdFromPlacementPathname, extractWorkspaceSlugFromSurfacePathname } from "../lib/workspaceSurfacePaths.js";
15
15
 
@@ -1,6 +1,6 @@
1
1
  <script setup>
2
2
  import { mdiCogOutline } from "@mdi/js";
3
- import UsersWorkspacePermissionMenuItem from "./UsersWorkspacePermissionMenuItem.vue";
3
+ import WorkspacePermissionMenuItem from "./WorkspacePermissionMenuItem.vue";
4
4
 
5
5
  const props = defineProps({
6
6
  label: {
@@ -28,7 +28,7 @@ const WORKSPACE_SETTINGS_MENU_PERMISSIONS = Object.freeze([
28
28
  </script>
29
29
 
30
30
  <template>
31
- <UsersWorkspacePermissionMenuItem
31
+ <WorkspacePermissionMenuItem
32
32
  :label="props.label"
33
33
  :to="props.to"
34
34
  :icon="props.icon"
@@ -12,10 +12,10 @@ import {
12
12
  WORKSPACES_TRANSPORT,
13
13
  WORKSPACE_INVITE_REDEEM_TRANSPORT
14
14
  } from "@jskit-ai/workspaces-core/shared/jsonApiTransports";
15
- import { useCommand } from "@jskit-ai/users-web/client/composables/useCommand";
16
- import { useView } from "@jskit-ai/users-web/client/composables/useView";
17
- import { usePaths } from "@jskit-ai/users-web/client/composables/usePaths";
18
- import { useRealtimeQueryInvalidation } from "@jskit-ai/users-web/client/composables/useRealtimeQueryInvalidation";
15
+ import { useCommand } from "@jskit-ai/http-web/client/composables/useCommand";
16
+ import { useView } from "@jskit-ai/http-web/client/composables/useView";
17
+ import { usePaths } from "@jskit-ai/shell-web/client/navigation/usePaths";
18
+ import { useRealtimeQueryInvalidation } from "@jskit-ai/http-web/client/composables/useRealtimeQueryInvalidation";
19
19
  import { useWorkspaceSurfaceId } from "../composables/useWorkspaceSurfaceId.js";
20
20
  import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
21
21
 
@@ -76,7 +76,7 @@ const redeemInviteModel = reactive({
76
76
  token: "",
77
77
  decision: ""
78
78
  });
79
- const bootstrapQueryKey = Object.freeze(["users-web", "bootstrap", "__none__"]);
79
+ const bootstrapQueryKey = Object.freeze(["workspaces-web", "bootstrap", "__none__"]);
80
80
  const OWNERSHIP_PUBLIC = ROUTE_VISIBILITY_PUBLIC;
81
81
 
82
82
  const bootstrapView = useView({
@@ -179,12 +179,12 @@ function reportFeedback({
179
179
  }
180
180
 
181
181
  errorRuntime.report({
182
- source: "users-web.workspaces-view",
182
+ source: "workspaces-web.workspaces-view",
183
183
  message: normalizedMessage,
184
184
  intent: "action-feedback",
185
185
  severity,
186
186
  channel,
187
- dedupeKey: dedupeKey || `users-web.workspaces-view:${severity}:${normalizedMessage}`,
187
+ dedupeKey: dedupeKey || `workspaces-web.workspaces-view:${severity}:${normalizedMessage}`,
188
188
  dedupeWindowMs: 3000
189
189
  });
190
190
  }
@@ -235,7 +235,7 @@ async function openWorkspace(workspaceSlug) {
235
235
  reportFeedback({
236
236
  message: "Workspace surface is not configured.",
237
237
  severity: "error",
238
- dedupeKey: "users-web.workspaces-view:workspace-surface-missing"
238
+ dedupeKey: "workspaces-web.workspaces-view:workspace-surface-missing"
239
239
  });
240
240
  return;
241
241
  }
@@ -259,7 +259,7 @@ async function openWorkspace(workspaceSlug) {
259
259
  reportFeedback({
260
260
  message: String(error?.message || "Unable to open workspace."),
261
261
  severity: "error",
262
- dedupeKey: `users-web.workspaces-view:open-workspace:${normalizedSlug}`
262
+ dedupeKey: `workspaces-web.workspaces-view:open-workspace:${normalizedSlug}`
263
263
  });
264
264
  } finally {
265
265
  selectingWorkspaceSlug.value = "";
@@ -301,7 +301,7 @@ async function respondToInvite(invite, decision) {
301
301
  reportFeedback({
302
302
  message: "Invitation refused.",
303
303
  severity: "success",
304
- dedupeKey: `users-web.workspaces-view:invite-refused:${token}`
304
+ dedupeKey: `workspaces-web.workspaces-view:invite-refused:${token}`
305
305
  });
306
306
  } catch (error) {
307
307
  reportFeedback({
@@ -309,7 +309,7 @@ async function respondToInvite(invite, decision) {
309
309
  error?.message || (normalizedDecision === "accept" ? "Unable to accept invite." : "Unable to refuse invite.")
310
310
  ),
311
311
  severity: "error",
312
- dedupeKey: `users-web.workspaces-view:invite-${normalizedDecision}:${token}`
312
+ dedupeKey: `workspaces-web.workspaces-view:invite-${normalizedDecision}:${token}`
313
313
  });
314
314
  } finally {
315
315
  inviteAction.value = {
@@ -339,7 +339,7 @@ async function createWorkspace() {
339
339
  reportFeedback({
340
340
  message: "Workspace name is required.",
341
341
  severity: "error",
342
- dedupeKey: "users-web.workspaces-view:create-workspace-name-required"
342
+ dedupeKey: "workspaces-web.workspaces-view:create-workspace-name-required"
343
343
  });
344
344
  return;
345
345
  }
@@ -358,7 +358,7 @@ async function createWorkspace() {
358
358
  reportFeedback({
359
359
  message: String(error?.message || "Unable to create workspace."),
360
360
  severity: "error",
361
- dedupeKey: "users-web.workspaces-view:create-workspace-error"
361
+ dedupeKey: "workspaces-web.workspaces-view:create-workspace-error"
362
362
  });
363
363
  }
364
364
  }
@@ -1,5 +1,5 @@
1
1
  import { computed } from "vue";
2
- import { useSurfaceRouteContext } from "@jskit-ai/users-web/client/composables/useSurfaceRouteContext";
2
+ import { useSurfaceRouteContext } from "@jskit-ai/shell-web/client/navigation/useSurfaceRouteContext";
3
3
  import { readWorkspaceRouteScope } from "../support/workspaceScopeSupport.js";
4
4
 
5
5
  function useWorkspaceRouteContext() {
@@ -1,8 +1,3 @@
1
- import { WorkspacesWebClientProvider } from "./providers/WorkspacesWebClientProvider.js";
2
-
3
- const clientProviders = Object.freeze([WorkspacesWebClientProvider]);
4
-
5
1
  export { WorkspacesWebClientProvider } from "./providers/WorkspacesWebClientProvider.js";
6
2
  export { default as WorkspaceMembersClientElement } from "./components/WorkspaceMembersClientElement.vue";
7
3
  export { default as WorkspaceInviteLanding } from "./components/WorkspaceInviteLanding.vue";
8
- export { clientProviders };
@@ -4,7 +4,10 @@ import {
4
4
  normalizeRecord,
5
5
  normalizeWorkspaceBootstrapStatusValue
6
6
  } from "../support/runtimeNormalization.js";
7
- import { hasPermission, normalizePermissionList } from "./permissions.js";
7
+ import {
8
+ hasPermission,
9
+ normalizePermissionList
10
+ } from "@jskit-ai/http-web/client/lib/permissions";
8
11
 
9
12
  const WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND = "not_found";
10
13
  const WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN = "forbidden";