@erdoai/cli 0.139.0 → 0.140.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/index.js +97 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,13 +15,34 @@ function advertiserVerificationAction(container) {
|
|
|
15
15
|
|
|
16
16
|
// src/refresh.ts
|
|
17
17
|
function describeRefreshTrigger(state) {
|
|
18
|
-
|
|
19
|
-
if (state.
|
|
20
|
-
if (state.strategy === "
|
|
21
|
-
if (
|
|
22
|
-
if (state.
|
|
23
|
-
if (state.
|
|
24
|
-
|
|
18
|
+
const event = describeEventTriggers(state);
|
|
19
|
+
if (state.disarmed) return event ? `disarmed \u2014 the experiment has settled; ${event}` : "disarmed \u2014 the experiment has settled";
|
|
20
|
+
if (state.strategy === "live_webhook") return event ? `incoming webhook events \u2014 page views do not trigger this feed; ${event}` : "incoming webhook events \u2014 page views do not trigger this feed";
|
|
21
|
+
if (state.strategy === "live_native_poll") return event ? `not running \u2014 native polling is unavailable; ${event}` : "not running \u2014 native polling is unavailable; configure script_js with a schedule or live_webhook";
|
|
22
|
+
if (!state.job_id) return event ? `not running \u2014 no linked job; ${event}` : "not running \u2014 no linked job; configure the refresh again";
|
|
23
|
+
if (state.job_enabled === false) return event ? `not running \u2014 the linked job is disabled; ${event}` : "not running \u2014 the linked job is disabled; configure the refresh again";
|
|
24
|
+
const trigger = state.schedule ? state.schedule_enabled === false ? `cron ${state.schedule} is disabled` : `cron: ${state.schedule}` : state.refresh_on_view_enabled !== false ? "runs on view \u2014 when a bound page is opened and the data is stale" : event ? void 0 : "manual only \u2014 page views do not trigger this refresh";
|
|
25
|
+
return [trigger, event, state.test_run_success === false ? "configuration test failed" : void 0].filter(Boolean).join("; ");
|
|
26
|
+
}
|
|
27
|
+
function describeEventTriggers(state) {
|
|
28
|
+
if (!state.event_triggers?.length) {
|
|
29
|
+
if (!state.event_dataset_ids?.length) return void 0;
|
|
30
|
+
return `event-driven \u2014 configured for ${state.event_dataset_ids.join(", ")} (debounce ${state.event_debounce_seconds ?? 0}s)`;
|
|
31
|
+
}
|
|
32
|
+
const triggers = state.event_triggers;
|
|
33
|
+
const ownerActive = !!state.job_id && state.disarmed !== true && state.job_enabled !== false;
|
|
34
|
+
const enabled = ownerActive ? triggers.filter((trigger) => trigger.enabled) : [];
|
|
35
|
+
const disabled = ownerActive ? triggers.filter((trigger) => !trigger.enabled) : triggers;
|
|
36
|
+
const parts = [];
|
|
37
|
+
if (enabled.length) {
|
|
38
|
+
const debounce = new Set(enabled.map((trigger) => trigger.debounce_seconds));
|
|
39
|
+
parts.push(`event-driven \u2014 enabled for ${enabled.map((trigger) => trigger.dataset_id).join(", ")}${debounce.size === 1 ? ` (debounce ${enabled[0].debounce_seconds}s)` : ""}`);
|
|
40
|
+
}
|
|
41
|
+
if (disabled.length || enabled.length !== triggers.length) {
|
|
42
|
+
const unavailable = disabled.map((trigger) => trigger.dataset_id);
|
|
43
|
+
parts.push(`event-driven \u2014 disabled for ${unavailable.join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
return parts.join("; ");
|
|
25
46
|
}
|
|
26
47
|
function describeRefreshWrites(strategy, mode, key, liveMode) {
|
|
27
48
|
if (strategy?.startsWith("live_")) return liveMode === "append" ? "append \u2014 each incoming event adds rows" : "replace \u2014 each incoming event replaces the current rows";
|
|
@@ -1223,6 +1244,9 @@ var ErdoClient = class {
|
|
|
1223
1244
|
getDatasetDeclaredSchema(slug) {
|
|
1224
1245
|
return this.request("POST", `/v1/datasets/${encodeURIComponent(slug)}/fetch`, { view: "declared_schema" });
|
|
1225
1246
|
}
|
|
1247
|
+
getDatasetResourceSchema(slug) {
|
|
1248
|
+
return this.request("POST", `/v1/datasets/${encodeURIComponent(slug)}/fetch`, { view: "resource_schema" });
|
|
1249
|
+
}
|
|
1226
1250
|
// Create an empty dataset with its declared columns. The server refuses a
|
|
1227
1251
|
// create without a schema unless the purpose's columns are platform-defined.
|
|
1228
1252
|
createDataset(input) {
|
|
@@ -7281,7 +7305,7 @@ Read one with: erdo datasets fetch ${res.dataset_slug} --revision <id> --sql "SE
|
|
|
7281
7305
|
}
|
|
7282
7306
|
});
|
|
7283
7307
|
datasetsCmd.command("schema <slug>").alias("describe").description(
|
|
7284
|
-
"Show physical columns by default, or the declared write contract with --declared.
|
|
7308
|
+
"Show physical columns by default, or the declared write contract with --declared. File datasets read the stored `data` table; integration datasets show their discovered resource tables and columns. For an integration dataset, choose a resource/table explicitly when fetching: `datasets fetch <slug> --sql 'SELECT * FROM <table>'`."
|
|
7285
7309
|
).option("--json", "print the raw JSON result instead of a table").option("--declared", "read the declared write contract (column names, type hints, required flags, semantic roles) instead of the physical columns").action(async (slug, opts) => {
|
|
7286
7310
|
try {
|
|
7287
7311
|
const client = new ErdoClient();
|
|
@@ -7310,7 +7334,35 @@ datasetsCmd.command("schema <slug>").alias("describe").description(
|
|
|
7310
7334
|
);
|
|
7311
7335
|
return;
|
|
7312
7336
|
}
|
|
7313
|
-
const res = await client.
|
|
7337
|
+
const res = await client.getDatasetResourceSchema(slug);
|
|
7338
|
+
if (!res || typeof res !== "object" || res.view !== "resource_schema")
|
|
7339
|
+
throw new Error("Invalid dataset schema response: the server did not answer the resource_schema view");
|
|
7340
|
+
if (res.schema_provenance === "resource_catalog") {
|
|
7341
|
+
const resources = res.resources ?? [];
|
|
7342
|
+
if (!Array.isArray(resources) || resources.some((resource) => !resource || !Array.isArray(resource.columns)))
|
|
7343
|
+
throw new Error("Invalid dataset schema response: malformed resource catalog");
|
|
7344
|
+
if (opts.json) {
|
|
7345
|
+
print(res);
|
|
7346
|
+
return;
|
|
7347
|
+
}
|
|
7348
|
+
if (!resources.length) {
|
|
7349
|
+
console.log(`${slug} has no discovered integration resources yet.`);
|
|
7350
|
+
return;
|
|
7351
|
+
}
|
|
7352
|
+
const rows = resources.flatMap(
|
|
7353
|
+
(resource) => resource.columns.length ? resource.columns.map((column) => [
|
|
7354
|
+
resource.table_name || resource.key || resource.name,
|
|
7355
|
+
column.name,
|
|
7356
|
+
column.type || ""
|
|
7357
|
+
]) : [[resource.table_name || resource.key || resource.name, "", "(columns unavailable)"]]
|
|
7358
|
+
);
|
|
7359
|
+
printAlignedTable(["table", "column", "type"], rows);
|
|
7360
|
+
console.log(`
|
|
7361
|
+
Fetch a selected table with: erdo datasets fetch ${slug} --sql "SELECT * FROM <table>"`);
|
|
7362
|
+
return;
|
|
7363
|
+
}
|
|
7364
|
+
if (res.schema_provenance !== "dataset_storage" || !Array.isArray(res.columns) || !Array.isArray(res.rows))
|
|
7365
|
+
throw new Error("Invalid dataset schema response: malformed physical schema");
|
|
7314
7366
|
if (opts.json) {
|
|
7315
7367
|
print(res);
|
|
7316
7368
|
return;
|
|
@@ -7439,6 +7491,8 @@ refreshCmd.command("show <slug>").description(
|
|
|
7439
7491
|
if (res.experiment_run_id) rows.push(["experiment", res.experiment_run_id]);
|
|
7440
7492
|
rows.push(["writes", describeRefreshWrites(res.strategy, res.refresh_mode, res.key_column, res.live_write_mode)]);
|
|
7441
7493
|
rows.push(["trigger", describeRefreshTrigger(res)]);
|
|
7494
|
+
const eventTriggers = describeEventTriggers(res);
|
|
7495
|
+
if (eventTriggers) rows.push(["event triggers", eventTriggers]);
|
|
7442
7496
|
if (res.schedule) {
|
|
7443
7497
|
const zone = res.schedule_timezone || "UTC";
|
|
7444
7498
|
rows.push([
|
|
@@ -7489,7 +7543,7 @@ refreshCmd.command("show <slug>").description(
|
|
|
7489
7543
|
}
|
|
7490
7544
|
if (res.job_id) rows.push(["job", res.job_id]);
|
|
7491
7545
|
printAlignedTable(["setting", "value"], rows);
|
|
7492
|
-
if (!res.strategy?.startsWith("live_") && res.job_id && res.job_enabled !== false && !res.disarmed && !res.schedule && !res.refresh_on_view_enabled) {
|
|
7546
|
+
if (!res.strategy?.startsWith("live_") && res.job_id && res.job_enabled !== false && !res.disarmed && !res.schedule && !res.refresh_on_view_enabled && !eventTriggers) {
|
|
7493
7547
|
console.log(
|
|
7494
7548
|
`
|
|
7495
7549
|
Nothing triggers this refresh on its own \u2014 it runs only when asked: erdo datasets refresh run ${res.dataset_slug}`
|
|
@@ -7523,7 +7577,7 @@ refreshCmd.command("set <slug>").description(
|
|
|
7523
7577
|
).option("--agent-prompt <textOr@file>", "instructions for the agent_run strategy, inline or @path").option(
|
|
7524
7578
|
"--context-datasets <csv>",
|
|
7525
7579
|
"slugs of other datasets the recipe reads besides the one it writes"
|
|
7526
|
-
).option(
|
|
7580
|
+
).option("--event-datasets <csv>", "dataset slugs whose writes trigger this refresh (up to 16, comma-separated)").option("--event-debounce <seconds>", "wait after the first source write to coalesce a burst (integer 0\u20133600 seconds)").option(
|
|
7527
7581
|
"--on-view",
|
|
7528
7582
|
"let a page view trigger this refresh (the platform default); pass --no-on-view to turn it off. Sent only when you pass one of the two"
|
|
7529
7583
|
).option("--no-on-view", "stop page views from triggering this refresh").option(
|
|
@@ -7586,6 +7640,31 @@ refreshCmd.command("set <slug>").description(
|
|
|
7586
7640
|
const slugs = opts.contextDatasets.split(",").map((s) => s.trim()).filter(Boolean);
|
|
7587
7641
|
if (slugs.length) body.context_dataset_slugs = slugs;
|
|
7588
7642
|
}
|
|
7643
|
+
let eventDatasetSlugs;
|
|
7644
|
+
if (opts.eventDatasets !== void 0) {
|
|
7645
|
+
eventDatasetSlugs = opts.eventDatasets.split(",").map((s) => s.trim());
|
|
7646
|
+
if (!eventDatasetSlugs.length || eventDatasetSlugs.some((slug2) => !slug2)) {
|
|
7647
|
+
fail(new Error("--event-datasets must include at least one non-blank dataset slug"));
|
|
7648
|
+
return;
|
|
7649
|
+
}
|
|
7650
|
+
if (eventDatasetSlugs.length > 16) {
|
|
7651
|
+
fail(new Error("--event-datasets supports at most 16 dataset slugs"));
|
|
7652
|
+
return;
|
|
7653
|
+
}
|
|
7654
|
+
body.event_dataset_slugs = eventDatasetSlugs;
|
|
7655
|
+
}
|
|
7656
|
+
if (opts.eventDebounce !== void 0) {
|
|
7657
|
+
const value = Number(opts.eventDebounce);
|
|
7658
|
+
if (!opts.eventDebounce.trim() || !Number.isFinite(value) || !Number.isInteger(value) || value < 0 || value > 3600) {
|
|
7659
|
+
fail(new Error("--event-debounce must be a finite integer between 0 and 3600"));
|
|
7660
|
+
return;
|
|
7661
|
+
}
|
|
7662
|
+
if (!eventDatasetSlugs?.length) {
|
|
7663
|
+
fail(new Error("--event-debounce requires non-empty --event-datasets"));
|
|
7664
|
+
return;
|
|
7665
|
+
}
|
|
7666
|
+
body.event_debounce_seconds = value;
|
|
7667
|
+
}
|
|
7589
7668
|
if (opts.onView !== void 0) body.refresh_on_view_enabled = opts.onView;
|
|
7590
7669
|
if (opts.staleAfter !== void 0) {
|
|
7591
7670
|
body.refresh_on_view_stale_after_seconds = opts.staleAfter;
|
|
@@ -7606,7 +7685,13 @@ refreshCmd.command("set <slug>").description(
|
|
|
7606
7685
|
`Installed a ${res.strategy} refresh on ${res.dataset_slug}${res.previous_strategy ? ` (replacing ${res.previous_strategy})` : ""}`
|
|
7607
7686
|
);
|
|
7608
7687
|
console.log(`writes: ${describeRefreshWrites(res.strategy, res.refresh_mode, body.key_column, body.live_write_mode)}`);
|
|
7609
|
-
console.log(describeRefreshTrigger({
|
|
7688
|
+
console.log(describeRefreshTrigger({
|
|
7689
|
+
...res,
|
|
7690
|
+
event_dataset_ids: res.event_dataset_ids,
|
|
7691
|
+
event_debounce_seconds: res.event_debounce_seconds ?? body.event_debounce_seconds,
|
|
7692
|
+
refresh_on_view_enabled: body.refresh_on_view_enabled,
|
|
7693
|
+
test_run_success: res.test_run?.success
|
|
7694
|
+
}));
|
|
7610
7695
|
if (res.job_id) console.log(`job: ${res.job_id}`);
|
|
7611
7696
|
if (res.webhook_url) {
|
|
7612
7697
|
console.log(`webhook url: ${res.webhook_url}`);
|