@jbctechsolutions/mcp-office365 2.5.1 → 3.0.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/README.md +32 -0
- package/dist/approval/token-manager.d.ts +28 -16
- package/dist/approval/token-manager.d.ts.map +1 -1
- package/dist/approval/token-manager.js +125 -37
- package/dist/approval/token-manager.js.map +1 -1
- package/dist/cli.d.ts +17 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +85 -2
- package/dist/cli.js.map +1 -1
- package/dist/graph/auth/config.d.ts +1 -1
- package/dist/graph/auth/config.d.ts.map +1 -1
- package/dist/graph/auth/config.js +5 -1
- package/dist/graph/auth/config.js.map +1 -1
- package/dist/graph/auth/device-code-flow.d.ts +3 -1
- package/dist/graph/auth/device-code-flow.d.ts.map +1 -1
- package/dist/graph/auth/device-code-flow.js +42 -14
- package/dist/graph/auth/device-code-flow.js.map +1 -1
- package/dist/graph/auth/token-cache.js +2 -2
- package/dist/graph/auth/token-cache.js.map +1 -1
- package/dist/graph/client/graph-client.d.ts +36 -8
- package/dist/graph/client/graph-client.d.ts.map +1 -1
- package/dist/graph/client/graph-client.js +128 -36
- package/dist/graph/client/graph-client.js.map +1 -1
- package/dist/graph/repository.d.ts +9 -6
- package/dist/graph/repository.d.ts.map +1 -1
- package/dist/graph/repository.js +63 -66
- package/dist/graph/repository.js.map +1 -1
- package/dist/ids/mint.d.ts +31 -0
- package/dist/ids/mint.d.ts.map +1 -0
- package/dist/ids/mint.js +36 -0
- package/dist/ids/mint.js.map +1 -0
- package/dist/ids/resolver.d.ts +30 -0
- package/dist/ids/resolver.d.ts.map +1 -0
- package/dist/ids/resolver.js +37 -0
- package/dist/ids/resolver.js.map +1 -0
- package/dist/ids/token.d.ts +56 -0
- package/dist/ids/token.d.ts.map +1 -0
- package/dist/ids/token.js +186 -0
- package/dist/ids/token.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +226 -5859
- package/dist/index.js.map +1 -1
- package/dist/registry/all-tools.d.ts +14 -0
- package/dist/registry/all-tools.d.ts.map +1 -0
- package/dist/registry/all-tools.js +64 -0
- package/dist/registry/all-tools.js.map +1 -0
- package/dist/registry/context.d.ts +25 -0
- package/dist/registry/context.d.ts.map +1 -0
- package/dist/registry/context.js +31 -0
- package/dist/registry/context.js.map +1 -0
- package/dist/registry/define-tool.d.ts +15 -0
- package/dist/registry/define-tool.d.ts.map +1 -0
- package/dist/registry/define-tool.js +8 -0
- package/dist/registry/define-tool.js.map +1 -0
- package/dist/registry/index.d.ts +13 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +8 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/registry.d.ts +62 -0
- package/dist/registry/registry.d.ts.map +1 -0
- package/dist/registry/registry.js +134 -0
- package/dist/registry/registry.js.map +1 -0
- package/dist/registry/types.d.ts +98 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +6 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/search/compiler.d.ts +49 -0
- package/dist/search/compiler.d.ts.map +1 -0
- package/dist/search/compiler.js +168 -0
- package/dist/search/compiler.js.map +1 -0
- package/dist/signature.js +2 -2
- package/dist/signature.js.map +1 -1
- package/dist/state/migrate.d.ts +23 -0
- package/dist/state/migrate.d.ts.map +1 -0
- package/dist/state/migrate.js +81 -0
- package/dist/state/migrate.js.map +1 -0
- package/dist/state/schema.d.ts +27 -0
- package/dist/state/schema.d.ts.map +1 -0
- package/dist/state/schema.js +54 -0
- package/dist/state/schema.js.map +1 -0
- package/dist/state/store.d.ts +152 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/store.js +317 -0
- package/dist/state/store.js.map +1 -0
- package/dist/tools/accounts.d.ts +37 -0
- package/dist/tools/accounts.d.ts.map +1 -0
- package/dist/tools/accounts.js +68 -0
- package/dist/tools/accounts.js.map +1 -0
- package/dist/tools/calendar-apple.d.ts +39 -0
- package/dist/tools/calendar-apple.d.ts.map +1 -0
- package/dist/tools/calendar-apple.js +159 -0
- package/dist/tools/calendar-apple.js.map +1 -0
- package/dist/tools/calendar-graph.d.ts +41 -0
- package/dist/tools/calendar-graph.d.ts.map +1 -0
- package/dist/tools/calendar-graph.js +298 -0
- package/dist/tools/calendar-graph.js.map +1 -0
- package/dist/tools/calendar-permissions.d.ts +10 -0
- package/dist/tools/calendar-permissions.d.ts.map +1 -1
- package/dist/tools/calendar-permissions.js +53 -0
- package/dist/tools/calendar-permissions.js.map +1 -1
- package/dist/tools/calendar.d.ts +151 -0
- package/dist/tools/calendar.d.ts.map +1 -1
- package/dist/tools/calendar.js +274 -0
- package/dist/tools/calendar.js.map +1 -1
- package/dist/tools/categories.d.ts +10 -0
- package/dist/tools/categories.d.ts.map +1 -1
- package/dist/tools/categories.js +54 -0
- package/dist/tools/categories.js.map +1 -1
- package/dist/tools/checklist-items.d.ts +10 -0
- package/dist/tools/checklist-items.d.ts.map +1 -1
- package/dist/tools/checklist-items.js +63 -0
- package/dist/tools/checklist-items.js.map +1 -1
- package/dist/tools/contact-folders.d.ts +50 -0
- package/dist/tools/contact-folders.d.ts.map +1 -0
- package/dist/tools/contact-folders.js +133 -0
- package/dist/tools/contact-folders.js.map +1 -0
- package/dist/tools/contacts-graph.d.ts +45 -0
- package/dist/tools/contacts-graph.d.ts.map +1 -0
- package/dist/tools/contacts-graph.js +172 -0
- package/dist/tools/contacts-graph.js.map +1 -0
- package/dist/tools/contacts.d.ts +66 -0
- package/dist/tools/contacts.d.ts.map +1 -1
- package/dist/tools/contacts.js +165 -0
- package/dist/tools/contacts.js.map +1 -1
- package/dist/tools/excel.d.ts +10 -0
- package/dist/tools/excel.d.ts.map +1 -1
- package/dist/tools/excel.js +73 -0
- package/dist/tools/excel.js.map +1 -1
- package/dist/tools/focused-overrides.d.ts +10 -0
- package/dist/tools/focused-overrides.d.ts.map +1 -1
- package/dist/tools/focused-overrides.js +54 -0
- package/dist/tools/focused-overrides.js.map +1 -1
- package/dist/tools/linked-resources.d.ts +10 -0
- package/dist/tools/linked-resources.d.ts.map +1 -1
- package/dist/tools/linked-resources.js +53 -0
- package/dist/tools/linked-resources.js.map +1 -1
- package/dist/tools/mail-apple.d.ts +40 -0
- package/dist/tools/mail-apple.d.ts.map +1 -0
- package/dist/tools/mail-apple.js +146 -0
- package/dist/tools/mail-apple.js.map +1 -0
- package/dist/tools/mail-graph.d.ts +38 -0
- package/dist/tools/mail-graph.d.ts.map +1 -0
- package/dist/tools/mail-graph.js +178 -0
- package/dist/tools/mail-graph.js.map +1 -0
- package/dist/tools/mail-rules.d.ts +12 -0
- package/dist/tools/mail-rules.d.ts.map +1 -1
- package/dist/tools/mail-rules.js +56 -0
- package/dist/tools/mail-rules.js.map +1 -1
- package/dist/tools/mail-send.d.ts +12 -0
- package/dist/tools/mail-send.d.ts.map +1 -1
- package/dist/tools/mail-send.js +219 -5
- package/dist/tools/mail-send.js.map +1 -1
- package/dist/tools/mail.d.ts +82 -2
- package/dist/tools/mail.d.ts.map +1 -1
- package/dist/tools/mail.js +239 -2
- package/dist/tools/mail.js.map +1 -1
- package/dist/tools/mailbox-organization.d.ts +20 -0
- package/dist/tools/mailbox-organization.d.ts.map +1 -1
- package/dist/tools/mailbox-organization.js +275 -0
- package/dist/tools/mailbox-organization.js.map +1 -1
- package/dist/tools/mailbox-settings.d.ts +59 -0
- package/dist/tools/mailbox-settings.d.ts.map +1 -0
- package/dist/tools/mailbox-settings.js +136 -0
- package/dist/tools/mailbox-settings.js.map +1 -0
- package/dist/tools/meetings.d.ts +10 -0
- package/dist/tools/meetings.d.ts.map +1 -1
- package/dist/tools/meetings.js +74 -0
- package/dist/tools/meetings.js.map +1 -1
- package/dist/tools/notes.d.ts +12 -0
- package/dist/tools/notes.d.ts.map +1 -1
- package/dist/tools/notes.js +66 -0
- package/dist/tools/notes.js.map +1 -1
- package/dist/tools/onedrive.d.ts +10 -0
- package/dist/tools/onedrive.d.ts.map +1 -1
- package/dist/tools/onedrive.js +124 -0
- package/dist/tools/onedrive.js.map +1 -1
- package/dist/tools/people.d.ts +10 -0
- package/dist/tools/people.d.ts.map +1 -1
- package/dist/tools/people.js +94 -0
- package/dist/tools/people.js.map +1 -1
- package/dist/tools/planner-visualization.d.ts +10 -0
- package/dist/tools/planner-visualization.d.ts.map +1 -1
- package/dist/tools/planner-visualization.js +53 -0
- package/dist/tools/planner-visualization.js.map +1 -1
- package/dist/tools/planner.d.ts +10 -0
- package/dist/tools/planner.d.ts.map +1 -1
- package/dist/tools/planner.js +183 -0
- package/dist/tools/planner.js.map +1 -1
- package/dist/tools/scheduling.d.ts +12 -0
- package/dist/tools/scheduling.d.ts.map +1 -1
- package/dist/tools/scheduling.js +38 -0
- package/dist/tools/scheduling.js.map +1 -1
- package/dist/tools/sharepoint.d.ts +10 -0
- package/dist/tools/sharepoint.d.ts.map +1 -1
- package/dist/tools/sharepoint.js +74 -0
- package/dist/tools/sharepoint.js.map +1 -1
- package/dist/tools/task-attachments.d.ts +10 -0
- package/dist/tools/task-attachments.d.ts.map +1 -1
- package/dist/tools/task-attachments.js +53 -0
- package/dist/tools/task-attachments.js.map +1 -1
- package/dist/tools/task-lists.d.ts +56 -0
- package/dist/tools/task-lists.d.ts.map +1 -0
- package/dist/tools/task-lists.js +151 -0
- package/dist/tools/task-lists.js.map +1 -0
- package/dist/tools/tasks-graph.d.ts +49 -0
- package/dist/tools/tasks-graph.d.ts.map +1 -0
- package/dist/tools/tasks-graph.js +191 -0
- package/dist/tools/tasks-graph.js.map +1 -0
- package/dist/tools/tasks.d.ts +127 -0
- package/dist/tools/tasks.d.ts.map +1 -1
- package/dist/tools/tasks.js +155 -0
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/teams.d.ts +11 -0
- package/dist/tools/teams.d.ts.map +1 -1
- package/dist/tools/teams.js +254 -0
- package/dist/tools/teams.js.map +1 -1
- package/dist/utils/errors.d.ts +96 -5
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +227 -8
- package/dist/utils/errors.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 JBC Tech Solutions, LLC
|
|
3
|
+
* Licensed under the MIT License. See LICENSE file in the project root.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Resolves an initialized Graph-backend toolset from the runtime context, or
|
|
7
|
+
* throws a clear error when the Graph backend is unavailable.
|
|
8
|
+
*
|
|
9
|
+
* Centralizes the per-domain "resolve toolset or throw" boilerplate so every
|
|
10
|
+
* migrated domain shares one implementation instead of hand-rolling a null
|
|
11
|
+
* check. The `key` is type-checked against the augmented `GraphToolsets`, and
|
|
12
|
+
* the return type is the exact toolset class for that key.
|
|
13
|
+
*/
|
|
14
|
+
export function requireGraphToolset(ctx, key) {
|
|
15
|
+
if (ctx.graph == null) {
|
|
16
|
+
throw new Error('This tool requires the Microsoft Graph API backend.');
|
|
17
|
+
}
|
|
18
|
+
return ctx.graph[key];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolves an initialized AppleScript-backend toolset from the runtime context,
|
|
22
|
+
* or throws when the AppleScript backend is unavailable. The dual-backend
|
|
23
|
+
* counterpart to {@link requireGraphToolset}.
|
|
24
|
+
*/
|
|
25
|
+
export function requireAppleScriptToolset(ctx, key) {
|
|
26
|
+
if (ctx.applescript == null) {
|
|
27
|
+
throw new Error('This tool requires the AppleScript (classic Outlook) backend.');
|
|
28
|
+
}
|
|
29
|
+
return ctx.applescript[key];
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/registry/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAgB,EAChB,GAAM;IAEN,IAAI,GAAG,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,GAAgB,EAChB,GAAM;IAEN,IAAI,GAAG,CAAC,WAAW,IAAI,IAAI,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 JBC Tech Solutions, LLC
|
|
3
|
+
* Licensed under the MIT License. See LICENSE file in the project root.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* `defineTool` — typed helper for authoring a tool definition.
|
|
7
|
+
*
|
|
8
|
+
* Preserves the inference link between the Zod input schema and the handler's
|
|
9
|
+
* `params` argument, so a domain module declares its schema once and the
|
|
10
|
+
* handler is type-checked against it.
|
|
11
|
+
*/
|
|
12
|
+
import type { z } from 'zod';
|
|
13
|
+
import type { ToolDefinition } from './types.js';
|
|
14
|
+
export declare function defineTool<S extends z.ZodType>(def: ToolDefinition<S>): ToolDefinition<S>;
|
|
15
|
+
//# sourceMappingURL=define-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-tool.d.ts","sourceRoot":"","sources":["../../src/registry/define-tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAEzF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-tool.js","sourceRoot":"","sources":["../../src/registry/define-tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,MAAM,UAAU,UAAU,CAAsB,GAAsB;IACpE,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 JBC Tech Solutions, LLC
|
|
3
|
+
* Licensed under the MIT License. See LICENSE file in the project root.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Tool registry barrel.
|
|
7
|
+
*/
|
|
8
|
+
export type { Backend, Preset, ToolAnnotations, ToolResult, ToolContext, ToolDefinition, GraphToolsets, AppleScriptToolsets, } from './types.js';
|
|
9
|
+
export { ToolRegistry, toInputSchema } from './registry.js';
|
|
10
|
+
export type { SurfaceOptions } from './registry.js';
|
|
11
|
+
export { defineTool } from './define-tool.js';
|
|
12
|
+
export { requireGraphToolset, requireAppleScriptToolset } from './context.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AAEH,YAAY,EACV,OAAO,EACP,MAAM,EACN,eAAe,EACf,UAAU,EACV,WAAW,EACX,cAAc,EACd,aAAa,EACb,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 JBC Tech Solutions, LLC
|
|
3
|
+
* Licensed under the MIT License. See LICENSE file in the project root.
|
|
4
|
+
*/
|
|
5
|
+
export { ToolRegistry, toInputSchema } from './registry.js';
|
|
6
|
+
export { defineTool } from './define-tool.js';
|
|
7
|
+
export { requireGraphToolset, requireAppleScriptToolset } from './context.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 JBC Tech Solutions, LLC
|
|
3
|
+
* Licensed under the MIT License. See LICENSE file in the project root.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* ToolRegistry — single source of truth for the MCP tool surface (U1).
|
|
7
|
+
*
|
|
8
|
+
* Holds tool definitions, derives the advertised JSON Schema from each Zod
|
|
9
|
+
* schema, filters the surface by backend / preset / read-only, and dispatches
|
|
10
|
+
* a call to the matching handler after validating its arguments.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
14
|
+
import type { Backend, Preset, ToolContext, ToolDefinition, ToolResult } from './types.js';
|
|
15
|
+
/** Options controlling which tools are exposed to a client. */
|
|
16
|
+
export interface SurfaceOptions {
|
|
17
|
+
readonly backend: Backend;
|
|
18
|
+
/** Presets to include. Undefined/empty means the full surface. */
|
|
19
|
+
readonly presets?: readonly Preset[];
|
|
20
|
+
/** When true, only non-destructive tools are exposed. */
|
|
21
|
+
readonly readOnly?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Converts a Zod schema to an MCP-compatible `inputSchema`.
|
|
25
|
+
*
|
|
26
|
+
* Uses zod 4's native `z.toJSONSchema` (draft-07 target) and strips the
|
|
27
|
+
* `$schema` key, which MCP's `Tool.inputSchema` does not carry. Transitional
|
|
28
|
+
* alias keys (U6/D11) are handled by the input pipeline, not here; when a
|
|
29
|
+
* schema opts into aliases it should expose them as optional properties so the
|
|
30
|
+
* advertised schema stays validation-safe.
|
|
31
|
+
*/
|
|
32
|
+
export declare function toInputSchema(schema: z.ZodType): Tool['inputSchema'];
|
|
33
|
+
/**
|
|
34
|
+
* In-memory registry of tool definitions.
|
|
35
|
+
*/
|
|
36
|
+
export declare class ToolRegistry {
|
|
37
|
+
private readonly definitions;
|
|
38
|
+
/** Registers a batch of tool definitions. Throws on a duplicate name. */
|
|
39
|
+
register(defs: readonly ToolDefinition[]): void;
|
|
40
|
+
/** True when a tool with this name is registered. */
|
|
41
|
+
has(name: string): boolean;
|
|
42
|
+
/** All registered names, insertion order preserved. */
|
|
43
|
+
names(): string[];
|
|
44
|
+
/** Returns a single definition, or undefined. */
|
|
45
|
+
get(name: string): ToolDefinition | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Returns the MCP tool list for a given surface, filtered by backend,
|
|
48
|
+
* preset membership, and read-only mode.
|
|
49
|
+
*/
|
|
50
|
+
listTools(options: SurfaceOptions): Tool[];
|
|
51
|
+
/** True when a tool is exposed under the given surface. */
|
|
52
|
+
isExposed(name: string, options: SurfaceOptions): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Validates arguments against the tool's schema and invokes its handler.
|
|
55
|
+
* Returns undefined when no tool with this name is registered, so the caller
|
|
56
|
+
* can fall back to the legacy dispatch during the U2 migration window.
|
|
57
|
+
*/
|
|
58
|
+
dispatch(name: string, args: unknown, ctx: ToolContext, options: SurfaceOptions): Promise<ToolResult | undefined>;
|
|
59
|
+
private filtered;
|
|
60
|
+
private matches;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry/registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACN,WAAW,EACX,cAAc,EACd,UAAU,EACX,MAAM,YAAY,CAAC;AAEpB,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,CAWpE;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqC;IAEjE,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,GAAG,IAAI;IAS/C,qDAAqD;IACrD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,uDAAuD;IACvD,KAAK,IAAI,MAAM,EAAE;IAIjB,iDAAiD;IACjD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI7C;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,EAAE;IAc1C,2DAA2D;IAC3D,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO;IAKzD;;;;OAIG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAsBlC,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,OAAO;CAahB"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 JBC Tech Solutions, LLC
|
|
3
|
+
* Licensed under the MIT License. See LICENSE file in the project root.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* ToolRegistry — single source of truth for the MCP tool surface (U1).
|
|
7
|
+
*
|
|
8
|
+
* Holds tool definitions, derives the advertised JSON Schema from each Zod
|
|
9
|
+
* schema, filters the surface by backend / preset / read-only, and dispatches
|
|
10
|
+
* a call to the matching handler after validating its arguments.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { ReadOnlyModeError } from '../utils/errors.js';
|
|
14
|
+
/**
|
|
15
|
+
* Converts a Zod schema to an MCP-compatible `inputSchema`.
|
|
16
|
+
*
|
|
17
|
+
* Uses zod 4's native `z.toJSONSchema` (draft-07 target) and strips the
|
|
18
|
+
* `$schema` key, which MCP's `Tool.inputSchema` does not carry. Transitional
|
|
19
|
+
* alias keys (U6/D11) are handled by the input pipeline, not here; when a
|
|
20
|
+
* schema opts into aliases it should expose them as optional properties so the
|
|
21
|
+
* advertised schema stays validation-safe.
|
|
22
|
+
*/
|
|
23
|
+
export function toInputSchema(schema) {
|
|
24
|
+
// `io: 'input'` — the advertised schema describes what a CLIENT sends, so a
|
|
25
|
+
// field with a `.default()` is optional (the server fills the default at
|
|
26
|
+
// parse time). Zod 4's default `io: 'output'` would mark defaulted fields as
|
|
27
|
+
// required, misleading agents into always supplying them.
|
|
28
|
+
const json = z.toJSONSchema(schema, { target: 'draft-7', io: 'input' });
|
|
29
|
+
delete json['$schema'];
|
|
30
|
+
if (json['type'] == null) {
|
|
31
|
+
json['type'] = 'object';
|
|
32
|
+
}
|
|
33
|
+
return json;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* In-memory registry of tool definitions.
|
|
37
|
+
*/
|
|
38
|
+
export class ToolRegistry {
|
|
39
|
+
definitions = new Map();
|
|
40
|
+
/** Registers a batch of tool definitions. Throws on a duplicate name. */
|
|
41
|
+
register(defs) {
|
|
42
|
+
for (const def of defs) {
|
|
43
|
+
if (this.definitions.has(def.name)) {
|
|
44
|
+
throw new Error(`Duplicate tool registration: "${def.name}"`);
|
|
45
|
+
}
|
|
46
|
+
this.definitions.set(def.name, def);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** True when a tool with this name is registered. */
|
|
50
|
+
has(name) {
|
|
51
|
+
return this.definitions.has(name);
|
|
52
|
+
}
|
|
53
|
+
/** All registered names, insertion order preserved. */
|
|
54
|
+
names() {
|
|
55
|
+
return [...this.definitions.keys()];
|
|
56
|
+
}
|
|
57
|
+
/** Returns a single definition, or undefined. */
|
|
58
|
+
get(name) {
|
|
59
|
+
return this.definitions.get(name);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Returns the MCP tool list for a given surface, filtered by backend,
|
|
63
|
+
* preset membership, and read-only mode.
|
|
64
|
+
*/
|
|
65
|
+
listTools(options) {
|
|
66
|
+
return this.filtered(options).map((def) => {
|
|
67
|
+
const tool = {
|
|
68
|
+
name: def.name,
|
|
69
|
+
description: def.description,
|
|
70
|
+
inputSchema: toInputSchema(def.input),
|
|
71
|
+
};
|
|
72
|
+
if (Object.keys(def.annotations).length > 0) {
|
|
73
|
+
return { ...tool, annotations: def.annotations };
|
|
74
|
+
}
|
|
75
|
+
return tool;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/** True when a tool is exposed under the given surface. */
|
|
79
|
+
isExposed(name, options) {
|
|
80
|
+
const def = this.definitions.get(name);
|
|
81
|
+
return def != null && this.matches(def, options);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Validates arguments against the tool's schema and invokes its handler.
|
|
85
|
+
* Returns undefined when no tool with this name is registered, so the caller
|
|
86
|
+
* can fall back to the legacy dispatch during the U2 migration window.
|
|
87
|
+
*/
|
|
88
|
+
async dispatch(name, args, ctx, options) {
|
|
89
|
+
const def = this.definitions.get(name);
|
|
90
|
+
if (def == null) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
if (!this.matches(def, options)) {
|
|
94
|
+
// Distinguish the read-only rejection so it surfaces a stable
|
|
95
|
+
// READ_ONLY_MODE envelope (D13) — but only when read-only is the *sole*
|
|
96
|
+
// reason (the tool would otherwise be exposed). A tool also filtered by
|
|
97
|
+
// backend/preset gets the generic error, avoiding misattribution.
|
|
98
|
+
if (options.readOnly === true && this.matches(def, { ...options, readOnly: false })) {
|
|
99
|
+
throw new ReadOnlyModeError(name);
|
|
100
|
+
}
|
|
101
|
+
throw new Error(`Tool "${name}" is not available in the current mode.`);
|
|
102
|
+
}
|
|
103
|
+
// MCP marks `arguments` optional; default to {} so no-input tools
|
|
104
|
+
// (e.g. list_mail_rules) parse cleanly, matching the codebase-wide
|
|
105
|
+
// `parse(args ?? {})` convention.
|
|
106
|
+
const params = def.input.parse(args ?? {});
|
|
107
|
+
return def.handler(ctx, params);
|
|
108
|
+
}
|
|
109
|
+
filtered(options) {
|
|
110
|
+
return [...this.definitions.values()].filter((def) => this.matches(def, options));
|
|
111
|
+
}
|
|
112
|
+
matches(def, options) {
|
|
113
|
+
if (!def.backends.includes(options.backend)) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
if (options.readOnly === true && !isReadOnly(def)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
const presets = options.presets;
|
|
120
|
+
if (presets != null && presets.length > 0 && def.presets.length > 0) {
|
|
121
|
+
return def.presets.some((p) => presets.includes(p));
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* A tool is read-only iff it explicitly advertises `readOnlyHint: true`. This is
|
|
128
|
+
* stricter than `!destructive` — a non-destructive write (e.g. create_draft,
|
|
129
|
+
* mark_email_read) still mutates state and must be excluded from `--read-only`.
|
|
130
|
+
*/
|
|
131
|
+
function isReadOnly(def) {
|
|
132
|
+
return def.annotations.readOnlyHint === true;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/registry/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 JBC Tech Solutions, LLC
|
|
3
|
+
* Licensed under the MIT License. See LICENSE file in the project root.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Tool registry types (v3 registry-driven architecture, U1).
|
|
7
|
+
*
|
|
8
|
+
* A tool definition is the single source of truth for what the four
|
|
9
|
+
* previously hand-maintained lists carried independently: the JSON-schema
|
|
10
|
+
* `TOOLS` array, per-module Zod schemas, the dispatch switch, and
|
|
11
|
+
* `GRAPH_ONLY_TOOL_NAMES`. Definitions register their static metadata
|
|
12
|
+
* eagerly (before any backend is initialized, so ListTools works without
|
|
13
|
+
* auth) and resolve their live handler dependencies lazily via ToolContext.
|
|
14
|
+
*/
|
|
15
|
+
import type { z } from 'zod';
|
|
16
|
+
import type { ApprovalTokenManager } from '../approval/index.js';
|
|
17
|
+
/** Which backend(s) expose a tool. */
|
|
18
|
+
export type Backend = 'graph' | 'applescript';
|
|
19
|
+
/** Preset groups a client can select with --preset to shrink the surface. */
|
|
20
|
+
export type Preset = 'mail' | 'calendar' | 'contacts' | 'tasks' | 'notes' | 'teams' | 'planner' | 'files' | 'sharepoint' | 'excel' | 'people' | 'meetings';
|
|
21
|
+
/**
|
|
22
|
+
* MCP tool annotations (spec 2025-03-26+). Clients use these to auto-approve
|
|
23
|
+
* safe reads and gate destructive calls.
|
|
24
|
+
*/
|
|
25
|
+
export interface ToolAnnotations {
|
|
26
|
+
readonly title?: string;
|
|
27
|
+
readonly readOnlyHint?: boolean;
|
|
28
|
+
readonly destructiveHint?: boolean;
|
|
29
|
+
readonly idempotentHint?: boolean;
|
|
30
|
+
readonly openWorldHint?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** The MCP text-content result shape every tool returns. */
|
|
33
|
+
export interface ToolResult {
|
|
34
|
+
content: Array<{
|
|
35
|
+
type: 'text';
|
|
36
|
+
text: string;
|
|
37
|
+
}>;
|
|
38
|
+
isError?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Bag of initialized Graph-backend tool instances, resolved after the backend
|
|
42
|
+
* is lazily initialized.
|
|
43
|
+
*
|
|
44
|
+
* This is an augmentation target: each domain module declares its own field
|
|
45
|
+
* via `declare module '../registry/types.js'`, so migrating a domain never
|
|
46
|
+
* edits this file — avoiding a 25-domain merge-conflict hotspot. Handlers read
|
|
47
|
+
* their instance through `requireGraphToolset(ctx, key)`.
|
|
48
|
+
*/
|
|
49
|
+
export interface GraphToolsets {
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Bag of initialized AppleScript-backend tool instances. The AppleScript
|
|
53
|
+
* backend is frozen (v3), but dual-backend tools (mail, calendar, contacts,
|
|
54
|
+
* tasks, notes, mailbox organization) still register their AppleScript toolset
|
|
55
|
+
* here so a single registry handler can branch on `ctx.backend`. Like
|
|
56
|
+
* GraphToolsets, this is a per-file augmentation target — read instances via
|
|
57
|
+
* `requireAppleScriptToolset(ctx, key)`.
|
|
58
|
+
*/
|
|
59
|
+
export interface AppleScriptToolsets {
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Runtime context passed to a tool handler. Built once per call after the
|
|
63
|
+
* backend is initialized; carries the live toolset instances so handlers no
|
|
64
|
+
* longer need the 23-positional-parameter dispatch signature.
|
|
65
|
+
*/
|
|
66
|
+
export interface ToolContext {
|
|
67
|
+
readonly backend: Backend;
|
|
68
|
+
readonly tokenManager: ApprovalTokenManager;
|
|
69
|
+
readonly graph: GraphToolsets | null;
|
|
70
|
+
readonly applescript: AppleScriptToolsets | null;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A single tool definition — static metadata plus a lazily-bound handler.
|
|
74
|
+
*
|
|
75
|
+
* @typeParam S - the Zod input schema; the handler receives its parsed output.
|
|
76
|
+
*/
|
|
77
|
+
export interface ToolDefinition<S extends z.ZodType = z.ZodType> {
|
|
78
|
+
/** Tool name exposed over MCP (snake_case). */
|
|
79
|
+
readonly name: string;
|
|
80
|
+
/** One-line description shown to the model. */
|
|
81
|
+
readonly description: string;
|
|
82
|
+
/** Zod input schema; the advertised JSON Schema is derived from it. */
|
|
83
|
+
readonly input: S;
|
|
84
|
+
/** MCP annotations surfaced in ListTools. */
|
|
85
|
+
readonly annotations: ToolAnnotations;
|
|
86
|
+
/**
|
|
87
|
+
* True when the tool participates in a destructive flow (delete/send/upload,
|
|
88
|
+
* including the prepare_/confirm_ halves). Drives --read-only filtering.
|
|
89
|
+
*/
|
|
90
|
+
readonly destructive: boolean;
|
|
91
|
+
/** Presets that include this tool. Empty means "always exposed". */
|
|
92
|
+
readonly presets: readonly Preset[];
|
|
93
|
+
/** Backends that expose this tool. */
|
|
94
|
+
readonly backends: readonly Backend[];
|
|
95
|
+
/** Handler invoked with the runtime context and validated params. */
|
|
96
|
+
readonly handler: (ctx: ToolContext, params: z.infer<S>) => Promise<ToolResult> | ToolResult;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,sCAAsC;AACtC,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,aAAa,CAAC;AAE9C,6EAA6E;AAC7E,MAAM,MAAM,MAAM,GACd,MAAM,GACN,UAAU,GACV,UAAU,GACV,OAAO,GACP,OAAO,GACP,OAAO,GACP,SAAS,GACT,OAAO,GACP,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,UAAU,CAAC;AAEf;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;GAQG;AAEH,MAAM,WAAW,aAAa;CAAG;AAEjC;;;;;;;GAOG;AAEH,MAAM,WAAW,mBAAmB;CAAG;AAEvC;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,mBAAmB,GAAG,IAAI,CAAC;CAClD;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO;IAC7D,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,6CAA6C;IAC7C,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC;CAC9F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 JBC Tech Solutions, LLC
|
|
3
|
+
* Licensed under the MIT License. See LICENSE file in the project root.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Structured, typed email-search criteria (replaces the raw `query` KQL). Fields
|
|
7
|
+
* are `| undefined`-tolerant so a zod-parsed input object (which carries explicit
|
|
8
|
+
* `undefined` for absent optionals under exactOptionalPropertyTypes) passes
|
|
9
|
+
* directly; every field is guarded with `!= null` before use.
|
|
10
|
+
*/
|
|
11
|
+
export interface EmailSearchParams {
|
|
12
|
+
/** Sender address (exact). Property → `$filter`. */
|
|
13
|
+
from?: string | undefined;
|
|
14
|
+
/** Recipient address (exact). Property → `$filter`. */
|
|
15
|
+
to?: string | undefined;
|
|
16
|
+
/** Received on/after this ISO date/datetime. Property → `$filter`. */
|
|
17
|
+
received_after?: string | undefined;
|
|
18
|
+
/** Received on/before this ISO date/datetime. Property → `$filter`. */
|
|
19
|
+
received_before?: string | undefined;
|
|
20
|
+
/** Only messages with attachments. Property → `$filter`. */
|
|
21
|
+
has_attachments?: boolean | undefined;
|
|
22
|
+
/** Only unread messages. Property → `$filter`. */
|
|
23
|
+
is_unread?: boolean | undefined;
|
|
24
|
+
/** Importance level. Property → `$filter`. */
|
|
25
|
+
importance?: 'low' | 'normal' | 'high' | undefined;
|
|
26
|
+
/** Subject contains (free-text — Graph `$filter` has no `contains` here). */
|
|
27
|
+
subject_contains?: string | undefined;
|
|
28
|
+
/** Body contains (free-text). */
|
|
29
|
+
body_contains?: string | undefined;
|
|
30
|
+
/** Free-text across the message. */
|
|
31
|
+
text?: string | undefined;
|
|
32
|
+
}
|
|
33
|
+
/** The compiled query and which Graph mechanism executes it. */
|
|
34
|
+
export type CompiledSearch = {
|
|
35
|
+
mechanism: 'filter';
|
|
36
|
+
filter: string;
|
|
37
|
+
} | {
|
|
38
|
+
mechanism: 'search';
|
|
39
|
+
search: string;
|
|
40
|
+
} | {
|
|
41
|
+
mechanism: 'searchQuery';
|
|
42
|
+
kql: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Compiles structured params into the correct Graph mechanism + query string.
|
|
46
|
+
* Throws {@link ValidationError} when no criterion is given or a date is malformed.
|
|
47
|
+
*/
|
|
48
|
+
export declare function compileEmailSearch(params: EmailSearchParams): CompiledSearch;
|
|
49
|
+
//# sourceMappingURL=compiler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/search/compiler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,sEAAsE;IACtE,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,4DAA4D;IAC5D,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,8CAA8C;IAC9C,UAAU,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IACnD,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,iCAAiC;IACjC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GACtB;IAAE,SAAS,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,SAAS,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,SAAS,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAI9C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,GAAG,cAAc,CAiB5E"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 JBC Tech Solutions, LLC
|
|
3
|
+
* Licensed under the MIT License. See LICENSE file in the project root.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Structured email-search compiler (U7 / D9). Replaces raw KQL — the #1 observed
|
|
7
|
+
* failure class — with typed params compiled server-side, so correct operator
|
|
8
|
+
* syntax, quoting, and date formatting are code, not model guesswork.
|
|
9
|
+
*
|
|
10
|
+
* Graph makes `$filter` and `$search` mutually exclusive on messages, so:
|
|
11
|
+
* - property-only criteria → `$filter`
|
|
12
|
+
* - free-text-only criteria → quoted `$search`
|
|
13
|
+
* - mixed → server-built KQL for `POST /search/query`
|
|
14
|
+
* (the only single-request path for both at once).
|
|
15
|
+
*
|
|
16
|
+
* Field → mechanism classification below is the documented default; per D9's
|
|
17
|
+
* execution note it is confirmed/refined by a live-mailbox spike before release
|
|
18
|
+
* (Graph's `$filter` has no `contains` on message subject/body, so those are
|
|
19
|
+
* treated as free-text here).
|
|
20
|
+
*/
|
|
21
|
+
import { ValidationError } from '../utils/errors.js';
|
|
22
|
+
const ISO_DATE = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})?)?$/;
|
|
23
|
+
/**
|
|
24
|
+
* Compiles structured params into the correct Graph mechanism + query string.
|
|
25
|
+
* Throws {@link ValidationError} when no criterion is given or a date is malformed.
|
|
26
|
+
*/
|
|
27
|
+
export function compileEmailSearch(params) {
|
|
28
|
+
const filters = buildFilters(params);
|
|
29
|
+
const terms = buildSearchTerms(params);
|
|
30
|
+
if (filters.length === 0 && terms.length === 0) {
|
|
31
|
+
throw new ValidationError('Provide at least one search criterion (e.g. from, subject_contains, received_after, text).');
|
|
32
|
+
}
|
|
33
|
+
if (terms.length === 0) {
|
|
34
|
+
return { mechanism: 'filter', filter: filters.join(' and ') };
|
|
35
|
+
}
|
|
36
|
+
if (filters.length === 0) {
|
|
37
|
+
return { mechanism: 'search', search: quoteSearch(terms) };
|
|
38
|
+
}
|
|
39
|
+
return { mechanism: 'searchQuery', kql: buildKql(params) };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Property criteria → OData `$filter` clauses (order is stable for snapshots).
|
|
43
|
+
* Addressing fields (`from`/`to`) are deliberately NOT here: the D9 live spike
|
|
44
|
+
* showed Graph rejects a recipient `any()` lambda (`ErrorInvalidUrlQueryFilter`)
|
|
45
|
+
* and returns `InefficientFilter` when a sender/flag `$filter` is combined with
|
|
46
|
+
* `$orderby`. So `from`/`to` are handled as `from:`/`to:` in the $search/KQL
|
|
47
|
+
* layer instead, where both work reliably.
|
|
48
|
+
*/
|
|
49
|
+
function buildFilters(p) {
|
|
50
|
+
const out = [];
|
|
51
|
+
if (p.received_after != null) {
|
|
52
|
+
out.push(`receivedDateTime ge ${requireIsoDate(p.received_after, 'received_after')}`);
|
|
53
|
+
}
|
|
54
|
+
if (p.received_before != null) {
|
|
55
|
+
out.push(`receivedDateTime le ${requireIsoDate(p.received_before, 'received_before')}`);
|
|
56
|
+
}
|
|
57
|
+
if (p.has_attachments != null) {
|
|
58
|
+
out.push(`hasAttachments eq ${p.has_attachments ? 'true' : 'false'}`);
|
|
59
|
+
}
|
|
60
|
+
if (p.is_unread != null) {
|
|
61
|
+
out.push(`isRead eq ${p.is_unread ? 'false' : 'true'}`);
|
|
62
|
+
}
|
|
63
|
+
if (p.importance != null) {
|
|
64
|
+
out.push(`importance eq '${p.importance}'`);
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* `$search`/KQL terms. Includes the addressing fields (`from`/`to`) — Graph's
|
|
70
|
+
* `$filter` can't reliably express them (see buildFilters) but the `from:`/`to:`
|
|
71
|
+
* KQL operators work in `$search` and `/search/query` (D9 spike). Order is stable
|
|
72
|
+
* for snapshots.
|
|
73
|
+
*/
|
|
74
|
+
function buildSearchTerms(p) {
|
|
75
|
+
const out = [];
|
|
76
|
+
if (p.from != null && p.from.trim().length > 0) {
|
|
77
|
+
out.push(`from:${p.from.trim()}`);
|
|
78
|
+
}
|
|
79
|
+
if (p.to != null && p.to.trim().length > 0) {
|
|
80
|
+
out.push(`to:${p.to.trim()}`);
|
|
81
|
+
}
|
|
82
|
+
if (p.subject_contains != null && p.subject_contains.trim().length > 0) {
|
|
83
|
+
out.push(`subject:${p.subject_contains.trim()}`);
|
|
84
|
+
}
|
|
85
|
+
if (p.body_contains != null && p.body_contains.trim().length > 0) {
|
|
86
|
+
out.push(`body:${p.body_contains.trim()}`);
|
|
87
|
+
}
|
|
88
|
+
if (p.text != null && p.text.trim().length > 0) {
|
|
89
|
+
out.push(p.text.trim());
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Builds the `$search` value: each term wrapped in a quoted phrase, AND-joined.
|
|
95
|
+
* Embedded double quotes are STRIPPED (not backslash-escaped): Graph's $search
|
|
96
|
+
* has no documented in-phrase escape, so a `"` in a value could otherwise close
|
|
97
|
+
* the phrase early and inject a boolean/property clause.
|
|
98
|
+
*/
|
|
99
|
+
function quoteSearch(terms) {
|
|
100
|
+
return terms.map((t) => kqlPhrase(t)).join(' AND ');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Builds a KQL string for `POST /search/query` combining property and free-text
|
|
104
|
+
* criteria (the only single-request path when both are present). EVERY free
|
|
105
|
+
* value — including from/to — is wrapped as a quoted phrase so a value with
|
|
106
|
+
* whitespace or KQL operators (e.g. `alice@x.com AND body:secret`) cannot inject
|
|
107
|
+
* extra clauses. Dates are day-granular here (KQL range syntax); the $filter
|
|
108
|
+
* path preserves time-of-day, so mixed-mode queries are intentionally
|
|
109
|
+
* day-granular on dates (documented on the tool in U7b).
|
|
110
|
+
*/
|
|
111
|
+
function buildKql(p) {
|
|
112
|
+
const clauses = [];
|
|
113
|
+
if (p.from != null && p.from.length > 0)
|
|
114
|
+
clauses.push(`from:${kqlPhrase(p.from)}`);
|
|
115
|
+
if (p.to != null && p.to.length > 0)
|
|
116
|
+
clauses.push(`to:${kqlPhrase(p.to)}`);
|
|
117
|
+
if (p.received_after != null)
|
|
118
|
+
clauses.push(`received>=${toKqlDate(p.received_after, 'received_after')}`);
|
|
119
|
+
if (p.received_before != null)
|
|
120
|
+
clauses.push(`received<=${toKqlDate(p.received_before, 'received_before')}`);
|
|
121
|
+
if (p.has_attachments != null)
|
|
122
|
+
clauses.push(`hasattachment:${p.has_attachments ? 'true' : 'false'}`);
|
|
123
|
+
if (p.is_unread === true)
|
|
124
|
+
clauses.push('isread:false');
|
|
125
|
+
else if (p.is_unread === false)
|
|
126
|
+
clauses.push('isread:true');
|
|
127
|
+
if (p.importance != null)
|
|
128
|
+
clauses.push(`importance:${p.importance}`);
|
|
129
|
+
if (p.subject_contains != null && p.subject_contains.trim().length > 0) {
|
|
130
|
+
clauses.push(`subject:${kqlPhrase(p.subject_contains.trim())}`);
|
|
131
|
+
}
|
|
132
|
+
if (p.body_contains != null && p.body_contains.trim().length > 0) {
|
|
133
|
+
clauses.push(`body:${kqlPhrase(p.body_contains.trim())}`);
|
|
134
|
+
}
|
|
135
|
+
if (p.text != null && p.text.trim().length > 0) {
|
|
136
|
+
clauses.push(kqlPhrase(p.text.trim()));
|
|
137
|
+
}
|
|
138
|
+
return clauses.join(' AND ');
|
|
139
|
+
}
|
|
140
|
+
function requireIsoDate(value, field) {
|
|
141
|
+
if (!ISO_DATE.test(value) || Number.isNaN(Date.parse(value))) {
|
|
142
|
+
throw invalidDate(field, value);
|
|
143
|
+
}
|
|
144
|
+
// Reject rollover-invalid calendar dates: Date.parse('2026-02-30') is NOT NaN
|
|
145
|
+
// (it rolls to Mar 2), so re-serialize the date part and require an exact
|
|
146
|
+
// match to catch day/month overflow.
|
|
147
|
+
const datePart = value.slice(0, 10);
|
|
148
|
+
if (new Date(`${datePart}T00:00:00Z`).toISOString().slice(0, 10) !== datePart) {
|
|
149
|
+
throw invalidDate(field, value);
|
|
150
|
+
}
|
|
151
|
+
// A bare date becomes midnight UTC so `ge`/`le` compare against a full instant.
|
|
152
|
+
return value.includes('T') ? value : `${value}T00:00:00Z`;
|
|
153
|
+
}
|
|
154
|
+
function invalidDate(field, value) {
|
|
155
|
+
return new ValidationError(`${field} must be a valid ISO date (YYYY-MM-DD) or datetime; got "${value}".`);
|
|
156
|
+
}
|
|
157
|
+
function toKqlDate(value, field) {
|
|
158
|
+
requireIsoDate(value, field);
|
|
159
|
+
return value.slice(0, 10);
|
|
160
|
+
}
|
|
161
|
+
/** Wraps a value as a quoted KQL phrase, stripping embedded double quotes. */
|
|
162
|
+
function kqlPhrase(value) {
|
|
163
|
+
return `"${stripQuotes(value)}"`;
|
|
164
|
+
}
|
|
165
|
+
function stripQuotes(value) {
|
|
166
|
+
return value.replace(/"/g, '');
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=compiler.js.map
|