@miragon/mcp-toolkit-core 2.4.1 → 2.6.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.
Files changed (68) hide show
  1. package/README.md +1 -1
  2. package/dist/auth/caller.d.ts +55 -0
  3. package/dist/auth/caller.d.ts.map +1 -0
  4. package/dist/auth/caller.js +81 -0
  5. package/dist/auth/caller.js.map +1 -0
  6. package/dist/engine/pipeline-executor.d.ts +32 -4
  7. package/dist/engine/pipeline-executor.d.ts.map +1 -1
  8. package/dist/engine/pipeline-executor.js +22 -2
  9. package/dist/engine/pipeline-executor.js.map +1 -1
  10. package/dist/framework/catalogue.d.ts +2 -2
  11. package/dist/framework/render-view.d.ts +6 -4
  12. package/dist/framework/render-view.d.ts.map +1 -1
  13. package/dist/framework/render-view.js.map +1 -1
  14. package/dist/index.d.ts +5 -3
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +5 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/middleware/org-gate.d.ts +31 -7
  19. package/dist/middleware/org-gate.d.ts.map +1 -1
  20. package/dist/middleware/org-gate.js +9 -6
  21. package/dist/middleware/org-gate.js.map +1 -1
  22. package/dist/middleware/role-filter.d.ts +39 -7
  23. package/dist/middleware/role-filter.d.ts.map +1 -1
  24. package/dist/middleware/role-filter.js +24 -28
  25. package/dist/middleware/role-filter.js.map +1 -1
  26. package/dist/tools/create-framework-app.d.ts +12 -1
  27. package/dist/tools/create-framework-app.d.ts.map +1 -1
  28. package/dist/tools/create-framework-app.js +10 -5
  29. package/dist/tools/create-framework-app.js.map +1 -1
  30. package/dist/tools/dashboard-store.d.ts +83 -13
  31. package/dist/tools/dashboard-store.d.ts.map +1 -1
  32. package/dist/tools/dashboard-store.js +174 -73
  33. package/dist/tools/dashboard-store.js.map +1 -1
  34. package/dist/tools/index.d.ts +5 -3
  35. package/dist/tools/index.d.ts.map +1 -1
  36. package/dist/tools/index.js +1 -1
  37. package/dist/tools/index.js.map +1 -1
  38. package/dist/tools/install-toolkit.d.ts +22 -1
  39. package/dist/tools/install-toolkit.d.ts.map +1 -1
  40. package/dist/tools/install-toolkit.js +15 -3
  41. package/dist/tools/install-toolkit.js.map +1 -1
  42. package/dist/tools/register-catalogue-tool.d.ts.map +1 -1
  43. package/dist/tools/register-catalogue-tool.js +2 -5
  44. package/dist/tools/register-catalogue-tool.js.map +1 -1
  45. package/dist/tools/register-dashboard-tools.d.ts +15 -3
  46. package/dist/tools/register-dashboard-tools.d.ts.map +1 -1
  47. package/dist/tools/register-dashboard-tools.js +120 -20
  48. package/dist/tools/register-dashboard-tools.js.map +1 -1
  49. package/dist/tools/register-framework-tools.d.ts.map +1 -1
  50. package/dist/tools/register-framework-tools.js +4 -6
  51. package/dist/tools/register-framework-tools.js.map +1 -1
  52. package/dist/tools/register-tool.d.ts +67 -9
  53. package/dist/tools/register-tool.d.ts.map +1 -1
  54. package/dist/tools/register-tool.js +17 -8
  55. package/dist/tools/register-tool.js.map +1 -1
  56. package/dist/tools/register-widget-tool.d.ts +46 -5
  57. package/dist/tools/register-widget-tool.d.ts.map +1 -1
  58. package/dist/tools/register-widget-tool.js +25 -27
  59. package/dist/tools/register-widget-tool.js.map +1 -1
  60. package/dist/tools/registrar-shared.d.ts +74 -0
  61. package/dist/tools/registrar-shared.d.ts.map +1 -0
  62. package/dist/tools/registrar-shared.js +32 -0
  63. package/dist/tools/registrar-shared.js.map +1 -0
  64. package/dist/tools/tool-name-guard.d.ts +37 -0
  65. package/dist/tools/tool-name-guard.d.ts.map +1 -0
  66. package/dist/tools/tool-name-guard.js +81 -0
  67. package/dist/tools/tool-name-guard.js.map +1 -0
  68. package/package.json +7 -7
