@miragon/mcp-toolkit-core 0.10.1
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/README.md +32 -0
- package/dist/engine/context-builder.d.ts +5 -0
- package/dist/engine/context-builder.d.ts.map +1 -0
- package/dist/engine/context-builder.js +22 -0
- package/dist/engine/context-builder.js.map +1 -0
- package/dist/engine/pipeline-executor.d.ts +21 -0
- package/dist/engine/pipeline-executor.d.ts.map +1 -0
- package/dist/engine/pipeline-executor.js +80 -0
- package/dist/engine/pipeline-executor.js.map +1 -0
- package/dist/framework/active-modules.d.ts +30 -0
- package/dist/framework/active-modules.d.ts.map +1 -0
- package/dist/framework/active-modules.js +44 -0
- package/dist/framework/active-modules.js.map +1 -0
- package/dist/framework/catalogue.d.ts +148 -0
- package/dist/framework/catalogue.d.ts.map +1 -0
- package/dist/framework/catalogue.js +132 -0
- package/dist/framework/catalogue.js.map +1 -0
- package/dist/framework/dashboard-store.d.ts +136 -0
- package/dist/framework/dashboard-store.d.ts.map +1 -0
- package/dist/framework/dashboard-store.js +301 -0
- package/dist/framework/dashboard-store.js.map +1 -0
- package/dist/framework/layout-schemas.d.ts +106 -0
- package/dist/framework/layout-schemas.d.ts.map +1 -0
- package/dist/framework/layout-schemas.js +67 -0
- package/dist/framework/layout-schemas.js.map +1 -0
- package/dist/framework/layout-types.d.ts +25 -0
- package/dist/framework/layout-types.d.ts.map +1 -0
- package/dist/framework/layout-types.js +7 -0
- package/dist/framework/layout-types.js.map +1 -0
- package/dist/framework/manifest.d.ts +65 -0
- package/dist/framework/manifest.d.ts.map +1 -0
- package/dist/framework/manifest.js +47 -0
- package/dist/framework/manifest.js.map +1 -0
- package/dist/framework/render-view.d.ts +53 -0
- package/dist/framework/render-view.d.ts.map +1 -0
- package/dist/framework/render-view.js +73 -0
- package/dist/framework/render-view.js.map +1 -0
- package/dist/framework/view-builders.d.ts +79 -0
- package/dist/framework/view-builders.d.ts.map +1 -0
- package/dist/framework/view-builders.js +113 -0
- package/dist/framework/view-builders.js.map +1 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +6 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/translator.d.ts +59 -0
- package/dist/i18n/translator.d.ts.map +1 -0
- package/dist/i18n/translator.js +48 -0
- package/dist/i18n/translator.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/org-gate.d.ts +22 -0
- package/dist/middleware/org-gate.d.ts.map +1 -0
- package/dist/middleware/org-gate.js +28 -0
- package/dist/middleware/org-gate.js.map +1 -0
- package/dist/middleware/role-filter.d.ts +79 -0
- package/dist/middleware/role-filter.d.ts.map +1 -0
- package/dist/middleware/role-filter.js +95 -0
- package/dist/middleware/role-filter.js.map +1 -0
- package/dist/registry/app-loader.d.ts +35 -0
- package/dist/registry/app-loader.d.ts.map +1 -0
- package/dist/registry/app-loader.js +55 -0
- package/dist/registry/app-loader.js.map +1 -0
- package/dist/registry/step-registry.d.ts +27 -0
- package/dist/registry/step-registry.d.ts.map +1 -0
- package/dist/registry/step-registry.js +53 -0
- package/dist/registry/step-registry.js.map +1 -0
- package/dist/registry/widget-registry.d.ts +15 -0
- package/dist/registry/widget-registry.d.ts.map +1 -0
- package/dist/registry/widget-registry.js +28 -0
- package/dist/registry/widget-registry.js.map +1 -0
- package/dist/rest/client.d.ts +3 -0
- package/dist/rest/client.d.ts.map +1 -0
- package/dist/rest/client.js +155 -0
- package/dist/rest/client.js.map +1 -0
- package/dist/rest/errors.d.ts +14 -0
- package/dist/rest/errors.d.ts.map +1 -0
- package/dist/rest/errors.js +21 -0
- package/dist/rest/errors.js.map +1 -0
- package/dist/rest/index.d.ts +6 -0
- package/dist/rest/index.d.ts.map +1 -0
- package/dist/rest/index.js +4 -0
- package/dist/rest/index.js.map +1 -0
- package/dist/rest/tool.d.ts +60 -0
- package/dist/rest/tool.d.ts.map +1 -0
- package/dist/rest/tool.js +81 -0
- package/dist/rest/tool.js.map +1 -0
- package/dist/rest/types.d.ts +66 -0
- package/dist/rest/types.d.ts.map +1 -0
- package/dist/rest/types.js +2 -0
- package/dist/rest/types.js.map +1 -0
- package/dist/tools/app-resource-uri.d.ts +28 -0
- package/dist/tools/app-resource-uri.d.ts.map +1 -0
- package/dist/tools/app-resource-uri.js +30 -0
- package/dist/tools/app-resource-uri.js.map +1 -0
- package/dist/tools/backend-registry.d.ts +111 -0
- package/dist/tools/backend-registry.d.ts.map +1 -0
- package/dist/tools/backend-registry.js +154 -0
- package/dist/tools/backend-registry.js.map +1 -0
- package/dist/tools/create-framework-app.d.ts +147 -0
- package/dist/tools/create-framework-app.d.ts.map +1 -0
- package/dist/tools/create-framework-app.js +111 -0
- package/dist/tools/create-framework-app.js.map +1 -0
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/register-catalogue-tool.d.ts +22 -0
- package/dist/tools/register-catalogue-tool.d.ts.map +1 -0
- package/dist/tools/register-catalogue-tool.js +45 -0
- package/dist/tools/register-catalogue-tool.js.map +1 -0
- package/dist/tools/register-dashboard-tools.d.ts +32 -0
- package/dist/tools/register-dashboard-tools.d.ts.map +1 -0
- package/dist/tools/register-dashboard-tools.js +149 -0
- package/dist/tools/register-dashboard-tools.js.map +1 -0
- package/dist/tools/register-framework-tools.d.ts +83 -0
- package/dist/tools/register-framework-tools.d.ts.map +1 -0
- package/dist/tools/register-framework-tools.js +154 -0
- package/dist/tools/register-framework-tools.js.map +1 -0
- package/dist/tools/register-tool.d.ts +45 -0
- package/dist/tools/register-tool.d.ts.map +1 -0
- package/dist/tools/register-tool.js +82 -0
- package/dist/tools/register-tool.js.map +1 -0
- package/dist/tools/register-widget-tool.d.ts +51 -0
- package/dist/tools/register-widget-tool.d.ts.map +1 -0
- package/dist/tools/register-widget-tool.js +45 -0
- package/dist/tools/register-widget-tool.js.map +1 -0
- package/dist/tools/tool-call-name.d.ts +53 -0
- package/dist/tools/tool-call-name.d.ts.map +1 -0
- package/dist/tools/tool-call-name.js +92 -0
- package/dist/tools/tool-call-name.js.map +1 -0
- package/dist/tools/with-tool-errors.d.ts +16 -0
- package/dist/tools/with-tool-errors.d.ts.map +1 -0
- package/dist/tools/with-tool-errors.js +28 -0
- package/dist/tools/with-tool-errors.js.map +1 -0
- package/dist/types/app.d.ts +44 -0
- package/dist/types/app.d.ts.map +1 -0
- package/dist/types/app.js +2 -0
- package/dist/types/app.js.map +1 -0
- package/dist/types/config.d.ts +15 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +2 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/context.d.ts +18 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/context.js +2 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/meta.d.ts +99 -0
- package/dist/types/meta.d.ts.map +1 -0
- package/dist/types/meta.js +66 -0
- package/dist/types/meta.js.map +1 -0
- package/dist/types/pipeline.d.ts +9 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +2 -0
- package/dist/types/pipeline.js.map +1 -0
- package/dist/types/step.d.ts +51 -0
- package/dist/types/step.d.ts.map +1 -0
- package/dist/types/step.js +2 -0
- package/dist/types/step.js.map +1 -0
- package/dist/types/view-data.d.ts +67 -0
- package/dist/types/view-data.d.ts.map +1 -0
- package/dist/types/view-data.js +2 -0
- package/dist/types/view-data.js.map +1 -0
- package/dist/types/widget.d.ts +57 -0
- package/dist/types/widget.d.ts.map +1 -0
- package/dist/types/widget.js +2 -0
- package/dist/types/widget.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { PipelineStepRef } from "../types/pipeline.js";
|
|
2
|
+
import type { LayoutConfig } from "./layout-types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Current on-disk schema version stamped onto every saved record. Bump this
|
|
5
|
+
* whenever the persisted shape changes in a way a loader would need to
|
|
6
|
+
* migrate. Records persisted before versioning carry no `schemaVersion`
|
|
7
|
+
* (treated as the implicit version 0).
|
|
8
|
+
*/
|
|
9
|
+
export declare const DASHBOARD_SCHEMA_VERSION = 1;
|
|
10
|
+
/**
|
|
11
|
+
* Persisted dashboard = full `render-view` input plus identity and
|
|
12
|
+
* ownership metadata. The server generates `id`, `createdAt`, `updatedAt`;
|
|
13
|
+
* `userId` is copied from `ctx.auth.user.userId` on save when present.
|
|
14
|
+
*/
|
|
15
|
+
export interface DashboardRecord {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
/** Owner; omitted when the host boots without OAuth (global scope). */
|
|
20
|
+
userId?: string;
|
|
21
|
+
keys?: Record<string, unknown>;
|
|
22
|
+
steps?: PipelineStepRef[];
|
|
23
|
+
layout: LayoutConfig;
|
|
24
|
+
title?: string;
|
|
25
|
+
/**
|
|
26
|
+
* On-disk schema version, set to {@link DASHBOARD_SCHEMA_VERSION} on every
|
|
27
|
+
* save. Optional so records written before versioning still type-check;
|
|
28
|
+
* loaders treat its absence as version 0.
|
|
29
|
+
*/
|
|
30
|
+
schemaVersion?: number;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
}
|
|
34
|
+
export interface DashboardSaveInput {
|
|
35
|
+
id?: string;
|
|
36
|
+
name: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
userId?: string;
|
|
39
|
+
keys?: Record<string, unknown>;
|
|
40
|
+
steps?: PipelineStepRef[];
|
|
41
|
+
layout: LayoutConfig;
|
|
42
|
+
title?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface DashboardListFilter {
|
|
45
|
+
userId?: string;
|
|
46
|
+
}
|
|
47
|
+
/** Summary view returned by `list` — full layout body deliberately omitted. */
|
|
48
|
+
export interface DashboardSummary {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
description?: string;
|
|
52
|
+
title?: string;
|
|
53
|
+
updatedAt: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Persistence backing for dashboards. The framework is indifferent to how
|
|
57
|
+
* records are stored — consumers inject whichever implementation fits
|
|
58
|
+
* their deployment (in-memory for tests, filesystem for local dev, a DB-
|
|
59
|
+
* backed one for production).
|
|
60
|
+
*
|
|
61
|
+
* All methods accept an optional `userId` filter so implementations can
|
|
62
|
+
* enforce ownership. Implementations that don't need ownership (global
|
|
63
|
+
* scope) should simply ignore the filter.
|
|
64
|
+
*
|
|
65
|
+
* `save` carries the acting user as `input.userId`: updating an existing
|
|
66
|
+
* record owned by a different user is rejected with
|
|
67
|
+
* {@link DashboardOwnershipError}, and `input.userId` can never reassign an
|
|
68
|
+
* existing record's owner. Records persisted without a `userId` (global
|
|
69
|
+
* scope) stay writable by anyone, matching the read/delete convention.
|
|
70
|
+
*/
|
|
71
|
+
export interface DashboardStore {
|
|
72
|
+
save(input: DashboardSaveInput): Promise<DashboardRecord>;
|
|
73
|
+
list(filter: DashboardListFilter): Promise<DashboardSummary[]>;
|
|
74
|
+
get(id: string, filter: DashboardListFilter): Promise<DashboardRecord | undefined>;
|
|
75
|
+
delete(id: string, filter: DashboardListFilter): Promise<boolean>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validate a value read back from persistence into a {@link DashboardRecord},
|
|
79
|
+
* or `undefined` when it isn't one this version can safely use.
|
|
80
|
+
*
|
|
81
|
+
* Untrusted disk state is otherwise cast straight to `DashboardRecord`, so a
|
|
82
|
+
* corrupt or partial file (e.g. a missing `updatedAt`) slips through and later
|
|
83
|
+
* crashes `list` (its `updatedAt.localeCompare` sort) or feeds garbage into
|
|
84
|
+
* `render-view`. This is the single fail-soft gate: a record that fails the
|
|
85
|
+
* schema — or carries a `schemaVersion` newer than this build understands — is
|
|
86
|
+
* rejected here so callers skip it instead of trusting it.
|
|
87
|
+
*
|
|
88
|
+
* Exported for unit testing.
|
|
89
|
+
*/
|
|
90
|
+
export declare function parseDashboardRecord(raw: unknown): DashboardRecord | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Error thrown by `save()` when an update would touch a record the caller
|
|
93
|
+
* doesn't own, or would change a record's owner. Distinct from the
|
|
94
|
+
* fail-soft "not found" of `get`/`delete` (which return `undefined`/`false`)
|
|
95
|
+
* because `save` has no nullable return — a write that violates ownership is
|
|
96
|
+
* an explicit denial, not a silent no-op.
|
|
97
|
+
*/
|
|
98
|
+
export declare class DashboardOwnershipError extends Error {
|
|
99
|
+
constructor(message: string);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Resolve the record to persist for a `save`, enforcing ownership on updates.
|
|
103
|
+
*
|
|
104
|
+
* - New record (no `existing`): returns `null`, signalling the caller to
|
|
105
|
+
* create from `input`.
|
|
106
|
+
* - Update (`existing` present): throws {@link DashboardOwnershipError} when
|
|
107
|
+
* `input.userId` doesn't own `existing`, otherwise returns the merged
|
|
108
|
+
* record with `id`, `createdAt`, and — critically — `existing.userId`
|
|
109
|
+
* preserved so `input.userId` can never reassign the owner.
|
|
110
|
+
*
|
|
111
|
+
* Records without a `userId` (global scope, e.g. a host booted without OAuth)
|
|
112
|
+
* are deliberately writable by anyone — same convention `ownedBy` uses for
|
|
113
|
+
* read/delete — so single-user and OAuth-less deployments keep working.
|
|
114
|
+
*
|
|
115
|
+
* Exported for unit testing; the store factories below are the public API.
|
|
116
|
+
*/
|
|
117
|
+
export declare function resolveSavedRecord(existing: DashboardRecord | undefined, input: DashboardSaveInput, now: string): DashboardRecord | null;
|
|
118
|
+
/**
|
|
119
|
+
* Process-local in-memory store. Fine for tests and throwaway demos; loses
|
|
120
|
+
* everything on restart. Default when `createFrameworkApp` is called
|
|
121
|
+
* without an explicit `dashboardStore`.
|
|
122
|
+
*/
|
|
123
|
+
export declare function createInMemoryDashboardStore(): DashboardStore;
|
|
124
|
+
export interface FileSystemDashboardStoreOptions {
|
|
125
|
+
/** Directory where `<id>.json` files are written. Created on first save. */
|
|
126
|
+
dir: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Dashboards stored as one JSON file per record under `dir`. Suitable for
|
|
130
|
+
* single-node deployments that need survival across restarts. Locking is
|
|
131
|
+
* advisory: concurrent writes of the same id can race — fine for the v1
|
|
132
|
+
* "single user clicking Save" workflow, not fine for multi-writer
|
|
133
|
+
* production.
|
|
134
|
+
*/
|
|
135
|
+
export declare function createFileSystemDashboardStore(options: FileSystemDashboardStoreOptions): DashboardStore;
|
|
136
|
+
//# sourceMappingURL=dashboard-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-store.d.ts","sourceRoot":"","sources":["../../src/framework/dashboard-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrD;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;IACzB,MAAM,EAAE,YAAY,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;IACzB,MAAM,EAAE,YAAY,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IACzD,IAAI,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAA;IAC9D,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAAA;IAClF,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAClE;AA2BD;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAO9E;AAYD;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,KAAK,EAAE,kBAAkB,EACzB,GAAG,EAAE,MAAM,GACV,eAAe,GAAG,IAAI,CAgBxB;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,cAAc,CAuD7D;AAED,MAAM,WAAW,+BAA+B;IAC9C,4EAA4E;IAC5E,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,+BAA+B,GACvC,cAAc,CA0GhB"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { layoutSchema } from "./layout-schemas.js";
|
|
6
|
+
/**
|
|
7
|
+
* Current on-disk schema version stamped onto every saved record. Bump this
|
|
8
|
+
* whenever the persisted shape changes in a way a loader would need to
|
|
9
|
+
* migrate. Records persisted before versioning carry no `schemaVersion`
|
|
10
|
+
* (treated as the implicit version 0).
|
|
11
|
+
*/
|
|
12
|
+
export const DASHBOARD_SCHEMA_VERSION = 1;
|
|
13
|
+
const stepRefSchema = z.object({
|
|
14
|
+
id: z.string(),
|
|
15
|
+
step: z.string(),
|
|
16
|
+
optional: z.boolean().optional(),
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Runtime shape of a persisted dashboard. Kept in sync with
|
|
20
|
+
* {@link DashboardRecord}; `layout` reuses {@link layoutSchema} so a stored
|
|
21
|
+
* record and a fresh `render-view` layout validate against the same contract.
|
|
22
|
+
*/
|
|
23
|
+
const dashboardRecordSchema = z.object({
|
|
24
|
+
id: z.string(),
|
|
25
|
+
name: z.string(),
|
|
26
|
+
description: z.string().optional(),
|
|
27
|
+
userId: z.string().optional(),
|
|
28
|
+
keys: z.record(z.string(), z.unknown()).optional(),
|
|
29
|
+
steps: z.array(stepRefSchema).optional(),
|
|
30
|
+
layout: layoutSchema,
|
|
31
|
+
title: z.string().optional(),
|
|
32
|
+
schemaVersion: z.number().optional(),
|
|
33
|
+
createdAt: z.string(),
|
|
34
|
+
updatedAt: z.string(),
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Validate a value read back from persistence into a {@link DashboardRecord},
|
|
38
|
+
* or `undefined` when it isn't one this version can safely use.
|
|
39
|
+
*
|
|
40
|
+
* Untrusted disk state is otherwise cast straight to `DashboardRecord`, so a
|
|
41
|
+
* corrupt or partial file (e.g. a missing `updatedAt`) slips through and later
|
|
42
|
+
* crashes `list` (its `updatedAt.localeCompare` sort) or feeds garbage into
|
|
43
|
+
* `render-view`. This is the single fail-soft gate: a record that fails the
|
|
44
|
+
* schema — or carries a `schemaVersion` newer than this build understands — is
|
|
45
|
+
* rejected here so callers skip it instead of trusting it.
|
|
46
|
+
*
|
|
47
|
+
* Exported for unit testing.
|
|
48
|
+
*/
|
|
49
|
+
export function parseDashboardRecord(raw) {
|
|
50
|
+
const result = dashboardRecordSchema.safeParse(raw);
|
|
51
|
+
if (!result.success)
|
|
52
|
+
return undefined;
|
|
53
|
+
// A record written by a newer build may use fields/semantics this version
|
|
54
|
+
// can't honour — refuse it rather than silently mis-reading it.
|
|
55
|
+
if ((result.data.schemaVersion ?? 0) > DASHBOARD_SCHEMA_VERSION)
|
|
56
|
+
return undefined;
|
|
57
|
+
return result.data;
|
|
58
|
+
}
|
|
59
|
+
function nowIso() {
|
|
60
|
+
return new Date().toISOString();
|
|
61
|
+
}
|
|
62
|
+
function ownedBy(record, userId) {
|
|
63
|
+
if (!userId)
|
|
64
|
+
return true;
|
|
65
|
+
if (!record.userId)
|
|
66
|
+
return true;
|
|
67
|
+
return record.userId === userId;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Error thrown by `save()` when an update would touch a record the caller
|
|
71
|
+
* doesn't own, or would change a record's owner. Distinct from the
|
|
72
|
+
* fail-soft "not found" of `get`/`delete` (which return `undefined`/`false`)
|
|
73
|
+
* because `save` has no nullable return — a write that violates ownership is
|
|
74
|
+
* an explicit denial, not a silent no-op.
|
|
75
|
+
*/
|
|
76
|
+
export class DashboardOwnershipError extends Error {
|
|
77
|
+
constructor(message) {
|
|
78
|
+
super(message);
|
|
79
|
+
this.name = "DashboardOwnershipError";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the record to persist for a `save`, enforcing ownership on updates.
|
|
84
|
+
*
|
|
85
|
+
* - New record (no `existing`): returns `null`, signalling the caller to
|
|
86
|
+
* create from `input`.
|
|
87
|
+
* - Update (`existing` present): throws {@link DashboardOwnershipError} when
|
|
88
|
+
* `input.userId` doesn't own `existing`, otherwise returns the merged
|
|
89
|
+
* record with `id`, `createdAt`, and — critically — `existing.userId`
|
|
90
|
+
* preserved so `input.userId` can never reassign the owner.
|
|
91
|
+
*
|
|
92
|
+
* Records without a `userId` (global scope, e.g. a host booted without OAuth)
|
|
93
|
+
* are deliberately writable by anyone — same convention `ownedBy` uses for
|
|
94
|
+
* read/delete — so single-user and OAuth-less deployments keep working.
|
|
95
|
+
*
|
|
96
|
+
* Exported for unit testing; the store factories below are the public API.
|
|
97
|
+
*/
|
|
98
|
+
export function resolveSavedRecord(existing, input, now) {
|
|
99
|
+
if (!existing)
|
|
100
|
+
return null;
|
|
101
|
+
if (!ownedBy(existing, input.userId)) {
|
|
102
|
+
throw new DashboardOwnershipError(`Access denied: dashboard "${existing.id}" is owned by another user.`);
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
...existing,
|
|
106
|
+
...stripUndefined(input),
|
|
107
|
+
id: existing.id,
|
|
108
|
+
userId: existing.userId,
|
|
109
|
+
schemaVersion: DASHBOARD_SCHEMA_VERSION,
|
|
110
|
+
createdAt: existing.createdAt,
|
|
111
|
+
updatedAt: now,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Process-local in-memory store. Fine for tests and throwaway demos; loses
|
|
116
|
+
* everything on restart. Default when `createFrameworkApp` is called
|
|
117
|
+
* without an explicit `dashboardStore`.
|
|
118
|
+
*/
|
|
119
|
+
export function createInMemoryDashboardStore() {
|
|
120
|
+
const byId = new Map();
|
|
121
|
+
return {
|
|
122
|
+
save(input) {
|
|
123
|
+
// Resolve-then-compute so a synchronous ownership violation surfaces as
|
|
124
|
+
// a rejected promise (matching the `Promise<DashboardRecord>` contract
|
|
125
|
+
// and the filesystem store), not a throw escaping the call site.
|
|
126
|
+
return Promise.resolve().then(() => {
|
|
127
|
+
const now = nowIso();
|
|
128
|
+
const existing = input.id ? byId.get(input.id) : undefined;
|
|
129
|
+
const record = resolveSavedRecord(existing, input, now) ?? {
|
|
130
|
+
id: input.id ?? randomUUID(),
|
|
131
|
+
name: input.name,
|
|
132
|
+
description: input.description,
|
|
133
|
+
userId: input.userId,
|
|
134
|
+
keys: input.keys,
|
|
135
|
+
steps: input.steps,
|
|
136
|
+
layout: input.layout,
|
|
137
|
+
title: input.title,
|
|
138
|
+
schemaVersion: DASHBOARD_SCHEMA_VERSION,
|
|
139
|
+
createdAt: now,
|
|
140
|
+
updatedAt: now,
|
|
141
|
+
};
|
|
142
|
+
byId.set(record.id, record);
|
|
143
|
+
return record;
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
list(filter) {
|
|
147
|
+
const all = [...byId.values()].filter((r) => ownedBy(r, filter.userId));
|
|
148
|
+
all.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
149
|
+
return Promise.resolve(all.map((r) => ({
|
|
150
|
+
id: r.id,
|
|
151
|
+
name: r.name,
|
|
152
|
+
description: r.description,
|
|
153
|
+
title: r.title,
|
|
154
|
+
updatedAt: r.updatedAt,
|
|
155
|
+
})));
|
|
156
|
+
},
|
|
157
|
+
get(id, filter) {
|
|
158
|
+
const record = byId.get(id);
|
|
159
|
+
if (!record)
|
|
160
|
+
return Promise.resolve(undefined);
|
|
161
|
+
if (!ownedBy(record, filter.userId))
|
|
162
|
+
return Promise.resolve(undefined);
|
|
163
|
+
return Promise.resolve(record);
|
|
164
|
+
},
|
|
165
|
+
delete(id, filter) {
|
|
166
|
+
const record = byId.get(id);
|
|
167
|
+
if (!record)
|
|
168
|
+
return Promise.resolve(false);
|
|
169
|
+
if (!ownedBy(record, filter.userId))
|
|
170
|
+
return Promise.resolve(false);
|
|
171
|
+
byId.delete(id);
|
|
172
|
+
return Promise.resolve(true);
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Dashboards stored as one JSON file per record under `dir`. Suitable for
|
|
178
|
+
* single-node deployments that need survival across restarts. Locking is
|
|
179
|
+
* advisory: concurrent writes of the same id can race — fine for the v1
|
|
180
|
+
* "single user clicking Save" workflow, not fine for multi-writer
|
|
181
|
+
* production.
|
|
182
|
+
*/
|
|
183
|
+
export function createFileSystemDashboardStore(options) {
|
|
184
|
+
const { dir } = options;
|
|
185
|
+
const ensureDir = async () => {
|
|
186
|
+
await fs.mkdir(dir, { recursive: true });
|
|
187
|
+
};
|
|
188
|
+
const fileFor = (id) => path.join(dir, `${encodeURIComponent(id)}.json`);
|
|
189
|
+
const readRecord = async (id) => {
|
|
190
|
+
let raw;
|
|
191
|
+
try {
|
|
192
|
+
raw = await fs.readFile(fileFor(id), "utf-8");
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
if (err.code === "ENOENT")
|
|
196
|
+
return undefined;
|
|
197
|
+
throw err;
|
|
198
|
+
}
|
|
199
|
+
// Corrupt/incompatible content is treated as "not present" (fail-soft) so a
|
|
200
|
+
// single bad file can't crash `get`/`save`; a real fs error above still
|
|
201
|
+
// throws.
|
|
202
|
+
let parsed;
|
|
203
|
+
try {
|
|
204
|
+
parsed = JSON.parse(raw);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
console.warn(`[dashboard-store] Ignoring dashboard "${id}": file is not valid JSON.`);
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
const record = parseDashboardRecord(parsed);
|
|
211
|
+
if (!record) {
|
|
212
|
+
console.warn(`[dashboard-store] Ignoring dashboard "${id}": does not match the current record schema.`);
|
|
213
|
+
}
|
|
214
|
+
return record;
|
|
215
|
+
};
|
|
216
|
+
const writeRecord = async (record) => {
|
|
217
|
+
await ensureDir();
|
|
218
|
+
await fs.writeFile(fileFor(record.id), JSON.stringify(record, null, 2), "utf-8");
|
|
219
|
+
};
|
|
220
|
+
return {
|
|
221
|
+
async save(input) {
|
|
222
|
+
const now = nowIso();
|
|
223
|
+
const existing = input.id ? await readRecord(input.id) : undefined;
|
|
224
|
+
const record = resolveSavedRecord(existing, input, now) ?? {
|
|
225
|
+
id: input.id ?? randomUUID(),
|
|
226
|
+
name: input.name,
|
|
227
|
+
description: input.description,
|
|
228
|
+
userId: input.userId,
|
|
229
|
+
keys: input.keys,
|
|
230
|
+
steps: input.steps,
|
|
231
|
+
layout: input.layout,
|
|
232
|
+
title: input.title,
|
|
233
|
+
schemaVersion: DASHBOARD_SCHEMA_VERSION,
|
|
234
|
+
createdAt: now,
|
|
235
|
+
updatedAt: now,
|
|
236
|
+
};
|
|
237
|
+
await writeRecord(record);
|
|
238
|
+
return record;
|
|
239
|
+
},
|
|
240
|
+
async list(filter) {
|
|
241
|
+
await ensureDir();
|
|
242
|
+
const entries = await fs.readdir(dir);
|
|
243
|
+
const records = [];
|
|
244
|
+
for (const name of entries) {
|
|
245
|
+
if (!name.endsWith(".json"))
|
|
246
|
+
continue;
|
|
247
|
+
let parsed;
|
|
248
|
+
try {
|
|
249
|
+
parsed = JSON.parse(await fs.readFile(path.join(dir, name), "utf-8"));
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// Not valid JSON — not one of our records. Skip.
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
// Validate before trusting: a partial record (e.g. missing `updatedAt`)
|
|
256
|
+
// would otherwise crash the sort below and take the whole listing down.
|
|
257
|
+
const record = parseDashboardRecord(parsed);
|
|
258
|
+
if (!record) {
|
|
259
|
+
console.warn(`[dashboard-store] Skipping "${name}": does not match the record schema.`);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (ownedBy(record, filter.userId))
|
|
263
|
+
records.push(record);
|
|
264
|
+
}
|
|
265
|
+
records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
266
|
+
return records.map((r) => ({
|
|
267
|
+
id: r.id,
|
|
268
|
+
name: r.name,
|
|
269
|
+
description: r.description,
|
|
270
|
+
title: r.title,
|
|
271
|
+
updatedAt: r.updatedAt,
|
|
272
|
+
}));
|
|
273
|
+
},
|
|
274
|
+
async get(id, filter) {
|
|
275
|
+
const record = await readRecord(id);
|
|
276
|
+
if (!record)
|
|
277
|
+
return undefined;
|
|
278
|
+
if (!ownedBy(record, filter.userId))
|
|
279
|
+
return undefined;
|
|
280
|
+
return record;
|
|
281
|
+
},
|
|
282
|
+
async delete(id, filter) {
|
|
283
|
+
const record = await readRecord(id);
|
|
284
|
+
if (!record)
|
|
285
|
+
return false;
|
|
286
|
+
if (!ownedBy(record, filter.userId))
|
|
287
|
+
return false;
|
|
288
|
+
await fs.rm(fileFor(id), { force: true });
|
|
289
|
+
return true;
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
function stripUndefined(obj) {
|
|
294
|
+
const out = {};
|
|
295
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
296
|
+
if (v !== undefined)
|
|
297
|
+
out[k] = v;
|
|
298
|
+
}
|
|
299
|
+
return out;
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=dashboard-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-store.js","sourceRoot":"","sources":["../../src/framework/dashboard-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Zod schemas for the layout shape passed to `render-view` / `refresh-view`.
|
|
4
|
+
*
|
|
5
|
+
* Kept next to the `LayoutConfig` TypeScript types (see `./layout-types.ts`) so
|
|
6
|
+
* the runtime validation and the static type of `LayoutConfig` stay in sync.
|
|
7
|
+
* The framework-tool registrar (`../tools/register-framework-tools.ts`) plugs
|
|
8
|
+
* these schemas into the mcp-use tool definitions.
|
|
9
|
+
*/
|
|
10
|
+
export declare const rowSchema: z.ZodObject<{
|
|
11
|
+
row: z.ZodArray<z.ZodObject<{
|
|
12
|
+
widget: z.ZodString;
|
|
13
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
14
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
15
|
+
}, z.core.$strip>>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export declare const layoutSchema: z.ZodUnion<readonly [z.ZodArray<z.ZodObject<{
|
|
18
|
+
row: z.ZodArray<z.ZodObject<{
|
|
19
|
+
widget: z.ZodString;
|
|
20
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
}, z.core.$strip>>, z.ZodObject<{
|
|
24
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
25
|
+
row: z.ZodArray<z.ZodObject<{
|
|
26
|
+
widget: z.ZodString;
|
|
27
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
29
|
+
}, z.core.$strip>>;
|
|
30
|
+
}, z.core.$strip>>;
|
|
31
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
32
|
+
tabs: z.ZodArray<z.ZodObject<{
|
|
33
|
+
label: z.ZodString;
|
|
34
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
35
|
+
row: z.ZodArray<z.ZodObject<{
|
|
36
|
+
widget: z.ZodString;
|
|
37
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
39
|
+
}, z.core.$strip>>;
|
|
40
|
+
}, z.core.$strip>>;
|
|
41
|
+
}, z.core.$strip>>;
|
|
42
|
+
}, z.core.$strip>]>;
|
|
43
|
+
/**
|
|
44
|
+
* Tool-input variant of {@link layoutSchema} for `render-view` /
|
|
45
|
+
* `refresh-view`: the three layout forms plus a JSON-string branch.
|
|
46
|
+
*
|
|
47
|
+
* Why: as a union, `layout` surfaces on the wire as a top-level `anyOf`
|
|
48
|
+
* WITHOUT its own `type` field. Some MCP hosts (observed with claude.ai)
|
|
49
|
+
* react to such properties by sending the argument as a JSON-encoded STRING —
|
|
50
|
+
* which the plain union rejects, failing the whole call. The string branch
|
|
51
|
+
* parses that form and pipes it through {@link layoutSchema}, so stringified
|
|
52
|
+
* calls validate exactly like the object form. The three object branches are
|
|
53
|
+
* reused from {@link layoutSchema} unchanged.
|
|
54
|
+
*/
|
|
55
|
+
export declare const layoutInputSchema: z.ZodUnion<readonly [z.ZodArray<z.ZodObject<{
|
|
56
|
+
row: z.ZodArray<z.ZodObject<{
|
|
57
|
+
widget: z.ZodString;
|
|
58
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
59
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
60
|
+
}, z.core.$strip>>;
|
|
61
|
+
}, z.core.$strip>>, z.ZodObject<{
|
|
62
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
63
|
+
row: z.ZodArray<z.ZodObject<{
|
|
64
|
+
widget: z.ZodString;
|
|
65
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
66
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
67
|
+
}, z.core.$strip>>;
|
|
68
|
+
}, z.core.$strip>>;
|
|
69
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
70
|
+
tabs: z.ZodArray<z.ZodObject<{
|
|
71
|
+
label: z.ZodString;
|
|
72
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
73
|
+
row: z.ZodArray<z.ZodObject<{
|
|
74
|
+
widget: z.ZodString;
|
|
75
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
76
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
77
|
+
}, z.core.$strip>>;
|
|
78
|
+
}, z.core.$strip>>;
|
|
79
|
+
}, z.core.$strip>>;
|
|
80
|
+
}, z.core.$strip>, z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<unknown, string>>, z.ZodUnion<readonly [z.ZodArray<z.ZodObject<{
|
|
81
|
+
row: z.ZodArray<z.ZodObject<{
|
|
82
|
+
widget: z.ZodString;
|
|
83
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
84
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
85
|
+
}, z.core.$strip>>;
|
|
86
|
+
}, z.core.$strip>>, z.ZodObject<{
|
|
87
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
88
|
+
row: z.ZodArray<z.ZodObject<{
|
|
89
|
+
widget: z.ZodString;
|
|
90
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
91
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
92
|
+
}, z.core.$strip>>;
|
|
93
|
+
}, z.core.$strip>>;
|
|
94
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
95
|
+
tabs: z.ZodArray<z.ZodObject<{
|
|
96
|
+
label: z.ZodString;
|
|
97
|
+
rows: z.ZodArray<z.ZodObject<{
|
|
98
|
+
row: z.ZodArray<z.ZodObject<{
|
|
99
|
+
widget: z.ZodString;
|
|
100
|
+
span: z.ZodOptional<z.ZodNumber>;
|
|
101
|
+
props: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
102
|
+
}, z.core.$strip>>;
|
|
103
|
+
}, z.core.$strip>>;
|
|
104
|
+
}, z.core.$strip>>;
|
|
105
|
+
}, z.core.$strip>]>>]>;
|
|
106
|
+
//# sourceMappingURL=layout-schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout-schemas.d.ts","sourceRoot":"","sources":["../../src/framework/layout-schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;GAOG;AAEH,eAAO,MAAM,SAAS;;;;;;iBAapB,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;mBAeqC,CAAA;AAE9D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAuB3B,CAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Zod schemas for the layout shape passed to `render-view` / `refresh-view`.
|
|
4
|
+
*
|
|
5
|
+
* Kept next to the `LayoutConfig` TypeScript types (see `./layout-types.ts`) so
|
|
6
|
+
* the runtime validation and the static type of `LayoutConfig` stay in sync.
|
|
7
|
+
* The framework-tool registrar (`../tools/register-framework-tools.ts`) plugs
|
|
8
|
+
* these schemas into the mcp-use tool definitions.
|
|
9
|
+
*/
|
|
10
|
+
export const rowSchema = z.object({
|
|
11
|
+
row: z.array(z.object({
|
|
12
|
+
widget: z.string().describe("Widget ID from the framework manifest. Must be registered."),
|
|
13
|
+
span: z.number().optional().describe("Grid columns (1-12)"),
|
|
14
|
+
props: z
|
|
15
|
+
.record(z.string(), z.unknown())
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Optional per-instance props passed to the widget at render time. Lets the same widget appear multiple times in one view with different scoping (e.g. `{ processDefinitionKey: 'miraveloLeasing' }` for a per-process dashboard tab)."),
|
|
18
|
+
})),
|
|
19
|
+
});
|
|
20
|
+
export const layoutSchema = z
|
|
21
|
+
.union([
|
|
22
|
+
z.array(rowSchema).describe("Flat rows (legacy form)"),
|
|
23
|
+
z.object({ rows: z.array(rowSchema) }).describe("Explicit rows wrapper"),
|
|
24
|
+
z
|
|
25
|
+
.object({
|
|
26
|
+
tabs: z.array(z.object({
|
|
27
|
+
label: z.string().describe("Tab label"),
|
|
28
|
+
rows: z.array(rowSchema),
|
|
29
|
+
})),
|
|
30
|
+
})
|
|
31
|
+
.describe("Tabs — widgets grouped in tabs"),
|
|
32
|
+
])
|
|
33
|
+
.describe("Widget layout: flat rows, { rows }, or { tabs }");
|
|
34
|
+
/**
|
|
35
|
+
* Tool-input variant of {@link layoutSchema} for `render-view` /
|
|
36
|
+
* `refresh-view`: the three layout forms plus a JSON-string branch.
|
|
37
|
+
*
|
|
38
|
+
* Why: as a union, `layout` surfaces on the wire as a top-level `anyOf`
|
|
39
|
+
* WITHOUT its own `type` field. Some MCP hosts (observed with claude.ai)
|
|
40
|
+
* react to such properties by sending the argument as a JSON-encoded STRING —
|
|
41
|
+
* which the plain union rejects, failing the whole call. The string branch
|
|
42
|
+
* parses that form and pipes it through {@link layoutSchema}, so stringified
|
|
43
|
+
* calls validate exactly like the object form. The three object branches are
|
|
44
|
+
* reused from {@link layoutSchema} unchanged.
|
|
45
|
+
*/
|
|
46
|
+
export const layoutInputSchema = z
|
|
47
|
+
.union([
|
|
48
|
+
...layoutSchema.def.options,
|
|
49
|
+
z
|
|
50
|
+
.string()
|
|
51
|
+
.transform((value, ctx) => {
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(value);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
ctx.addIssue({
|
|
57
|
+
code: "custom",
|
|
58
|
+
message: "layout was sent as a string but is not valid JSON",
|
|
59
|
+
});
|
|
60
|
+
return z.NEVER;
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
.pipe(layoutSchema)
|
|
64
|
+
.describe("Layout as a JSON-encoded string (some hosts serialize complex parameters this way); parsed and validated like the object form."),
|
|
65
|
+
])
|
|
66
|
+
.describe("Widget layout: flat rows, { rows }, or { tabs } — or the same as a JSON-encoded string");
|
|
67
|
+
//# sourceMappingURL=layout-schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout-schemas.js","sourceRoot":"","sources":["../../src/framework/layout-schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,GAAG,EAAE,CAAC,CAAC,KAAK,CACV,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4DAA4D,CAAC;QACzF,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QAC3D,KAAK,EAAE,CAAC;aACL,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;aAC/B,QAAQ,EAAE;aACV,QAAQ,CACP,sOAAsO,CACvO;KACJ,CAAC,CACH;CACF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC1B,KAAK,CAAC;IACL,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,yBAAyB,CAAC;IACtD,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC;IACxE,CAAC;SACE,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,KAAK,CACX,CAAC,CAAC,MAAM,CAAC;YACP,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;YACvC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;SACzB,CAAC,CACH;KACF,CAAC;SACD,QAAQ,CAAC,gCAAgC,CAAC;CAC9C,CAAC;KACD,QAAQ,CAAC,iDAAiD,CAAC,CAAA;AAE9D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,KAAK,CAAC;IACL,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO;IAC3B,CAAC;SACE,MAAM,EAAE;SACR,SAAS,CAAC,CAAC,KAAK,EAAE,GAAG,EAAW,EAAE;QACjC,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,mDAAmD;aAC7D,CAAC,CAAA;YACF,OAAO,CAAC,CAAC,KAAK,CAAA;QAChB,CAAC;IACH,CAAC,CAAC;SACD,IAAI,CAAC,YAAY,CAAC;SAClB,QAAQ,CACP,gIAAgI,CACjI;CACJ,CAAC;KACD,QAAQ,CACP,wFAAwF,CACzF,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface RowDef {
|
|
2
|
+
row: {
|
|
3
|
+
widget: string;
|
|
4
|
+
span?: number;
|
|
5
|
+
props?: Record<string, unknown>;
|
|
6
|
+
}[];
|
|
7
|
+
}
|
|
8
|
+
export type LayoutConfig = RowDef[] | {
|
|
9
|
+
rows: RowDef[];
|
|
10
|
+
} | {
|
|
11
|
+
tabs: {
|
|
12
|
+
label: string;
|
|
13
|
+
rows: RowDef[];
|
|
14
|
+
}[];
|
|
15
|
+
};
|
|
16
|
+
/** Normalizes any layout format to the canonical union type (rows or tabs object). */
|
|
17
|
+
export declare function normalizeLayout(layout: LayoutConfig): {
|
|
18
|
+
rows: RowDef[];
|
|
19
|
+
} | {
|
|
20
|
+
tabs: {
|
|
21
|
+
label: string;
|
|
22
|
+
rows: RowDef[];
|
|
23
|
+
}[];
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=layout-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout-types.d.ts","sourceRoot":"","sources":["../../src/framework/layout-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,CAAA;CAC1E;AAED,MAAM,MAAM,YAAY,GACpB,MAAM,EAAE,GACR;IAAE,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;CAAE,CAAA;AAEjD,sFAAsF;AACtF,wBAAgB,eAAe,CAC7B,MAAM,EAAE,YAAY,GACnB;IAAE,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;CAAE,CAGpE"}
|