@cyanheads/mcp-ts-core 0.8.7 → 0.8.9
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/CLAUDE.md +2 -0
- package/README.md +1 -1
- package/biome.json +1 -1
- package/changelog/0.8.x/0.8.8.md +11 -0
- package/changelog/0.8.x/0.8.9.md +34 -0
- package/dist/canvas/core/CanvasInstance.d.ts +43 -0
- package/dist/canvas/core/CanvasInstance.d.ts.map +1 -0
- package/dist/canvas/core/CanvasInstance.js +63 -0
- package/dist/canvas/core/CanvasInstance.js.map +1 -0
- package/dist/canvas/core/CanvasRegistry.d.ts +96 -0
- package/dist/canvas/core/CanvasRegistry.d.ts.map +1 -0
- package/dist/canvas/core/CanvasRegistry.js +250 -0
- package/dist/canvas/core/CanvasRegistry.js.map +1 -0
- package/dist/canvas/core/DataCanvas.d.ts +49 -0
- package/dist/canvas/core/DataCanvas.d.ts.map +1 -0
- package/dist/canvas/core/DataCanvas.js +85 -0
- package/dist/canvas/core/DataCanvas.js.map +1 -0
- package/dist/canvas/core/IDataCanvasProvider.d.ts +47 -0
- package/dist/canvas/core/IDataCanvasProvider.d.ts.map +1 -0
- package/dist/canvas/core/IDataCanvasProvider.js +10 -0
- package/dist/canvas/core/IDataCanvasProvider.js.map +1 -0
- package/dist/canvas/core/canvasFactory.d.ts +26 -0
- package/dist/canvas/core/canvasFactory.d.ts.map +1 -0
- package/dist/canvas/core/canvasFactory.js +63 -0
- package/dist/canvas/core/canvasFactory.js.map +1 -0
- package/dist/canvas/core/sqlGate.d.ts +107 -0
- package/dist/canvas/core/sqlGate.d.ts.map +1 -0
- package/dist/canvas/core/sqlGate.js +267 -0
- package/dist/canvas/core/sqlGate.js.map +1 -0
- package/dist/canvas/index.d.ts +21 -0
- package/dist/canvas/index.d.ts.map +1 -0
- package/dist/canvas/index.js +19 -0
- package/dist/canvas/index.js.map +1 -0
- package/dist/canvas/providers/duckdb/DuckdbProvider.d.ts +56 -0
- package/dist/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -0
- package/dist/canvas/providers/duckdb/DuckdbProvider.js +600 -0
- package/dist/canvas/providers/duckdb/DuckdbProvider.js.map +1 -0
- package/dist/canvas/providers/duckdb/exportWriter.d.ts +48 -0
- package/dist/canvas/providers/duckdb/exportWriter.d.ts.map +1 -0
- package/dist/canvas/providers/duckdb/exportWriter.js +119 -0
- package/dist/canvas/providers/duckdb/exportWriter.js.map +1 -0
- package/dist/canvas/providers/duckdb/schemaSniffer.d.ts +44 -0
- package/dist/canvas/providers/duckdb/schemaSniffer.d.ts.map +1 -0
- package/dist/canvas/providers/duckdb/schemaSniffer.js +134 -0
- package/dist/canvas/providers/duckdb/schemaSniffer.js.map +1 -0
- package/dist/canvas/types.d.ts +134 -0
- package/dist/canvas/types.d.ts.map +1 -0
- package/dist/canvas/types.js +9 -0
- package/dist/canvas/types.js.map +1 -0
- package/dist/config/index.d.ts +51 -15
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +44 -0
- package/dist/config/index.js.map +1 -1
- package/dist/core/app.d.ts +8 -0
- package/dist/core/app.d.ts.map +1 -1
- package/dist/core/app.js +11 -0
- package/dist/core/app.js.map +1 -1
- package/dist/core/worker.d.ts +7 -0
- package/dist/core/worker.d.ts.map +1 -1
- package/dist/core/worker.js +1 -0
- package/dist/core/worker.js.map +1 -1
- package/dist/logs/combined.log +4 -4
- package/dist/logs/error.log +4 -4
- package/dist/storage/core/storageValidation.d.ts.map +1 -1
- package/dist/storage/core/storageValidation.js +7 -1
- package/dist/storage/core/storageValidation.js.map +1 -1
- package/dist/utils/internal/error-handler/errorHandler.d.ts.map +1 -1
- package/dist/utils/internal/error-handler/errorHandler.js +2 -1
- package/dist/utils/internal/error-handler/errorHandler.js.map +1 -1
- package/package.json +18 -8
- package/skills/api-canvas/SKILL.md +260 -0
- package/skills/api-config/SKILL.md +18 -0
- package/skills/api-workers/SKILL.md +6 -0
- package/skills/report-issue-framework/SKILL.md +1 -0
- package/skills/report-issue-local/SKILL.md +2 -0
- package/templates/.github/ISSUE_TEMPLATE/bug_report.yml +1 -0
- package/templates/.github/ISSUE_TEMPLATE/feature_request.yml +1 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Path resolution and sandboxing for canvas export targets.
|
|
3
|
+
*
|
|
4
|
+
* Refinement #1 in issue #97: path-based exports must be sandboxed to
|
|
5
|
+
* `CANVAS_EXPORT_PATH`. Absolute paths and `..` traversal are rejected;
|
|
6
|
+
* the resolved path is always inside the sandbox root. Stream-based exports
|
|
7
|
+
* write to a temp file inside the sandbox and pipe its bytes to the caller's
|
|
8
|
+
* `WritableStream`, then unlink the temp file.
|
|
9
|
+
*
|
|
10
|
+
* @module src/canvas/providers/duckdb/exportWriter
|
|
11
|
+
*/
|
|
12
|
+
import type { ExportFormat, ExportTarget } from '../../types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a caller-supplied relative path against the sandbox root, refusing
|
|
15
|
+
* absolute inputs and traversal escapes. Always returns an absolute path
|
|
16
|
+
* that is, by post-condition, a descendant of `rootPath`.
|
|
17
|
+
*
|
|
18
|
+
* The sandbox root itself is created if missing.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveExportPath(rootPath: string, requested: string): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Map an export format to its DuckDB `COPY ... TO` `(FORMAT ...)` clause.
|
|
23
|
+
* JSON uses DuckDB's `JSON` format (line-delimited JSON by default).
|
|
24
|
+
*/
|
|
25
|
+
export declare function copyFormatClause(format: ExportFormat): string;
|
|
26
|
+
/**
|
|
27
|
+
* Pipe a written sandbox file into a caller-supplied `WritableStream`,
|
|
28
|
+
* unlinking the temp file when finished. Used for the stream branch of
|
|
29
|
+
* {@link ExportTarget}.
|
|
30
|
+
*/
|
|
31
|
+
export declare function pipeFileToStream(filePath: string, stream: WritableStream<Uint8Array>): Promise<{
|
|
32
|
+
sizeBytes: number;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Generate a unique temp file path inside the sandbox for stream-based exports.
|
|
36
|
+
* Creates the sandbox root if missing so the caller can write immediately.
|
|
37
|
+
*/
|
|
38
|
+
export declare function tempFilePathFor(rootPath: string, format: ExportFormat): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Best-effort size lookup for a written file. Returns 0 if `stat` fails.
|
|
41
|
+
*/
|
|
42
|
+
export declare function safeSizeBytes(path: string): Promise<number>;
|
|
43
|
+
/** Discriminator for {@link ExportTarget}. */
|
|
44
|
+
export declare function isPathTarget(target: ExportTarget): target is {
|
|
45
|
+
format: ExportFormat;
|
|
46
|
+
path: string;
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=exportWriter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exportWriter.d.ts","sourceRoot":"","sources":["../../../../src/canvas/providers/duckdb/exportWriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEjE;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB5F;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAS7D;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GACjC,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BhC;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAM7F;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOjE;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAC1B,MAAM,EAAE,YAAY,GACnB,MAAM,IAAI;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAElD"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Path resolution and sandboxing for canvas export targets.
|
|
3
|
+
*
|
|
4
|
+
* Refinement #1 in issue #97: path-based exports must be sandboxed to
|
|
5
|
+
* `CANVAS_EXPORT_PATH`. Absolute paths and `..` traversal are rejected;
|
|
6
|
+
* the resolved path is always inside the sandbox root. Stream-based exports
|
|
7
|
+
* write to a temp file inside the sandbox and pipe its bytes to the caller's
|
|
8
|
+
* `WritableStream`, then unlink the temp file.
|
|
9
|
+
*
|
|
10
|
+
* @module src/canvas/providers/duckdb/exportWriter
|
|
11
|
+
*/
|
|
12
|
+
import { mkdir, open, stat, unlink } from 'node:fs/promises';
|
|
13
|
+
import { isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
14
|
+
import { validationError } from '../../../types-global/errors.js';
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a caller-supplied relative path against the sandbox root, refusing
|
|
17
|
+
* absolute inputs and traversal escapes. Always returns an absolute path
|
|
18
|
+
* that is, by post-condition, a descendant of `rootPath`.
|
|
19
|
+
*
|
|
20
|
+
* The sandbox root itself is created if missing.
|
|
21
|
+
*/
|
|
22
|
+
export async function resolveExportPath(rootPath, requested) {
|
|
23
|
+
if (typeof requested !== 'string' || requested.length === 0) {
|
|
24
|
+
throw validationError('Export path must be a non-empty string.', {
|
|
25
|
+
reason: 'export_path_empty',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
if (isAbsolute(requested)) {
|
|
29
|
+
throw validationError('Export path must be relative — absolute paths are rejected to keep writes inside the canvas sandbox.', { reason: 'export_path_absolute', requested });
|
|
30
|
+
}
|
|
31
|
+
const root = resolve(rootPath);
|
|
32
|
+
const candidate = resolve(root, requested);
|
|
33
|
+
const rel = relative(root, candidate);
|
|
34
|
+
if (rel.startsWith(`..${sep}`) || rel === '..') {
|
|
35
|
+
throw validationError('Export path escapes the canvas sandbox. Use a path inside CANVAS_EXPORT_PATH.', { reason: 'export_path_escapes', requested });
|
|
36
|
+
}
|
|
37
|
+
await mkdir(root, { recursive: true });
|
|
38
|
+
return candidate;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Map an export format to its DuckDB `COPY ... TO` `(FORMAT ...)` clause.
|
|
42
|
+
* JSON uses DuckDB's `JSON` format (line-delimited JSON by default).
|
|
43
|
+
*/
|
|
44
|
+
export function copyFormatClause(format) {
|
|
45
|
+
switch (format) {
|
|
46
|
+
case 'csv':
|
|
47
|
+
return "(FORMAT 'csv', HEADER true)";
|
|
48
|
+
case 'parquet':
|
|
49
|
+
return "(FORMAT 'parquet')";
|
|
50
|
+
case 'json':
|
|
51
|
+
return "(FORMAT 'json')";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Pipe a written sandbox file into a caller-supplied `WritableStream`,
|
|
56
|
+
* unlinking the temp file when finished. Used for the stream branch of
|
|
57
|
+
* {@link ExportTarget}.
|
|
58
|
+
*/
|
|
59
|
+
export async function pipeFileToStream(filePath, stream) {
|
|
60
|
+
const writer = stream.getWriter();
|
|
61
|
+
let total = 0;
|
|
62
|
+
try {
|
|
63
|
+
const handle = await open(filePath, 'r');
|
|
64
|
+
try {
|
|
65
|
+
const chunkSize = 64 * 1024;
|
|
66
|
+
const buffer = new Uint8Array(chunkSize);
|
|
67
|
+
while (true) {
|
|
68
|
+
const { bytesRead } = await handle.read(buffer, 0, chunkSize, null);
|
|
69
|
+
if (bytesRead === 0)
|
|
70
|
+
break;
|
|
71
|
+
// Slice owns its bytes — safe to pass to the writer.
|
|
72
|
+
await writer.write(buffer.slice(0, bytesRead));
|
|
73
|
+
total += bytesRead;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
await handle.close();
|
|
78
|
+
}
|
|
79
|
+
await writer.close();
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
await writer.abort(err);
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
await unlink(filePath).catch(() => {
|
|
87
|
+
// Best-effort cleanup — file may already be gone if abort raced.
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return { sizeBytes: total };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Generate a unique temp file path inside the sandbox for stream-based exports.
|
|
94
|
+
* Creates the sandbox root if missing so the caller can write immediately.
|
|
95
|
+
*/
|
|
96
|
+
export async function tempFilePathFor(rootPath, format) {
|
|
97
|
+
const root = resolve(rootPath);
|
|
98
|
+
await mkdir(root, { recursive: true });
|
|
99
|
+
const stamp = Date.now().toString(36);
|
|
100
|
+
const rand = Math.random().toString(36).slice(2, 10);
|
|
101
|
+
return join(root, `.canvas-export-${stamp}-${rand}.${format}`);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Best-effort size lookup for a written file. Returns 0 if `stat` fails.
|
|
105
|
+
*/
|
|
106
|
+
export async function safeSizeBytes(path) {
|
|
107
|
+
try {
|
|
108
|
+
const info = await stat(path);
|
|
109
|
+
return info.size;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** Discriminator for {@link ExportTarget}. */
|
|
116
|
+
export function isPathTarget(target) {
|
|
117
|
+
return 'path' in target;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=exportWriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exportWriter.js","sourceRoot":"","sources":["../../../../src/canvas/providers/duckdb/exportWriter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Schema inference for {@link DuckdbProvider.registerTable}.
|
|
3
|
+
* Materializes the first N rows of an iterable, unions JS-side types per
|
|
4
|
+
* column, and maps to DuckDB column types. Used only when the caller does
|
|
5
|
+
* not pass an explicit `schema` to `registerTable`. For `AsyncIterable`
|
|
6
|
+
* inputs the caller must supply a schema — we cannot peek without consuming.
|
|
7
|
+
*
|
|
8
|
+
* Algorithm (refinement 4 in issue #97):
|
|
9
|
+
* 1. Buffer up to `sniffRowCount` rows (default 100).
|
|
10
|
+
* 2. For each column, take the union of observed JS-side types
|
|
11
|
+
* (`string`, `number-int`, `number-float`, `bigint`, `boolean`, `null`,
|
|
12
|
+
* `object`).
|
|
13
|
+
* 3. Map the union to a DuckDB type via {@link unionToDuckdbType}, with
|
|
14
|
+
* `VARCHAR` as the safe fallback when the union has no clean answer.
|
|
15
|
+
* 4. Return `(schema, sniffedRows)` so the caller can append the buffered
|
|
16
|
+
* rows without re-iterating.
|
|
17
|
+
*
|
|
18
|
+
* @module src/canvas/providers/duckdb/schemaSniffer
|
|
19
|
+
*/
|
|
20
|
+
import type { ColumnSchema } from '../../types.js';
|
|
21
|
+
/** Row-shape used internally — mirrors what registerTable accepts. */
|
|
22
|
+
type Row = Record<string, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* Outcome of a sniff: the inferred schema plus the buffered rows we consumed
|
|
25
|
+
* from the iterable. Callers append `sniffedRows` first, then continue
|
|
26
|
+
* draining whatever's left of the iterator.
|
|
27
|
+
*/
|
|
28
|
+
export interface SniffedSchema {
|
|
29
|
+
schema: ColumnSchema[];
|
|
30
|
+
/** Rows already consumed from the iterable. Append these first. */
|
|
31
|
+
sniffedRows: Row[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Materialize up to `sniffRowCount` rows from the iterable and return the
|
|
35
|
+
* inferred schema plus the buffered rows. Throws if the input is empty.
|
|
36
|
+
*
|
|
37
|
+
* Column ordering is determined by first-appearance across the buffered rows
|
|
38
|
+
* — column names from the first row come first, then any new keys added by
|
|
39
|
+
* later rows (each appended in observation order). Missing keys in any row
|
|
40
|
+
* count as `null` for type inference purposes.
|
|
41
|
+
*/
|
|
42
|
+
export declare function sniffSchema(iterable: Iterable<Row>, sniffRowCount: number): SniffedSchema;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=schemaSniffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaSniffer.d.ts","sourceRoot":"","sources":["../../../../src/canvas/providers/duckdb/schemaSniffer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,gBAAgB,CAAC;AAE/D,sEAAsE;AACtE,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnC;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,mEAAmE;IACnE,WAAW,EAAE,GAAG,EAAE,CAAC;CACpB;AA6DD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,EAAE,MAAM,GAAG,aAAa,CAiDzF"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Schema inference for {@link DuckdbProvider.registerTable}.
|
|
3
|
+
* Materializes the first N rows of an iterable, unions JS-side types per
|
|
4
|
+
* column, and maps to DuckDB column types. Used only when the caller does
|
|
5
|
+
* not pass an explicit `schema` to `registerTable`. For `AsyncIterable`
|
|
6
|
+
* inputs the caller must supply a schema — we cannot peek without consuming.
|
|
7
|
+
*
|
|
8
|
+
* Algorithm (refinement 4 in issue #97):
|
|
9
|
+
* 1. Buffer up to `sniffRowCount` rows (default 100).
|
|
10
|
+
* 2. For each column, take the union of observed JS-side types
|
|
11
|
+
* (`string`, `number-int`, `number-float`, `bigint`, `boolean`, `null`,
|
|
12
|
+
* `object`).
|
|
13
|
+
* 3. Map the union to a DuckDB type via {@link unionToDuckdbType}, with
|
|
14
|
+
* `VARCHAR` as the safe fallback when the union has no clean answer.
|
|
15
|
+
* 4. Return `(schema, sniffedRows)` so the caller can append the buffered
|
|
16
|
+
* rows without re-iterating.
|
|
17
|
+
*
|
|
18
|
+
* @module src/canvas/providers/duckdb/schemaSniffer
|
|
19
|
+
*/
|
|
20
|
+
import { validationError } from '../../../types-global/errors.js';
|
|
21
|
+
function classify(value) {
|
|
22
|
+
if (value === null || value === undefined)
|
|
23
|
+
return 'null';
|
|
24
|
+
if (typeof value === 'string')
|
|
25
|
+
return 'string';
|
|
26
|
+
if (typeof value === 'boolean')
|
|
27
|
+
return 'boolean';
|
|
28
|
+
if (typeof value === 'bigint')
|
|
29
|
+
return 'bigint';
|
|
30
|
+
if (typeof value === 'number') {
|
|
31
|
+
return Number.isInteger(value) ? 'integer' : 'double';
|
|
32
|
+
}
|
|
33
|
+
// Arrays, plain objects, dates, etc. all fall through here. Stored as JSON.
|
|
34
|
+
return 'object';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Choose a DuckDB column type for a column based on the union of JS types
|
|
38
|
+
* observed in the first N rows. Conservative: when the union mixes strings
|
|
39
|
+
* with numerics, falls back to `VARCHAR` rather than guessing.
|
|
40
|
+
*/
|
|
41
|
+
function unionToDuckdbType(observed) {
|
|
42
|
+
const nonNull = new Set(observed);
|
|
43
|
+
nonNull.delete('null');
|
|
44
|
+
if (nonNull.size === 0)
|
|
45
|
+
return 'VARCHAR';
|
|
46
|
+
if (nonNull.size === 1) {
|
|
47
|
+
const [only] = nonNull;
|
|
48
|
+
switch (only) {
|
|
49
|
+
case 'string':
|
|
50
|
+
return 'VARCHAR';
|
|
51
|
+
case 'integer':
|
|
52
|
+
return 'BIGINT';
|
|
53
|
+
case 'double':
|
|
54
|
+
return 'DOUBLE';
|
|
55
|
+
case 'bigint':
|
|
56
|
+
return 'BIGINT';
|
|
57
|
+
case 'boolean':
|
|
58
|
+
return 'BOOLEAN';
|
|
59
|
+
case 'object':
|
|
60
|
+
return 'JSON';
|
|
61
|
+
default:
|
|
62
|
+
return 'VARCHAR';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Numeric widening — INTEGER + DOUBLE → DOUBLE; INTEGER + BIGINT → BIGINT.
|
|
66
|
+
if (nonNull.has('double') && nonNull.has('integer') && nonNull.size === 2)
|
|
67
|
+
return 'DOUBLE';
|
|
68
|
+
if (nonNull.has('bigint') && nonNull.has('integer') && nonNull.size === 2)
|
|
69
|
+
return 'BIGINT';
|
|
70
|
+
if (nonNull.has('double') &&
|
|
71
|
+
nonNull.has('integer') &&
|
|
72
|
+
nonNull.has('bigint') &&
|
|
73
|
+
nonNull.size === 3) {
|
|
74
|
+
return 'DOUBLE';
|
|
75
|
+
}
|
|
76
|
+
// Mixed string+structured → JSON when string is absent; otherwise VARCHAR.
|
|
77
|
+
if (!nonNull.has('string') && nonNull.has('object'))
|
|
78
|
+
return 'JSON';
|
|
79
|
+
return 'VARCHAR';
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Materialize up to `sniffRowCount` rows from the iterable and return the
|
|
83
|
+
* inferred schema plus the buffered rows. Throws if the input is empty.
|
|
84
|
+
*
|
|
85
|
+
* Column ordering is determined by first-appearance across the buffered rows
|
|
86
|
+
* — column names from the first row come first, then any new keys added by
|
|
87
|
+
* later rows (each appended in observation order). Missing keys in any row
|
|
88
|
+
* count as `null` for type inference purposes.
|
|
89
|
+
*/
|
|
90
|
+
export function sniffSchema(iterable, sniffRowCount) {
|
|
91
|
+
if (sniffRowCount < 1) {
|
|
92
|
+
throw validationError('sniffRowCount must be at least 1.', { sniffRowCount });
|
|
93
|
+
}
|
|
94
|
+
const sniffedRows = [];
|
|
95
|
+
let count = 0;
|
|
96
|
+
for (const row of iterable) {
|
|
97
|
+
sniffedRows.push(row);
|
|
98
|
+
count += 1;
|
|
99
|
+
if (count >= sniffRowCount)
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
if (sniffedRows.length === 0) {
|
|
103
|
+
throw validationError('Cannot infer schema from an empty input. Provide either rows or an explicit `schema`.', { reason: 'empty_input' });
|
|
104
|
+
}
|
|
105
|
+
const observedByCol = new Map();
|
|
106
|
+
const columnOrder = [];
|
|
107
|
+
for (const row of sniffedRows) {
|
|
108
|
+
for (const key of Object.keys(row)) {
|
|
109
|
+
let bag = observedByCol.get(key);
|
|
110
|
+
if (!bag) {
|
|
111
|
+
bag = new Set();
|
|
112
|
+
observedByCol.set(key, bag);
|
|
113
|
+
columnOrder.push(key);
|
|
114
|
+
}
|
|
115
|
+
bag.add(classify(row[key]));
|
|
116
|
+
}
|
|
117
|
+
// Account for missing keys as `null` against existing columns.
|
|
118
|
+
for (const key of columnOrder) {
|
|
119
|
+
if (!(key in row)) {
|
|
120
|
+
observedByCol.get(key)?.add('null');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const schema = columnOrder.map((name) => {
|
|
125
|
+
const observed = observedByCol.get(name) ?? new Set(['null']);
|
|
126
|
+
return {
|
|
127
|
+
name,
|
|
128
|
+
type: unionToDuckdbType(observed),
|
|
129
|
+
nullable: observed.has('null') || observed.size === 0,
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
return { schema, sniffedRows };
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=schemaSniffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaSniffer.js","sourceRoot":"","sources":["../../../../src/canvas/providers/duckdb/schemaSniffer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public types for the DataCanvas primitive — column schemas,
|
|
3
|
+
* table info, and option/result shapes for register/query/export/describe.
|
|
4
|
+
* Engine-agnostic: DuckDB is the v1 implementation but these types do not bind
|
|
5
|
+
* to it.
|
|
6
|
+
* @module src/canvas/types
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Column type tag used when an explicit schema is provided to
|
|
10
|
+
* {@link IDataCanvasProvider.registerTable}. The DuckDB provider maps these
|
|
11
|
+
* to native DuckDB types; future engines map to their nearest equivalents.
|
|
12
|
+
*/
|
|
13
|
+
export type ColumnType = 'VARCHAR' | 'INTEGER' | 'BIGINT' | 'DOUBLE' | 'BOOLEAN' | 'TIMESTAMP' | 'DATE' | 'JSON' | 'BLOB';
|
|
14
|
+
/** Single column declaration in an explicit table schema. */
|
|
15
|
+
export interface ColumnSchema {
|
|
16
|
+
/** Column name. Validated against the canvas identifier rules. */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Whether NULL values are permitted. Defaults to `true`. */
|
|
19
|
+
nullable?: boolean;
|
|
20
|
+
/** Column type tag. */
|
|
21
|
+
type: ColumnType;
|
|
22
|
+
}
|
|
23
|
+
/** Metadata returned by {@link CanvasInstance.describe}. */
|
|
24
|
+
export interface TableInfo {
|
|
25
|
+
/** Approximate in-memory footprint in bytes (engine-specific estimate). */
|
|
26
|
+
approxSizeBytes?: number;
|
|
27
|
+
/** Resolved schema for the table. */
|
|
28
|
+
columns: ColumnSchema[];
|
|
29
|
+
/** Canvas-local table name. */
|
|
30
|
+
name: string;
|
|
31
|
+
/** Number of rows currently stored. */
|
|
32
|
+
rowCount: number;
|
|
33
|
+
}
|
|
34
|
+
/** Options for {@link CanvasInstance.registerTable}. */
|
|
35
|
+
export interface RegisterTableOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Explicit schema. When omitted, the provider sniffs the first N rows
|
|
38
|
+
* (default 100) to infer types, falling back to `VARCHAR` for ambiguous
|
|
39
|
+
* columns. **Required** when `rows` is an `AsyncIterable` — the provider
|
|
40
|
+
* cannot peek without consuming.
|
|
41
|
+
*/
|
|
42
|
+
schema?: ColumnSchema[];
|
|
43
|
+
/** Cancellation signal forwarded to the provider. */
|
|
44
|
+
signal?: AbortSignal;
|
|
45
|
+
}
|
|
46
|
+
/** Result of a successful {@link CanvasInstance.registerTable} call. */
|
|
47
|
+
export interface RegisterTableResult {
|
|
48
|
+
/** Column names in declaration order. */
|
|
49
|
+
columns: string[];
|
|
50
|
+
/** Number of rows ingested. */
|
|
51
|
+
rowCount: number;
|
|
52
|
+
/** Resolved (validated, quoted-safe) table name. */
|
|
53
|
+
tableName: string;
|
|
54
|
+
}
|
|
55
|
+
/** Options for {@link CanvasInstance.query}. */
|
|
56
|
+
export interface QueryOptions {
|
|
57
|
+
/**
|
|
58
|
+
* Number of rows to include in the immediate response. Defaults to
|
|
59
|
+
* `rowLimit`. Use a smaller value (e.g. 50) when `registerAs` is set and
|
|
60
|
+
* the caller only wants a sample.
|
|
61
|
+
*/
|
|
62
|
+
preview?: number;
|
|
63
|
+
/**
|
|
64
|
+
* Persist the result set as a new canvas table. The returned `rows` is
|
|
65
|
+
* still bounded by `preview`/`rowLimit`; the full result lives on-canvas
|
|
66
|
+
* under this name. Throws `Conflict` if a table with this name already
|
|
67
|
+
* exists.
|
|
68
|
+
*/
|
|
69
|
+
registerAs?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Hard cap on rows materialized into the response. Default 10_000. To keep
|
|
72
|
+
* a full result set, use `registerAs` (canonical) rather than raising this.
|
|
73
|
+
*/
|
|
74
|
+
rowLimit?: number;
|
|
75
|
+
/** Cancellation signal — interrupts the underlying connection. */
|
|
76
|
+
signal?: AbortSignal;
|
|
77
|
+
}
|
|
78
|
+
/** Result of a successful {@link CanvasInstance.query} call. */
|
|
79
|
+
export interface QueryResult {
|
|
80
|
+
/** Column names in projection order. */
|
|
81
|
+
columns: string[];
|
|
82
|
+
/** Total rows the query produced (may exceed `rows.length` when capped). */
|
|
83
|
+
rowCount: number;
|
|
84
|
+
/** Materialized rows (bounded by `preview`/`rowLimit`). */
|
|
85
|
+
rows: Record<string, unknown>[];
|
|
86
|
+
/** Set when `registerAs` was supplied. */
|
|
87
|
+
tableName?: string;
|
|
88
|
+
}
|
|
89
|
+
/** Supported export formats. */
|
|
90
|
+
export type ExportFormat = 'csv' | 'parquet' | 'json';
|
|
91
|
+
/**
|
|
92
|
+
* Discriminated export target. Path-targeted exports are sandboxed to
|
|
93
|
+
* `CANVAS_EXPORT_PATH`; absolute paths and `..` traversal are rejected.
|
|
94
|
+
*/
|
|
95
|
+
export type ExportTarget = {
|
|
96
|
+
format: ExportFormat;
|
|
97
|
+
path: string;
|
|
98
|
+
} | {
|
|
99
|
+
format: ExportFormat;
|
|
100
|
+
stream: WritableStream<Uint8Array>;
|
|
101
|
+
};
|
|
102
|
+
/** Options for {@link CanvasInstance.export}. */
|
|
103
|
+
export interface ExportOptions {
|
|
104
|
+
/** Cancellation signal. */
|
|
105
|
+
signal?: AbortSignal;
|
|
106
|
+
}
|
|
107
|
+
/** Result of a successful {@link CanvasInstance.export} call. */
|
|
108
|
+
export interface ExportResult {
|
|
109
|
+
/** Format that was written. */
|
|
110
|
+
format: ExportFormat;
|
|
111
|
+
/** Absolute path written, when the target was a path; undefined for streams. */
|
|
112
|
+
path?: string;
|
|
113
|
+
/** Rows written. */
|
|
114
|
+
rowCount: number;
|
|
115
|
+
/** Bytes written. */
|
|
116
|
+
sizeBytes: number;
|
|
117
|
+
}
|
|
118
|
+
/** Options for {@link CanvasInstance.describe}. */
|
|
119
|
+
export interface DescribeOptions {
|
|
120
|
+
/** When set, return only the named table. */
|
|
121
|
+
tableName?: string;
|
|
122
|
+
}
|
|
123
|
+
/** Options for {@link DataCanvas.acquire}. */
|
|
124
|
+
export interface AcquireOptions {
|
|
125
|
+
/** Cancellation signal for the acquire/init handshake. */
|
|
126
|
+
signal?: AbortSignal;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Async row iterator accepted by {@link CanvasInstance.registerTable}.
|
|
130
|
+
* Materialized arrays are also accepted; iterables are forwarded row-by-row
|
|
131
|
+
* to the provider's appender.
|
|
132
|
+
*/
|
|
133
|
+
export type RegisterRows = AsyncIterable<Record<string, unknown>> | Iterable<Record<string, unknown>>;
|
|
134
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/canvas/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public types for the DataCanvas primitive — column schemas,
|
|
3
|
+
* table info, and option/result shapes for register/query/export/describe.
|
|
4
|
+
* Engine-agnostic: DuckDB is the v1 implementation but these types do not bind
|
|
5
|
+
* to it.
|
|
6
|
+
* @module src/canvas/types
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/canvas/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|