@jskit-ai/shell-web 0.1.154 → 0.1.156

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.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/shell-web",
3
- "version": "0.1.154",
3
+ "version": "0.1.156",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -14,6 +14,8 @@
14
14
  "./client/bootstrap": "./src/client/bootstrap/index.js",
15
15
  "./server/support/localLinkItemScaffolds": "./src/server/support/localLinkItemScaffolds.js",
16
16
  "./client/navigation/linkResolver": "./src/client/navigation/linkResolver.js",
17
+ "./client/navigation/usePaths": "./src/client/navigation/usePaths.js",
18
+ "./client/navigation/useSurfaceRouteContext": "./src/client/navigation/useSurfaceRouteContext.js",
17
19
  "./client/components/ShellLayout": "./src/client/components/ShellLayout.vue",
18
20
  "./client/components/ShellOutlet": "./src/client/components/ShellOutlet.vue",
19
21
  "./client/components/ShellOutletMenuWidget": "./src/client/components/ShellOutletMenuWidget.vue",
@@ -28,7 +30,7 @@
28
30
  },
29
31
  "dependencies": {
30
32
  "@mdi/js": "^7.4.47",
31
- "@jskit-ai/kernel": "0.1.150"
33
+ "@jskit-ai/kernel": "0.1.152"
32
34
  },
33
35
  "peerDependencies": {
34
36
  "pinia": "^3.0.4",
@@ -83,6 +85,14 @@
83
85
  "subpath": "./client/placement",
84
86
  "summary": "Exports placement registry, placement context access, runtime token, and surface path helpers."
85
87
  },