@@ -11,6 +11,10 @@
11
11
  * `ctx.params.name`. When no name is present it fails *open* by default
12
12
  * (allow) — pass `failClosed: true` to deny instead.
13
13
  *
14
+ * The caller's roles come from {@link resolveCaller}, which reads both mcp-use 2
15
+ * shapes — middleware receives the SDK `AuthInfo` with the provider-mapped user
16
+ * under `ctx.auth.extra.user`, never `ctx.auth.user`.
17
+ *
14
18
  * Batches need no special handling: mcp-use invokes `mcp:tools/call`
15
19
  * middleware once per call, so each entry of a JSON-RPC batch is guarded
16
20
  * individually (verified against 2.0.4 — a two-entry batch fires the guard
@@ -26,41 +30,31 @@
26
30
  * *unrestricted* access — this is deliberately opt-in so that adding a new
27
31
  * role doesn't silently revoke anyone's tools.
28
32
  */
33
+ import { resolveCaller } from "../auth/caller.js";
34
+ const modulePrefixOf = (toolName) => toolName.split("_")[0] ?? "";
29
35
  export function createRoleFilterMiddleware(roleToModules, opts = {}) {
30
36
  const failClosed = opts.failClosed ?? false;
31
37
  const hasRules = Object.keys(roleToModules).length > 0;
32
38
  // Returns `null` = unrestricted (full access), array = restricted.
33
- const allowedModulesFor = (user) => {
34
- if (!hasRules)
35
- return null;
36
- const roles = Array.isArray(user?.roles) ? user.roles : [];
37
- const restrictedRoles = roles.filter((r) => r in roleToModules);
39
+ const allowedModulesFor = (caller) => {
40
+ const restrictedRoles = (caller?.roles ?? []).filter((r) => r in roleToModules);
38
41
  if (restrictedRoles.length === 0)
39
42
  return null;
40
43
  return [...new Set(restrictedRoles.flatMap((r) => roleToModules[r] ?? []))];
41
44
  };
45
+ // Tools without an underscore are framework/app-level and always allowed.
46
+ const isAllowed = (toolName, allowed) => !toolName.includes("_") || allowed.includes(modulePrefixOf(toolName));
42
47
  const toolsList = async (ctx, next) => {
43
- const tools = (await next());
44
- if (!hasRules || !Array.isArray(tools))
45
- return tools;
46
- const allowed = allowedModulesFor(ctx.auth?.user);
48
+ const result = await next();
49
+ if (!hasRules || !Array.isArray(result))
50
+ return result;
51
+ const allowed = allowedModulesFor(resolveCaller(ctx));
47
52
  if (allowed === null)
48
- return tools;
49
- return tools.filter((t) => {
50
- if (!t.name.includes("_"))
51
- return true;
52
- return allowed.includes(t.name.split("_")[0] ?? "");
53
- });
54
- };
55
- // Tools without an underscore are framework/app-level and always allowed.
56
- const assertModuleAllowed = (toolName, allowed, user) => {
57
- if (!toolName.includes("_"))
58
- return;
59
- const modulePrefix = toolName.split("_")[0] ?? "";
60
- if (!allowed.includes(modulePrefix)) {
61
- const userRoles = user?.roles ?? [];
62
- throw new Error(`Access denied: role(s) "${userRoles.join(", ")}" have no access to module "${modulePrefix}".`);
63
- }
53
+ return result;
54
+ // Filtering keeps the element type, so the narrowed array is still the
55
+ // chain's `TResult` — TypeScript just cannot carry that through
56
+ // `Array.isArray`.
57
+ return result.filter((tool) => typeof tool.name === "string" && isAllowed(tool.name, allowed));
64
58
  };
65
59
  const toolsCall = async (ctx, next) => {
66
60
  if (!hasRules)
@@ -72,9 +66,11 @@ export function createRoleFilterMiddleware(roleToModules, opts = {}) {
72
66
  }
73
67
  return next();
74
68
  }
75
- const allowed = allowedModulesFor(ctx.auth?.user);
76
- if (allowed !== null)
77
- assertModuleAllowed(name, allowed, ctx.auth?.user);
69
+ const caller = resolveCaller(ctx);
70
+ const allowed = allowedModulesFor(caller);
71
+ if (allowed !== null && !isAllowed(name, allowed)) {
72
+ throw new Error(`Access denied: role(s) "${(caller?.roles ?? []).join(", ")}" have no access to module "${modulePrefixOf(name)}".`);
73
+ }
78
74
  return next();
79
75
  };
80
76
  return { toolsList, toolsCall };
@@ -1 +1 @@
1
- {"version":3,"file":"role-filter.js","sourceRoot":"","sources":["../../src/middleware/role-filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"role-filter.js","sourceRoot":"","sources":["../../src/middleware/role-filter.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import type { OAuthProvider } from "mcp-use/oauth";
3
3
  import type { DashboardStore } from "./dashboard-store.js";
4
4
  import type { AppConfig, AppPlugin } from "../types/index.js";
5
5
  import type { AppResourceCsp } from "../types/meta.js";
6
+ import type { DuplicateToolNamePolicy } from "./tool-name-guard.js";
6
7
  export interface CreateFrameworkAppOptionsBase {
7
8
  name: string;
8
9
  version?: string;
@@ -26,7 +27,11 @@ export interface CreateFrameworkAppOptionsBase {
26
27
  serverOptions?: Omit<ServerConfig, "name" | "version" | "description" | "host" | "oauth">;
27
28
  plugins: AppPlugin[];
28
29
  middleware?: {
29
- /** When set, every RPC must come from a token with this organization_id. */
30
+ /**
31
+ * When set, every RPC must come from a caller whose provider-mapped user
32
+ * carries this organization (`organizationId`, or the 1.x-era
33
+ * `organization_id`).
34
+ */
30
35
  orgGate?: string;
31
36
  /** role → allowed module prefixes. Empty / missing → no restriction. */
32
37
  roleFilter?: Record<string, string[]>;
@@ -103,6 +108,12 @@ export interface CreateFrameworkAppOptionsBase {
103
108
  * this option has no effect.
104
109
  */
105
110
  dashboardStore?: DashboardStore;
111
+ /**
112
+ * Duplicate tool names across plugins, the framework tools, and later
113
+ * registrations: `"warn"` (default in 2.x) or `"throw"` (fail the boot).
114
+ * See `InstallToolkitOptions.duplicateToolNames`.
115
+ */
116
+ duplicateToolNames?: DuplicateToolNamePolicy;
106
117
  };
107
118
  /** Supplies the non-empty set of apps each plugin represents. */
108
119
  appConfig?: AppConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"create-framework-app.d.ts","sourceRoot":"","sources":["../../src/tools/create-framework-app.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EAET,KAAK,YAAY,EAGlB,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAGlD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAGtD,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;IACzF,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,UAAU,CAAC,EAAE;QACX,4EAA4E;QAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,wEAAwE;QACxE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;QACrC;;;;;;;WAOG;QACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;KAC/B,CAAA;IACD,GAAG,EAAE;QACH;;;;;;WAMG;QACH,MAAM,EAAE;YACN,wEAAwE;YACxE,MAAM,EAAE,MAAM,CAAA;YACd,0EAA0E;YAC1E,OAAO,CAAC,EAAE,MAAM,CAAA;SACjB,CAAA;QACD,gEAAgE;QAChE,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB;;;;;;WAMG;QACH,GAAG,CAAC,EAAE,cAAc,CAAA;QACpB;;;;;;;;;;;;;;;;;;;;;WAqBG;QACH,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB;;;;;WAKG;QACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B;;;;;;;WAOG;QACH,cAAc,CAAC,EAAE,cAAc,CAAA;KAChC,CAAA;IACD,iEAAiE;IACjE,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,kCAAkC,CACjD,KAAK,GAAG,OAAO,CACf,SAAQ,6BAA6B;IACrC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,qCAAsC,SAAQ,6BAA6B;IAC1F,KAAK,CAAC,EAAE,SAAS,CAAA;CAClB;AAED,MAAM,MAAM,yBAAyB,CAAC,KAAK,GAAG,OAAO,IACnD,kCAAkC,CAAC,KAAK,CAAC,GAAG,qCAAqC,CAAA;AAoBnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EACtC,OAAO,EAAE,kCAAkC,CAAC,KAAK,CAAC,GACjD,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;AAC5B,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,SAAS,CAAC,CAAA"}
1
+ {"version":3,"file":"create-framework-app.d.ts","sourceRoot":"","sources":["../../src/tools/create-framework-app.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EAET,KAAK,YAAY,EAGlB,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAGlD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAEnE,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;IACzF,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,UAAU,CAAC,EAAE;QACX;;;;WAIG;QACH,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,wEAAwE;QACxE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;QACrC;;;;;;;WAOG;QACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;KAC/B,CAAA;IACD,GAAG,EAAE;QACH;;;;;;WAMG;QACH,MAAM,EAAE;YACN,wEAAwE;YACxE,MAAM,EAAE,MAAM,CAAA;YACd,0EAA0E;YAC1E,OAAO,CAAC,EAAE,MAAM,CAAA;SACjB,CAAA;QACD,gEAAgE;QAChE,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB;;;;;;WAMG;QACH,GAAG,CAAC,EAAE,cAAc,CAAA;QACpB;;;;;;;;;;;;;;;;;;;;;WAqBG;QACH,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB;;;;;WAKG;QACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B;;;;;;;WAOG;QACH,cAAc,CAAC,EAAE,cAAc,CAAA;QAC/B;;;;WAIG;QACH,kBAAkB,CAAC,EAAE,uBAAuB,CAAA;KAC7C,CAAA;IACD,iEAAiE;IACjE,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,kCAAkC,CACjD,KAAK,GAAG,OAAO,CACf,SAAQ,6BAA6B;IACrC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,qCAAsC,SAAQ,6BAA6B;IAC1F,KAAK,CAAC,EAAE,SAAS,CAAA;CAClB;AAED,MAAM,MAAM,yBAAyB,CAAC,KAAK,GAAG,OAAO,IACnD,kCAAkC,CAAC,KAAK,CAAC,GAAG,qCAAqC,CAAA;AAoBnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EACtC,OAAO,EAAE,kCAAkC,CAAC,KAAK,CAAC,GACjD,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;AAC5B,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,SAAS,CAAC,CAAA"}
@@ -47,7 +47,8 @@ export async function createFrameworkApp(options) {
47
47
  : new MCPServer({ ...options.serverOptions, ...baseConfig });
48
48
  // The registrars are typed against the OAuth-less `MCPServer`; a
49
49
  // `MCPServer<TUser>` differs only in the `ctx.auth` its callbacks receive,
50
- // which none of them read.
50
+ // which they read structurally through `resolveCaller` (never via the
51
+ // `TUser` type).
51
52
  const serverForRegistrars = server;
52
53
  // Collect every view name bound during boot so the registry can be primed
53
54
  // once at the end (mcp-use accepts `view` bindings before priming — they
@@ -65,11 +66,12 @@ export async function createFrameworkApp(options) {
65
66
  return originalTool(definition, callback);
66
67
  };
67
68
  serverForRegistrars.tool = wrappedTool;
69
+ // Both middlewares are typed structurally (host-agnostic, no mcp-use import
70
+ // in the root barrel) yet shaped so mcp-use 2's `MiddlewareContext` — SDK
71
+ // `AuthInfo` with the mapped user under `auth.extra.user` — is assignable to
72
+ // them; registering them needs no cast.
68
73
  const orgGateId = options.middleware?.orgGate;
69
74
  if (orgGateId) {
70
- // The middleware is typed structurally on purpose so it stays host-
71
- // agnostic; mcp-use 2.x types `ctx.auth` as its own `AuthInfo`, which is
72
- // not mutually assignable with that shape. Only `auth.user` is read.
73
75
  server.use("mcp:*", createOrgGateMiddleware(orgGateId));
74
76
  }
75
77
  const roleFilter = options.middleware?.roleFilter;
@@ -77,7 +79,6 @@ export async function createFrameworkApp(options) {
77
79
  const { toolsList, toolsCall } = createRoleFilterMiddleware(roleFilter, {
78
80
  failClosed: options.middleware?.roleFilterFailClosed ?? false,
79
81
  });
80
- // Cast for the same reason as the org gate above.
81
82
  server.use("mcp:tools/list", toolsList);
82
83
  server.use("mcp:tools/call", toolsCall);
83
84
  }
@@ -92,7 +93,11 @@ export async function createFrameworkApp(options) {
92
93
  builder: options.app.builder,
93
94
  catalogueToolName: options.app.catalogueToolName,
94
95
  dashboardStore: options.app.dashboardStore,
96
+ // Under OAuth a dashboard call without a resolvable caller id is refused,
97
+ // never widened to global (owner-less) scope.
98
+ requireCallerIdentity: Boolean(options.oauth),
95
99
  appConfig: options.appConfig,
100
+ duplicateToolNames: options.app.duplicateToolNames,
96
101
  });
97
102
  // Prime the view registry LAST, once every registrar and plugin has bound
98
103
  // its views. One inline entry per bound name, all sharing the same bundle
@@ -1 +1 @@
1
- {"version":3,"file":"create-framework-app.js","sourceRoot":"","sources":["../../src/tools/create-framework-app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create-framework-app.js","sourceRoot":"","sources":["../../src/tools/create-framework-app.ts"],"names":[],"mappings":"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"}
@@ -10,13 +10,17 @@ export declare const DASHBOARD_SCHEMA_VERSION = 1;
10
10
  /**
11
11
  * Persisted dashboard = full `render-view` input plus identity and
12
12
  * ownership metadata. The server generates `id`, `createdAt`, `updatedAt`;
13
- * `userId` is copied from `ctx.auth.user.userId` on save when present.
13
+ * `userId` is the caller id `resolveCallerId(ctx)` resolves on save.
14
14
  */
15
15
  export interface DashboardRecord {
16
16
  id: string;
17
17
  name: string;
18
18
  description?: string;
19
- /** Owner; omitted when the host boots without OAuth (global scope). */
19
+ /**
20
+ * Owner; omitted only when the host boots without OAuth (global scope). An
21
+ * owner-less record is invisible to — and never writable by — an
22
+ * identified caller.
23
+ */
20
24
  userId?: string;
21
25
  keys?: Record<string, unknown>;
22
26
  steps?: PipelineStepRef[];
@@ -51,6 +55,22 @@ export interface DashboardSummary {
51
55
  description?: string;
52
56
  title?: string;
53
57
  updatedAt: string;
58
+ /**
59
+ * The record's owner, as in {@link DashboardRecord.userId}. The built-in
60
+ * stores report it, and a custom store should: the dashboard tools hold an
61
+ * identified caller to its own summaries with it. A summary without one is
62
+ * verified through `get` instead (one read per entry).
63
+ */
64
+ userId?: string;
65
+ /**
66
+ * Set (to the reason) when the record exists but this build cannot read it
67
+ * — a newer `schemaVersion`, corrupt JSON, a failed schema check, or (in a
68
+ * listing) an entry the filesystem refuses to read. `name` then repeats the
69
+ * id and `updatedAt` is best-effort (empty when unknown).
70
+ * Reported instead of skipped so it can't silently vanish, and refused by
71
+ * `get` / `save` / `delete` with {@link DashboardUnreadableError}.
72
+ */
73
+ unreadable?: string;
54
74
  }
55
75
  /**
56
76
  * Persistence backing for dashboards. The framework is indifferent to how
@@ -59,14 +79,34 @@ export interface DashboardSummary {
59
79
  * backed one for production).
60
80
  *
61
81
  * 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.
82
+ * enforce ownership:
83
+ *
84
+ * - **No `userId`** — global scope, the no-OAuth boot: every record is
85
+ * visible and writable.
86
+ * - **A `userId`** — the caller sees and touches only records whose
87
+ * `userId` equals it. An owner-less record is NOT the caller's: it stays
88
+ * invisible to `list`/`get`/`delete`, and `save` refuses to update it.
89
+ * (The dashboard tools never reach a store without a `userId` once the
90
+ * request is authenticated — they refuse the call instead.)
91
+ *
92
+ * {@link isDashboardOwnedBy} is that rule; a custom store should apply it
93
+ * rather than re-derive it, and report each summary's owner
94
+ * ({@link DashboardSummary.userId}). The dashboard tools re-check every
95
+ * answer for an identified caller anyway — `get`, `list`, and the record a
96
+ * `save` or `delete` would touch — so a store on the laxer 2.5 rule (an
97
+ * owner-less record counted as everyone's) cannot leak or hand out such a
98
+ * record; it only costs extra reads.
64
99
  *
65
100
  * `save` carries the acting user as `input.userId`: updating an existing
66
- * record owned by a different user is rejected with
101
+ * record the caller doesn't own is rejected with
67
102
  * {@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.
103
+ * existing record's owner.
104
+ *
105
+ * A record that exists but cannot be read (newer `schemaVersion`, corrupt
106
+ * JSON, failed schema) is a conflict, never "absent": `get`, `save` and
107
+ * `delete` reject with {@link DashboardUnreadableError}, and `list` reports it
108
+ * with {@link DashboardSummary.unreadable} — so a save can never overwrite it
109
+ * and hand it a new owner.
70
110
  */
71
111
  export interface DashboardStore {
72
112
  save(input: DashboardSaveInput): Promise<DashboardRecord>;
@@ -88,6 +128,16 @@ export interface DashboardStore {
88
128
  * Exported for unit testing.
89
129
  */
90
130
  export declare function parseDashboardRecord(raw: unknown): DashboardRecord | undefined;
131
+ /**
132
+ * The ownership rule of the {@link DashboardStore} contract, shared by every
133
+ * built-in store and by the dashboard tools: no caller id = global scope
134
+ * (no-OAuth boot, everything visible); an identified caller owns exactly the
135
+ * records stamped with its id — an owner-less record is not one of them.
136
+ *
137
+ * Exported so a custom store applies the same rule instead of re-deriving it
138
+ * (the 2.5 rule also granted owner-less records to every identified caller).
139
+ */
140
+ export declare function isDashboardOwnedBy(ownerId: string | undefined, userId: string | undefined): boolean;
91
141
  /**
92
142
  * Error thrown by `save()` when an update would touch a record the caller
93
143
  * doesn't own, or would change a record's owner. Distinct from the
@@ -98,6 +148,24 @@ export declare function parseDashboardRecord(raw: unknown): DashboardRecord | un
98
148
  export declare class DashboardOwnershipError extends Error {
99
149
  constructor(message: string);
100
150
  }
151
+ /**
152
+ * Error thrown by `get`, `save` and `delete` when the addressed record exists
153
+ * but this build cannot read it (newer `schemaVersion`, corrupt JSON, failed
154
+ * schema). Treating such a record as absent would let `save` overwrite it —
155
+ * stamping a fresh owner onto someone else's data — so it is a conflict the
156
+ * caller has to see.
157
+ */
158
+ export declare class DashboardUnreadableError extends Error {
159
+ readonly dashboardId: string;
160
+ readonly reason: string;
161
+ constructor(dashboardId: string, reason: string);
162
+ }
163
+ /**
164
+ * Throw {@link DashboardOwnershipError} unless `userId` may update `existing`
165
+ * ({@link isDashboardOwnedBy}). Shared by {@link resolveSavedRecord} and the
166
+ * dashboard tools, which re-check a custom store's answer before a save.
167
+ */
168
+ export declare function assertDashboardWritable(existing: DashboardRecord, userId: string | undefined): void;
101
169
  /**
102
170
  * Resolve the record to persist for a `save`, enforcing ownership on updates.
103
171
  *
@@ -108,9 +176,10 @@ export declare class DashboardOwnershipError extends Error {
108
176
  * record with `id`, `createdAt`, and — critically — `existing.userId`
109
177
  * preserved so `input.userId` can never reassign the owner.
110
178
  *
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.
179
+ * Without an `input.userId` (global scope: a host booted without OAuth) every
180
+ * record is writable, so single-user deployments keep working. An identified
181
+ * actor owns only records stamped with its id — an owner-less record is
182
+ * refused, never silently claimed.
114
183
  *
115
184
  * Exported for unit testing; the store factories below are the public API.
116
185
  */
@@ -127,9 +196,10 @@ export interface FileSystemDashboardStoreOptions {
127
196
  }
128
197
  /**
129
198
  * 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
199
+ * single-node deployments that need survival across restarts. Writes are
200
+ * atomic (temp file + rename), so a crash never leaves a torn record.
201
+ * Locking is advisory: concurrent writes of the same id can race — fine for
202
+ * the v1 "single user clicking Save" workflow, not fine for multi-writer
133
203
  * production.
134
204
  */
135
205
  export declare function createFileSystemDashboardStore(options: FileSystemDashboardStoreOptions): DashboardStore;
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-store.d.ts","sourceRoot":"","sources":["../../src/tools/dashboard-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAGhE;;;;;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"}
1
+ {"version":3,"file":"dashboard-store.d.ts","sourceRoot":"","sources":["../../src/tools/dashboard-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAGhE;;;;;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;;;;OAIG;IACH,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;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;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;AAMD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,OAAO,CAGT;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;GAMG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IAE/C,QAAQ,CAAC,WAAW,EAAE,MAAM;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADd,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM;CAO1B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,IAAI,CAON;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,KAAK,EAAE,kBAAkB,EACzB,GAAG,EAAE,MAAM,GACV,eAAe,GAAG,IAAI,CAYxB;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,cAAc,CA+C7D;AAED,MAAM,WAAW,+BAA+B;IAC9C,4EAA4E;IAC5E,GAAG,EAAE,MAAM,CAAA;CACZ;AA4CD;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,+BAA+B,GACvC,cAAc,CA2IhB"}