@flytedesk/app-kit 4.0.0 → 6.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/dist/auth/plugin.js +22 -2
- package/dist/auth/plugin.js.map +1 -1
- package/dist/auth/testing/fake-idp.d.ts +9 -0
- package/dist/auth/testing/fake-idp.js +33 -5
- package/dist/auth/testing/fake-idp.js.map +1 -1
- package/dist/bigquery/client.d.ts +4 -4
- package/dist/bigquery/client.js +2 -2
- package/dist/bigquery/client.js.map +1 -1
- package/dist/bigquery/errors.d.ts +19 -0
- package/dist/bigquery/errors.js +41 -0
- package/dist/bigquery/errors.js.map +1 -1
- package/dist/bigquery/index.d.ts +3 -3
- package/dist/bigquery/index.js +1 -1
- package/dist/bigquery/index.js.map +1 -1
- package/dist/bigquery/load.d.ts +25 -7
- package/dist/bigquery/load.js +61 -31
- package/dist/bigquery/load.js.map +1 -1
- package/dist/bigquery/query.js +14 -1
- package/dist/bigquery/query.js.map +1 -1
- package/dist/bigquery/schema.d.ts +5 -0
- package/dist/bigquery/schema.js +35 -0
- package/dist/bigquery/schema.js.map +1 -0
- package/dist/bigquery/types.d.ts +57 -17
- package/dist/chat/index.d.ts +52 -21
- package/dist/chat/index.js +50 -20
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/mcp/entry.d.ts +37 -0
- package/dist/chat/mcp/entry.js +135 -0
- package/dist/chat/mcp/entry.js.map +1 -0
- package/dist/cli/is-running-as-main.d.ts +1 -0
- package/dist/cli/is-running-as-main.js +54 -0
- package/dist/cli/is-running-as-main.js.map +1 -0
- package/dist/cli/sync-engine.d.ts +1 -32
- package/dist/cli/sync-engine.js +7 -45
- package/dist/cli/sync-engine.js.map +1 -1
- package/dist/flags/evaluate.d.ts +43 -0
- package/dist/flags/evaluate.js +64 -0
- package/dist/flags/evaluate.js.map +1 -0
- package/dist/flags/index.d.ts +22 -6
- package/dist/flags/index.js +21 -6
- package/dist/flags/index.js.map +1 -1
- package/dist/flags/plugin.js +73 -7
- package/dist/flags/plugin.js.map +1 -1
- package/dist/flags/types.d.ts +25 -0
- package/package.json +3 -2
package/dist/bigquery/load.js
CHANGED
|
@@ -1,61 +1,91 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Load-job capability (AK-14 follow-on, MP-200/PLN-2):
|
|
3
|
-
* BigQuery table
|
|
2
|
+
* Load-job capability (AK-14 follow-on, MP-200/PLN-2): loads a stream of rows
|
|
3
|
+
* into a BigQuery table in one load job, with retry-with-backoff limited to
|
|
4
4
|
* BigQuery's own rate-limit/quota class of error — generalized out of
|
|
5
5
|
* media-planner's `apps/api/src/lib/bigqueryLoad.ts` (via flytedesk-id's
|
|
6
6
|
* verbatim port at `src/lib/bigqueryLoad.ts`, MP-200), which this module
|
|
7
|
-
* replaces.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* replaces.
|
|
8
|
+
*
|
|
9
|
+
* Memory is bounded by `chunkBytes`, never by the row count (AK-28): rows are
|
|
10
|
+
* pulled from the caller's source one at a time, serialized into NDJSON chunks
|
|
11
|
+
* of about `chunkBytes`, and piped into the load job's write stream with
|
|
12
|
+
* `stream.pipeline`, which stops pulling from the source whenever the write
|
|
13
|
+
* stream's buffer is full and resumes on its `drain`. A caller that reads its
|
|
14
|
+
* rows page by page (a keyset-paged or cursor read) can therefore load any
|
|
15
|
+
* number of rows in a fixed amount of memory.
|
|
10
16
|
*/
|
|
11
|
-
import {
|
|
17
|
+
import { once } from "node:events";
|
|
18
|
+
import { pipeline } from "node:stream/promises";
|
|
19
|
+
import { BigQueryReadError, classifyBigQueryError, isRetryableBigQueryError, } from "./errors.js";
|
|
12
20
|
const DEFAULT_ATTEMPTS = 5;
|
|
13
21
|
const DEFAULT_INITIAL_DELAY_MS = 1_000;
|
|
22
|
+
const DEFAULT_CHUNK_BYTES = 1024 * 1024;
|
|
14
23
|
const DEFAULT_SOURCE_FORMAT = "NEWLINE_DELIMITED_JSON";
|
|
15
24
|
function defaultSleep(ms) {
|
|
16
25
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
17
26
|
}
|
|
18
|
-
|
|
27
|
+
/** Serializes `rows` into NDJSON, one `Buffer` of about `chunkBytes` at a
|
|
28
|
+
* time, counting rows into `counter` as they are consumed. */
|
|
29
|
+
async function* ndjsonChunks(rows, chunkBytes, counter) {
|
|
30
|
+
let lines = [];
|
|
31
|
+
let size = 0;
|
|
32
|
+
for await (const row of rows) {
|
|
33
|
+
const line = `${JSON.stringify(row)}\n`;
|
|
34
|
+
lines.push(line);
|
|
35
|
+
size += Buffer.byteLength(line);
|
|
36
|
+
counter.rows += 1;
|
|
37
|
+
if (size >= chunkBytes) {
|
|
38
|
+
yield Buffer.from(lines.join(""));
|
|
39
|
+
lines = [];
|
|
40
|
+
size = 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (lines.length > 0)
|
|
44
|
+
yield Buffer.from(lines.join(""));
|
|
45
|
+
}
|
|
46
|
+
async function runLoadJob(bq, options, source) {
|
|
19
47
|
const table = bq.dataset(options.datasetId).table(options.tableId);
|
|
20
48
|
const createWriteStream = table.createWriteStream;
|
|
21
49
|
if (!createWriteStream) {
|
|
22
50
|
throw new BigQueryReadError(`dataset(${options.datasetId}).table(${options.tableId}) does not implement createWriteStream — this BigQueryLike was not constructed for load jobs`);
|
|
23
51
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
labels: options.labels,
|
|
32
|
-
jobId: options.jobId,
|
|
33
|
-
});
|
|
34
|
-
stream.on("error", reject);
|
|
35
|
-
stream.on("complete", () => resolve());
|
|
36
|
-
for (const line of ndjson)
|
|
37
|
-
stream.write(line);
|
|
38
|
-
stream.end();
|
|
52
|
+
const stream = createWriteStream.call(table, {
|
|
53
|
+
sourceFormat: options.sourceFormat ?? DEFAULT_SOURCE_FORMAT,
|
|
54
|
+
schema: options.schema,
|
|
55
|
+
writeDisposition: options.writeDisposition,
|
|
56
|
+
createDisposition: options.createDisposition,
|
|
57
|
+
labels: options.labels,
|
|
58
|
+
jobId: options.jobId,
|
|
39
59
|
});
|
|
60
|
+
const counter = { rows: 0 };
|
|
61
|
+
// The load is done only when BigQuery reports the job "complete" AND the
|
|
62
|
+
// pipeline has flushed every chunk. `once` rejects on the stream's "error",
|
|
63
|
+
// which is how a failed job surfaces; `pipeline` rejects (and destroys the
|
|
64
|
+
// stream, aborting the upload) when the source itself throws.
|
|
65
|
+
await Promise.all([
|
|
66
|
+
once(stream, "complete"),
|
|
67
|
+
pipeline(ndjsonChunks(source(), options.chunkBytes ?? DEFAULT_CHUNK_BYTES, counter), stream),
|
|
68
|
+
]);
|
|
69
|
+
return { rowCount: counter.rows };
|
|
40
70
|
}
|
|
41
71
|
/**
|
|
42
|
-
*
|
|
43
|
-
* exponential backoff ONLY when the failure is BigQuery's
|
|
72
|
+
* Streams the rows `source` yields into `datasetId.tableId` in one load job,
|
|
73
|
+
* retrying with exponential backoff ONLY when the failure is BigQuery's
|
|
44
74
|
* rateLimitExceeded/quotaExceeded class of error (see
|
|
45
|
-
* `isRetryableBigQueryError`). Any other error (bad schema, auth failure,
|
|
46
|
-
* etc.) is classified and rethrown on the first
|
|
75
|
+
* `isRetryableBigQueryError`). Any other error (bad schema, auth failure, a
|
|
76
|
+
* throw from the source, etc.) is classified and rethrown on the first
|
|
77
|
+
* attempt. Each attempt calls `source` afresh — see `LoadRowSource`.
|
|
47
78
|
*
|
|
48
|
-
* Pass `writeDisposition: "WRITE_TRUNCATE"` for a full-refresh reload
|
|
49
|
-
*
|
|
79
|
+
* Pass `writeDisposition: "WRITE_TRUNCATE"` for a full-refresh reload; omit it
|
|
80
|
+
* for an append load.
|
|
50
81
|
*/
|
|
51
|
-
export async function loadRowsWithRetry(bq, options,
|
|
82
|
+
export async function loadRowsWithRetry(bq, options, source) {
|
|
52
83
|
const attempts = options.attempts ?? DEFAULT_ATTEMPTS;
|
|
53
84
|
const initialDelayMs = options.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
|
|
54
85
|
const sleep = options.sleep ?? defaultSleep;
|
|
55
86
|
for (let attempt = 1;; attempt += 1) {
|
|
56
87
|
try {
|
|
57
|
-
await runLoadJob(bq, options,
|
|
58
|
-
return;
|
|
88
|
+
return await runLoadJob(bq, options, source);
|
|
59
89
|
}
|
|
60
90
|
catch (err) {
|
|
61
91
|
if (attempt >= attempts || !isRetryableBigQueryError(err)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/bigquery/load.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/bigquery/load.ts"],"names":[],"mappings":"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"}
|
package/dist/bigquery/query.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* (AK-11). Inventory-specific SQL stays in media-planner; this module only
|
|
5
5
|
* ever takes SQL + params from the caller and runs it.
|
|
6
6
|
*/
|
|
7
|
-
import { BadQueryError, classifyBigQueryError } from "./errors.js";
|
|
7
|
+
import { BadQueryError, classifyBigQueryError, isJobTimeoutError, JobTimeoutError } from "./errors.js";
|
|
8
8
|
import { DryRunBudgetExceededError } from "./errors.js";
|
|
9
|
+
import { normalizeResultSchema } from "./schema.js";
|
|
9
10
|
/** Runs one page of a parameterised, read-only query. Always bind
|
|
10
11
|
* user-supplied values through `options.params`/`options.types` — never
|
|
11
12
|
* string-interpolate them into `options.sql`.
|
|
@@ -34,9 +35,13 @@ export async function runQuery(bq, options) {
|
|
|
34
35
|
maximumBytesBilled: options.maximumBytesBilled !== undefined
|
|
35
36
|
? String(options.maximumBytesBilled)
|
|
36
37
|
: undefined,
|
|
38
|
+
jobTimeoutMs: options.jobTimeoutMs,
|
|
37
39
|
});
|
|
38
40
|
}
|
|
39
41
|
catch (err) {
|
|
42
|
+
if (options.jobTimeoutMs !== undefined && isJobTimeoutError(err)) {
|
|
43
|
+
throw new JobTimeoutError(options.jobTimeoutMs, err);
|
|
44
|
+
}
|
|
40
45
|
throw classifyBigQueryError(err);
|
|
41
46
|
}
|
|
42
47
|
}
|
|
@@ -52,6 +57,9 @@ export async function runQuery(bq, options) {
|
|
|
52
57
|
};
|
|
53
58
|
}
|
|
54
59
|
catch (err) {
|
|
60
|
+
if (options.jobTimeoutMs !== undefined && isJobTimeoutError(err)) {
|
|
61
|
+
throw new JobTimeoutError(options.jobTimeoutMs, err);
|
|
62
|
+
}
|
|
55
63
|
throw classifyBigQueryError(err);
|
|
56
64
|
}
|
|
57
65
|
}
|
|
@@ -87,9 +95,13 @@ export async function estimateQueryBytes(bq, options) {
|
|
|
87
95
|
types: options.types,
|
|
88
96
|
location: options.location,
|
|
89
97
|
dryRun: true,
|
|
98
|
+
jobTimeoutMs: options.jobTimeoutMs,
|
|
90
99
|
});
|
|
91
100
|
}
|
|
92
101
|
catch (err) {
|
|
102
|
+
if (options.jobTimeoutMs !== undefined && isJobTimeoutError(err)) {
|
|
103
|
+
throw new JobTimeoutError(options.jobTimeoutMs, err);
|
|
104
|
+
}
|
|
93
105
|
throw classifyBigQueryError(err);
|
|
94
106
|
}
|
|
95
107
|
const stats = metadata.statistics?.query;
|
|
@@ -98,6 +110,7 @@ export async function estimateQueryBytes(bq, options) {
|
|
|
98
110
|
cacheHit: stats?.cacheHit ?? false,
|
|
99
111
|
statementType: stats?.statementType,
|
|
100
112
|
referencedTables: stats?.referencedTables,
|
|
113
|
+
schema: normalizeResultSchema(stats?.schema),
|
|
101
114
|
};
|
|
102
115
|
if (options.maxBytesBilled !== undefined &&
|
|
103
116
|
estimate.totalBytesProcessed > options.maxBytesBilled) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/bigquery/query.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/bigquery/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BigQueryRawSchema, BigQueryResultSchemaField } from "./types.js";
|
|
2
|
+
/** `undefined` when BigQuery sent no schema at all; `[]` when it sent one with
|
|
3
|
+
* no fields. Throws `MalformedResultSchemaError` for a field lacking a
|
|
4
|
+
* non-empty `name` or `type`, at any nesting depth. */
|
|
5
|
+
export declare function normalizeResultSchema(schema: BigQueryRawSchema | undefined): BigQueryResultSchemaField[] | undefined;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses BigQuery's raw dry-run result schema (every property optional, as the
|
|
3
|
+
* real SDK types it) into the normalised `BigQueryResultSchemaField[]` callers
|
|
4
|
+
* get. Parse at the boundary: a field missing `name` or `type` is a typed error
|
|
5
|
+
* here rather than a silent `undefined` downstream (AK-31).
|
|
6
|
+
*/
|
|
7
|
+
import { MalformedResultSchemaError } from "./errors.js";
|
|
8
|
+
/** `undefined` when BigQuery sent no schema at all; `[]` when it sent one with
|
|
9
|
+
* no fields. Throws `MalformedResultSchemaError` for a field lacking a
|
|
10
|
+
* non-empty `name` or `type`, at any nesting depth. */
|
|
11
|
+
export function normalizeResultSchema(schema) {
|
|
12
|
+
if (schema === undefined)
|
|
13
|
+
return undefined;
|
|
14
|
+
return normalizeFields(schema.fields ?? [], "");
|
|
15
|
+
}
|
|
16
|
+
function normalizeFields(fields, parentPath) {
|
|
17
|
+
return fields.map((field, index) => normalizeField(field, index, parentPath));
|
|
18
|
+
}
|
|
19
|
+
function normalizeField(field, index, parentPath) {
|
|
20
|
+
const { name, type } = field;
|
|
21
|
+
if (!name) {
|
|
22
|
+
throw new MalformedResultSchemaError(`${parentPath}fields[${index}]`, "name");
|
|
23
|
+
}
|
|
24
|
+
const path = `${parentPath}${name}`;
|
|
25
|
+
if (!type) {
|
|
26
|
+
throw new MalformedResultSchemaError(path, "type");
|
|
27
|
+
}
|
|
28
|
+
const normalized = { name, type };
|
|
29
|
+
if (field.mode !== undefined)
|
|
30
|
+
normalized.mode = field.mode;
|
|
31
|
+
if (field.fields !== undefined)
|
|
32
|
+
normalized.fields = normalizeFields(field.fields, `${path}.`);
|
|
33
|
+
return normalized;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/bigquery/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAOzD;;wDAEwD;AACxD,MAAM,UAAU,qBAAqB,CACnC,MAAqC;IAErC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,eAAe,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,eAAe,CACtB,MAAgC,EAChC,UAAkB;IAElB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,cAAc,CACrB,KAA6B,EAC7B,KAAa,EACb,UAAkB;IAElB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,0BAA0B,CAAC,GAAG,UAAU,UAAU,KAAK,GAAG,EAAE,MAAM,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,UAAU,GAAG,IAAI,EAAE,CAAC;IACpC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,0BAA0B,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC;IACD,MAAM,UAAU,GAA8B,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC7D,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,UAAU,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAC3D,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,UAAU,CAAC,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC;IAC9F,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
package/dist/bigquery/types.d.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* `@google-cloud/bigquery` calls it made; inventory-specific SQL stays behind
|
|
12
12
|
* in media-planner.
|
|
13
13
|
*/
|
|
14
|
+
import type { Writable } from "node:stream";
|
|
14
15
|
/** One structured error entry, same shape the Google APIs client library
|
|
15
16
|
* attaches to a rejected job promise's `.errors` array. */
|
|
16
17
|
export interface BigQueryApiErrorDetail {
|
|
@@ -31,6 +32,20 @@ export interface BigQueryTableReference {
|
|
|
31
32
|
datasetId?: string;
|
|
32
33
|
tableId?: string;
|
|
33
34
|
}
|
|
35
|
+
/** A result-schema field exactly as BigQuery's job statistics report it: the
|
|
36
|
+
* real SDK's `ITableFieldSchema`, where every property is optional. Only the
|
|
37
|
+
* raw boundary speaks this shape; callers get `BigQueryResultSchemaField`
|
|
38
|
+
* (name and type guaranteed) from `estimateQueryBytes`. */
|
|
39
|
+
export interface BigQueryRawSchemaField {
|
|
40
|
+
name?: string;
|
|
41
|
+
type?: string;
|
|
42
|
+
mode?: string;
|
|
43
|
+
fields?: BigQueryRawSchemaField[];
|
|
44
|
+
}
|
|
45
|
+
/** `IJobStatistics2.schema`, an `ITableSchema`. */
|
|
46
|
+
export interface BigQueryRawSchema {
|
|
47
|
+
fields?: BigQueryRawSchemaField[];
|
|
48
|
+
}
|
|
34
49
|
export interface BigQueryJobStatistics {
|
|
35
50
|
query?: {
|
|
36
51
|
totalBytesProcessed?: string | number;
|
|
@@ -41,6 +56,9 @@ export interface BigQueryJobStatistics {
|
|
|
41
56
|
statementType?: string;
|
|
42
57
|
/** Every table the query touches — `IJobStatistics2.referencedTables`. */
|
|
43
58
|
referencedTables?: BigQueryTableReference[];
|
|
59
|
+
/** The result schema BigQuery computed for the (dry-run) query —
|
|
60
|
+
* `IJobStatistics2.schema`, an `ITableSchema` (`{ fields }`). */
|
|
61
|
+
schema?: BigQueryRawSchema;
|
|
44
62
|
};
|
|
45
63
|
}
|
|
46
64
|
export interface BigQueryJobMetadata {
|
|
@@ -91,6 +109,10 @@ export interface BigQueryCreateQueryJobOptions {
|
|
|
91
109
|
* than run. Distinct from `EstimateQueryBytesOptions.maxBytesBilled`
|
|
92
110
|
* (a pre-flight dry-run check this module enforces client-side). */
|
|
93
111
|
maximumBytesBilled?: string;
|
|
112
|
+
/** BigQuery's own `configuration.jobTimeoutMs` — the job fails with
|
|
113
|
+
* `stopped` state once it runs longer than this, wall-clock, from job
|
|
114
|
+
* creation. The SDK converts this number to the wire's decimal string. */
|
|
115
|
+
jobTimeoutMs?: number;
|
|
94
116
|
}
|
|
95
117
|
export interface BigQueryExtractOptions {
|
|
96
118
|
/** `@google-cloud/bigquery`'s own extract-job vocabulary — note this is
|
|
@@ -109,24 +131,26 @@ export interface GcsFileLike {
|
|
|
109
131
|
readonly name: string;
|
|
110
132
|
};
|
|
111
133
|
}
|
|
112
|
-
/** Structural subset of Node's own Writable that `Table#createWriteStream`
|
|
113
|
-
* needs to expose — the "error"/"complete" events a load-job caller pipes
|
|
114
|
-
* rows into and waits on. */
|
|
115
|
-
export interface BigQueryWriteStreamLike {
|
|
116
|
-
on(event: "error", listener: (err: unknown) => void): this;
|
|
117
|
-
on(event: "complete", listener: () => void): this;
|
|
118
|
-
write(chunk: string): boolean;
|
|
119
|
-
end(): void;
|
|
120
|
-
}
|
|
121
134
|
/** One BigQuery table-schema field, as `createWriteStream`'s `schema` option
|
|
122
|
-
* (and the REST API's `tables.insert`) accepts it
|
|
123
|
-
* RECORD/STRUCT
|
|
135
|
+
* (and the REST API's `tables.insert`) accepts it: load-job INPUT, where the
|
|
136
|
+
* caller must state `name` and `type`. `fields` recurses for RECORD/STRUCT
|
|
137
|
+
* columns. The schema BigQuery reports back is `BigQueryResultSchemaField`. */
|
|
124
138
|
export interface BigQuerySchemaField {
|
|
125
139
|
name: string;
|
|
126
140
|
type: string;
|
|
127
141
|
mode?: "NULLABLE" | "REQUIRED" | "REPEATED";
|
|
128
142
|
fields?: BigQuerySchemaField[];
|
|
129
143
|
}
|
|
144
|
+
/** One column of a query's result schema, normalised from BigQuery's own
|
|
145
|
+
* dry-run statistics: `name` and `type` are guaranteed (a field missing
|
|
146
|
+
* either is rejected with `MalformedResultSchemaError`); `mode` is BigQuery's
|
|
147
|
+
* string as reported. `fields` recurses for RECORD/STRUCT columns. */
|
|
148
|
+
export interface BigQueryResultSchemaField {
|
|
149
|
+
name: string;
|
|
150
|
+
type: string;
|
|
151
|
+
mode?: string;
|
|
152
|
+
fields?: BigQueryResultSchemaField[];
|
|
153
|
+
}
|
|
130
154
|
export interface BigQueryLoadOptions {
|
|
131
155
|
sourceFormat?: "NEWLINE_DELIMITED_JSON" | "CSV" | "AVRO" | "PARQUET";
|
|
132
156
|
/** Full destination-table schema. Required when the table doesn't already
|
|
@@ -143,12 +167,15 @@ export interface BigQueryLoadOptions {
|
|
|
143
167
|
}
|
|
144
168
|
export interface BigQueryTableLike {
|
|
145
169
|
createExtractJob(destination: GcsFileLike, options?: BigQueryExtractOptions): Promise<[BigQueryJobLike, BigQueryJobMetadata]>;
|
|
146
|
-
/** Opens a load-job write stream —
|
|
147
|
-
*
|
|
148
|
-
* "
|
|
149
|
-
*
|
|
150
|
-
* `
|
|
151
|
-
|
|
170
|
+
/** Opens a load-job write stream — a real Node `Writable`, since the loader
|
|
171
|
+
* pipes NDJSON into it with `stream.pipeline` and relies on its
|
|
172
|
+
* backpressure (`write()` returning false, then "drain"). The stream emits
|
|
173
|
+
* "complete" once BigQuery finishes the job, or "error" if the job fails.
|
|
174
|
+
* Mirrors `@google-cloud/bigquery`'s `Table#createWriteStream`, which
|
|
175
|
+
* returns a `Writable`. Optional: read-only callers (query/extract) never
|
|
176
|
+
* need it — only `loadRowsWithRetry` (./load.js) does, and it fails loudly
|
|
177
|
+
* if missing. */
|
|
178
|
+
createWriteStream?(options: BigQueryLoadOptions): Writable;
|
|
152
179
|
}
|
|
153
180
|
export interface BigQueryDatasetLike {
|
|
154
181
|
table(id: string): BigQueryTableLike;
|
|
@@ -187,6 +214,11 @@ export interface RunQueryOptions {
|
|
|
187
214
|
* belt to that check's suspenders, since data can grow between a dry
|
|
188
215
|
* run and the real job, or a caller can skip the dry run entirely. */
|
|
189
216
|
maximumBytesBilled?: number;
|
|
217
|
+
/** Fails the job with a typed `JobTimeoutError` once it runs longer than
|
|
218
|
+
* this many milliseconds, wall-clock from job creation — set on the job's
|
|
219
|
+
* own `configuration.jobTimeoutMs` (BigQuery enforces it server-side),
|
|
220
|
+
* not a client-side `Promise.race`. */
|
|
221
|
+
jobTimeoutMs?: number;
|
|
190
222
|
}
|
|
191
223
|
export interface QueryPage<T = Record<string, unknown>> {
|
|
192
224
|
rows: T[];
|
|
@@ -202,6 +234,10 @@ export interface EstimateQueryBytesOptions {
|
|
|
202
234
|
/** When given, `estimateQueryBytes` throws `DryRunBudgetExceededError`
|
|
203
235
|
* instead of returning once the estimate exceeds this many bytes. */
|
|
204
236
|
maxBytesBilled?: number;
|
|
237
|
+
/** Same `configuration.jobTimeoutMs` enforcement as `RunQueryOptions` —
|
|
238
|
+
* applies to the dry-run job itself, not the (never-run) query it
|
|
239
|
+
* estimates. */
|
|
240
|
+
jobTimeoutMs?: number;
|
|
205
241
|
}
|
|
206
242
|
export interface DryRunEstimate {
|
|
207
243
|
totalBytesProcessed: number;
|
|
@@ -216,6 +252,10 @@ export interface DryRunEstimate {
|
|
|
216
252
|
* checks every entry against its own read-only table allowlist before
|
|
217
253
|
* ever submitting the real job. */
|
|
218
254
|
referencedTables?: BigQueryTableReference[];
|
|
255
|
+
/** BigQuery's own result schema for the query, typed directly from the
|
|
256
|
+
* dry-run job's `statistics.query.schema` — never inferred client-side.
|
|
257
|
+
* `undefined` only when BigQuery's dry-run statistics omitted it. */
|
|
258
|
+
schema?: BigQueryResultSchemaField[];
|
|
219
259
|
}
|
|
220
260
|
export interface ExtractTableToGCSInput {
|
|
221
261
|
datasetId: string;
|
package/dist/chat/index.d.ts
CHANGED
|
@@ -41,32 +41,63 @@
|
|
|
41
41
|
* async (request) => recordReply(request.body),
|
|
42
42
|
* );
|
|
43
43
|
*
|
|
44
|
-
* Usage — the MCP server
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* Usage — the MCP server the dispatched agent's clean room actually runs (AK-34): a
|
|
45
|
+
* `.danxbot/config/mcp-servers/*.yml` launches the PUBLISHED `app-kit-chat-mcp` bin
|
|
46
|
+
* directly, no vendored copy and no local install in the app's own repo. This
|
|
47
|
+
* package publishes FIVE bins and none is named `app-kit`, so `npx` needs
|
|
48
|
+
* `--package=` to say which package to fetch, separately from which bin to run —
|
|
49
|
+
* `npx -y @flytedesk/app-kit@<v> app-kit-chat-mcp` fails ("could not determine
|
|
50
|
+
* executable to run"); this is the form that actually works (verified against a real
|
|
51
|
+
* `npm pack` tarball run via `npx --package=<tgz>` from a clean directory with no
|
|
52
|
+
* `node_modules` — see `mcp/entry.test.ts`):
|
|
47
53
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
54
|
+
* server:
|
|
55
|
+
* command: npx
|
|
56
|
+
* args:
|
|
57
|
+
* - "-y"
|
|
58
|
+
* - "--package=@flytedesk/app-kit@6.0.0"
|
|
59
|
+
* - "app-kit-chat-mcp"
|
|
60
|
+
* - "--tools"
|
|
61
|
+
* - "${DANX_REPO_ROOT}/packages/audience-chat-mcp/src/chatTools.mjs"
|
|
53
62
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
63
|
+
* `--tools <path>` MUST be absolute — danxbot's cwd for this process is its own
|
|
64
|
+
* clean room, never assumed to equal the app's repo root, hence the
|
|
65
|
+
* `${DANX_REPO_ROOT}`-prefixed path above rather than a bare relative one.
|
|
66
|
+
*
|
|
67
|
+
* The path names the ONE thing this package cannot supply itself: the app's own
|
|
68
|
+
* tools module. That module must NOT `import` anything from `@flytedesk/app-kit` —
|
|
69
|
+
* a bare package import cannot resolve from danxbot's unbuilt dispatch clone (no
|
|
70
|
+
* `node_modules`). Instead, `app-kit-chat-mcp` INJECTS the pieces the module needs as
|
|
71
|
+
* a `ChatMcpKit` argument, and the module returns a (optionally wrapped)
|
|
72
|
+
* `ChatMcpProtocol` rather than a plain options bag:
|
|
73
|
+
*
|
|
74
|
+
* // chatTools.mjs — the app's own file, never vendored, never copied, never
|
|
75
|
+
* // imports @flytedesk/app-kit as a VALUE (a type-only `// @ts-check` JSDoc
|
|
76
|
+
* // reference to BuildChatServer/ChatMcpKit is fine — see mcp/entry.ts's header)
|
|
77
|
+
* export default function buildChatServer(kit) {
|
|
78
|
+
* return kit.createChatMcpProtocol({
|
|
79
|
+
* serverName: "sms-app-chat",
|
|
80
|
+
* tools: [
|
|
81
|
+
* kit.createReplyTool({ description: "...", deliver: postReplyToApi }),
|
|
82
|
+
* // The extension point: register whatever app-specific tools the agent
|
|
83
|
+
* // needs — each is just { name, description, inputSchema, handler }.
|
|
84
|
+
* { name: "audience_validate", description: "...", inputSchema: {...}, handler: validateAudience },
|
|
85
|
+
* ],
|
|
86
|
+
* });
|
|
87
|
+
* }
|
|
88
|
+
*
|
|
89
|
+
* `app-kit-chat-mcp` (`src/chat/mcp/entry.ts`, published as `dist/chat/mcp/entry.js`)
|
|
90
|
+
* loads that module, calls its default export with the kit, and starts the stdio
|
|
91
|
+
* loop on whatever `ChatMcpProtocol` it returns — see `entry.ts`'s own doc comment
|
|
92
|
+
* for the full contract, why it stays dependency-free, and how a consumer (e.g.
|
|
93
|
+
* media-planner's MP-169 `loggedProtocol`) wraps `handleMessage` before returning.
|
|
64
94
|
*/
|
|
65
|
-
export { createDanxbotLauncher, DanxbotError, isFailedJobStatus, isTerminalJobStatus } from "./launcher.js";
|
|
66
|
-
export { callbackSecretMatches, requireCallbackSecret } from "./callback-secret.js";
|
|
95
|
+
export { createDanxbotLauncher, DanxbotError, isFailedJobStatus, isTerminalJobStatus, } from "./launcher.js";
|
|
96
|
+
export { callbackSecretMatches, requireCallbackSecret, } from "./callback-secret.js";
|
|
67
97
|
export { createChatMcpProtocol, createReplyTool, parseReplyArguments, FALLBACK_PROTOCOL_VERSION, JSON_RPC, } from "./mcp-protocol.js";
|
|
68
98
|
export { createChatMcpStdioServer } from "./mcp-server.js";
|
|
69
99
|
export { parseChatEnv, ChatEnvError } from "./env.js";
|
|
70
100
|
export type { AppRegisteredTool, ChatEnv, ChatToolCallResult, ChatToolContent, DanxbotDispatchResult, DanxbotJobStatus, DanxbotLauncher, DanxbotLauncherOptions, } from "./types.js";
|
|
71
101
|
export type { ChatMcpProtocol, ChatMcpProtocolOptions, ChatReplyPayload, ParseReplyArgumentsOptions, ReplyDeliverResult, ReplyToolOptions, } from "./mcp-protocol.js";
|
|
72
|
-
export type { ChatMcpStdioServer, ChatMcpStdioServerOptions } from "./mcp-server.js";
|
|
102
|
+
export type { ChatMcpStdioServer, ChatMcpStdioServerOptions, } from "./mcp-server.js";
|
|
103
|
+
export type { BuildChatServer, ChatMcpKit } from "./mcp/entry.js";
|
package/dist/chat/index.js
CHANGED
|
@@ -41,29 +41,59 @@
|
|
|
41
41
|
* async (request) => recordReply(request.body),
|
|
42
42
|
* );
|
|
43
43
|
*
|
|
44
|
-
* Usage — the MCP server
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* Usage — the MCP server the dispatched agent's clean room actually runs (AK-34): a
|
|
45
|
+
* `.danxbot/config/mcp-servers/*.yml` launches the PUBLISHED `app-kit-chat-mcp` bin
|
|
46
|
+
* directly, no vendored copy and no local install in the app's own repo. This
|
|
47
|
+
* package publishes FIVE bins and none is named `app-kit`, so `npx` needs
|
|
48
|
+
* `--package=` to say which package to fetch, separately from which bin to run —
|
|
49
|
+
* `npx -y @flytedesk/app-kit@<v> app-kit-chat-mcp` fails ("could not determine
|
|
50
|
+
* executable to run"); this is the form that actually works (verified against a real
|
|
51
|
+
* `npm pack` tarball run via `npx --package=<tgz>` from a clean directory with no
|
|
52
|
+
* `node_modules` — see `mcp/entry.test.ts`):
|
|
47
53
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
54
|
+
* server:
|
|
55
|
+
* command: npx
|
|
56
|
+
* args:
|
|
57
|
+
* - "-y"
|
|
58
|
+
* - "--package=@flytedesk/app-kit@6.0.0"
|
|
59
|
+
* - "app-kit-chat-mcp"
|
|
60
|
+
* - "--tools"
|
|
61
|
+
* - "${DANX_REPO_ROOT}/packages/audience-chat-mcp/src/chatTools.mjs"
|
|
53
62
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
63
|
+
* `--tools <path>` MUST be absolute — danxbot's cwd for this process is its own
|
|
64
|
+
* clean room, never assumed to equal the app's repo root, hence the
|
|
65
|
+
* `${DANX_REPO_ROOT}`-prefixed path above rather than a bare relative one.
|
|
66
|
+
*
|
|
67
|
+
* The path names the ONE thing this package cannot supply itself: the app's own
|
|
68
|
+
* tools module. That module must NOT `import` anything from `@flytedesk/app-kit` —
|
|
69
|
+
* a bare package import cannot resolve from danxbot's unbuilt dispatch clone (no
|
|
70
|
+
* `node_modules`). Instead, `app-kit-chat-mcp` INJECTS the pieces the module needs as
|
|
71
|
+
* a `ChatMcpKit` argument, and the module returns a (optionally wrapped)
|
|
72
|
+
* `ChatMcpProtocol` rather than a plain options bag:
|
|
73
|
+
*
|
|
74
|
+
* // chatTools.mjs — the app's own file, never vendored, never copied, never
|
|
75
|
+
* // imports @flytedesk/app-kit as a VALUE (a type-only `// @ts-check` JSDoc
|
|
76
|
+
* // reference to BuildChatServer/ChatMcpKit is fine — see mcp/entry.ts's header)
|
|
77
|
+
* export default function buildChatServer(kit) {
|
|
78
|
+
* return kit.createChatMcpProtocol({
|
|
79
|
+
* serverName: "sms-app-chat",
|
|
80
|
+
* tools: [
|
|
81
|
+
* kit.createReplyTool({ description: "...", deliver: postReplyToApi }),
|
|
82
|
+
* // The extension point: register whatever app-specific tools the agent
|
|
83
|
+
* // needs — each is just { name, description, inputSchema, handler }.
|
|
84
|
+
* { name: "audience_validate", description: "...", inputSchema: {...}, handler: validateAudience },
|
|
85
|
+
* ],
|
|
86
|
+
* });
|
|
87
|
+
* }
|
|
88
|
+
*
|
|
89
|
+
* `app-kit-chat-mcp` (`src/chat/mcp/entry.ts`, published as `dist/chat/mcp/entry.js`)
|
|
90
|
+
* loads that module, calls its default export with the kit, and starts the stdio
|
|
91
|
+
* loop on whatever `ChatMcpProtocol` it returns — see `entry.ts`'s own doc comment
|
|
92
|
+
* for the full contract, why it stays dependency-free, and how a consumer (e.g.
|
|
93
|
+
* media-planner's MP-169 `loggedProtocol`) wraps `handleMessage` before returning.
|
|
64
94
|
*/
|
|
65
|
-
export { createDanxbotLauncher, DanxbotError, isFailedJobStatus, isTerminalJobStatus } from "./launcher.js";
|
|
66
|
-
export { callbackSecretMatches, requireCallbackSecret } from "./callback-secret.js";
|
|
95
|
+
export { createDanxbotLauncher, DanxbotError, isFailedJobStatus, isTerminalJobStatus, } from "./launcher.js";
|
|
96
|
+
export { callbackSecretMatches, requireCallbackSecret, } from "./callback-secret.js";
|
|
67
97
|
export { createChatMcpProtocol, createReplyTool, parseReplyArguments, FALLBACK_PROTOCOL_VERSION, JSON_RPC, } from "./mcp-protocol.js";
|
|
68
98
|
export { createChatMcpStdioServer } from "./mcp-server.js";
|
|
69
99
|
export { parseChatEnv, ChatEnvError } from "./env.js";
|
package/dist/chat/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/chat/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/chat/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6FG;AACH,OAAO,EACL,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,yBAAyB,EACzB,QAAQ,GACT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createChatMcpProtocol, createReplyTool, parseReplyArguments, type ChatMcpProtocol } from "../mcp-protocol.js";
|
|
3
|
+
/**
|
|
4
|
+
* Everything a `--tools` module needs, injected rather than imported — see this
|
|
5
|
+
* file's own doc comment for why a runtime `import "@flytedesk/app-kit/chat"` from
|
|
6
|
+
* the module itself cannot work in danxbot's unbuilt dispatch clone.
|
|
7
|
+
*/
|
|
8
|
+
export interface ChatMcpKit {
|
|
9
|
+
createReplyTool: typeof createReplyTool;
|
|
10
|
+
parseReplyArguments: typeof parseReplyArguments;
|
|
11
|
+
createChatMcpProtocol: typeof createChatMcpProtocol;
|
|
12
|
+
}
|
|
13
|
+
/** The contract a `--tools` module's default export must satisfy: given the kit,
|
|
14
|
+
* return a (possibly wrapped) `ChatMcpProtocol`. */
|
|
15
|
+
export type BuildChatServer = (kit: ChatMcpKit) => ChatMcpProtocol | Promise<ChatMcpProtocol>;
|
|
16
|
+
export declare class ChatMcpEntryError extends Error {
|
|
17
|
+
}
|
|
18
|
+
export interface ChatMcpEntryArgs {
|
|
19
|
+
/** Path to the app's tools module. MUST be absolute in real dispatch use (see this
|
|
20
|
+
* file's own doc comment) — resolved against `process.cwd()` only as a fallback
|
|
21
|
+
* for a genuinely relative path, which `path.resolve` leaves untouched when the
|
|
22
|
+
* input is already absolute. */
|
|
23
|
+
toolsPath: string;
|
|
24
|
+
}
|
|
25
|
+
/** Parse argv into `{toolsPath}`. Exported for direct unit testing. */
|
|
26
|
+
export declare function parseArgs(argv: string[]): ChatMcpEntryArgs;
|
|
27
|
+
/**
|
|
28
|
+
* Dynamically `import()` the app's tools module and validate its default export.
|
|
29
|
+
* Exported for direct unit testing (no process spawn needed to exercise the loading
|
|
30
|
+
* and validation logic — see entry.test.ts's own split between a fast in-process
|
|
31
|
+
* suite for this function and real stdio/npx spawn suites for the whole process).
|
|
32
|
+
*/
|
|
33
|
+
export declare function loadBuildChatServer(toolsPath: string): Promise<BuildChatServer>;
|
|
34
|
+
/** Run the server: load the tools module, build the protocol (via the injected
|
|
35
|
+
* kit), and start stdio. Exported for direct unit testing of argument/validation
|
|
36
|
+
* failures without a process spawn. */
|
|
37
|
+
export declare function main(argv: string[]): Promise<void>;
|