88
+ {
89
+ "subpath": "./client/navigation/usePaths",
90
+ "summary": "Exports surface-aware page and API path resolution."
91
+ },
92
+ {
93
+ "subpath": "./client/navigation/useSurfaceRouteContext",
94
+ "summary": "Exports the current route, placement context, and resolved surface id."
95
+ },
86
96
  {
87
97
  "subpath": "./client/error",
88
98
  "summary": "Exports default error policy and runtime error reporter hook."
@@ -381,7 +391,7 @@
381
391
  "dependencies": {
382
392
  "runtime": {
383
393
  "@mdi/js": "^7.4.47",
384
- "@jskit-ai/kernel": "0.1.150"
394
+ "@jskit-ai/kernel": "0.1.152"
385
395
  },
386
396
  "dev": {
387
397
  "@playwright/test": "1.61.1"
@@ -0,0 +1,119 @@
1
+ import { computed, unref } from "vue";
2
+ import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
3
+ import { resolveScopedApiBasePath } from "@jskit-ai/kernel/shared/surface";
4
+ import { resolveSurfaceDefinitionFromPlacementContext } from "../placement/index.js";
5
+ import { useShellLinkResolver } from "./linkResolver.js";
6
+ import { useSurfaceRouteContext } from "./useSurfaceRouteContext.js";
7
+
8
+ function normalizePathSuffix(value = "") {
9
+ const raw = normalizeText(unref(value));
10
+ if (!raw) {
11
+ return "";
12
+ }
13
+
14
+ return raw.startsWith("/") ? raw : `/${raw}`;
15
+ }
16
+
17
+ function resolveSurfaceId(value, fallback = "") {
18
+ const normalized = normalizeText(unref(value)).toLowerCase();
19
+ if (normalized && normalized !== "*") {
20
+ return normalized;
21
+ }
22
+
23
+ const normalizedFallback = normalizeText(unref(fallback)).toLowerCase();
24
+ if (normalizedFallback && normalizedFallback !== "*") {
25
+ return normalizedFallback;
26
+ }
27
+
28
+ return "";
29
+ }
30
+
31
+ function resolveDefaultSurfaceIdFromPlacementContext(placementContext = null) {
32
+ return resolveSurfaceId(placementContext?.surfaceConfig?.defaultSurfaceId, "");
33
+ }
34
+
35
+ function normalizeRouteParams(params = null) {
36
+ if (!params || typeof params !== "object" || Array.isArray(params)) {
37
+ return {};
38
+ }
39
+
40
+ const output = {};
41
+ for (const [rawKey, rawValue] of Object.entries(params)) {
42
+ const key = normalizeText(rawKey);
43
+ if (!key) {
44
+ continue;
45
+ }
46
+
47
+ const value = Array.isArray(rawValue) ? rawValue[0] : rawValue;
48
+ const normalizedValue = normalizeText(value);
49
+ if (normalizedValue) {
50
+ output[key] = normalizedValue;
51
+ }
52
+ }
53
+ return output;
54
+ }
55
+
56
+ function resolveRouteParams(baseParams = {}, overrideParams = null) {
57
+ return {
58
+ ...normalizeRouteParams(baseParams),
59
+ ...normalizeRouteParams(overrideParams)
60
+ };
61
+ }
62
+
63
+ function usePaths({ routeContext: sourceRouteContext = null } = {}) {
64
+ const routeContext = sourceRouteContext || useSurfaceRouteContext();
65
+ const shellLinkResolver = useShellLinkResolver();
66
+ const routeParams = computed(() => normalizeRouteParams(routeContext.route?.params));
67
+
68
+ function page(relativePath = "/", options = {}) {
69
+ const source = options && typeof options === "object" && !Array.isArray(options) ? options : {};
70
+ const surface =
71
+ resolveSurfaceId(source.surface, routeContext.currentSurfaceId.value) ||
72
+ resolveDefaultSurfaceIdFromPlacementContext(routeContext.placementContext.value);
73
+ if (!surface) {
74
+ return "";
75
+ }
76
+ return shellLinkResolver.resolve(relativePath, {
77
+ surface,
78
+ explicitTo: source.explicitTo,
79
+ surfaceRelativePath: source.surfaceRelativePath,
80
+ params: resolveRouteParams(routeParams.value, source.params),
81
+ strictParams: source.strictParams !== false
82
+ });
83
+ }
84
+
85
+ function api(relativePath = "", options = {}) {
86
+ const source = options && typeof options === "object" && !Array.isArray(options) ? options : {};
87
+ const surface =
88
+ resolveSurfaceId(source.surface, routeContext.currentSurfaceId.value) ||
89
+ resolveDefaultSurfaceIdFromPlacementContext(routeContext.placementContext.value);
90
+ const suffix = normalizePathSuffix(relativePath);
91
+
92
+ if (!suffix) {
93
+ throw new TypeError("usePaths().api(relativePath) requires a non-empty relativePath.");
94
+ }
95
+
96
+ const routeBase = resolveSurfaceDefinitionFromPlacementContext(
97
+ routeContext.placementContext.value,
98
+ surface
99
+ )?.routeBase || "/";
100
+
101
+ return resolveScopedApiBasePath({
102
+ routeBase,
103
+ relativePath: suffix,
104
+ params: resolveRouteParams(routeParams.value, source.params),
105
+ strictParams: source.strictParams !== false
106
+ });
107
+ }
108
+
109
+ return Object.freeze({
110
+ route: routeContext.route,
111
+ placementContext: routeContext.placementContext,
112
+ currentSurfaceId: routeContext.currentSurfaceId,
113
+ routeParams,
114
+ page,
115
+ api
116
+ });
117
+ }
118
+
119
+ export { usePaths };
@@ -0,0 +1,26 @@
1
+ import { computed } from "vue";
2
+ import { useRoute } from "vue-router";
3
+ import {
4
+ resolveRuntimePathname,
5
+ resolveSurfaceIdFromPlacementPathname,
6
+ useWebPlacementContext
7
+ } from "../placement/index.js";
8
+
9
+ function useSurfaceRouteContext() {
10
+ const route = useRoute();
11
+ const { context: placementContext, mergeContext: mergePlacementContext } = useWebPlacementContext();
12
+ const routePath = computed(() => resolveRuntimePathname(route?.path));
13
+ const currentSurfaceId = computed(() =>
14
+ resolveSurfaceIdFromPlacementPathname(placementContext.value, routePath.value)
15
+ );
16
+
17
+ return Object.freeze({
18
+ route,
19
+ routePath,
20
+ placementContext,
21
+ mergePlacementContext,
22
+ currentSurfaceId
23
+ });
24
+ }
25
+
26
+ export { useSurfaceRouteContext };
@@ -114,13 +114,6 @@ function normalizePlacementDefinition(value, { strict = false, source = "placeme
114
114
  return null;
115
115
  }
116
116
 
117
- if (Object.hasOwn(value, "host") || Object.hasOwn(value, "position")) {
118
- if (strict) {
119
- throw new TypeError(`${source} must use "target" only. Legacy "host" and "position" fields are not supported.`);
120
- }
121
- return null;
122
- }
123
-
124
117
  const id = normalizeText(value.id);
125
118
  if (!id) {
126
119
  if (strict) {
@@ -125,10 +125,6 @@ function resolveQueryMeta(query = null) {
125
125
 
126
126
  function isRequestRecoveryDisabled(query = null) {
127
127
  const meta = resolveQueryMeta(query);
128
- if (meta.jskitRequestRecovery === false || meta.requestRecovery === false) {
129
- return true;
130
- }
131
-
132
128
  const jskitMeta = isRecord(meta.jskit) ? meta.jskit : {};
133
129
  return jskitMeta.requestRecovery === false;
134
130
  }
@@ -138,11 +134,7 @@ function resolveQueryRecoveryLabel(query = null) {
138
134
  const jskitMeta = isRecord(meta.jskit) ? meta.jskit : {};
139
135
 
140
136
  return normalizeText(
141
- jskitMeta.requestRecoveryLabel ||
142
- jskitMeta.label ||
143
- meta.jskitRequestRecoveryLabel ||
144
- meta.requestRecoveryLabel ||
145
- meta.label,
137
+ jskitMeta.requestRecoveryLabel,
146
138
  "Request"
147
139
  );
148
140
  }
@@ -152,9 +144,7 @@ function resolveQueryRecoverySource(query = null) {
152
144
  const jskitMeta = isRecord(meta.jskit) ? meta.jskit : {};
153
145
 
154
146
  return normalizeText(
155
- jskitMeta.requestRecoverySource ||
156
- meta.jskitRequestRecoverySource ||
157
- meta.requestRecoverySource,
147
+ jskitMeta.requestRecoverySource,
158
148
  "shell-web.request-recovery.query"
159
149
  );
160
150
  }
@@ -164,9 +154,7 @@ function resolveQueryRecoveryDedupeKey(query = null, fallback = "") {
164
154
  const jskitMeta = isRecord(meta.jskit) ? meta.jskit : {};
165
155
 
166
156
  return normalizeText(
167
- jskitMeta.requestRecoveryDedupeKey ||
168
- meta.jskitRequestRecoveryDedupeKey ||
169
- meta.requestRecoveryDedupeKey,
157
+ jskitMeta.requestRecoveryDedupeKey,
170
158
  fallback
171
159
  );
172
160
  }
@@ -174,10 +162,7 @@ function resolveQueryRecoveryDedupeKey(query = null, fallback = "") {
174
162
  function resolveQueryRecoveryDedupeWindowMs(query = null) {
175
163
  const meta = resolveQueryMeta(query);
176
164
  const jskitMeta = isRecord(meta.jskit) ? meta.jskit : {};
177
- const value =
178
- jskitMeta.requestRecoveryDedupeWindowMs ??
179
- meta.jskitRequestRecoveryDedupeWindowMs ??
180
- meta.requestRecoveryDedupeWindowMs;
165
+ const value = jskitMeta.requestRecoveryDedupeWindowMs;
181
166
 
182
167
  return Number.isFinite(Number(value)) ? Math.max(0, Number(value)) : null;
183
168
  }
@@ -186,11 +171,7 @@ function resolveQueryRecoveryMethod(query = null) {
186
171
  const meta = resolveQueryMeta(query);
187
172
  const jskitMeta = isRecord(meta.jskit) ? meta.jskit : {};
188
173
 
189
- return normalizeText(
190
- jskitMeta.requestRecoveryMethod ||
191
- meta.jskitRequestRecoveryMethod ||
192
- meta.requestRecoveryMethod
193
- ).toUpperCase();
174
+ return normalizeText(jskitMeta.requestRecoveryMethod).toUpperCase();
194
175
  }
195
176
 
196
177
  function isSafeQueryRecoveryMethod(query = null) {
@@ -41,7 +41,7 @@ test("placement registry accepts explicit non-global surface ids", () => {
41
41
  assert.equal(added, true);
42
42
  });
43
43
 
44
- test("placement registry rejects split target fields", () => {
44
+ test("placement registry requires target", () => {
45
45
  const registry = createPlacementRegistry();
46
46
 
47
47
  assert.throws(
@@ -51,6 +51,6 @@ test("placement registry rejects split target fields", () => {
51
51
  position: "top-right",
52
52
  componentToken: "example.split.component"
53
53
  }),
54
- /must use "target" only/
54
+ /requires semantic target/
55
55
  );
56
56
  });