@jskit-ai/shell-web 0.1.86 → 0.1.87

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.
@@ -1,7 +1,7 @@
1
1
  export default Object.freeze({
2
2
  packageVersion: 1,
3
3
  packageId: "@jskit-ai/shell-web",
4
- version: "0.1.86",
4
+ version: "0.1.87",
5
5
  kind: "runtime",
6
6
  description: "Web shell layout runtime with outlet-based placement contributions.",
7
7
  dependsOn: [],
@@ -294,7 +294,7 @@ export default Object.freeze({
294
294
  dependencies: {
295
295
  runtime: {
296
296
  "@mdi/js": "^7.4.47",
297
- "@jskit-ai/kernel": "0.1.87"
297
+ "@jskit-ai/kernel": "0.1.88"
298
298
  },
299
299
  dev: {}
300
300
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/shell-web",
3
- "version": "0.1.86",
3
+ "version": "0.1.87",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -9,6 +9,7 @@
9
9
  "./client": "./src/client/index.js",
10
10
  "./client/error": "./src/client/error/index.js",
11
11
  "./client/placement": "./src/client/placement/index.js",
12
+ "./client/asyncModuleRecovery": "./src/client/asyncModuleRecovery/index.js",
12
13
  "./client/bootstrap": "./src/client/bootstrap/index.js",
13
14
  "./server/support/localLinkItemScaffolds": "./src/server/support/localLinkItemScaffolds.js",
14
15
  "./client/navigation/linkResolver": "./src/client/navigation/linkResolver.js",
@@ -26,7 +27,7 @@
26
27
  },
27
28
  "dependencies": {
28
29
  "@mdi/js": "^7.4.47",
29
- "@jskit-ai/kernel": "0.1.87"
30
+ "@jskit-ai/kernel": "0.1.88"
30
31
  },
31
32
  "peerDependencies": {
32
33
  "pinia": "^3.0.4",
@@ -0,0 +1,4 @@
1
+ export {
2
+ SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY,
3
+ useShellAsyncModuleRecoveryRuntime
4
+ } from "./inject.js";
@@ -0,0 +1,30 @@
1
+ import {
2
+ hasInjectionContext,
3
+ inject
4
+ } from "vue";
5
+
6
+ const SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY =
7
+ "jskit.shell-web.runtime.web-async-module-recovery.client";
8
+
9
+ function isShellAsyncModuleRecoveryRuntime(value) {
10
+ return Boolean(
11
+ value &&
12
+ typeof value.notify === "function" &&
13
+ typeof value.reload === "function"
14
+ );
15
+ }
16
+
17
+ function useShellAsyncModuleRecoveryRuntime() {
18
+ if (!hasInjectionContext()) {
19
+ return null;
20
+ }
21
+
22
+ const runtime = inject(SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY, null);
23
+ return isShellAsyncModuleRecoveryRuntime(runtime) ? runtime : null;
24
+ }
25
+
26
+ export {
27
+ SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY,
28
+ isShellAsyncModuleRecoveryRuntime,
29
+ useShellAsyncModuleRecoveryRuntime
30
+ };
@@ -17,6 +17,10 @@ export { default as ShellTabLinkItem } from "./components/ShellTabLinkItem.vue";
17
17
  export { useShellLayoutState } from "./composables/useShellLayoutState.js";
18
18
  export { useShellLayoutStore } from "./stores/useShellLayoutStore.js";
19
19
  export { useShellErrorPresentationStore } from "./stores/useShellErrorPresentationStore.js";
20
+ export {
21
+ SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY,
22
+ useShellAsyncModuleRecoveryRuntime
23
+ } from "./asyncModuleRecovery/index.js";
20
24
  export {
21
25
  BOOTSTRAP_PAYLOAD_HANDLER_TAG,
22
26
  registerBootstrapPayloadHandler,
@@ -10,6 +10,9 @@ import {
10
10
  isMissingDynamicModule,
11
11
  notifyDynamicImportFailure
12
12
  } from "./appModuleLoadFailure.js";
13
+ import {
14
+ SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY
15
+ } from "../asyncModuleRecovery/inject.js";
13
16
  import {
14
17
  isRecord
15
18
  } from "@jskit-ai/kernel/shared/support";
@@ -654,7 +657,7 @@ class ShellWebClientProvider {
654
657
  vueApp.provide("jskit.shell-web.runtime.web-placement.client", placementRuntime);
655
658
  vueApp.provide("jskit.shell-web.runtime.web-refresh.client", refreshRuntime);
656
659
  vueApp.provide("jskit.shell-web.runtime.web-error.client", errorRuntime);
657
- vueApp.provide("jskit.shell-web.runtime.web-async-module-recovery.client", asyncModuleRecoveryRuntime);
660
+ vueApp.provide(SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY, asyncModuleRecoveryRuntime);
658
661
  vueApp.provide(
659
662
  "jskit.shell-web.runtime.web-error.presentation-store.client",
660
663
  errorPresentationStore
@@ -0,0 +1,49 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { createApp } from "vue";
4
+ import {
5
+ SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY,
6
+ useShellAsyncModuleRecoveryRuntime
7
+ } from "../src/client/asyncModuleRecovery/index.js";
8
+
9
+ test("shell async module recovery runtime composable returns null outside Vue injection context", () => {
10
+ assert.equal(useShellAsyncModuleRecoveryRuntime(), null);
11
+ });
12
+
13
+ test("shell async module recovery runtime composable resolves the provided public runtime", async () => {
14
+ const runtime = {
15
+ notify(error, options) {
16
+ return { error, options };
17
+ },
18
+ async reload() {
19
+ return true;
20
+ }
21
+ };
22
+ const app = createApp({
23
+ render() {
24
+ return null;
25
+ }
26
+ });
27
+ app.provide(SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY, runtime);
28
+
29
+ assert.equal(
30
+ app.runWithContext(() => useShellAsyncModuleRecoveryRuntime()),
31
+ runtime
32
+ );
33
+ });
34
+
35
+ test("shell async module recovery runtime composable rejects incomplete runtimes", () => {
36
+ const app = createApp({
37
+ render() {
38
+ return null;
39
+ }
40
+ });
41
+ app.provide(SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY, {
42
+ notify() {}
43
+ });
44
+
45
+ assert.equal(
46
+ app.runWithContext(() => useShellAsyncModuleRecoveryRuntime()),
47
+ null
48
+ );
49
+ });
@@ -8,6 +8,9 @@ import {
8
8
  import {
9
9
  isMissingDynamicModule
10
10
  } from "../src/client/providers/appModuleLoadFailure.js";
11
+ import {
12
+ SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY
13
+ } from "../src/client/asyncModuleRecovery/index.js";
11
14
  import { useShellErrorPresentationStore } from "../src/client/stores/useShellErrorPresentationStore.js";
12
15
  const CLIENT_APP_CONFIG_GLOBAL_KEY = "__JSKIT_CLIENT_APP_CONFIG__";
13
16
 
@@ -229,7 +232,7 @@ test("shell web client provider binds runtime and injects it into Vue app", asyn
229
232
  assert.equal(providedByKey.has("jskit.shell-web.runtime.web-placement.client"), true);
230
233
  assert.equal(providedByKey.has("jskit.shell-web.runtime.web-refresh.client"), true);
231
234
  assert.equal(providedByKey.has("jskit.shell-web.runtime.web-error.client"), true);
232
- assert.equal(providedByKey.has("jskit.shell-web.runtime.web-async-module-recovery.client"), true);
235
+ assert.equal(providedByKey.has(SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY), true);
233
236
  assert.equal(providedByKey.has("jskit.shell-web.runtime.web-error.presentation-store.client"), true);
234
237
 
235
238
  const placementRuntime = providedByKey.get("jskit.shell-web.runtime.web-placement.client");
@@ -245,7 +248,7 @@ test("shell web client provider binds runtime and injects it into Vue app", asyn
245
248
  const refreshRuntime = providedByKey.get("jskit.shell-web.runtime.web-refresh.client");
246
249
  assert.equal(typeof refreshRuntime.refresh, "function");
247
250
 
248
- const asyncModuleRecoveryRuntime = providedByKey.get("jskit.shell-web.runtime.web-async-module-recovery.client");
251
+ const asyncModuleRecoveryRuntime = providedByKey.get(SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY);
249
252
  assert.equal(typeof asyncModuleRecoveryRuntime.install, "function");
250
253
  assert.equal(typeof asyncModuleRecoveryRuntime.notify, "function");
251
254
  assert.equal(typeof asyncModuleRecoveryRuntime.reload, "function");
@@ -148,6 +148,29 @@ test("shell-web installs generated adaptive shell Playwright smoke coverage", as
148
148
  assert.equal(packageJson?.exports?.["./test/adaptiveShellSmoke"], "./src/test/adaptiveShellSmoke.js");
149
149
  });
150
150
 
151
+ test("shell-web exports async module recovery runtime access as a public client API", async () => {
152
+ const packageJson = JSON.parse(await readFile(path.join(PACKAGE_DIR, "package.json"), "utf8"));
153
+ const clientIndex = await readFile(path.join(PACKAGE_DIR, "src", "client", "index.js"), "utf8");
154
+ const recoveryIndex = await readFile(
155
+ path.join(PACKAGE_DIR, "src", "client", "asyncModuleRecovery", "index.js"),
156
+ "utf8"
157
+ );
158
+ const providerSource = await readFile(
159
+ path.join(PACKAGE_DIR, "src", "client", "providers", "ShellWebClientProvider.js"),
160
+ "utf8"
161
+ );
162
+
163
+ assert.equal(
164
+ packageJson?.exports?.["./client/asyncModuleRecovery"],
165
+ "./src/client/asyncModuleRecovery/index.js"
166
+ );
167
+ assert.match(clientIndex, /useShellAsyncModuleRecoveryRuntime/);
168
+ assert.match(clientIndex, /SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY/);
169
+ assert.match(recoveryIndex, /useShellAsyncModuleRecoveryRuntime/);
170
+ assert.match(recoveryIndex, /SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY/);
171
+ assert.match(providerSource, /SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY/);
172
+ });
173
+
151
174
  test("shell-web route transition keeps mobile route motion placement-driven", async () => {
152
175
  const source = await readFile(
153
176
  path.join(PACKAGE_DIR, "src", "client", "components", "ShellRouteTransition.vue"),