@jskit-ai/users-web 0.1.53 → 0.1.55

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 (70) hide show
  1. package/package.descriptor.mjs +15 -53
  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 -11
  31. package/test/theme.test.js +0 -56
  32. package/src/client/components/MembersAdminClientElement.vue +0 -400
  33. package/src/client/components/UsersProfileSurfaceSwitchMenuItem.vue +0 -39
  34. package/src/client/components/UsersWorkspaceMembersMenuItem.vue +0 -36
  35. package/src/client/components/UsersWorkspacePermissionMenuItem.vue +0 -90
  36. package/src/client/components/UsersWorkspaceSelector.vue +0 -248
  37. package/src/client/components/UsersWorkspaceSettingsMenuItem.vue +0 -39
  38. package/src/client/components/UsersWorkspaceToolsWidget.vue +0 -12
  39. package/src/client/components/WorkspaceMembersClientElement.vue +0 -655
  40. package/src/client/components/WorkspaceProfileClientElement.vue +0 -116
  41. package/src/client/components/WorkspaceSettingsClientElement.vue +0 -102
  42. package/src/client/components/WorkspaceSettingsFieldsClientElement.vue +0 -265
  43. package/src/client/components/WorkspacesClientElement.vue +0 -509
  44. package/src/client/composables/account-settings/accountSettingsInvitesRuntime.js +0 -88
  45. package/src/client/composables/useBootstrapQuery.js +0 -52
  46. package/src/client/composables/useWorkspaceRouteContext.js +0 -28
  47. package/src/client/composables/useWorkspaceSurfaceId.js +0 -43
  48. package/src/client/lib/menuIcons.js +0 -201
  49. package/src/client/lib/profileSurfaceMenuLinks.js +0 -142
  50. package/src/client/lib/surfaceAccessPolicy.js +0 -350
  51. package/src/client/lib/workspaceLinkResolver.js +0 -207
  52. package/src/client/lib/workspaceSurfaceContext.js +0 -82
  53. package/src/client/lib/workspaceSurfacePaths.js +0 -163
  54. package/src/client/providers/UsersWorkspacesClientProvider.js +0 -24
  55. package/src/client/runtime/bootstrapPlacementRouteGuards.js +0 -371
  56. package/src/client/runtime/bootstrapPlacementRuntime.js +0 -463
  57. package/src/client/runtime/bootstrapPlacementRuntimeConstants.js +0 -28
  58. package/src/client/runtime/bootstrapPlacementRuntimeHelpers.js +0 -147
  59. package/src/client/support/menuLinkTarget.js +0 -93
  60. package/src/client/support/realtimeWorkspace.js +0 -21
  61. package/src/client/support/runtimeNormalization.js +0 -27
  62. package/src/client/support/workspaceQueryKeys.js +0 -15
  63. package/templates/src/components/account/settings/AccountSettingsInvitesSection.vue +0 -77
  64. package/test/bootstrapPlacementRuntime.test.js +0 -1095
  65. package/test/menuIcons.test.js +0 -34
  66. package/test/menuLinkTarget.test.js +0 -116
  67. package/test/profileSurfaceMenuLinks.test.js +0 -208
  68. package/test/surfaceAccessPolicy.test.js +0 -129
  69. package/test/workspaceLinkResolver.test.js +0 -61
  70. package/test/workspaceSurfacePaths.test.js +0 -39
