@happyvertical/smrt-svelte 0.43.9 → 0.44.0
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/AGENTS.md +38 -2
- package/dist/Provider.svelte +11 -0
- package/dist/Provider.svelte.d.ts.map +1 -1
- package/dist/components/forms/Form.svelte +29 -13
- package/dist/components/forms/Form.svelte.d.ts +5 -0
- package/dist/components/forms/Form.svelte.d.ts.map +1 -1
- package/dist/components/forms/__tests__/Form.webmcp.test.js +115 -6
- package/dist/components/settings/SettingsCatalog.svelte +9 -0
- package/dist/components/settings/SettingsCatalog.svelte.d.ts +9 -0
- package/dist/components/settings/SettingsCatalog.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/ActivityBadge.svelte +2 -0
- package/dist/components/workspace/admin-shell/ActivityBadge.svelte.d.ts +2 -0
- package/dist/components/workspace/admin-shell/ActivityBadge.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/ActivityItem.svelte +1 -0
- package/dist/components/workspace/admin-shell/ActivityItem.svelte.d.ts +1 -0
- package/dist/components/workspace/admin-shell/ActivityItem.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/ActivityList.svelte +3 -0
- package/dist/components/workspace/admin-shell/ActivityList.svelte.d.ts +3 -0
- package/dist/components/workspace/admin-shell/ActivityList.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/ActivityToasts.svelte +1 -0
- package/dist/components/workspace/admin-shell/ActivityToasts.svelte.d.ts +1 -0
- package/dist/components/workspace/admin-shell/ActivityToasts.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/AdminShell.svelte +15 -0
- package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +15 -0
- package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/AppScopePanel.svelte +7 -0
- package/dist/components/workspace/admin-shell/AppScopePanel.svelte.d.ts +7 -0
- package/dist/components/workspace/admin-shell/AppScopePanel.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/HotkeyInput.svelte +4 -0
- package/dist/components/workspace/admin-shell/HotkeyInput.svelte.d.ts +4 -0
- package/dist/components/workspace/admin-shell/HotkeyInput.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/ShellCorner.svelte +1 -0
- package/dist/components/workspace/admin-shell/ShellCorner.svelte.d.ts +1 -0
- package/dist/components/workspace/admin-shell/ShellCorner.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/ShortcutsOverlay.svelte +1 -0
- package/dist/components/workspace/admin-shell/ShortcutsOverlay.svelte.d.ts +1 -0
- package/dist/components/workspace/admin-shell/ShortcutsOverlay.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/SystemScopePanel.svelte +2 -0
- package/dist/components/workspace/admin-shell/SystemScopePanel.svelte.d.ts +2 -0
- package/dist/components/workspace/admin-shell/SystemScopePanel.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/SystemStatusChips.svelte +1 -0
- package/dist/components/workspace/admin-shell/SystemStatusChips.svelte.d.ts +1 -0
- package/dist/components/workspace/admin-shell/SystemStatusChips.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/TenantNav.svelte +5 -0
- package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts +5 -0
- package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte +11 -0
- package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte.d.ts +11 -0
- package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/web/__tests__/view-intent-provider.fixture.svelte +28 -0
- package/dist/web/__tests__/view-intent-provider.fixture.svelte.d.ts +13 -0
- package/dist/web/__tests__/view-intent-provider.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/view-intent.fixture.svelte +33 -0
- package/dist/web/__tests__/view-intent.fixture.svelte.d.ts +15 -0
- package/dist/web/__tests__/view-intent.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/view-intent.intents.d.ts +14 -0
- package/dist/web/__tests__/view-intent.intents.d.ts.map +1 -0
- package/dist/web/__tests__/view-intent.intents.js +38 -0
- package/dist/web/__tests__/view-intent.svelte.test.js +201 -0
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte +11 -0
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte.d.ts.map +1 -1
- package/dist/web/__tests__/webmcp-composed.integration.svelte.test.js +4 -0
- package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte +16 -0
- package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte.d.ts +19 -0
- package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte +11 -0
- package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte.d.ts +8 -0
- package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte +20 -0
- package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte.d.ts +7 -0
- package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/webmcp-harness-unannotated.svelte +14 -0
- package/dist/web/__tests__/webmcp-harness-unannotated.svelte.d.ts +19 -0
- package/dist/web/__tests__/webmcp-harness-unannotated.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/webmcp-harness.svelte +4 -0
- package/dist/web/__tests__/webmcp-harness.svelte.d.ts.map +1 -1
- package/dist/web/__tests__/webmcp.test.js +136 -9
- package/dist/web/view-intent.svelte.d.ts +64 -0
- package/dist/web/view-intent.svelte.d.ts.map +1 -0
- package/dist/web/view-intent.svelte.js +83 -0
- package/dist/web/webmcp-bespoke-context.d.ts +14 -0
- package/dist/web/webmcp-bespoke-context.d.ts.map +1 -0
- package/dist/web/webmcp-bespoke-context.js +8 -0
- package/dist/web/webmcp.svelte.d.ts +29 -13
- package/dist/web/webmcp.svelte.d.ts.map +1 -1
- package/dist/web/webmcp.svelte.js +92 -12
- package/package.json +8 -7
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// The dependency-free intent entry, NOT the package root: it pulls no
|
|
2
|
+
// client-data engine, so a component binding an intent pays only for the
|
|
3
|
+
// declaration contract. The registrar itself is still loaded lazily, by
|
|
4
|
+
// `useWebMcpTool`.
|
|
5
|
+
import { compileViewIntentToolSpec } from '@happyvertical/smrt-web/intents';
|
|
6
|
+
import { useWebMcpTool } from './webmcp.svelte.js';
|
|
7
|
+
import { tryGetWebMcpUiContext } from './webmcp-ui-context.js';
|
|
8
|
+
/**
|
|
9
|
+
* Bind a declared view intent (#2588) to this component's mounted registry
|
|
10
|
+
* identity, for exactly this component's lifetime.
|
|
11
|
+
*
|
|
12
|
+
* Svelte is the FIRST binding, not the only one: the declaration contract,
|
|
13
|
+
* the registry, and the compilation to a browser tool all live in
|
|
14
|
+
* `@happyvertical/smrt-web` with no Svelte dependency. This file is the thin
|
|
15
|
+
* part — it resolves the mounted registries from the nearest Provider and
|
|
16
|
+
* hands the compiled spec to {@link useWebMcpTool}, which already owns the
|
|
17
|
+
* WebMCP lifecycle: the synchronous Provider policy read, the `options.effects`
|
|
18
|
+
* fallback, serialized same-name re-registration across effect reruns, and
|
|
19
|
+
* the lazy `@happyvertical/smrt-web` import.
|
|
20
|
+
*
|
|
21
|
+
* Registration therefore goes through `registerWebMcpBespokeTool`, so an
|
|
22
|
+
* intent is subject to the same fail-closed exposure policy as a generated
|
|
23
|
+
* model tool. Execution dispatches exactly one registry command with
|
|
24
|
+
* `source: 'agent'` — `StagedControlReview` stays on the path, agent-staged
|
|
25
|
+
* values remain proposals, and there is no path to REST.
|
|
26
|
+
*
|
|
27
|
+
* Declare the intent itself at module scope in a `.ts` sidecar
|
|
28
|
+
* (`Foo.intents.ts`) so #2591's scanner can emit it; import it here.
|
|
29
|
+
*
|
|
30
|
+
* With no Provider ancestor and no explicit registry override, this is a
|
|
31
|
+
* silent no-op — an intent with nothing mounted to dispatch to registers
|
|
32
|
+
* nothing, the same way every WebMCP entry point no-ops off-WebMCP. Because
|
|
33
|
+
* the registries are resolved INSIDE the tool factory, a Provider that
|
|
34
|
+
* enables `webmcp.ui` after this component initializes, or that swaps a
|
|
35
|
+
* registry, re-runs the effect and registers the intent against the current
|
|
36
|
+
* one rather than staying stuck on what was there at init.
|
|
37
|
+
*
|
|
38
|
+
* @throws if `identity` does not match the intent's declared target registry,
|
|
39
|
+
* or contradicts an identity the declaration pinned — both are author errors,
|
|
40
|
+
* not environment differences.
|
|
41
|
+
*/
|
|
42
|
+
export function useViewIntent(intent, options) {
|
|
43
|
+
// `getContext` is only valid during component initialization, so the
|
|
44
|
+
// CONTEXT OBJECT must be captured here. Its `enabled` and registry members
|
|
45
|
+
// are reactive getters, though, and reading them here would freeze one
|
|
46
|
+
// value for the component's whole life — so they are read inside the
|
|
47
|
+
// factory below, which `useWebMcpTool` runs within its `$effect`.
|
|
48
|
+
const uiContext = tryGetWebMcpUiContext();
|
|
49
|
+
// The identity SHAPE is a static author decision, so it is checked eagerly:
|
|
50
|
+
// a mismatch surfaces at the call site rather than inside an effect, where
|
|
51
|
+
// a throw is harder to attribute. Only the registries are deferred.
|
|
52
|
+
assertIdentityShape(intent, options.identity);
|
|
53
|
+
useWebMcpTool(() => {
|
|
54
|
+
const controlRegistry = options.controlRegistry ??
|
|
55
|
+
(uiContext?.enabled ? uiContext.controlRegistry : undefined);
|
|
56
|
+
const dataSurfaceRegistry = options.dataSurfaceRegistry ??
|
|
57
|
+
(uiContext?.enabled ? uiContext.dataSurfaceRegistry : undefined);
|
|
58
|
+
const binding = resolveBinding(intent, options.identity, controlRegistry, dataSurfaceRegistry);
|
|
59
|
+
return binding ? compileViewIntentToolSpec(intent, binding) : null;
|
|
60
|
+
}, options.effects ? { effects: options.effects } : {});
|
|
61
|
+
}
|
|
62
|
+
function assertIdentityShape(intent, identity) {
|
|
63
|
+
if (intent.target.registry === 'control' && !('formId' in identity)) {
|
|
64
|
+
throw new Error(`[smrt-svelte] intent '${intent.id}' targets the control registry and needs a { formId, controlId } identity`);
|
|
65
|
+
}
|
|
66
|
+
if (intent.target.registry === 'dataSurface' && !('surfaceId' in identity)) {
|
|
67
|
+
throw new Error(`[smrt-svelte] intent '${intent.id}' targets the dataSurface registry and needs a { surfaceId, kind } identity`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function resolveBinding(intent, identity, controlRegistry, dataSurfaceRegistry) {
|
|
71
|
+
if (intent.target.registry === 'control') {
|
|
72
|
+
if (!controlRegistry || !('formId' in identity))
|
|
73
|
+
return null;
|
|
74
|
+
return { registry: 'control', registryPort: controlRegistry, identity };
|
|
75
|
+
}
|
|
76
|
+
if (!dataSurfaceRegistry || !('surfaceId' in identity))
|
|
77
|
+
return null;
|
|
78
|
+
return {
|
|
79
|
+
registry: 'dataSurface',
|
|
80
|
+
registryPort: dataSurfaceRegistry,
|
|
81
|
+
identity,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WebMcpToolEffect } from '@happyvertical/smrt-web';
|
|
2
|
+
/**
|
|
3
|
+
* The `effects` exposure policy `useWebMcpTool` applies to a bespoke
|
|
4
|
+
* component tool (#2586). Provider sets this from the same `webmcp.effects`
|
|
5
|
+
* config it passes to `registerWebMcpTools` for generated tools, so a
|
|
6
|
+
* bespoke and a generated tool share one policy. Absent a Provider ancestor,
|
|
7
|
+
* `useWebMcpTool` falls back to the registrar's own default (read-only).
|
|
8
|
+
*/
|
|
9
|
+
export interface WebMcpBespokeContext {
|
|
10
|
+
readonly effects?: readonly WebMcpToolEffect[];
|
|
11
|
+
}
|
|
12
|
+
export declare function setWebMcpBespokeContext(context: WebMcpBespokeContext): void;
|
|
13
|
+
export declare function tryGetWebMcpBespokeContext(): WebMcpBespokeContext | null;
|
|
14
|
+
//# sourceMappingURL=webmcp-bespoke-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webmcp-bespoke-context.d.ts","sourceRoot":"","sources":["../../src/web/webmcp-bespoke-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAKhE;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAChD;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAE3E;AAED,wBAAgB,0BAA0B,IAAI,oBAAoB,GAAG,IAAI,CAExE"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
const WEBMCP_BESPOKE_CONTEXT_KEY = Symbol('smrt-webmcp-bespoke-context');
|
|
3
|
+
export function setWebMcpBespokeContext(context) {
|
|
4
|
+
setContext(WEBMCP_BESPOKE_CONTEXT_KEY, context);
|
|
5
|
+
}
|
|
6
|
+
export function tryGetWebMcpBespokeContext() {
|
|
7
|
+
return getContext(WEBMCP_BESPOKE_CONTEXT_KEY) ?? null;
|
|
8
|
+
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import type { WebMcpBespokeToolSpec, WebMcpToolEffect } from '@happyvertical/smrt-web';
|
|
1
2
|
/** A tool exposed to the browser's WebMCP model context. */
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
execute: (args: Record<string, unknown>) => string | Promise<string>;
|
|
3
|
+
export type WebMcpToolSpec = WebMcpBespokeToolSpec;
|
|
4
|
+
export interface UseWebMcpToolOptions {
|
|
5
|
+
/**
|
|
6
|
+
* This tool's own `effects` exposure-policy fallback, used only when no
|
|
7
|
+
* Provider ancestor supplies an explicit `webmcp.effects` policy. A
|
|
8
|
+
* Provider's explicit policy always wins over this default — even a
|
|
9
|
+
* narrower one — so a component cannot use its own default to grant
|
|
10
|
+
* itself more than an ancestor Provider allows (#2586). Omit to keep the
|
|
11
|
+
* registrar's own read-only default as the no-Provider fallback.
|
|
12
|
+
*/
|
|
13
|
+
effects?: readonly WebMcpToolEffect[];
|
|
14
14
|
}
|
|
15
15
|
declare global {
|
|
16
16
|
interface Document {
|
|
@@ -26,6 +26,22 @@ declare global {
|
|
|
26
26
|
* Register a component-owned WebMCP intent for exactly that component's
|
|
27
27
|
* lifetime. The factory runs inside the effect so rune dependencies used by a
|
|
28
28
|
* bespoke intent cause the tool to be replaced when its spec changes.
|
|
29
|
+
*
|
|
30
|
+
* Routes through `@happyvertical/smrt-web`'s `registerWebMcpBespokeTool` so a
|
|
31
|
+
* bespoke tool is subject to the same fail-closed `effects` exposure policy
|
|
32
|
+
* as generated model tools (#2586): a spec with no `annotations`, or with
|
|
33
|
+
* annotations that leave its effect undeclared, classifies destructive,
|
|
34
|
+
* non-idempotent, open-world, and is excluded unless policy allows
|
|
35
|
+
* `destructive`. The policy is the nearest Provider's `webmcp.effects` (read
|
|
36
|
+
* from context so a bespoke and a generated tool share one policy); absent a
|
|
37
|
+
* Provider ancestor, it falls back to the registrar's own read-only default.
|
|
38
|
+
* `namespace` and `maxTools` deliberately do not apply to a bespoke tool.
|
|
39
|
+
*
|
|
40
|
+
* `@happyvertical/smrt-web` loads lazily, on first use, so a page that only
|
|
41
|
+
* calls `useWebMcpTool` never bundles the client-data engine.
|
|
42
|
+
*
|
|
43
|
+
* @param options.effects a fallback exposure policy applied only when no
|
|
44
|
+
* Provider ancestor declares one — see {@link UseWebMcpToolOptions}.
|
|
29
45
|
*/
|
|
30
|
-
export declare function useWebMcpTool(factory: () => WebMcpToolSpec | null | undefined): void;
|
|
46
|
+
export declare function useWebMcpTool(factory: () => WebMcpToolSpec | null | undefined, options?: UseWebMcpToolOptions): void;
|
|
31
47
|
//# sourceMappingURL=webmcp.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webmcp.svelte.d.ts","sourceRoot":"","sources":["../../src/web/webmcp.svelte.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"webmcp.svelte.d.ts","sourceRoot":"","sources":["../../src/web/webmcp.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EAErB,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AAGjC,4DAA4D;AAC5D,MAAM,MAAM,cAAc,GAAG,qBAAqB,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACvC;AAID,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,QAAQ;QAChB,YAAY,CAAC,EAAE,kBAAkB,CAAC;KACnC;IAED,UAAU,kBAAkB;QAC1B,YAAY,CACV,IAAI,EAAE,cAAc,EACpB,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,WAAW,CAAA;SAAE,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;KAClB;CACF;AAYD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,SAAS,EAChD,OAAO,GAAE,oBAAyB,GACjC,IAAI,CAuFN"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { tryGetWebMcpBespokeContext } from './webmcp-bespoke-context.js';
|
|
1
2
|
function getModelContext() {
|
|
2
3
|
// Do not read `document` at module evaluation time: this module is imported
|
|
3
4
|
// by SSR bundles and by browsers without the WebMCP origin trial.
|
|
@@ -11,22 +12,101 @@ function getModelContext() {
|
|
|
11
12
|
* Register a component-owned WebMCP intent for exactly that component's
|
|
12
13
|
* lifetime. The factory runs inside the effect so rune dependencies used by a
|
|
13
14
|
* bespoke intent cause the tool to be replaced when its spec changes.
|
|
15
|
+
*
|
|
16
|
+
* Routes through `@happyvertical/smrt-web`'s `registerWebMcpBespokeTool` so a
|
|
17
|
+
* bespoke tool is subject to the same fail-closed `effects` exposure policy
|
|
18
|
+
* as generated model tools (#2586): a spec with no `annotations`, or with
|
|
19
|
+
* annotations that leave its effect undeclared, classifies destructive,
|
|
20
|
+
* non-idempotent, open-world, and is excluded unless policy allows
|
|
21
|
+
* `destructive`. The policy is the nearest Provider's `webmcp.effects` (read
|
|
22
|
+
* from context so a bespoke and a generated tool share one policy); absent a
|
|
23
|
+
* Provider ancestor, it falls back to the registrar's own read-only default.
|
|
24
|
+
* `namespace` and `maxTools` deliberately do not apply to a bespoke tool.
|
|
25
|
+
*
|
|
26
|
+
* `@happyvertical/smrt-web` loads lazily, on first use, so a page that only
|
|
27
|
+
* calls `useWebMcpTool` never bundles the client-data engine.
|
|
28
|
+
*
|
|
29
|
+
* @param options.effects a fallback exposure policy applied only when no
|
|
30
|
+
* Provider ancestor declares one — see {@link UseWebMcpToolOptions}.
|
|
14
31
|
*/
|
|
15
|
-
export function useWebMcpTool(factory) {
|
|
32
|
+
export function useWebMcpTool(factory, options = {}) {
|
|
33
|
+
const bespokeContext = tryGetWebMcpBespokeContext();
|
|
34
|
+
// Survives across effect reruns (unlike the per-run `dispose`/`cancelled`
|
|
35
|
+
// locals below) so a new run can serialize its registration against the
|
|
36
|
+
// previous run's — see the comment at its read site.
|
|
37
|
+
let previousDisposer;
|
|
16
38
|
$effect(() => {
|
|
17
|
-
|
|
18
|
-
if (!context)
|
|
39
|
+
if (typeof window === 'undefined')
|
|
19
40
|
return;
|
|
20
|
-
|
|
21
|
-
|
|
41
|
+
// Feature-detect locally first so a browser without WebMCP never pays for
|
|
42
|
+
// the dynamic import below.
|
|
43
|
+
if (!getModelContext())
|
|
22
44
|
return;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
45
|
+
const factorySpec = factory();
|
|
46
|
+
if (!factorySpec)
|
|
47
|
+
return;
|
|
48
|
+
// Rebind to a definitely-non-nullish const: TypeScript does not carry
|
|
49
|
+
// the `!factorySpec` narrowing above into the `register` closure below,
|
|
50
|
+
// since it runs later, asynchronously.
|
|
51
|
+
const spec = factorySpec;
|
|
52
|
+
// Read the Provider's effects policy synchronously, inside this effect's
|
|
53
|
+
// tracking window — `bespokeContext.effects` is a reactive getter, and a
|
|
54
|
+
// read from inside the dynamic import's `.then()` below happens after
|
|
55
|
+
// the effect has already finished its synchronous run, so it would never
|
|
56
|
+
// register as a dependency. Capturing it here means a later change to
|
|
57
|
+
// the Provider's policy re-runs this effect, tearing down and
|
|
58
|
+
// re-registering the tool under the new policy. A Provider's explicit
|
|
59
|
+
// policy always wins; this call's own `options.effects` is only the
|
|
60
|
+
// no-Provider fallback.
|
|
61
|
+
const effects = bespokeContext?.effects ?? options.effects;
|
|
62
|
+
// Snapshotted before this run's async work starts: the previous run's
|
|
63
|
+
// cleanup (below) synchronously aborts its controller, but a host is not
|
|
64
|
+
// required to finish processing that abort before this run's dynamic
|
|
65
|
+
// import resolves. Awaiting the prior disposer's `.ready` settling first
|
|
66
|
+
// serializes same-name re-registration so this run never asks the host
|
|
67
|
+
// to accept a new registration while it may still consider the old one
|
|
68
|
+
// live.
|
|
69
|
+
const priorReady = previousDisposer?.ready;
|
|
70
|
+
let cancelled = false;
|
|
71
|
+
let dispose = () => { };
|
|
72
|
+
async function register() {
|
|
73
|
+
// The dynamic import failing to load is expected in bundle profiles
|
|
74
|
+
// without `@happyvertical/smrt-web` — treat it like WebMCP being
|
|
75
|
+
// unavailable and no-op, silently. Only THIS statement's failure is
|
|
76
|
+
// caught: a synchronous throw from `registerWebMcpBespokeTool` below
|
|
77
|
+
// (e.g. an invalid `effects` policy) happens outside this try block
|
|
78
|
+
// and is deliberately left to propagate as an unhandled rejection of
|
|
79
|
+
// `register()`'s own promise, rather than being swallowed alongside
|
|
80
|
+
// the load-failure case.
|
|
81
|
+
let registerWebMcpBespokeTool;
|
|
82
|
+
try {
|
|
83
|
+
({ registerWebMcpBespokeTool } = await import('@happyvertical/smrt-web'));
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (cancelled)
|
|
89
|
+
return;
|
|
90
|
+
if (priorReady) {
|
|
91
|
+
await priorReady.catch(() => undefined);
|
|
92
|
+
// A newer run may have superseded this one while the wait above
|
|
93
|
+
// was pending; re-check before registering under this run's name.
|
|
94
|
+
if (cancelled)
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const registration = registerWebMcpBespokeTool(spec, { effects });
|
|
98
|
+
dispose = registration;
|
|
99
|
+
previousDisposer = registration;
|
|
100
|
+
void registration.ready.catch((error) => {
|
|
101
|
+
if (!cancelled) {
|
|
102
|
+
console.warn('[smrt-svelte] bespoke WebMCP tool registration failed', spec.name, error);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
29
105
|
}
|
|
30
|
-
|
|
106
|
+
void register();
|
|
107
|
+
return () => {
|
|
108
|
+
cancelled = true;
|
|
109
|
+
dispose();
|
|
110
|
+
};
|
|
31
111
|
});
|
|
32
112
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
|
+
"smrtJsdoc": "strict",
|
|
4
5
|
"description": "Svelte 5 components for SMRT user management - auth, users, tenants, roles, permissions, groups",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"smrtRawPrimitives": "strict",
|
|
@@ -123,10 +124,10 @@
|
|
|
123
124
|
"@tanstack/db": "^0.6.14",
|
|
124
125
|
"@tanstack/svelte-db": "^0.1.91",
|
|
125
126
|
"esm-env": "^1.2.2",
|
|
126
|
-
"@happyvertical/smrt-languages": "0.
|
|
127
|
-
"@happyvertical/smrt-
|
|
128
|
-
"@happyvertical/smrt-ui": "0.
|
|
129
|
-
"@happyvertical/smrt-
|
|
127
|
+
"@happyvertical/smrt-languages": "0.44.0",
|
|
128
|
+
"@happyvertical/smrt-types": "0.44.0",
|
|
129
|
+
"@happyvertical/smrt-ui": "0.44.0",
|
|
130
|
+
"@happyvertical/smrt-web": "0.44.0"
|
|
130
131
|
},
|
|
131
132
|
"peerDependencies": {
|
|
132
133
|
"@huggingface/transformers": ">=3.8.1",
|
|
@@ -166,8 +167,8 @@
|
|
|
166
167
|
"typescript": "5.9.3",
|
|
167
168
|
"vite": "8.1.4",
|
|
168
169
|
"vitest": "4.1.10",
|
|
169
|
-
"@happyvertical/smrt-core": "0.
|
|
170
|
-
"@happyvertical/smrt-scanner": "0.
|
|
170
|
+
"@happyvertical/smrt-core": "0.44.0",
|
|
171
|
+
"@happyvertical/smrt-scanner": "0.44.0"
|
|
171
172
|
},
|
|
172
173
|
"scripts": {
|
|
173
174
|
"build": "svelte-package -i src --tsconfig tsconfig.svelte.json",
|