deepline 0.2.48 → 0.2.50
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/bundling-sources/sdk/src/client.ts +15 -3
- package/dist/bundling-sources/sdk/src/play.ts +15 -1
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +89 -1
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +35 -7
- package/dist/bundling-sources/shared_libs/plays/enrich-compat-adapter.ts +21 -0
- package/dist/bundling-sources/shared_libs/plays/enrich-play-compiler.ts +1555 -0
- package/dist/bundling-sources/shared_libs/plays/user-code-safety.ts +61 -0
- package/dist/cli/index.js +147 -15
- package/dist/cli/index.mjs +150 -16
- package/dist/{compiler-manifest-CGZadg-v.d.mts → compiler-manifest-BPA3r-VG.d.mts} +84 -0
- package/dist/{compiler-manifest-CGZadg-v.d.ts → compiler-manifest-BPA3r-VG.d.ts} +84 -0
- package/dist/index.d.mts +27 -6
- package/dist/index.d.ts +27 -6
- package/dist/index.js +10 -4
- package/dist/index.mjs +10 -4
- package/dist/install-integrity.json +5 -2
- package/dist/plays/bundle-play-file.d.mts +4 -2
- package/dist/plays/bundle-play-file.d.ts +4 -2
- package/dist/plays/bundle-play-file.mjs +102 -7
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Compile-time safety gate for user-authored play code (enrich `extract_js`,
|
|
2
|
+
// `run_if_js`, and `run_javascript` step `code`).
|
|
3
|
+
//
|
|
4
|
+
// Plays replay deterministically under Worker Loader, and the step code runs
|
|
5
|
+
// with provider data in scope. So user code may NOT be non-deterministic
|
|
6
|
+
// (Math.random, Date.now, ...) — replay would diverge — and may NOT reach out
|
|
7
|
+
// of the sandbox (fetch, require, process, ...). We reject those at compile
|
|
8
|
+
// time with a clear, named error (fail loud, per the repo non-negotiables).
|
|
9
|
+
//
|
|
10
|
+
// This is a fast static scan, not a security boundary on its own: the play
|
|
11
|
+
// runtime is the real boundary (it executes step code in an isolate that does
|
|
12
|
+
// not expose these globals). The scan exists to fail authoring early with a
|
|
13
|
+
// readable message instead of producing a play that silently misbehaves at run
|
|
14
|
+
// time. The `(?<!\.)` guards keep it from flagging harmless property access on
|
|
15
|
+
// user objects (e.g. `row.process_date`, `data.fetch`).
|
|
16
|
+
|
|
17
|
+
type ForbiddenRule = { readonly pattern: RegExp; readonly reason: string };
|
|
18
|
+
|
|
19
|
+
const FORBIDDEN: readonly ForbiddenRule[] = [
|
|
20
|
+
// Non-deterministic — breaks replay.
|
|
21
|
+
{ pattern: /\bMath\s*\.\s*random\b/, reason: 'Math.random()' },
|
|
22
|
+
{ pattern: /\bDate\s*\.\s*now\b/, reason: 'Date.now()' },
|
|
23
|
+
{ pattern: /\bnew\s+Date\s*\(\s*\)/, reason: 'new Date() with no argument' },
|
|
24
|
+
{ pattern: /\bperformance\s*\.\s*now\b/, reason: 'performance.now()' },
|
|
25
|
+
{
|
|
26
|
+
pattern: /\bcrypto\s*\.\s*(?:randomUUID|getRandomValues)\b/,
|
|
27
|
+
reason: 'crypto random',
|
|
28
|
+
},
|
|
29
|
+
// Sandbox escape / I/O.
|
|
30
|
+
{ pattern: /(?<!\.)\bfetch\s*\(/, reason: 'fetch()' },
|
|
31
|
+
{ pattern: /(?<!\.)\bimport\s*\(/, reason: 'dynamic import()' },
|
|
32
|
+
{ pattern: /(?<!\.)\brequire\s*\(/, reason: 'require()' },
|
|
33
|
+
{ pattern: /(?<!\.)\beval\s*\(/, reason: 'eval()' },
|
|
34
|
+
{
|
|
35
|
+
pattern: /(?<!\.)\bnew\s+Function\b|(?<!\.)\bFunction\s*\(/,
|
|
36
|
+
reason: 'the Function constructor',
|
|
37
|
+
},
|
|
38
|
+
{ pattern: /(?<!\.)\bprocess\b/, reason: 'process' },
|
|
39
|
+
{ pattern: /(?<!\.)\bglobalThis\b/, reason: 'globalThis' },
|
|
40
|
+
{ pattern: /(?<!\.)\b(?:window|self)\b/, reason: 'window/self' },
|
|
41
|
+
{ pattern: /(?<!\.)\bXMLHttpRequest\b/, reason: 'XMLHttpRequest' },
|
|
42
|
+
{ pattern: /(?<!\.)\bWebAssembly\b/, reason: 'WebAssembly' },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Throw if `code` references a forbidden (non-deterministic or sandbox-escaping)
|
|
47
|
+
* construct. `label` describes where the code came from for the error message,
|
|
48
|
+
* e.g. `extract_js for "email"` or `run_javascript step "enrich"`.
|
|
49
|
+
*/
|
|
50
|
+
export function assertUserCodeIsSafe(code: string, label: string): void {
|
|
51
|
+
if (typeof code !== 'string' || !code.trim()) return;
|
|
52
|
+
for (const { pattern, reason } of FORBIDDEN) {
|
|
53
|
+
if (pattern.test(code)) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`${label} uses ${reason}, which is not allowed in play code: it ` +
|
|
56
|
+
`breaks deterministic replay or escapes the sandbox. Remove it and ` +
|
|
57
|
+
`compute the value from the row/result instead.`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -1044,7 +1044,7 @@ var SDK_RELEASE = {
|
|
|
1044
1044
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
1045
1045
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
1046
1046
|
// release keeps lazy paging semantics independent of row residency.
|
|
1047
|
-
version: "0.2.
|
|
1047
|
+
version: "0.2.50",
|
|
1048
1048
|
contracts: {
|
|
1049
1049
|
api: {
|
|
1050
1050
|
name: "sdk-http-api",
|
|
@@ -3879,7 +3879,7 @@ var DeeplineClient = class {
|
|
|
3879
3879
|
deploy: (definition, options2) => this.deployMonitor(definition, options2),
|
|
3880
3880
|
list: (options2) => this.listMonitors(options2),
|
|
3881
3881
|
get: (key) => this.getMonitor(key),
|
|
3882
|
-
test: (key, payload) => this.testMonitorWebhook(key, payload),
|
|
3882
|
+
test: (key, payload, options2) => this.testMonitorWebhook(key, payload, options2),
|
|
3883
3883
|
validate: (key) => this.validateMonitor(key),
|
|
3884
3884
|
dependents: (key) => this.getMonitorDependents(key),
|
|
3885
3885
|
update: (key, patch) => this.updateMonitor(key, patch),
|
|
@@ -6048,10 +6048,16 @@ var DeeplineClient = class {
|
|
|
6048
6048
|
{ method: "GET" }
|
|
6049
6049
|
);
|
|
6050
6050
|
}
|
|
6051
|
-
async testMonitorWebhook(key, payload) {
|
|
6051
|
+
async testMonitorWebhook(key, payload, options) {
|
|
6052
6052
|
return this.http.request(
|
|
6053
6053
|
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/test`,
|
|
6054
|
-
{
|
|
6054
|
+
{
|
|
6055
|
+
method: "POST",
|
|
6056
|
+
body: {
|
|
6057
|
+
payload,
|
|
6058
|
+
...options?.validationOnly ? { mode: "validation_only" } : {}
|
|
6059
|
+
}
|
|
6060
|
+
}
|
|
6055
6061
|
);
|
|
6056
6062
|
}
|
|
6057
6063
|
async setupMonitor(tool, payload) {
|
|
@@ -15021,6 +15027,76 @@ var PLAY_AUTHORING_FIELD_REGISTRY = {
|
|
|
15021
15027
|
description: "HTTP header containing the webhook signature.",
|
|
15022
15028
|
errorMessage: "bindings.webhook.hmac.header must be a non-empty static string."
|
|
15023
15029
|
},
|
|
15030
|
+
"bindings.webhook.auth.type": {
|
|
15031
|
+
schema: Type.Literal("standard-webhooks"),
|
|
15032
|
+
fixtures: {
|
|
15033
|
+
valid: "standard-webhooks",
|
|
15034
|
+
invalid: "svix",
|
|
15035
|
+
absent: void 0,
|
|
15036
|
+
unresolved: { expression: "type" },
|
|
15037
|
+
edition1: void 0
|
|
15038
|
+
},
|
|
15039
|
+
referenceType: "'standard-webhooks'",
|
|
15040
|
+
// auth itself is optional; once present, the AST adapter requires this
|
|
15041
|
+
// field together with headerFamily and signingSecrets.
|
|
15042
|
+
required: false,
|
|
15043
|
+
resolution: "static-required",
|
|
15044
|
+
issueCode: "play_authoring_standard_webhooks_invalid",
|
|
15045
|
+
description: "Uses the Standard Webhooks v1 symmetric signing scheme.",
|
|
15046
|
+
errorMessage: 'bindings.webhook.auth.type must be the static literal "standard-webhooks".'
|
|
15047
|
+
},
|
|
15048
|
+
"bindings.webhook.auth.headerFamily": {
|
|
15049
|
+
schema: Type.Union([Type.Literal("standard"), Type.Literal("svix")]),
|
|
15050
|
+
fixtures: {
|
|
15051
|
+
valid: "svix",
|
|
15052
|
+
invalid: "webhook",
|
|
15053
|
+
absent: void 0,
|
|
15054
|
+
unresolved: { expression: "headerFamily" },
|
|
15055
|
+
edition1: void 0
|
|
15056
|
+
},
|
|
15057
|
+
referenceType: "'standard' | 'svix'",
|
|
15058
|
+
// auth itself is optional; once present, the AST adapter requires this
|
|
15059
|
+
// field together with type and signingSecrets.
|
|
15060
|
+
required: false,
|
|
15061
|
+
resolution: "static-required",
|
|
15062
|
+
issueCode: "play_authoring_standard_webhooks_invalid",
|
|
15063
|
+
description: "Header namespace expected from the webhook provider.",
|
|
15064
|
+
errorMessage: 'bindings.webhook.auth.headerFamily must be the static literal "standard" or "svix".'
|
|
15065
|
+
},
|
|
15066
|
+
"bindings.webhook.auth.signingSecrets[]": {
|
|
15067
|
+
schema: SecretEnvironmentNameSchema,
|
|
15068
|
+
fixtures: {
|
|
15069
|
+
valid: "VECTOR_WEBHOOK_SECRET",
|
|
15070
|
+
invalid: "vector_webhook_secret",
|
|
15071
|
+
absent: void 0,
|
|
15072
|
+
unresolved: { expression: "secret" },
|
|
15073
|
+
edition1: void 0
|
|
15074
|
+
},
|
|
15075
|
+
referenceType: "string",
|
|
15076
|
+
// auth itself is optional; once present, the AST adapter requires this
|
|
15077
|
+
// field together with type and headerFamily.
|
|
15078
|
+
required: false,
|
|
15079
|
+
resolution: "static-required",
|
|
15080
|
+
issueCode: "play_authoring_standard_webhooks_invalid",
|
|
15081
|
+
description: "Deepline Secret name used to verify Standard Webhooks.",
|
|
15082
|
+
errorMessage: "bindings.webhook.auth.signingSecrets entries must be uppercase Deepline Secret names beginning with a letter."
|
|
15083
|
+
},
|
|
15084
|
+
"bindings.webhook.auth.toleranceSeconds": {
|
|
15085
|
+
schema: Type.Integer({ minimum: 1, maximum: 3600 }),
|
|
15086
|
+
fixtures: {
|
|
15087
|
+
valid: 300,
|
|
15088
|
+
invalid: 0,
|
|
15089
|
+
absent: void 0,
|
|
15090
|
+
unresolved: { expression: "toleranceSeconds" },
|
|
15091
|
+
edition1: void 0
|
|
15092
|
+
},
|
|
15093
|
+
referenceType: "number",
|
|
15094
|
+
required: false,
|
|
15095
|
+
resolution: "static-required",
|
|
15096
|
+
issueCode: "play_authoring_standard_webhooks_invalid",
|
|
15097
|
+
description: "Accepted delivery timestamp skew in seconds, from 1 through 3600.",
|
|
15098
|
+
errorMessage: "bindings.webhook.auth.toleranceSeconds must be a static whole number from 1 through 3600."
|
|
15099
|
+
},
|
|
15024
15100
|
"bindings.cron.schedule": {
|
|
15025
15101
|
schema: Type.String({ minLength: 1 }),
|
|
15026
15102
|
fixtures: {
|
|
@@ -16045,7 +16121,7 @@ var PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
|
|
|
16045
16121
|
` inline?: ${cloudReferenceType("inline")};`,
|
|
16046
16122
|
` billing?: { maxCreditsPerRun?: ${cloudReferenceType("billing.maxCreditsPerRun")} };`,
|
|
16047
16123
|
` runtime?: { timeout?: ${cloudReferenceType("runtime.timeout")}; size?: ${cloudReferenceType("runtime.size")} };`,
|
|
16048
|
-
` webhook?: { hmac?: { algorithm?: ${cloudReferenceType("bindings.webhook.hmac.algorithm")}; header?: ${cloudReferenceType("bindings.webhook.hmac.header")}; secretEnv: ${cloudReferenceType("bindings.webhook.hmac.secretEnv")} } };`,
|
|
16124
|
+
` webhook?: { hmac?: { algorithm?: ${cloudReferenceType("bindings.webhook.hmac.algorithm")}; header?: ${cloudReferenceType("bindings.webhook.hmac.header")}; secretEnv: ${cloudReferenceType("bindings.webhook.hmac.secretEnv")} }; auth?: { type: ${cloudReferenceType("bindings.webhook.auth.type")}; headerFamily: ${cloudReferenceType("bindings.webhook.auth.headerFamily")}; signingSecrets: readonly ${cloudReferenceType("bindings.webhook.auth.signingSecrets[]")}[]; toleranceSeconds?: ${cloudReferenceType("bindings.webhook.auth.toleranceSeconds")} } };`,
|
|
16049
16125
|
` cron?: { schedule: ${cloudReferenceType("bindings.cron.schedule")}; timezone?: ${cloudReferenceType("bindings.cron.timezone")} };`,
|
|
16050
16126
|
" sqlListeners?: readonly SqlListenerDeclaration[];",
|
|
16051
16127
|
` secrets?: readonly ${cloudReferenceType("bindings.secrets[]")}[];`,
|
|
@@ -24587,7 +24663,7 @@ function getterFromLegacyExtractJs(extractJs, fallbackAlias) {
|
|
|
24587
24663
|
return null;
|
|
24588
24664
|
}
|
|
24589
24665
|
|
|
24590
|
-
//
|
|
24666
|
+
// ../shared_libs/plays/enrich-compat-adapter.ts
|
|
24591
24667
|
var ENRICH_COMPAT_DEFAULT_PLAY_NAME = "deepline-enrich-v1-compat";
|
|
24592
24668
|
var ENRICH_COMPAT_DEFAULT_MAP_NAME = "deepline_enrich_rows";
|
|
24593
24669
|
function buildEnrichCompatibilityPlan(options = {}) {
|
|
@@ -24597,7 +24673,7 @@ function buildEnrichCompatibilityPlan(options = {}) {
|
|
|
24597
24673
|
};
|
|
24598
24674
|
}
|
|
24599
24675
|
|
|
24600
|
-
//
|
|
24676
|
+
// ../shared_libs/plays/user-code-safety.ts
|
|
24601
24677
|
var FORBIDDEN = [
|
|
24602
24678
|
// Non-deterministic — breaks replay.
|
|
24603
24679
|
{ pattern: /\bMath\s*\.\s*random\b/, reason: "Math.random()" },
|
|
@@ -24634,7 +24710,7 @@ function assertUserCodeIsSafe(code, label) {
|
|
|
24634
24710
|
}
|
|
24635
24711
|
}
|
|
24636
24712
|
|
|
24637
|
-
//
|
|
24713
|
+
// ../shared_libs/plays/enrich-play-compiler.ts
|
|
24638
24714
|
function isWaterfall(command) {
|
|
24639
24715
|
return "with_waterfall" in command;
|
|
24640
24716
|
}
|
|
@@ -25065,7 +25141,9 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
|
|
|
25065
25141
|
const generatedAliases = collectGeneratedAliases(config.commands);
|
|
25066
25142
|
const runOptionsSource = options.failFast ? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }` : `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
|
|
25067
25143
|
const playOptionsSource = [
|
|
25068
|
-
`description: ${stringLiteral(
|
|
25144
|
+
`description: ${stringLiteral(
|
|
25145
|
+
"Read a CSV file, run the configured Deepline enrich commands, and return enriched rows."
|
|
25146
|
+
)}`,
|
|
25069
25147
|
...options.maxCreditsPerRun === void 0 ? [] : [`billing: { maxCreditsPerRun: ${String(options.maxCreditsPerRun)} }`]
|
|
25070
25148
|
].join(", ");
|
|
25071
25149
|
const body = [
|
|
@@ -30757,6 +30835,31 @@ function readDeployOutputContract(payload) {
|
|
|
30757
30835
|
});
|
|
30758
30836
|
return { tool: asString(contract.tool), streams };
|
|
30759
30837
|
}
|
|
30838
|
+
function renderDeployReplacementWarning(input2) {
|
|
30839
|
+
const summary = asRecord2(input2.payload.change_summary);
|
|
30840
|
+
const upstream = summary ? asRecord2(summary.upstream) : void 0;
|
|
30841
|
+
if (!summary || !upstream || upstream.resource_replaced !== true) return [];
|
|
30842
|
+
const definition = asRecord2(summary.definition);
|
|
30843
|
+
const changed = definition && Array.isArray(definition.changed) ? definition.changed : [];
|
|
30844
|
+
const lines = [
|
|
30845
|
+
input2.completed ? "WARNING: this deploy replaced the existing upstream monitor." : "WARNING: this deploy replaces the existing upstream monitor.",
|
|
30846
|
+
"Existing Customer DB rows are preserved. Provider backfill is not implied."
|
|
30847
|
+
];
|
|
30848
|
+
for (const raw of changed) {
|
|
30849
|
+
const item = asRecord2(raw);
|
|
30850
|
+
const path = item ? asString(item.path) : void 0;
|
|
30851
|
+
if (!item || !path) continue;
|
|
30852
|
+
lines.push(
|
|
30853
|
+
` ${path}: ${JSON.stringify(item.before ?? null)} \u2192 ${JSON.stringify(
|
|
30854
|
+
item.after ?? null
|
|
30855
|
+
)}`
|
|
30856
|
+
);
|
|
30857
|
+
}
|
|
30858
|
+
lines.push(
|
|
30859
|
+
input2.monitorKey ? `Use \`deepline monitors update ${input2.monitorKey} <patch>\` for a patch-style change.` : "Use `deepline monitors update <key> <patch>` for a patch-style change."
|
|
30860
|
+
);
|
|
30861
|
+
return lines;
|
|
30862
|
+
}
|
|
30760
30863
|
function renderMonitorDeployCompletion(payload) {
|
|
30761
30864
|
const monitor = asRecord2(payload.monitor);
|
|
30762
30865
|
const key = monitor ? asString(monitor.key) : void 0;
|
|
@@ -30784,6 +30887,12 @@ function renderMonitorDeployCompletion(payload) {
|
|
|
30784
30887
|
if (pricingLine) {
|
|
30785
30888
|
lines.push("", `Pricing: ${pricingLine}`);
|
|
30786
30889
|
}
|
|
30890
|
+
const replacementWarning = renderDeployReplacementWarning({
|
|
30891
|
+
payload,
|
|
30892
|
+
completed: true,
|
|
30893
|
+
monitorKey: key
|
|
30894
|
+
});
|
|
30895
|
+
if (replacementWarning.length) lines.push("", ...replacementWarning);
|
|
30787
30896
|
const guidance = asRecord2(payload.setup_guidance);
|
|
30788
30897
|
if (guidance) {
|
|
30789
30898
|
const callbackUrl = asString(guidance.callback_url);
|
|
@@ -30835,6 +30944,11 @@ function renderMonitorDeployPlan(payload) {
|
|
|
30835
30944
|
if (message) lines.push(` - ${path ? `${path}: ` : ""}${message}`);
|
|
30836
30945
|
}
|
|
30837
30946
|
}
|
|
30947
|
+
const replacementWarning = renderDeployReplacementWarning({
|
|
30948
|
+
payload,
|
|
30949
|
+
completed: false
|
|
30950
|
+
});
|
|
30951
|
+
if (replacementWarning.length) lines.push("", ...replacementWarning);
|
|
30838
30952
|
const estimate = asRecord2(payload.deploy_cost_estimate);
|
|
30839
30953
|
const credits = estimate ? asFiniteNumber(estimate.credits) : void 0;
|
|
30840
30954
|
if (credits !== void 0) {
|
|
@@ -31201,10 +31315,17 @@ async function handleMonitorsGet(key, options) {
|
|
|
31201
31315
|
}
|
|
31202
31316
|
async function handleMonitorsTest(key, payload, options) {
|
|
31203
31317
|
const explicitPayload = parseJsonObjectArg(payload, "<payload>");
|
|
31204
|
-
const result = await new DeeplineClient().monitors.test(
|
|
31205
|
-
|
|
31206
|
-
|
|
31207
|
-
|
|
31318
|
+
const result = await new DeeplineClient().monitors.test(
|
|
31319
|
+
key,
|
|
31320
|
+
explicitPayload,
|
|
31321
|
+
{
|
|
31322
|
+
validationOnly: options.dispatch !== true
|
|
31323
|
+
}
|
|
31324
|
+
);
|
|
31325
|
+
const dispatch = options.dispatch === true;
|
|
31326
|
+
const text = `Monitor diagnostic for ${key}: ${result.accepted === true ? "accepted" : "rejected"}
|
|
31327
|
+
` + (dispatch ? " mode: dispatch (writes rows and may dispatch bound Plays)\n" : " mode: validation_only (no rows written, credits spent, or Plays dispatched)\n") + `${dispatch ? "persisted" : "would persist"} rows: ${asFiniteNumber(result.persisted_rows) ?? 0}
|
|
31328
|
+
${dispatch ? "dispatched" : "would dispatch"} bound Plays: ${asFiniteNumber(result.dispatched_bound_plays) ?? 0}
|
|
31208
31329
|
`;
|
|
31209
31330
|
printCommandEnvelope(result, { json: options.json, text });
|
|
31210
31331
|
}
|
|
@@ -31416,12 +31537,18 @@ Examples:
|
|
|
31416
31537
|
withJsonOption(
|
|
31417
31538
|
monitors.command("test <key> <payload>").description(
|
|
31418
31539
|
"Send an explicit payload through a monitor\u2019s webhook ingestion path."
|
|
31540
|
+
).option(
|
|
31541
|
+
"--dispatch",
|
|
31542
|
+
"Inject the test event through normal ingestion (writes rows and may dispatch bound Plays)"
|
|
31419
31543
|
).addHelpText(
|
|
31420
31544
|
"after",
|
|
31421
31545
|
`
|
|
31422
31546
|
Notes:
|
|
31423
31547
|
<payload> must be an explicit JSON object. The command uses the deployed
|
|
31424
|
-
monitor\u2019s real
|
|
31548
|
+
monitor\u2019s real binding and payload validation, but is a side-effect-free
|
|
31549
|
+
diagnostic: it does not persist rows, spend credits, dispatch Plays, or alter
|
|
31550
|
+
monitor state. Pass --dispatch only when you deliberately need the historic
|
|
31551
|
+
full-ingestion test event; it can write rows and trigger bound Plays. It does
|
|
31425
31552
|
not synthesize a provider event or accept an omitted payload.
|
|
31426
31553
|
|
|
31427
31554
|
Examples:
|
|
@@ -31442,7 +31569,9 @@ Notes:
|
|
|
31442
31569
|
via --file <path>, or
|
|
31443
31570
|
from stdin with --file -. Does not deploy or spend credits.
|
|
31444
31571
|
For Deepline Native Company Radar monitors, check validates persona-filter enums and the
|
|
31445
|
-
job_titles Boolean-expression grammar locally
|
|
31572
|
+
job_titles Boolean-expression grammar locally (parentheses are unsupported;
|
|
31573
|
+
NOT > AND > OR).
|
|
31574
|
+
Inspect the exact schema with
|
|
31446
31575
|
\`deepline monitors available deepline_native.company_radar --json\`.
|
|
31447
31576
|
|
|
31448
31577
|
Examples:
|
|
@@ -31466,6 +31595,9 @@ Notes:
|
|
|
31466
31595
|
--dry-run validates the definition and shows the plan (deploy cost in Deepline
|
|
31467
31596
|
credits when the server reports it, plus any existing monitors that may
|
|
31468
31597
|
already cover this scope) WITHOUT deploying. Exits 0 when valid, 7 when not.
|
|
31598
|
+
Deploy is a full desired definition for its key: omitting a previously stored
|
|
31599
|
+
field removes it and can replace the upstream resource. Use \`monitors update\`
|
|
31600
|
+
for a patch-style change.
|
|
31469
31601
|
|
|
31470
31602
|
Examples:
|
|
31471
31603
|
deepline monitors deploy '{"key":"job-openings","tool":"deepline_native.company_radar","payload":{"domain":"stripe.com","radar_type":"company_job_openings"}}'
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1030,7 +1030,7 @@ var SDK_RELEASE = {
|
|
|
1030
1030
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
1031
1031
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
1032
1032
|
// release keeps lazy paging semantics independent of row residency.
|
|
1033
|
-
version: "0.2.
|
|
1033
|
+
version: "0.2.50",
|
|
1034
1034
|
contracts: {
|
|
1035
1035
|
api: {
|
|
1036
1036
|
name: "sdk-http-api",
|
|
@@ -3865,7 +3865,7 @@ var DeeplineClient = class {
|
|
|
3865
3865
|
deploy: (definition, options2) => this.deployMonitor(definition, options2),
|
|
3866
3866
|
list: (options2) => this.listMonitors(options2),
|
|
3867
3867
|
get: (key) => this.getMonitor(key),
|
|
3868
|
-
test: (key, payload) => this.testMonitorWebhook(key, payload),
|
|
3868
|
+
test: (key, payload, options2) => this.testMonitorWebhook(key, payload, options2),
|
|
3869
3869
|
validate: (key) => this.validateMonitor(key),
|
|
3870
3870
|
dependents: (key) => this.getMonitorDependents(key),
|
|
3871
3871
|
update: (key, patch) => this.updateMonitor(key, patch),
|
|
@@ -6034,10 +6034,16 @@ var DeeplineClient = class {
|
|
|
6034
6034
|
{ method: "GET" }
|
|
6035
6035
|
);
|
|
6036
6036
|
}
|
|
6037
|
-
async testMonitorWebhook(key, payload) {
|
|
6037
|
+
async testMonitorWebhook(key, payload, options) {
|
|
6038
6038
|
return this.http.request(
|
|
6039
6039
|
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/test`,
|
|
6040
|
-
{
|
|
6040
|
+
{
|
|
6041
|
+
method: "POST",
|
|
6042
|
+
body: {
|
|
6043
|
+
payload,
|
|
6044
|
+
...options?.validationOnly ? { mode: "validation_only" } : {}
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6041
6047
|
);
|
|
6042
6048
|
}
|
|
6043
6049
|
async setupMonitor(tool, payload) {
|
|
@@ -12307,7 +12313,9 @@ import {
|
|
|
12307
12313
|
extname,
|
|
12308
12314
|
isAbsolute as isAbsolute3,
|
|
12309
12315
|
join as join7,
|
|
12310
|
-
|
|
12316
|
+
relative as relative2,
|
|
12317
|
+
resolve as resolve8,
|
|
12318
|
+
sep
|
|
12311
12319
|
} from "path";
|
|
12312
12320
|
import { builtinModules } from "module";
|
|
12313
12321
|
import { Parser } from "acorn";
|
|
@@ -15058,6 +15066,76 @@ var PLAY_AUTHORING_FIELD_REGISTRY = {
|
|
|
15058
15066
|
description: "HTTP header containing the webhook signature.",
|
|
15059
15067
|
errorMessage: "bindings.webhook.hmac.header must be a non-empty static string."
|
|
15060
15068
|
},
|
|
15069
|
+
"bindings.webhook.auth.type": {
|
|
15070
|
+
schema: Type.Literal("standard-webhooks"),
|
|
15071
|
+
fixtures: {
|
|
15072
|
+
valid: "standard-webhooks",
|
|
15073
|
+
invalid: "svix",
|
|
15074
|
+
absent: void 0,
|
|
15075
|
+
unresolved: { expression: "type" },
|
|
15076
|
+
edition1: void 0
|
|
15077
|
+
},
|
|
15078
|
+
referenceType: "'standard-webhooks'",
|
|
15079
|
+
// auth itself is optional; once present, the AST adapter requires this
|
|
15080
|
+
// field together with headerFamily and signingSecrets.
|
|
15081
|
+
required: false,
|
|
15082
|
+
resolution: "static-required",
|
|
15083
|
+
issueCode: "play_authoring_standard_webhooks_invalid",
|
|
15084
|
+
description: "Uses the Standard Webhooks v1 symmetric signing scheme.",
|
|
15085
|
+
errorMessage: 'bindings.webhook.auth.type must be the static literal "standard-webhooks".'
|
|
15086
|
+
},
|
|
15087
|
+
"bindings.webhook.auth.headerFamily": {
|
|
15088
|
+
schema: Type.Union([Type.Literal("standard"), Type.Literal("svix")]),
|
|
15089
|
+
fixtures: {
|
|
15090
|
+
valid: "svix",
|
|
15091
|
+
invalid: "webhook",
|
|
15092
|
+
absent: void 0,
|
|
15093
|
+
unresolved: { expression: "headerFamily" },
|
|
15094
|
+
edition1: void 0
|
|
15095
|
+
},
|
|
15096
|
+
referenceType: "'standard' | 'svix'",
|
|
15097
|
+
// auth itself is optional; once present, the AST adapter requires this
|
|
15098
|
+
// field together with type and signingSecrets.
|
|
15099
|
+
required: false,
|
|
15100
|
+
resolution: "static-required",
|
|
15101
|
+
issueCode: "play_authoring_standard_webhooks_invalid",
|
|
15102
|
+
description: "Header namespace expected from the webhook provider.",
|
|
15103
|
+
errorMessage: 'bindings.webhook.auth.headerFamily must be the static literal "standard" or "svix".'
|
|
15104
|
+
},
|
|
15105
|
+
"bindings.webhook.auth.signingSecrets[]": {
|
|
15106
|
+
schema: SecretEnvironmentNameSchema,
|
|
15107
|
+
fixtures: {
|
|
15108
|
+
valid: "VECTOR_WEBHOOK_SECRET",
|
|
15109
|
+
invalid: "vector_webhook_secret",
|
|
15110
|
+
absent: void 0,
|
|
15111
|
+
unresolved: { expression: "secret" },
|
|
15112
|
+
edition1: void 0
|
|
15113
|
+
},
|
|
15114
|
+
referenceType: "string",
|
|
15115
|
+
// auth itself is optional; once present, the AST adapter requires this
|
|
15116
|
+
// field together with type and headerFamily.
|
|
15117
|
+
required: false,
|
|
15118
|
+
resolution: "static-required",
|
|
15119
|
+
issueCode: "play_authoring_standard_webhooks_invalid",
|
|
15120
|
+
description: "Deepline Secret name used to verify Standard Webhooks.",
|
|
15121
|
+
errorMessage: "bindings.webhook.auth.signingSecrets entries must be uppercase Deepline Secret names beginning with a letter."
|
|
15122
|
+
},
|
|
15123
|
+
"bindings.webhook.auth.toleranceSeconds": {
|
|
15124
|
+
schema: Type.Integer({ minimum: 1, maximum: 3600 }),
|
|
15125
|
+
fixtures: {
|
|
15126
|
+
valid: 300,
|
|
15127
|
+
invalid: 0,
|
|
15128
|
+
absent: void 0,
|
|
15129
|
+
unresolved: { expression: "toleranceSeconds" },
|
|
15130
|
+
edition1: void 0
|
|
15131
|
+
},
|
|
15132
|
+
referenceType: "number",
|
|
15133
|
+
required: false,
|
|
15134
|
+
resolution: "static-required",
|
|
15135
|
+
issueCode: "play_authoring_standard_webhooks_invalid",
|
|
15136
|
+
description: "Accepted delivery timestamp skew in seconds, from 1 through 3600.",
|
|
15137
|
+
errorMessage: "bindings.webhook.auth.toleranceSeconds must be a static whole number from 1 through 3600."
|
|
15138
|
+
},
|
|
15061
15139
|
"bindings.cron.schedule": {
|
|
15062
15140
|
schema: Type.String({ minLength: 1 }),
|
|
15063
15141
|
fixtures: {
|
|
@@ -16082,7 +16160,7 @@ var PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
|
|
|
16082
16160
|
` inline?: ${cloudReferenceType("inline")};`,
|
|
16083
16161
|
` billing?: { maxCreditsPerRun?: ${cloudReferenceType("billing.maxCreditsPerRun")} };`,
|
|
16084
16162
|
` runtime?: { timeout?: ${cloudReferenceType("runtime.timeout")}; size?: ${cloudReferenceType("runtime.size")} };`,
|
|
16085
|
-
` webhook?: { hmac?: { algorithm?: ${cloudReferenceType("bindings.webhook.hmac.algorithm")}; header?: ${cloudReferenceType("bindings.webhook.hmac.header")}; secretEnv: ${cloudReferenceType("bindings.webhook.hmac.secretEnv")} } };`,
|
|
16163
|
+
` webhook?: { hmac?: { algorithm?: ${cloudReferenceType("bindings.webhook.hmac.algorithm")}; header?: ${cloudReferenceType("bindings.webhook.hmac.header")}; secretEnv: ${cloudReferenceType("bindings.webhook.hmac.secretEnv")} }; auth?: { type: ${cloudReferenceType("bindings.webhook.auth.type")}; headerFamily: ${cloudReferenceType("bindings.webhook.auth.headerFamily")}; signingSecrets: readonly ${cloudReferenceType("bindings.webhook.auth.signingSecrets[]")}[]; toleranceSeconds?: ${cloudReferenceType("bindings.webhook.auth.toleranceSeconds")} } };`,
|
|
16086
16164
|
` cron?: { schedule: ${cloudReferenceType("bindings.cron.schedule")}; timezone?: ${cloudReferenceType("bindings.cron.timezone")} };`,
|
|
16087
16165
|
" sqlListeners?: readonly SqlListenerDeclaration[];",
|
|
16088
16166
|
` secrets?: readonly ${cloudReferenceType("bindings.secrets[]")}[];`,
|
|
@@ -24631,7 +24709,7 @@ function getterFromLegacyExtractJs(extractJs, fallbackAlias) {
|
|
|
24631
24709
|
return null;
|
|
24632
24710
|
}
|
|
24633
24711
|
|
|
24634
|
-
//
|
|
24712
|
+
// ../shared_libs/plays/enrich-compat-adapter.ts
|
|
24635
24713
|
var ENRICH_COMPAT_DEFAULT_PLAY_NAME = "deepline-enrich-v1-compat";
|
|
24636
24714
|
var ENRICH_COMPAT_DEFAULT_MAP_NAME = "deepline_enrich_rows";
|
|
24637
24715
|
function buildEnrichCompatibilityPlan(options = {}) {
|
|
@@ -24641,7 +24719,7 @@ function buildEnrichCompatibilityPlan(options = {}) {
|
|
|
24641
24719
|
};
|
|
24642
24720
|
}
|
|
24643
24721
|
|
|
24644
|
-
//
|
|
24722
|
+
// ../shared_libs/plays/user-code-safety.ts
|
|
24645
24723
|
var FORBIDDEN = [
|
|
24646
24724
|
// Non-deterministic — breaks replay.
|
|
24647
24725
|
{ pattern: /\bMath\s*\.\s*random\b/, reason: "Math.random()" },
|
|
@@ -24678,7 +24756,7 @@ function assertUserCodeIsSafe(code, label) {
|
|
|
24678
24756
|
}
|
|
24679
24757
|
}
|
|
24680
24758
|
|
|
24681
|
-
//
|
|
24759
|
+
// ../shared_libs/plays/enrich-play-compiler.ts
|
|
24682
24760
|
function isWaterfall(command) {
|
|
24683
24761
|
return "with_waterfall" in command;
|
|
24684
24762
|
}
|
|
@@ -25109,7 +25187,9 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
|
|
|
25109
25187
|
const generatedAliases = collectGeneratedAliases(config.commands);
|
|
25110
25188
|
const runOptionsSource = options.failFast ? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }` : `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
|
|
25111
25189
|
const playOptionsSource = [
|
|
25112
|
-
`description: ${stringLiteral(
|
|
25190
|
+
`description: ${stringLiteral(
|
|
25191
|
+
"Read a CSV file, run the configured Deepline enrich commands, and return enriched rows."
|
|
25192
|
+
)}`,
|
|
25113
25193
|
...options.maxCreditsPerRun === void 0 ? [] : [`billing: { maxCreditsPerRun: ${String(options.maxCreditsPerRun)} }`]
|
|
25114
25194
|
].join(", ");
|
|
25115
25195
|
const body = [
|
|
@@ -30808,6 +30888,31 @@ function readDeployOutputContract(payload) {
|
|
|
30808
30888
|
});
|
|
30809
30889
|
return { tool: asString(contract.tool), streams };
|
|
30810
30890
|
}
|
|
30891
|
+
function renderDeployReplacementWarning(input2) {
|
|
30892
|
+
const summary = asRecord2(input2.payload.change_summary);
|
|
30893
|
+
const upstream = summary ? asRecord2(summary.upstream) : void 0;
|
|
30894
|
+
if (!summary || !upstream || upstream.resource_replaced !== true) return [];
|
|
30895
|
+
const definition = asRecord2(summary.definition);
|
|
30896
|
+
const changed = definition && Array.isArray(definition.changed) ? definition.changed : [];
|
|
30897
|
+
const lines = [
|
|
30898
|
+
input2.completed ? "WARNING: this deploy replaced the existing upstream monitor." : "WARNING: this deploy replaces the existing upstream monitor.",
|
|
30899
|
+
"Existing Customer DB rows are preserved. Provider backfill is not implied."
|
|
30900
|
+
];
|
|
30901
|
+
for (const raw of changed) {
|
|
30902
|
+
const item = asRecord2(raw);
|
|
30903
|
+
const path = item ? asString(item.path) : void 0;
|
|
30904
|
+
if (!item || !path) continue;
|
|
30905
|
+
lines.push(
|
|
30906
|
+
` ${path}: ${JSON.stringify(item.before ?? null)} \u2192 ${JSON.stringify(
|
|
30907
|
+
item.after ?? null
|
|
30908
|
+
)}`
|
|
30909
|
+
);
|
|
30910
|
+
}
|
|
30911
|
+
lines.push(
|
|
30912
|
+
input2.monitorKey ? `Use \`deepline monitors update ${input2.monitorKey} <patch>\` for a patch-style change.` : "Use `deepline monitors update <key> <patch>` for a patch-style change."
|
|
30913
|
+
);
|
|
30914
|
+
return lines;
|
|
30915
|
+
}
|
|
30811
30916
|
function renderMonitorDeployCompletion(payload) {
|
|
30812
30917
|
const monitor = asRecord2(payload.monitor);
|
|
30813
30918
|
const key = monitor ? asString(monitor.key) : void 0;
|
|
@@ -30835,6 +30940,12 @@ function renderMonitorDeployCompletion(payload) {
|
|
|
30835
30940
|
if (pricingLine) {
|
|
30836
30941
|
lines.push("", `Pricing: ${pricingLine}`);
|
|
30837
30942
|
}
|
|
30943
|
+
const replacementWarning = renderDeployReplacementWarning({
|
|
30944
|
+
payload,
|
|
30945
|
+
completed: true,
|
|
30946
|
+
monitorKey: key
|
|
30947
|
+
});
|
|
30948
|
+
if (replacementWarning.length) lines.push("", ...replacementWarning);
|
|
30838
30949
|
const guidance = asRecord2(payload.setup_guidance);
|
|
30839
30950
|
if (guidance) {
|
|
30840
30951
|
const callbackUrl = asString(guidance.callback_url);
|
|
@@ -30886,6 +30997,11 @@ function renderMonitorDeployPlan(payload) {
|
|
|
30886
30997
|
if (message) lines.push(` - ${path ? `${path}: ` : ""}${message}`);
|
|
30887
30998
|
}
|
|
30888
30999
|
}
|
|
31000
|
+
const replacementWarning = renderDeployReplacementWarning({
|
|
31001
|
+
payload,
|
|
31002
|
+
completed: false
|
|
31003
|
+
});
|
|
31004
|
+
if (replacementWarning.length) lines.push("", ...replacementWarning);
|
|
30889
31005
|
const estimate = asRecord2(payload.deploy_cost_estimate);
|
|
30890
31006
|
const credits = estimate ? asFiniteNumber(estimate.credits) : void 0;
|
|
30891
31007
|
if (credits !== void 0) {
|
|
@@ -31252,10 +31368,17 @@ async function handleMonitorsGet(key, options) {
|
|
|
31252
31368
|
}
|
|
31253
31369
|
async function handleMonitorsTest(key, payload, options) {
|
|
31254
31370
|
const explicitPayload = parseJsonObjectArg(payload, "<payload>");
|
|
31255
|
-
const result = await new DeeplineClient().monitors.test(
|
|
31256
|
-
|
|
31257
|
-
|
|
31258
|
-
|
|
31371
|
+
const result = await new DeeplineClient().monitors.test(
|
|
31372
|
+
key,
|
|
31373
|
+
explicitPayload,
|
|
31374
|
+
{
|
|
31375
|
+
validationOnly: options.dispatch !== true
|
|
31376
|
+
}
|
|
31377
|
+
);
|
|
31378
|
+
const dispatch = options.dispatch === true;
|
|
31379
|
+
const text = `Monitor diagnostic for ${key}: ${result.accepted === true ? "accepted" : "rejected"}
|
|
31380
|
+
` + (dispatch ? " mode: dispatch (writes rows and may dispatch bound Plays)\n" : " mode: validation_only (no rows written, credits spent, or Plays dispatched)\n") + `${dispatch ? "persisted" : "would persist"} rows: ${asFiniteNumber(result.persisted_rows) ?? 0}
|
|
31381
|
+
${dispatch ? "dispatched" : "would dispatch"} bound Plays: ${asFiniteNumber(result.dispatched_bound_plays) ?? 0}
|
|
31259
31382
|
`;
|
|
31260
31383
|
printCommandEnvelope(result, { json: options.json, text });
|
|
31261
31384
|
}
|
|
@@ -31467,12 +31590,18 @@ Examples:
|
|
|
31467
31590
|
withJsonOption(
|
|
31468
31591
|
monitors.command("test <key> <payload>").description(
|
|
31469
31592
|
"Send an explicit payload through a monitor\u2019s webhook ingestion path."
|
|
31593
|
+
).option(
|
|
31594
|
+
"--dispatch",
|
|
31595
|
+
"Inject the test event through normal ingestion (writes rows and may dispatch bound Plays)"
|
|
31470
31596
|
).addHelpText(
|
|
31471
31597
|
"after",
|
|
31472
31598
|
`
|
|
31473
31599
|
Notes:
|
|
31474
31600
|
<payload> must be an explicit JSON object. The command uses the deployed
|
|
31475
|
-
monitor\u2019s real
|
|
31601
|
+
monitor\u2019s real binding and payload validation, but is a side-effect-free
|
|
31602
|
+
diagnostic: it does not persist rows, spend credits, dispatch Plays, or alter
|
|
31603
|
+
monitor state. Pass --dispatch only when you deliberately need the historic
|
|
31604
|
+
full-ingestion test event; it can write rows and trigger bound Plays. It does
|
|
31476
31605
|
not synthesize a provider event or accept an omitted payload.
|
|
31477
31606
|
|
|
31478
31607
|
Examples:
|
|
@@ -31493,7 +31622,9 @@ Notes:
|
|
|
31493
31622
|
via --file <path>, or
|
|
31494
31623
|
from stdin with --file -. Does not deploy or spend credits.
|
|
31495
31624
|
For Deepline Native Company Radar monitors, check validates persona-filter enums and the
|
|
31496
|
-
job_titles Boolean-expression grammar locally
|
|
31625
|
+
job_titles Boolean-expression grammar locally (parentheses are unsupported;
|
|
31626
|
+
NOT > AND > OR).
|
|
31627
|
+
Inspect the exact schema with
|
|
31497
31628
|
\`deepline monitors available deepline_native.company_radar --json\`.
|
|
31498
31629
|
|
|
31499
31630
|
Examples:
|
|
@@ -31517,6 +31648,9 @@ Notes:
|
|
|
31517
31648
|
--dry-run validates the definition and shows the plan (deploy cost in Deepline
|
|
31518
31649
|
credits when the server reports it, plus any existing monitors that may
|
|
31519
31650
|
already cover this scope) WITHOUT deploying. Exits 0 when valid, 7 when not.
|
|
31651
|
+
Deploy is a full desired definition for its key: omitting a previously stored
|
|
31652
|
+
field removes it and can replace the upstream resource. Use \`monitors update\`
|
|
31653
|
+
for a patch-style change.
|
|
31520
31654
|
|
|
31521
31655
|
Examples:
|
|
31522
31656
|
deepline monitors deploy '{"key":"job-openings","tool":"deepline_native.company_radar","payload":{"domain":"stripe.com","radar_type":"company_job_openings"}}'
|