@@ -1,463 +0,0 @@
1
- import {
2
- findWorkspaceBySlug,
3
- normalizeWorkspaceList,
4
- resolvePlacementUserFromBootstrapPayload
5
- } from "../lib/bootstrap.js";
6
- import { normalizePermissionList } from "../lib/permissions.js";
7
- import {
8
- persistBootstrapThemePreference,
9
- resolveBootstrapThemeName,
10
- setVuetifyPrimaryColorOverride,
11
- resolveVuetifyThemeController,
12
- setVuetifyThemeName
13
- } from "../lib/theme.js";
14
- import { createBootstrapPlacementRouteGuards } from "./bootstrapPlacementRouteGuards.js";
15
- import {
16
- WORKSPACE_BOOTSTRAP_STATUS_ERROR,
17
- WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN,
18
- WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND,
19
- WORKSPACE_BOOTSTRAP_STATUS_RESOLVED,
20
- WORKSPACE_BOOTSTRAP_STATUS_UNAUTHENTICATED
21
- } from "./bootstrapPlacementRuntimeConstants.js";
22
- import {
23
- countPendingInvites,
24
- createProviderLogger,
25
- fetchBootstrapPayload,
26
- normalizeWorkspaceBootstrapStatus,
27
- normalizeWorkspaceSlugKey,
28
- resolveAuthSignature,
29
- resolveRequestedWorkspaceBootstrapStatus,
30
- resolveRouteState
31
- } from "./bootstrapPlacementRuntimeHelpers.js";
32
- import { resolveErrorStatusCode } from "../support/runtimeNormalization.js";
33
-
34
- function createBootstrapPlacementRuntime({ app, logger = null, fetchBootstrap = fetchBootstrapPayload } = {}) {
35
- if (!app || typeof app.has !== "function" || typeof app.make !== "function") {
36
- throw new Error("createBootstrapPlacementRuntime requires application has()/make().");
37
- }
38
- if (!app.has("runtime.web-placement.client")) {
39
- throw new Error("createBootstrapPlacementRuntime requires shell-web placement runtime.");
40
- }
41
- if (typeof fetchBootstrap !== "function") {
42
- throw new TypeError("createBootstrapPlacementRuntime requires fetchBootstrap(workspaceSlug).");
43
- }
44
-
45
- const runtimeLogger = logger || createProviderLogger(app);
46
- const placementRuntime = app.make("runtime.web-placement.client");
47
- const router = app.has("jskit.client.router") ? app.make("jskit.client.router") : null;
48
- let vuetifyThemeController = resolveVuetifyThemeController(
49
- app.has("jskit.client.vue.app") ? app.make("jskit.client.vue.app") : null
50
- );
51
- const socket = app.has("runtime.realtime.client.socket") ? app.make("runtime.realtime.client.socket") : null;
52
- const cleanup = [];
53
- let refreshQueue = Promise.resolve();
54
- let shutdownRequested = false;
55
- let authSignature = resolveAuthSignature(placementRuntime.getContext());
56
- let lastRouteWorkspaceSlug = resolveRouteState(placementRuntime, router).workspaceSlug;
57
- const workspaceBootstrapStatusBySlug = new Map();
58
- const workspaceBootstrapStatusListeners = new Set();
59
- const root = typeof globalThis === "object" && globalThis ? globalThis : null;
60
-
61
- const routeGuards = createBootstrapPlacementRouteGuards({
62
- placementRuntime,
63
- router,
64
- root,
65
- getWorkspaceBootstrapStatus: (workspaceSlug) => getWorkspaceBootstrapStatus(workspaceSlug)
66
- });
67
-
68
- cleanup.push(() => {
69
- routeGuards.shutdown();
70
- });
71
-
72
- function setWorkspaceBootstrapStatus(workspaceSlug = "", status = "", source = "users-web.bootstrap-placement") {
73
- const workspaceSlugKey = normalizeWorkspaceSlugKey(workspaceSlug);
74
- const normalizedStatus = normalizeWorkspaceBootstrapStatus(status);
75
- if (!workspaceSlugKey || !normalizedStatus) {
76
- return;
77
- }
78
-
79
- const previousStatus = workspaceBootstrapStatusBySlug.get(workspaceSlugKey) || "";
80
- workspaceBootstrapStatusBySlug.set(workspaceSlugKey, normalizedStatus);
81
- if (previousStatus === normalizedStatus) {
82
- return;
83
- }
84
-
85
- placementRuntime.setContext(
86
- {
87
- workspaceBootstrapStatuses: Object.freeze(Object.fromEntries(workspaceBootstrapStatusBySlug))
88
- },
89
- {
90
- source
91
- }
92
- );
93
-
94
- const payload = Object.freeze({
95
- workspaceSlug: workspaceSlugKey,
96
- status: normalizedStatus,
97
- source: String(source || "users-web.bootstrap-placement").trim() || "users-web.bootstrap-placement"
98
- });
99
- for (const listener of workspaceBootstrapStatusListeners) {
100
- try {
101
- listener(payload);
102
- } catch {}
103
- }
104
- routeGuards.enforceWorkspaceRouteForStatusUpdate(payload);
105
- }
106
-
107
- function getWorkspaceBootstrapStatus(workspaceSlug = "") {
108
- const workspaceSlugKey = normalizeWorkspaceSlugKey(workspaceSlug);
109
- if (!workspaceSlugKey) {
110
- return "";
111
- }
112
- return String(workspaceBootstrapStatusBySlug.get(workspaceSlugKey) || "");
113
- }
114
-
115
- function subscribeWorkspaceBootstrapStatus(listener) {
116
- if (typeof listener !== "function") {
117
- return () => {};
118
- }
119
- workspaceBootstrapStatusListeners.add(listener);
120
- return () => {
121
- workspaceBootstrapStatusListeners.delete(listener);
122
- };
123
- }
124
-
125
- function writePlacementContext(payload = {}, state = {}, source = "users-web.bootstrap-placement") {
126
- const availableWorkspaces = normalizeWorkspaceList(payload?.workspaces);
127
- const currentWorkspace = findWorkspaceBySlug(availableWorkspaces, state.workspaceSlug);
128
- const workspaceSettings =
129
- payload?.workspaceSettings && typeof payload.workspaceSettings === "object"
130
- ? payload.workspaceSettings
131
- : null;
132
- const permissions = normalizePermissionList(payload?.permissions);
133
- const user = resolvePlacementUserFromBootstrapPayload(payload, state.context?.user);
134
- const workspaceInvitesEnabled = payload?.app?.features?.workspaceInvites === true;
135
- const pendingInvitesCount = workspaceInvitesEnabled ? countPendingInvites(payload?.pendingInvites) : 0;
136
-
137
- placementRuntime.setContext(
138
- {
139
- workspace: currentWorkspace,
140
- workspaceSettings,
141
- workspaces: availableWorkspaces,
142
- permissions,
143
- user,
144
- surfaceAccess: payload?.surfaceAccess && typeof payload.surfaceAccess === "object" ? payload.surfaceAccess : {},
145
- pendingInvitesCount,
146
- workspaceInvitesEnabled
147
- },
148
- {
149
- source
150
- }
151
- );
152
- routeGuards.enforceSurfaceAccessForCurrentRoute();
153
- applyWorkspaceColorFromPlacementContext("write");
154
- }
155
-
156
- function clearPlacementContext(source = "users-web.bootstrap-placement") {
157
- placementRuntime.setContext(
158
- {
159
- workspace: null,
160
- workspaceSettings: null,
161
- workspaces: [],
162
- permissions: [],
163
- user: null,
164
- surfaceAccess: {},
165
- pendingInvitesCount: 0,
166
- workspaceInvitesEnabled: false
167
- },
168
- {
169
- source
170
- }
171
- );
172
- routeGuards.enforceSurfaceAccessForCurrentRoute();
173
- applyWorkspaceColorFromPlacementContext("clear");
174
- }
175
-
176
- function getVuetifyThemeController() {
177
- if (vuetifyThemeController) {
178
- return vuetifyThemeController;
179
- }
180
- if (!app.has("jskit.client.vue.app")) {
181
- return null;
182
- }
183
-
184
- vuetifyThemeController = resolveVuetifyThemeController(app.make("jskit.client.vue.app"));
185
- return vuetifyThemeController;
186
- }
187
-
188
- function applyThemeFromBootstrapPayload(payload = {}, reason = "manual") {
189
- const themeController = getVuetifyThemeController();
190
- if (!themeController) {
191
- return;
192
- }
193
-
194
- try {
195
- const nextThemeName = resolveBootstrapThemeName(payload);
196
- setVuetifyThemeName(themeController, nextThemeName);
197
- persistBootstrapThemePreference(payload);
198
- } catch (error) {
199
- runtimeLogger.warn(
200
- {
201
- reason,
202
- error: String(error?.message || error || "unknown error")
203
- },
204
- "users-web bootstrap theme apply failed."
205
- );
206
- }
207
- }
208
-
209
- function resolveWorkspaceThemeForCurrentRoute() {
210
- const routeState = resolveRouteState(placementRuntime, router);
211
- if (!routeState.workspaceSlug) {
212
- return null;
213
- }
214
-
215
- const context = placementRuntime.getContext();
216
- const workspaceSettings =
217
- context?.workspaceSettings && typeof context.workspaceSettings === "object"
218
- ? context.workspaceSettings
219
- : null;
220
- if (workspaceSettings) {
221
- return workspaceSettings;
222
- }
223
-
224
- const workspace = context?.workspace && typeof context.workspace === "object" ? context.workspace : null;
225
- if (!workspace) {
226
- return null;
227
- }
228
- const workspaceSlug = normalizeWorkspaceSlugKey(workspace.slug);
229
- if (!workspaceSlug || workspaceSlug !== normalizeWorkspaceSlugKey(routeState.workspaceSlug)) {
230
- return null;
231
- }
232
-
233
- return workspace;
234
- }
235
-
236
- function applyWorkspaceColorFromPlacementContext(reason = "manual") {
237
- const themeController = getVuetifyThemeController();
238
- if (!themeController) {
239
- return;
240
- }
241
- try {
242
- const workspaceTheme = resolveWorkspaceThemeForCurrentRoute();
243
- setVuetifyPrimaryColorOverride(themeController, workspaceTheme);
244
- } catch (error) {
245
- runtimeLogger.warn(
246
- {
247
- reason,
248
- error: String(error?.message || error || "unknown error")
249
- },
250
- "users-web bootstrap workspace color apply failed."
251
- );
252
- }
253
- }
254
-
255
- async function refresh(reason = "manual") {
256
- if (shutdownRequested) {
257
- return;
258
- }
259
-
260
- const stateAtStart = resolveRouteState(placementRuntime, router);
261
- const source = `users-web.bootstrap-placement.${String(reason || "manual").trim() || "manual"}`;
262
- try {
263
- const payload = await fetchBootstrap(stateAtStart.workspaceSlug);
264
- const stateAtApply = resolveRouteState(placementRuntime, router);
265
- if (stateAtStart.path !== stateAtApply.path || stateAtStart.workspaceSlug !== stateAtApply.workspaceSlug) {
266
- return;
267
- }
268
-
269
- writePlacementContext(payload, stateAtStart, source);
270
- applyThemeFromBootstrapPayload(payload, reason);
271
- applyWorkspaceColorFromPlacementContext(reason);
272
- if (stateAtStart.workspaceSlug) {
273
- const sessionAuthenticated = payload?.session?.authenticated === true;
274
- if (!sessionAuthenticated) {
275
- setWorkspaceBootstrapStatus(stateAtStart.workspaceSlug, WORKSPACE_BOOTSTRAP_STATUS_UNAUTHENTICATED, source);
276
- return;
277
- }
278
-
279
- const requestedWorkspaceStatus = resolveRequestedWorkspaceBootstrapStatus(payload, stateAtStart.workspaceSlug);
280
- if (requestedWorkspaceStatus) {
281
- setWorkspaceBootstrapStatus(stateAtStart.workspaceSlug, requestedWorkspaceStatus, source);
282
- return;
283
- }
284
-
285
- const availableWorkspaces = normalizeWorkspaceList(payload?.workspaces);
286
- const currentWorkspace = findWorkspaceBySlug(availableWorkspaces, stateAtStart.workspaceSlug);
287
- setWorkspaceBootstrapStatus(
288
- stateAtStart.workspaceSlug,
289
- currentWorkspace ? WORKSPACE_BOOTSTRAP_STATUS_RESOLVED : WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN,
290
- source
291
- );
292
- }
293
- } catch (error) {
294
- const statusCode = resolveErrorStatusCode(error);
295
- const stateAtApply = resolveRouteState(placementRuntime, router);
296
- const sameWorkspaceRoute =
297
- stateAtStart.path === stateAtApply.path && stateAtStart.workspaceSlug === stateAtApply.workspaceSlug;
298
-
299
- if (statusCode === 401) {
300
- if (stateAtStart.workspaceSlug) {
301
- setWorkspaceBootstrapStatus(stateAtStart.workspaceSlug, WORKSPACE_BOOTSTRAP_STATUS_UNAUTHENTICATED, source);
302
- }
303
- clearPlacementContext(source);
304
- applyThemeFromBootstrapPayload(
305
- {
306
- session: {
307
- authenticated: false
308
- }
309
- },
310
- reason
311
- );
312
- return;
313
- }
314
- if (statusCode === 403) {
315
- if (stateAtStart.workspaceSlug) {
316
- setWorkspaceBootstrapStatus(stateAtStart.workspaceSlug, WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN, source);
317
- }
318
- if (sameWorkspaceRoute) {
319
- clearPlacementContext(source);
320
- }
321
- return;
322
- }
323
- if (statusCode === 404) {
324
- if (stateAtStart.workspaceSlug) {
325
- setWorkspaceBootstrapStatus(stateAtStart.workspaceSlug, WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND, source);
326
- }
327
- if (sameWorkspaceRoute) {
328
- clearPlacementContext(source);
329
- }
330
- return;
331
- }
332
-
333
- if (stateAtStart.workspaceSlug) {
334
- setWorkspaceBootstrapStatus(stateAtStart.workspaceSlug, WORKSPACE_BOOTSTRAP_STATUS_ERROR, source);
335
- }
336
-
337
- runtimeLogger.warn(
338
- {
339
- reason,
340
- error: String(error?.message || error || "unknown error")
341
- },
342
- "users-web bootstrap placement refresh failed."
343
- );
344
- }
345
- }
346
-
347
- function queueRefresh(reason = "manual") {
348
- refreshQueue = refreshQueue
349
- .then(() => refresh(reason))
350
- .catch((error) => {
351
- runtimeLogger.warn(
352
- {
353
- reason,
354
- error: String(error?.message || error || "unknown error")
355
- },
356
- "users-web bootstrap placement queued refresh failed."
357
- );
358
- });
359
- return refreshQueue;
360
- }
361
-
362
- async function initialize() {
363
- routeGuards.installWorkspaceGuardEvaluator();
364
-
365
- const contextAtInit = placementRuntime.getContext();
366
- if (contextAtInit?.auth?.authenticated !== true) {
367
- applyThemeFromBootstrapPayload({
368
- session: {
369
- authenticated: false
370
- }
371
- }, "init");
372
- }
373
- applyWorkspaceColorFromPlacementContext("init");
374
-
375
- if (typeof placementRuntime.subscribe === "function") {
376
- const unsubscribePlacement = placementRuntime.subscribe((event = {}) => {
377
- if (event.type !== "context.updated") {
378
- return;
379
- }
380
-
381
- const nextContext = placementRuntime.getContext();
382
- applyWorkspaceColorFromPlacementContext("context");
383
- const nextSignature = resolveAuthSignature(nextContext);
384
- if (nextSignature === authSignature) {
385
- return;
386
- }
387
-
388
- authSignature = nextSignature;
389
- if (nextContext?.auth?.authenticated !== true) {
390
- applyThemeFromBootstrapPayload({
391
- session: {
392
- authenticated: false
393
- }
394
- }, "auth");
395
- }
396
- void queueRefresh("auth");
397
- });
398
- cleanup.push(() => {
399
- if (typeof unsubscribePlacement === "function") {
400
- unsubscribePlacement();
401
- }
402
- });
403
- }
404
-
405
- await queueRefresh("init");
406
-
407
- if (router && typeof router.afterEach === "function") {
408
- const removeAfterEach = router.afterEach(() => {
409
- const nextWorkspaceSlug = resolveRouteState(placementRuntime, router).workspaceSlug;
410
- if (nextWorkspaceSlug === lastRouteWorkspaceSlug) {
411
- return;
412
- }
413
- lastRouteWorkspaceSlug = nextWorkspaceSlug;
414
- void queueRefresh("route");
415
- });
416
- cleanup.push(() => {
417
- if (typeof removeAfterEach === "function") {
418
- removeAfterEach();
419
- }
420
- });
421
- }
422
-
423
- if (socket && typeof socket.on === "function") {
424
- const handleBootstrapChanged = () => {
425
- void queueRefresh("realtime");
426
- };
427
- socket.on("users.bootstrap.changed", handleBootstrapChanged);
428
- cleanup.push(() => {
429
- if (typeof socket.off === "function") {
430
- socket.off("users.bootstrap.changed", handleBootstrapChanged);
431
- }
432
- });
433
- }
434
- }
435
-
436
- function shutdown() {
437
- shutdownRequested = true;
438
- for (const release of cleanup.splice(0, cleanup.length)) {
439
- if (typeof release === "function") {
440
- try {
441
- release();
442
- } catch {}
443
- }
444
- }
445
- }
446
-
447
- return Object.freeze({
448
- initialize,
449
- shutdown,
450
- refresh: queueRefresh,
451
- getWorkspaceBootstrapStatus,
452
- subscribeWorkspaceBootstrapStatus
453
- });
454
- }
455
-
456
- export {
457
- WORKSPACE_BOOTSTRAP_STATUS_RESOLVED,
458
- WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND,
459
- WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN,
460
- WORKSPACE_BOOTSTRAP_STATUS_UNAUTHENTICATED,
461
- WORKSPACE_BOOTSTRAP_STATUS_ERROR,
462
- createBootstrapPlacementRuntime
463
- };
@@ -1,28 +0,0 @@
1
- const WORKSPACE_BOOTSTRAP_STATUS_RESOLVED = "resolved";
2
- const WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND = "not_found";
3
- const WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN = "forbidden";
4
- const WORKSPACE_BOOTSTRAP_STATUS_UNAUTHENTICATED = "unauthenticated";
5
- const WORKSPACE_BOOTSTRAP_STATUS_ERROR = "error";
6
- const SHELL_GUARD_EVALUATOR_KEY = "__JSKIT_WEB_SHELL_GUARD_EVALUATOR__";
7
- const WORKSPACE_NOT_FOUND_GUARD_REASON = "workspace-not-found";
8
- const WORKSPACE_FORBIDDEN_GUARD_REASON = "workspace-forbidden";
9
-
10
- const WORKSPACE_BOOTSTRAP_STATUSES = new Set([
11
- WORKSPACE_BOOTSTRAP_STATUS_RESOLVED,
12
- WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND,
13
- WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN,
14
- WORKSPACE_BOOTSTRAP_STATUS_UNAUTHENTICATED,
15
- WORKSPACE_BOOTSTRAP_STATUS_ERROR
16
- ]);
17
-
18
- export {
19
- SHELL_GUARD_EVALUATOR_KEY,
20
- WORKSPACE_BOOTSTRAP_STATUSES,
21
- WORKSPACE_BOOTSTRAP_STATUS_ERROR,
22
- WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN,
23
- WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND,
24
- WORKSPACE_BOOTSTRAP_STATUS_RESOLVED,
25
- WORKSPACE_BOOTSTRAP_STATUS_UNAUTHENTICATED,
26
- WORKSPACE_FORBIDDEN_GUARD_REASON,
27
- WORKSPACE_NOT_FOUND_GUARD_REASON
28
- };
@@ -1,147 +0,0 @@
1
- import {
2
- createProviderLogger as createSharedProviderLogger
3
- } from "@jskit-ai/kernel/shared/support/providerLogger";
4
- import {
5
- resolveRuntimePathname,
6
- resolveSurfaceIdFromPlacementPathname
7
- } from "@jskit-ai/shell-web/client/placement";
8
- import { parseWorkspacePathname } from "@jskit-ai/users-core/shared/support/workspacePathModel";
9
- import { extractWorkspaceSlugFromSurfacePathname } from "../lib/workspaceSurfacePaths.js";
10
- import { usersWebHttpClient } from "../lib/httpClient.js";
11
- import { buildBootstrapApiPath } from "../lib/bootstrap.js";
12
- import {
13
- normalizeWorkspaceBootstrapStatusValue
14
- } from "../support/runtimeNormalization.js";
15
- import { WORKSPACE_BOOTSTRAP_STATUSES } from "./bootstrapPlacementRuntimeConstants.js";
16
-
17
- function createProviderLogger(app) {
18
- return createSharedProviderLogger(app);
19
- }
20
-
21
- function resolveRouteState(placementRuntime, router) {
22
- const context = placementRuntime.getContext();
23
- const path = resolveRuntimePathname(router?.currentRoute?.value?.path);
24
- const surfaceId = String(resolveSurfaceIdFromPlacementPathname(context, path) || "")
25
- .trim()
26
- .toLowerCase();
27
- const workspaceSlugFromSurface = String(extractWorkspaceSlugFromSurfacePathname(context, surfaceId, path) || "").trim();
28
- const workspaceSlug =
29
- workspaceSlugFromSurface ||
30
- String(parseWorkspacePathname(path)?.workspaceSlug || "").trim();
31
-
32
- return Object.freeze({
33
- context,
34
- path,
35
- workspaceSlug
36
- });
37
- }
38
-
39
- function normalizeSearch(search = "") {
40
- const normalizedSearch = String(search || "").trim();
41
- if (!normalizedSearch) {
42
- return "";
43
- }
44
- return normalizedSearch.startsWith("?") ? normalizedSearch : `?${normalizedSearch}`;
45
- }
46
-
47
- function resolveSearchFromFullPath(fullPath = "") {
48
- const normalizedFullPath = String(fullPath || "").trim();
49
- const queryStart = normalizedFullPath.indexOf("?");
50
- if (queryStart < 0) {
51
- return "";
52
- }
53
- const hashStart = normalizedFullPath.indexOf("#", queryStart);
54
- const search = hashStart < 0 ? normalizedFullPath.slice(queryStart) : normalizedFullPath.slice(queryStart, hashStart);
55
- return normalizeSearch(search);
56
- }
57
-
58
- function isGuardDenied(outcome) {
59
- if (outcome === false) {
60
- return true;
61
- }
62
- if (outcome == null || outcome === true || typeof outcome !== "object" || Array.isArray(outcome)) {
63
- return false;
64
- }
65
- return outcome.allow === false;
66
- }
67
-
68
- function normalizeWorkspaceSlugKey(workspaceSlug = "") {
69
- return String(workspaceSlug || "")
70
- .trim()
71
- .toLowerCase();
72
- }
73
-
74
- function normalizeWorkspaceBootstrapStatus(status = "") {
75
- return normalizeWorkspaceBootstrapStatusValue(status, WORKSPACE_BOOTSTRAP_STATUSES);
76
- }
77
-
78
- function resolveRequestedWorkspaceBootstrapStatus(payload = {}, workspaceSlug = "") {
79
- const normalizedWorkspaceSlug = normalizeWorkspaceSlugKey(workspaceSlug);
80
- if (!normalizedWorkspaceSlug) {
81
- return "";
82
- }
83
-
84
- const requestedWorkspace =
85
- payload?.requestedWorkspace && typeof payload.requestedWorkspace === "object" ? payload.requestedWorkspace : null;
86
- if (!requestedWorkspace) {
87
- return "";
88
- }
89
-
90
- const requestedWorkspaceSlug = normalizeWorkspaceSlugKey(requestedWorkspace.slug);
91
- if (!requestedWorkspaceSlug || requestedWorkspaceSlug !== normalizedWorkspaceSlug) {
92
- return "";
93
- }
94
-
95
- return normalizeWorkspaceBootstrapStatus(requestedWorkspace.status);
96
- }
97
-
98
- function resolveAuthSignature(context = {}) {
99
- const auth = context?.auth && typeof context.auth === "object" ? context.auth : {};
100
- const authenticated = auth.authenticated === true ? "1" : "0";
101
- const oauthDefaultProvider = String(auth.oauthDefaultProvider || "")
102
- .trim()
103
- .toLowerCase();
104
- const oauthProviders = Array.isArray(auth.oauthProviders)
105
- ? auth.oauthProviders
106
- .map((entry) => String(entry?.id || "").trim().toLowerCase())
107
- .filter(Boolean)
108
- .join(",")
109
- : "";
110
-
111
- return `${authenticated}|${oauthDefaultProvider}|${oauthProviders}`;
112
- }
113
-
114
- function countPendingInvites(entries = []) {
115
- if (!Array.isArray(entries)) {
116
- return 0;
117
- }
118
-
119
- let total = 0;
120
- for (const entry of entries) {
121
- if (!entry || typeof entry !== "object") {
122
- continue;
123
- }
124
- total += 1;
125
- }
126
- return total;
127
- }
128
-
129
- async function fetchBootstrapPayload(workspaceSlug = "") {
130
- return usersWebHttpClient.request(buildBootstrapApiPath(workspaceSlug), {
131
- method: "GET"
132
- });
133
- }
134
-
135
- export {
136
- countPendingInvites,
137
- createProviderLogger,
138
- fetchBootstrapPayload,
139
- isGuardDenied,
140
- normalizeSearch,
141
- normalizeWorkspaceBootstrapStatus,
142
- normalizeWorkspaceSlugKey,
143
- resolveAuthSignature,
144
- resolveRequestedWorkspaceBootstrapStatus,
145
- resolveRouteState,
146
- resolveSearchFromFullPath
147
- };