@cyanheads/mcp-ts-core 0.8.8 → 0.8.10

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 (74) hide show
  1. package/CLAUDE.md +3 -1
  2. package/README.md +4 -1
  3. package/biome.json +1 -1
  4. package/changelog/0.8.x/0.8.10.md +23 -0
  5. package/changelog/0.8.x/0.8.9.md +34 -0
  6. package/dist/config/index.d.ts +51 -15
  7. package/dist/config/index.d.ts.map +1 -1
  8. package/dist/config/index.js +44 -0
  9. package/dist/config/index.js.map +1 -1
  10. package/dist/core/app.d.ts +8 -0
  11. package/dist/core/app.d.ts.map +1 -1
  12. package/dist/core/app.js +11 -0
  13. package/dist/core/app.js.map +1 -1
  14. package/dist/core/worker.d.ts +7 -0
  15. package/dist/core/worker.d.ts.map +1 -1
  16. package/dist/core/worker.js +1 -0
  17. package/dist/core/worker.js.map +1 -1
  18. package/dist/logs/combined.log +4 -4
  19. package/dist/logs/error.log +4 -4
  20. package/dist/services/canvas/core/CanvasInstance.d.ts +43 -0
  21. package/dist/services/canvas/core/CanvasInstance.d.ts.map +1 -0
  22. package/dist/services/canvas/core/CanvasInstance.js +63 -0
  23. package/dist/services/canvas/core/CanvasInstance.js.map +1 -0
  24. package/dist/services/canvas/core/CanvasRegistry.d.ts +96 -0
  25. package/dist/services/canvas/core/CanvasRegistry.d.ts.map +1 -0
  26. package/dist/services/canvas/core/CanvasRegistry.js +250 -0
  27. package/dist/services/canvas/core/CanvasRegistry.js.map +1 -0
  28. package/dist/services/canvas/core/DataCanvas.d.ts +49 -0
  29. package/dist/services/canvas/core/DataCanvas.d.ts.map +1 -0
  30. package/dist/services/canvas/core/DataCanvas.js +85 -0
  31. package/dist/services/canvas/core/DataCanvas.js.map +1 -0
  32. package/dist/services/canvas/core/IDataCanvasProvider.d.ts +47 -0
  33. package/dist/services/canvas/core/IDataCanvasProvider.d.ts.map +1 -0
  34. package/dist/services/canvas/core/IDataCanvasProvider.js +10 -0
  35. package/dist/services/canvas/core/IDataCanvasProvider.js.map +1 -0
  36. package/dist/services/canvas/core/canvasFactory.d.ts +26 -0
  37. package/dist/services/canvas/core/canvasFactory.d.ts.map +1 -0
  38. package/dist/services/canvas/core/canvasFactory.js +63 -0
  39. package/dist/services/canvas/core/canvasFactory.js.map +1 -0
  40. package/dist/services/canvas/core/sqlGate.d.ts +107 -0
  41. package/dist/services/canvas/core/sqlGate.d.ts.map +1 -0
  42. package/dist/services/canvas/core/sqlGate.js +267 -0
  43. package/dist/services/canvas/core/sqlGate.js.map +1 -0
  44. package/dist/services/canvas/index.d.ts +21 -0
  45. package/dist/services/canvas/index.d.ts.map +1 -0
  46. package/dist/services/canvas/index.js +19 -0
  47. package/dist/services/canvas/index.js.map +1 -0
  48. package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts +56 -0
  49. package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -0
  50. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js +600 -0
  51. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js.map +1 -0
  52. package/dist/services/canvas/providers/duckdb/exportWriter.d.ts +48 -0
  53. package/dist/services/canvas/providers/duckdb/exportWriter.d.ts.map +1 -0
  54. package/dist/services/canvas/providers/duckdb/exportWriter.js +119 -0
  55. package/dist/services/canvas/providers/duckdb/exportWriter.js.map +1 -0
  56. package/dist/services/canvas/providers/duckdb/schemaSniffer.d.ts +44 -0
  57. package/dist/services/canvas/providers/duckdb/schemaSniffer.d.ts.map +1 -0
  58. package/dist/services/canvas/providers/duckdb/schemaSniffer.js +134 -0
  59. package/dist/services/canvas/providers/duckdb/schemaSniffer.js.map +1 -0
  60. package/dist/services/canvas/types.d.ts +134 -0
  61. package/dist/services/canvas/types.d.ts.map +1 -0
  62. package/dist/services/canvas/types.js +9 -0
  63. package/dist/services/canvas/types.js.map +1 -0
  64. package/package.json +14 -5
  65. package/skills/add-tool/SKILL.md +1 -0
  66. package/skills/api-canvas/SKILL.md +260 -0
  67. package/skills/api-config/SKILL.md +18 -0
  68. package/skills/api-workers/SKILL.md +6 -0
  69. package/skills/design-mcp-server/SKILL.md +3 -0
  70. package/skills/report-issue-framework/SKILL.md +1 -0
  71. package/skills/report-issue-local/SKILL.md +2 -0
  72. package/skills/security-pass/SKILL.md +24 -0
  73. package/templates/.github/ISSUE_TEMPLATE/bug_report.yml +1 -0
  74. package/templates/.github/ISSUE_TEMPLATE/feature_request.yml +1 -0
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @fileoverview Read-only SQL gate for the DataCanvas primitive. Engine-agnostic
3
+ * pure validators that the provider invokes after pulling DuckDB-specific
4
+ * metadata (statement extraction, prepared-statement type, EXPLAIN plan JSON).
5
+ *
6
+ * Three layers of enforcement, each authoritative on its own:
7
+ *
8
+ * 1. **Single-statement check.** The provider parses the input via DuckDB's
9
+ * `extractStatements` and passes the count here. Anything other than 1 is
10
+ * rejected — comment-hidden second statements, multi-statement smuggling,
11
+ * and Unicode tricks all collapse here because DuckDB's parser is the
12
+ * arbiter, not a regex.
13
+ * 2. **Statement-type check.** The provider prepares the single statement and
14
+ * passes the resulting `statementType`. We require `SELECT`. Any DDL, DML,
15
+ * or utility (PRAGMA/ATTACH/COPY/INSTALL/LOAD/SET/EXECUTE) fails to type as
16
+ * SELECT and is rejected here.
17
+ * 3. **Plan-walk allowlist.** The provider runs `EXPLAIN (FORMAT JSON)` and
18
+ * passes the plan JSON. We walk every node and reject if any operator
19
+ * name is outside the curated allowlist — defense-in-depth against future
20
+ * DuckDB additions that might smuggle work into a SELECT envelope.
21
+ *
22
+ * Rejection paths throw `ValidationError` with a structured `data.reason`
23
+ * suitable for surfacing to the agent.
24
+ *
25
+ * @module src/services/canvas/core/sqlGate
26
+ */
27
+ /**
28
+ * DuckDB statement-type strings emitted by the Neo client. Only `SELECT` is
29
+ * accepted by the canvas. Other values (`INSERT`, `UPDATE`, `DELETE`,
30
+ * `CREATE`, `DROP`, `ALTER`, `COPY`, `PRAGMA`, `ATTACH`, `DETACH`, `LOAD`,
31
+ * `INSTALL`, `SET`, `RESET`, `EXECUTE`, `EXPLAIN`, `TRANSACTION`, `VACUUM`,
32
+ * `CHECKPOINT`, `CALL`, …) are rejected outright. This is a surface — not
33
+ * an enum we own — so the gate matches on the literal string emitted.
34
+ */
35
+ export type DuckdbStatementType = string;
36
+ /** Subset of statement types the gate permits. */
37
+ export declare const ALLOWED_STATEMENT_TYPES: ReadonlySet<DuckdbStatementType>;
38
+ /**
39
+ * Curated allowlist of operator names that can appear in an EXPLAIN plan.
40
+ * Sourced from DuckDB's logical/physical-plan node families (1.5.x). Not
41
+ * every member is reachable from a SELECT — but every member is read-only.
42
+ *
43
+ * Pinned by `tests/canvas/sqlGate.fixtures.test.ts` against live DuckDB
44
+ * EXPLAIN output so version bumps that add operators are caught in CI rather
45
+ * than silently widening the gate.
46
+ *
47
+ * Operators **not** in this list cause rejection. Notable exclusions:
48
+ *
49
+ * - `READ_CSV`, `READ_PARQUET`, `READ_JSON` — bypass canvas, read external files.
50
+ * - `INSERT`, `UPDATE`, `DELETE`, `MERGE`, `CREATE_*`, `DROP_*`, `ALTER_*` — writes.
51
+ * - `COPY_TO_FILE`, `BATCH_COPY_TO_FILE` — exports a SELECT to a file.
52
+ * - `ATTACH`, `DETACH`, `LOAD`, `INSTALL`, `PRAGMA`, `SET`, `RESET` — utility.
53
+ */
54
+ export declare const ALLOWED_PLAN_OPERATORS: ReadonlySet<string>;
55
+ /**
56
+ * Public entry point — validates the trio of `(statementCount, statementType,
57
+ * planJson)`. Throws on the first violation, leaving the provider to pass
58
+ * results back to the caller untouched on success.
59
+ */
60
+ export declare function assertReadOnlyQuery(input: {
61
+ /** Number of statements DuckDB extracted from the user-supplied SQL. */
62
+ statementCount: number;
63
+ /** DuckDB statement type for the (single) prepared statement. */
64
+ statementType: DuckdbStatementType;
65
+ /** Parsed `EXPLAIN (FORMAT JSON)` payload. */
66
+ planJson: unknown;
67
+ }): void;
68
+ /**
69
+ * Pre-EXPLAIN gate: validate statement count and type. Run before the EXPLAIN
70
+ * call so non-SELECT statements (which DuckDB's EXPLAIN can't always wrap —
71
+ * e.g. ATTACH/PRAGMA/COPY/INSTALL) fail with a structured ValidationError
72
+ * here rather than a confusing parser error from EXPLAIN itself.
73
+ */
74
+ export declare function assertSelectOnly(input: {
75
+ statementCount: number;
76
+ statementType: DuckdbStatementType;
77
+ }): void;
78
+ /**
79
+ * Post-EXPLAIN gate: walk the plan tree and reject any operator outside the
80
+ * curated allowlist. Defense-in-depth against future DuckDB additions that
81
+ * smuggle work into a SELECT envelope.
82
+ */
83
+ export declare function assertPlanReadOnly(planJson: unknown): void;
84
+ /**
85
+ * Walks the EXPLAIN plan and returns the set of operator names not in
86
+ * `ALLOWED_PLAN_OPERATORS`. Exported for fixture-driven tests that want
87
+ * to inspect the gate's view of a plan without throwing.
88
+ *
89
+ * Tolerant of structural variation — DuckDB emits operator identity under
90
+ * either `name` (logical plan) or `operator_type` (physical/profile plan)
91
+ * depending on the EXPLAIN flavor. We honor both. Children traversal
92
+ * supports `children`, `child`, and `inputs` arrays.
93
+ */
94
+ export declare function collectDisallowedOperators(planJson: unknown): Set<string>;
95
+ /**
96
+ * Validate an identifier for use as a canvas-local table or column name.
97
+ * Throws `ValidationError` on rejection.
98
+ */
99
+ export declare function assertValidIdentifier(value: string, kind: 'table' | 'column'): void;
100
+ /**
101
+ * Wrap an identifier in double quotes for safe inclusion in SQL. Internal
102
+ * double quotes are doubled per the SQL standard. Callers should still
103
+ * validate via {@link assertValidIdentifier} before quoting — this helper
104
+ * only escapes; it does not validate shape.
105
+ */
106
+ export declare function quoteIdentifier(value: string): string;
107
+ //# sourceMappingURL=sqlGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlGate.d.ts","sourceRoot":"","sources":["../../../../src/services/canvas/core/sqlGate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC,kDAAkD;AAClD,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,mBAAmB,CAAuB,CAAC;AAE7F;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAwDrD,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,wEAAwE;IACxE,cAAc,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,aAAa,EAAE,mBAAmB,CAAC;IACnC,8CAA8C;IAC9C,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,IAAI,CAGP;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,mBAAmB,CAAC;CACpC,GAAG,IAAI,CAaP;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAW1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAIzE;AAsFD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAmBnF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD"}
@@ -0,0 +1,267 @@
1
+ /**
2
+ * @fileoverview Read-only SQL gate for the DataCanvas primitive. Engine-agnostic
3
+ * pure validators that the provider invokes after pulling DuckDB-specific
4
+ * metadata (statement extraction, prepared-statement type, EXPLAIN plan JSON).
5
+ *
6
+ * Three layers of enforcement, each authoritative on its own:
7
+ *
8
+ * 1. **Single-statement check.** The provider parses the input via DuckDB's
9
+ * `extractStatements` and passes the count here. Anything other than 1 is
10
+ * rejected — comment-hidden second statements, multi-statement smuggling,
11
+ * and Unicode tricks all collapse here because DuckDB's parser is the
12
+ * arbiter, not a regex.
13
+ * 2. **Statement-type check.** The provider prepares the single statement and
14
+ * passes the resulting `statementType`. We require `SELECT`. Any DDL, DML,
15
+ * or utility (PRAGMA/ATTACH/COPY/INSTALL/LOAD/SET/EXECUTE) fails to type as
16
+ * SELECT and is rejected here.
17
+ * 3. **Plan-walk allowlist.** The provider runs `EXPLAIN (FORMAT JSON)` and
18
+ * passes the plan JSON. We walk every node and reject if any operator
19
+ * name is outside the curated allowlist — defense-in-depth against future
20
+ * DuckDB additions that might smuggle work into a SELECT envelope.
21
+ *
22
+ * Rejection paths throw `ValidationError` with a structured `data.reason`
23
+ * suitable for surfacing to the agent.
24
+ *
25
+ * @module src/services/canvas/core/sqlGate
26
+ */
27
+ import { validationError } from '../../../types-global/errors.js';
28
+ /** Subset of statement types the gate permits. */
29
+ export const ALLOWED_STATEMENT_TYPES = new Set(['SELECT']);
30
+ /**
31
+ * Curated allowlist of operator names that can appear in an EXPLAIN plan.
32
+ * Sourced from DuckDB's logical/physical-plan node families (1.5.x). Not
33
+ * every member is reachable from a SELECT — but every member is read-only.
34
+ *
35
+ * Pinned by `tests/canvas/sqlGate.fixtures.test.ts` against live DuckDB
36
+ * EXPLAIN output so version bumps that add operators are caught in CI rather
37
+ * than silently widening the gate.
38
+ *
39
+ * Operators **not** in this list cause rejection. Notable exclusions:
40
+ *
41
+ * - `READ_CSV`, `READ_PARQUET`, `READ_JSON` — bypass canvas, read external files.
42
+ * - `INSERT`, `UPDATE`, `DELETE`, `MERGE`, `CREATE_*`, `DROP_*`, `ALTER_*` — writes.
43
+ * - `COPY_TO_FILE`, `BATCH_COPY_TO_FILE` — exports a SELECT to a file.
44
+ * - `ATTACH`, `DETACH`, `LOAD`, `INSTALL`, `PRAGMA`, `SET`, `RESET` — utility.
45
+ */
46
+ export const ALLOWED_PLAN_OPERATORS = new Set([
47
+ // Scans (registered tables only — file scans like READ_CSV are excluded)
48
+ 'SEQ_SCAN',
49
+ 'COLUMN_DATA_SCAN',
50
+ 'CHUNK_SCAN',
51
+ 'EXPRESSION_SCAN',
52
+ 'DUMMY_SCAN',
53
+ 'EMPTY_RESULT',
54
+ 'IN_MEMORY_TABLE_SCAN',
55
+ // Projection / filter
56
+ 'PROJECTION',
57
+ 'FILTER',
58
+ // Joins
59
+ 'HASH_JOIN',
60
+ 'NESTED_LOOP_JOIN',
61
+ 'BLOCKWISE_NL_JOIN',
62
+ 'IE_JOIN',
63
+ 'PIECEWISE_MERGE_JOIN',
64
+ 'CROSS_PRODUCT',
65
+ 'POSITIONAL_JOIN',
66
+ 'ASOF_JOIN',
67
+ 'DELIM_JOIN',
68
+ // Aggregates
69
+ 'HASH_GROUP_BY',
70
+ 'PERFECT_HASH_GROUP_BY',
71
+ 'UNGROUPED_AGGREGATE',
72
+ 'SIMPLE_AGGREGATE',
73
+ 'PARTITIONED_AGGREGATE',
74
+ // Distinct / set ops
75
+ 'HASH_DISTINCT',
76
+ 'DISTINCT',
77
+ 'UNION',
78
+ // Sorting / limits
79
+ 'ORDER_BY',
80
+ 'TOP_N',
81
+ 'LIMIT',
82
+ 'LIMIT_PERCENT',
83
+ 'STREAMING_LIMIT',
84
+ // Window
85
+ 'WINDOW',
86
+ // Nested
87
+ 'UNNEST',
88
+ // CTEs
89
+ 'CTE',
90
+ 'CTE_REF',
91
+ 'RECURSIVE_CTE',
92
+ 'MATERIALIZED_CTE',
93
+ // Sampling
94
+ 'RESERVOIR_SAMPLE',
95
+ 'SAMPLE',
96
+ 'STREAMING_SAMPLE',
97
+ // Result framing
98
+ 'RESULT_COLLECTOR',
99
+ 'EXPLAIN',
100
+ // Pivot/unpivot collapsed planner forms
101
+ 'PIVOT',
102
+ ]);
103
+ /**
104
+ * Public entry point — validates the trio of `(statementCount, statementType,
105
+ * planJson)`. Throws on the first violation, leaving the provider to pass
106
+ * results back to the caller untouched on success.
107
+ */
108
+ export function assertReadOnlyQuery(input) {
109
+ assertSelectOnly(input);
110
+ assertPlanReadOnly(input.planJson);
111
+ }
112
+ /**
113
+ * Pre-EXPLAIN gate: validate statement count and type. Run before the EXPLAIN
114
+ * call so non-SELECT statements (which DuckDB's EXPLAIN can't always wrap —
115
+ * e.g. ATTACH/PRAGMA/COPY/INSTALL) fail with a structured ValidationError
116
+ * here rather than a confusing parser error from EXPLAIN itself.
117
+ */
118
+ export function assertSelectOnly(input) {
119
+ if (input.statementCount !== 1) {
120
+ throw validationError('Canvas query must contain exactly one SQL statement.', {
121
+ reason: 'multi_statement',
122
+ statementCount: input.statementCount,
123
+ });
124
+ }
125
+ if (!ALLOWED_STATEMENT_TYPES.has(input.statementType)) {
126
+ throw validationError(`Canvas query must be SELECT; got ${input.statementType}. Mutations must use registerTable, drop, or clear.`, { reason: 'non_select_statement', statementType: input.statementType });
127
+ }
128
+ }
129
+ /**
130
+ * Post-EXPLAIN gate: walk the plan tree and reject any operator outside the
131
+ * curated allowlist. Defense-in-depth against future DuckDB additions that
132
+ * smuggle work into a SELECT envelope.
133
+ */
134
+ export function assertPlanReadOnly(planJson) {
135
+ const offending = collectDisallowedOperators(planJson);
136
+ if (offending.size > 0) {
137
+ throw validationError(`Canvas query contains disallowed operators: ${[...offending].sort().join(', ')}.`, {
138
+ reason: 'plan_operator_not_allowed',
139
+ operators: [...offending].sort(),
140
+ });
141
+ }
142
+ }
143
+ /**
144
+ * Walks the EXPLAIN plan and returns the set of operator names not in
145
+ * `ALLOWED_PLAN_OPERATORS`. Exported for fixture-driven tests that want
146
+ * to inspect the gate's view of a plan without throwing.
147
+ *
148
+ * Tolerant of structural variation — DuckDB emits operator identity under
149
+ * either `name` (logical plan) or `operator_type` (physical/profile plan)
150
+ * depending on the EXPLAIN flavor. We honor both. Children traversal
151
+ * supports `children`, `child`, and `inputs` arrays.
152
+ */
153
+ export function collectDisallowedOperators(planJson) {
154
+ const offending = new Set();
155
+ walk(planJson, offending);
156
+ return offending;
157
+ }
158
+ function walk(node, offending) {
159
+ if (node === null || typeof node !== 'object')
160
+ return;
161
+ if (Array.isArray(node)) {
162
+ for (const child of node)
163
+ walk(child, offending);
164
+ return;
165
+ }
166
+ const obj = node;
167
+ const operator = readOperatorName(obj);
168
+ if (operator !== undefined && !ALLOWED_PLAN_OPERATORS.has(operator)) {
169
+ offending.add(operator);
170
+ }
171
+ // Traverse known child slots; ignore string/number leaves.
172
+ for (const key of ['children', 'child', 'inputs', 'plan', 'root']) {
173
+ if (key in obj)
174
+ walk(obj[key], offending);
175
+ }
176
+ }
177
+ function readOperatorName(obj) {
178
+ const candidates = ['name', 'operator_type', 'operator', 'type'];
179
+ for (const key of candidates) {
180
+ const value = obj[key];
181
+ if (typeof value === 'string' && value !== '') {
182
+ return value.toUpperCase();
183
+ }
184
+ }
185
+ return;
186
+ }
187
+ // ---------------------------------------------------------------------------
188
+ // Identifier validation and quoting
189
+ // ---------------------------------------------------------------------------
190
+ /**
191
+ * Allowed shape for canvas-local table and column names. Matches the
192
+ * conservative SQL identifier convention: starts with letter/underscore,
193
+ * followed by letters/digits/underscores, max 63 chars (PostgreSQL/DuckDB cap).
194
+ */
195
+ const IDENTIFIER_REGEX = /^[A-Za-z_][A-Za-z0-9_]{0,62}$/;
196
+ /**
197
+ * DuckDB reserved words that must not be used as bare identifiers. Not
198
+ * exhaustive — this is a courtesy guard so misnamed tables fail at register
199
+ * time rather than confusing-error time. The `IDENTIFIER_REGEX` is the
200
+ * authoritative shape gate.
201
+ */
202
+ const RESERVED_IDENTIFIERS = new Set([
203
+ 'select',
204
+ 'from',
205
+ 'where',
206
+ 'order',
207
+ 'group',
208
+ 'having',
209
+ 'limit',
210
+ 'offset',
211
+ 'union',
212
+ 'intersect',
213
+ 'except',
214
+ 'all',
215
+ 'distinct',
216
+ 'as',
217
+ 'and',
218
+ 'or',
219
+ 'not',
220
+ 'null',
221
+ 'true',
222
+ 'false',
223
+ 'case',
224
+ 'when',
225
+ 'then',
226
+ 'else',
227
+ 'end',
228
+ 'join',
229
+ 'inner',
230
+ 'outer',
231
+ 'left',
232
+ 'right',
233
+ 'full',
234
+ 'cross',
235
+ 'on',
236
+ 'using',
237
+ 'with',
238
+ 'recursive',
239
+ ]);
240
+ /**
241
+ * Validate an identifier for use as a canvas-local table or column name.
242
+ * Throws `ValidationError` on rejection.
243
+ */
244
+ export function assertValidIdentifier(value, kind) {
245
+ if (typeof value !== 'string' || value.length === 0) {
246
+ throw validationError(`Canvas ${kind} name must be a non-empty string.`, {
247
+ reason: 'identifier_empty',
248
+ kind,
249
+ });
250
+ }
251
+ if (!IDENTIFIER_REGEX.test(value)) {
252
+ throw validationError(`Canvas ${kind} name "${value}" is invalid. Use letters, digits, and underscores; must start with a letter or underscore; max 63 chars.`, { reason: 'identifier_shape', kind, value });
253
+ }
254
+ if (RESERVED_IDENTIFIERS.has(value.toLowerCase())) {
255
+ throw validationError(`Canvas ${kind} name "${value}" is a reserved SQL keyword. Choose another name.`, { reason: 'identifier_reserved', kind, value });
256
+ }
257
+ }
258
+ /**
259
+ * Wrap an identifier in double quotes for safe inclusion in SQL. Internal
260
+ * double quotes are doubled per the SQL standard. Callers should still
261
+ * validate via {@link assertValidIdentifier} before quoting — this helper
262
+ * only escapes; it does not validate shape.
263
+ */
264
+ export function quoteIdentifier(value) {
265
+ return `"${value.replace(/"/g, '""')}"`;
266
+ }
267
+ //# sourceMappingURL=sqlGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlGate.js","sourceRoot":"","sources":["../../../../src/services/canvas/core/sqlGate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @fileoverview Public barrel for the DataCanvas primitive. Servers import
3
+ * from `@cyanheads/mcp-ts-core/canvas` to interact with `core.canvas` —
4
+ * either via tool handlers (acquire → register → query → export) or directly
5
+ * for advanced lifecycle work.
6
+ *
7
+ * The DuckDB provider is lazy-loaded; pulling this barrel does not pull in
8
+ * `@duckdb/node-api` until {@link DataCanvas.acquire} runs against an active
9
+ * canvas configuration.
10
+ *
11
+ * @module src/services/canvas/index
12
+ */
13
+ export { CanvasInstance } from './core/CanvasInstance.js';
14
+ export { type AcquireResult, CanvasRegistry, type CanvasRegistryOptions, DEFAULT_CANVAS_REGISTRY_OPTIONS, } from './core/CanvasRegistry.js';
15
+ export { createCanvasService } from './core/canvasFactory.js';
16
+ export { DataCanvas } from './core/DataCanvas.js';
17
+ export type { IDataCanvasProvider } from './core/IDataCanvasProvider.js';
18
+ export { ALLOWED_PLAN_OPERATORS, ALLOWED_STATEMENT_TYPES, assertReadOnlyQuery, assertValidIdentifier, collectDisallowedOperators, type DuckdbStatementType, quoteIdentifier, } from './core/sqlGate.js';
19
+ export { DuckdbProvider, type DuckdbProviderOptions, } from './providers/duckdb/DuckdbProvider.js';
20
+ export type { AcquireOptions, ColumnSchema, ColumnType, DescribeOptions, ExportFormat, ExportOptions, ExportResult, ExportTarget, QueryOptions, QueryResult, RegisterRows, RegisterTableOptions, RegisterTableResult, TableInfo, } from './types.js';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/canvas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EACL,KAAK,aAAa,EAClB,cAAc,EACd,KAAK,qBAAqB,EAC1B,+BAA+B,GAChC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,mBAAmB,EACxB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EACV,cAAc,EACd,YAAY,EACZ,UAAU,EACV,eAAe,EACf,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,mBAAmB,EACnB,SAAS,GACV,MAAM,YAAY,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @fileoverview Public barrel for the DataCanvas primitive. Servers import
3
+ * from `@cyanheads/mcp-ts-core/canvas` to interact with `core.canvas` —
4
+ * either via tool handlers (acquire → register → query → export) or directly
5
+ * for advanced lifecycle work.
6
+ *
7
+ * The DuckDB provider is lazy-loaded; pulling this barrel does not pull in
8
+ * `@duckdb/node-api` until {@link DataCanvas.acquire} runs against an active
9
+ * canvas configuration.
10
+ *
11
+ * @module src/services/canvas/index
12
+ */
13
+ export { CanvasInstance } from './core/CanvasInstance.js';
14
+ export { CanvasRegistry, DEFAULT_CANVAS_REGISTRY_OPTIONS, } from './core/CanvasRegistry.js';
15
+ export { createCanvasService } from './core/canvasFactory.js';
16
+ export { DataCanvas } from './core/DataCanvas.js';
17
+ export { ALLOWED_PLAN_OPERATORS, ALLOWED_STATEMENT_TYPES, assertReadOnlyQuery, assertValidIdentifier, collectDisallowedOperators, quoteIdentifier, } from './core/sqlGate.js';
18
+ export { DuckdbProvider, } from './providers/duckdb/DuckdbProvider.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/canvas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAEL,cAAc,EAEd,+BAA+B,GAChC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAE1B,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,cAAc,GAEf,MAAM,sCAAsC,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fileoverview DuckDB-backed implementation of {@link IDataCanvasProvider}.
3
+ * One DuckDB instance per canvasId for memory isolation; a shared connection
4
+ * for control-plane work (DDL, describe, drop) and per-query connections for
5
+ * data-plane work so that {@link DuckDBConnection.interrupt} cancels exactly
6
+ * the in-flight query without disturbing concurrent ops on the same canvas.
7
+ *
8
+ * Lazy-loaded via {@link lazyImport} so `@duckdb/node-api` stays a true peer
9
+ * dependency — servers that don't enable canvas pay no install cost.
10
+ *
11
+ * @module src/services/canvas/providers/duckdb/DuckdbProvider
12
+ */
13
+ import { type RequestContext } from '../../../../utils/internal/requestContext.js';
14
+ import type { IDataCanvasProvider } from '../../core/IDataCanvasProvider.js';
15
+ import type { DescribeOptions, ExportOptions, ExportResult, ExportTarget, QueryOptions, QueryResult, RegisterRows, RegisterTableOptions, RegisterTableResult, TableInfo } from '../../types.js';
16
+ /** Configuration for {@link DuckdbProvider}. Mirrors the AppConfig.canvas block. */
17
+ export interface DuckdbProviderOptions {
18
+ /** Default row cap for `query()` results. */
19
+ defaultRowLimit: number;
20
+ /** Sandbox root for path-targeted exports. */
21
+ exportRootPath: string;
22
+ /** Per-canvas `memory_limit` PRAGMA value, in MB. */
23
+ memoryLimitMb: number;
24
+ /** Number of rows to sniff for schema inference. */
25
+ schemaSniffRows: number;
26
+ }
27
+ /** DuckDB SELECT statement-type id (matches `StatementType.SELECT === 1`). */
28
+ declare const STATEMENT_TYPE_SELECT_ID = 1;
29
+ export declare class DuckdbProvider implements IDataCanvasProvider {
30
+ private readonly options;
31
+ readonly name = "duckdb";
32
+ private duck;
33
+ private readonly canvases;
34
+ constructor(options: DuckdbProviderOptions);
35
+ initCanvas(canvasId: string, _context: RequestContext): Promise<void>;
36
+ destroyCanvas(canvasId: string, _context: RequestContext): Promise<void>;
37
+ healthCheck(): Promise<boolean>;
38
+ shutdown(): Promise<void>;
39
+ registerTable(canvasId: string, name: string, rows: RegisterRows, _context: RequestContext, options?: RegisterTableOptions): Promise<RegisterTableResult>;
40
+ query(canvasId: string, sql: string, _context: RequestContext, options?: QueryOptions): Promise<QueryResult>;
41
+ export(canvasId: string, tableName: string, target: ExportTarget, _context: RequestContext, options?: ExportOptions): Promise<ExportResult>;
42
+ describe(canvasId: string, _context: RequestContext, options?: DescribeOptions): Promise<TableInfo[]>;
43
+ drop(canvasId: string, name: string, _context: RequestContext): Promise<boolean>;
44
+ clear(canvasId: string, _context: RequestContext): Promise<number>;
45
+ private requireCanvas;
46
+ private getModule;
47
+ private runExplain;
48
+ }
49
+ /** Re-export for tests and consumer-side parsing. */
50
+ export { STATEMENT_TYPE_SELECT_ID };
51
+ /**
52
+ * Map a DuckDB-thrown error to a framework error class.
53
+ * @internal Exported for unit testing — not re-exported from the canvas barrel.
54
+ */
55
+ export declare function classifyDuckdbError(err: unknown): Error;
56
+ //# sourceMappingURL=DuckdbProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DuckdbProvider.d.ts","sourceRoot":"","sources":["../../../../../src/services/canvas/providers/duckdb/DuckdbProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAAE,KAAK,cAAc,EAAyB,MAAM,oCAAoC,CAAC;AAEhG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAO7E,OAAO,KAAK,EAGV,eAAe,EACf,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,mBAAmB,EACnB,SAAS,EACV,MAAM,gBAAgB,CAAC;AAqBxB,oFAAoF;AACpF,MAAM,WAAW,qBAAqB;IACpC,6CAA6C;IAC7C,eAAe,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,cAAc,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,8EAA8E;AAC9E,QAAA,MAAM,wBAAwB,IAAI,CAAC;AAQnC,qBAAa,cAAe,YAAW,mBAAmB;IAM5C,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpC,QAAQ,CAAC,IAAI,YAAY;IAEzB,OAAO,CAAC,IAAI,CAA2B;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;gBAE/B,OAAO,EAAE,qBAAqB;IAMrD,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBrE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BxE,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAc/B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAczB,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,CAAC;IAoFzB,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,WAAW,CAAC;IAsGjB,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,CAAC;IA8DlB,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,SAAS,EAAE,CAAC;IA2CjB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAWhF,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBxE,OAAO,CAAC,aAAa;YAQP,SAAS;YAKT,UAAU;CAezB;AAsHD,qDAAqD;AACrD,OAAO,EAAE,wBAAwB,EAAE,CAAC;AA4EpC;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,CA0BvD"}