deepline 0.2.49 → 0.2.51

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.
@@ -711,6 +711,7 @@ export type MonitorListEntry = {
711
711
  webhook_state?: string;
712
712
  last_received_event?: string | null;
713
713
  bound_plays?: Array<Record<string, unknown>>;
714
+ consumer_health_truncated?: boolean;
714
715
  [key: string]: unknown;
715
716
  };
716
717
 
@@ -726,6 +727,8 @@ export type MonitorsListResult = {
726
727
  is_truncated?: boolean;
727
728
  next_cursor?: string | null;
728
729
  status_filter_applied?: string;
730
+ status_summary?: Array<{ status: string; count: number }>;
731
+ include_consumers?: boolean;
729
732
  [key: string]: unknown;
730
733
  };
731
734
 
@@ -737,6 +740,8 @@ export type MonitorsListOptions = {
737
740
  /** Page past a truncated result using a prior response's `next_cursor`. */
738
741
  cursor?: string;
739
742
  compact?: boolean;
743
+ /** Include bounded current SQL-listener delivery/run health (requires limit <= 20). */
744
+ includeConsumers?: boolean;
740
745
  };
741
746
 
742
747
  /**
@@ -814,9 +819,9 @@ export type MonitorsNamespace = {
814
819
  definition: MonitorDefinition,
815
820
  options?: { dryRun?: boolean },
816
821
  ) => Promise<MonitorDeployResult>;
817
- /** List deployed monitors (active by default). */
822
+ /** List deployed monitors (active by default). `includeConsumers` requires limit <= 20. */
818
823
  list: (options?: MonitorsListOptions) => Promise<MonitorsListResult>;
819
- /** Fetch one deployed monitor by public key (without dependents). */
824
+ /** Fetch one deployed monitor by public key with bounded current listener health. */
820
825
  get: (key: string) => Promise<MonitorDetail>;
821
826
  /**
822
827
  * Test a deployed monitor. `validationOnly` safely verifies the callback
@@ -825,7 +830,7 @@ export type MonitorsNamespace = {
825
830
  test: (
826
831
  key: string,
827
832
  payload: Record<string, unknown>,
828
- options?: { validationOnly?: boolean },
833
+ options?: { validationOnly?: boolean; dispatch?: boolean },
829
834
  ) => Promise<MonitorTestResult>;
830
835
  validate: (key: string) => Promise<MonitorValidateResult>;
831
836
  /** List the published plays depending on one monitor's output streams. */
@@ -4531,6 +4536,7 @@ export class DeeplineClient {
4531
4536
  params.set('limit', String(options.limit));
4532
4537
  if (options?.cursor) params.set('cursor', options.cursor);
4533
4538
  if (options?.compact) params.set('compact', 'true');
4539
+ if (options?.includeConsumers) params.set('include_consumers', 'true');
4534
4540
  const query = params.toString();
4535
4541
  // Single interpolation only — see availableMonitors: a nested template in
4536
4542
  // the path confuses the SDK/API contract path extractor.
@@ -4552,7 +4558,7 @@ export class DeeplineClient {
4552
4558
  async testMonitorWebhook(
4553
4559
  key: string,
4554
4560
  payload: Record<string, unknown>,
4555
- options?: { validationOnly?: boolean },
4561
+ options?: { validationOnly?: boolean; dispatch?: boolean },
4556
4562
  ): Promise<MonitorTestResult> {
4557
4563
  return this.http.request<MonitorTestResult>(
4558
4564
  `/api/v2/monitors/deployed/${encodeURIComponent(key)}/test`,
@@ -4560,7 +4566,11 @@ export class DeeplineClient {
4560
4566
  method: 'POST',
4561
4567
  body: {
4562
4568
  payload,
4563
- ...(options?.validationOnly ? { mode: 'validation_only' } : {}),
4569
+ ...(options?.validationOnly
4570
+ ? { mode: 'validation_only' }
4571
+ : options?.dispatch
4572
+ ? { mode: 'dispatch' }
4573
+ : {}),
4564
4574
  },
4565
4575
  },
4566
4576
  );
@@ -160,7 +160,7 @@ export const SDK_RELEASE = {
160
160
  // 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
161
161
  // exposed storage-dependent synchronous access. This deliberate minor
162
162
  // release keeps lazy paging semantics independent of row residency.
163
- version: '0.2.49',
163
+ version: '0.2.51',
164
164
  contracts: {
165
165
  api: {
166
166
  name: 'sdk-http-api',
@@ -1343,12 +1343,31 @@ export interface PlayCheckSqlListenerTrigger {
1343
1343
  };
1344
1344
  }
1345
1345
 
1346
+ /**
1347
+ * The input delivered to a SQL-listener Play invocation. One changed Customer
1348
+ * DB row starts one run with this top-level event object; it is not an events
1349
+ * array or a polling batch.
1350
+ */
1351
+ export interface PlayCheckSqlListenerEventSummary {
1352
+ delivery: 'one_event_per_matched_row';
1353
+ fields: Array<
1354
+ | 'tool'
1355
+ | 'stream'
1356
+ | 'operation'
1357
+ | 'before'
1358
+ | 'after'
1359
+ | 'changedAt'
1360
+ | 'metadata'
1361
+ >;
1362
+ }
1363
+
1346
1364
  /**
1347
1365
  * Concise summary of the trigger bindings the server recognized for a play.
1348
1366
  * Only present triggers are populated.
1349
1367
  */
1350
1368
  export interface PlayCheckTriggersSummary {
1351
1369
  sqlListeners?: PlayCheckSqlListenerTrigger[];
1370
+ sqlListenerEvent?: PlayCheckSqlListenerEventSummary;
1352
1371
  cron?: { schedule: string; timezone?: string };
1353
1372
  webhook?: true;
1354
1373
  }
@@ -157,6 +157,7 @@ import {
157
157
  validatePlayAuthoringField,
158
158
  type PlayAuthoringContractEdition,
159
159
  type PlaySqlQuery,
160
+ type PlayAuthoringRunScope,
160
161
  type PlayAuthoringRuntimeContext,
161
162
  } from '../plays/authoring-contract';
162
163
  import {
@@ -1338,6 +1339,7 @@ type ScalarPlayAuthoringRuntimeContext = Pick<
1338
1339
  PlayAuthoringRuntimeContext,
1339
1340
  | 'tools'
1340
1341
  | 'customerDb'
1342
+ | 'run'
1341
1343
  | 'tool'
1342
1344
  | 'step'
1343
1345
  | 'fetch'
@@ -3332,6 +3334,10 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
3332
3334
  return this.currentExecutionScope.logical.runId;
3333
3335
  }
3334
3336
 
3337
+ get run(): PlayAuthoringRunScope {
3338
+ return { id: this.currentRunId };
3339
+ }
3340
+
3335
3341
  private get currentReceiptOwnerRunId(): string {
3336
3342
  return this.currentExecutionScope.receipt.ownerRunId;
3337
3343
  }
@@ -68,6 +68,7 @@ export const PLAY_AUTHORING_CONTRACT_ISSUE_CODES = [
68
68
  'play_authoring_dynamic_identity_unvalidated',
69
69
  'play_authoring_fetch_secret_requires_tls',
70
70
  'play_authoring_fetch_idempotency_required',
71
+ 'play_authoring_fetch_key_reused_in_loop',
71
72
  'play_authoring_binding_invalid',
72
73
  'play_authoring_input_schema_unresolved',
73
74
  ] as const;
@@ -215,8 +216,23 @@ export type PlayTriggerSqlListenerSummary = {
215
216
  operations: string[];
216
217
  where?: PlaySqlListenerWhere;
217
218
  };
219
+ /** Author-facing shape of one SQL-listener invocation. */
220
+ export type PlayTriggerSqlListenerEventSummary = {
221
+ delivery: 'one_event_per_matched_row';
222
+ fields: Array<
223
+ | 'tool'
224
+ | 'stream'
225
+ | 'operation'
226
+ | 'before'
227
+ | 'after'
228
+ | 'changedAt'
229
+ | 'metadata'
230
+ >;
231
+ };
218
232
  export type PlayTriggersSummary = {
219
233
  sqlListeners?: PlayTriggerSqlListenerSummary[];
234
+ /** Present when the play has at least one sqlListener trigger. */
235
+ sqlListenerEvent?: PlayTriggerSqlListenerEventSummary;
220
236
  cron?: { schedule: string; timezone?: string };
221
237
  webhook?: true;
222
238
  };
@@ -237,6 +253,18 @@ export function derivePlayTriggersSummary(
237
253
  ? { where: listener.where as PlaySqlListenerWhere }
238
254
  : {}),
239
255
  }));
256
+ summary.sqlListenerEvent = {
257
+ delivery: 'one_event_per_matched_row',
258
+ fields: [
259
+ 'tool',
260
+ 'stream',
261
+ 'operation',
262
+ 'before',
263
+ 'after',
264
+ 'changedAt',
265
+ 'metadata',
266
+ ],
267
+ };
240
268
  }
241
269
  if (bindings.cron?.schedule) {
242
270
  summary.cron = bindings.cron.timezone
@@ -652,6 +680,7 @@ export const PLAY_AUTHORING_RUNTIME_CONTEXT_MEMBERS = [
652
680
  'dataset',
653
681
  'fetch',
654
682
  'log',
683
+ 'run',
655
684
  'runPlay',
656
685
  'runSteps',
657
686
  'secrets',
@@ -743,6 +772,31 @@ export type PlayAuthoringRunStepsOptions = {
743
772
  description?: string;
744
773
  };
745
774
 
775
+ /**
776
+ * Stable identity of the currently executing Play invocation.
777
+ *
778
+ * The id is unchanged while Deepline resumes or retries the same durable run.
779
+ * A separately submitted run intentionally receives a new id.
780
+ */
781
+ export type PlayAuthoringRunScope = {
782
+ readonly id: string;
783
+ };
784
+
785
+ /** Factual authoring guidance rendered into SDK and offline-agent references. */
786
+ export const PLAY_AUTHORING_DOCUMENTATION = {
787
+ fetchBatching: {
788
+ warning:
789
+ 'A static ctx.fetch key inside a loop is a warning because every iteration must still have distinct method, URL, body, or safe headers. One durable receipt must never stand in for every request.',
790
+ guidance:
791
+ 'Keep the static fetch label. For a mutating batch, make the body distinct and use a replay-stable external Idempotency-Key such as `${ctx.run.id}:signals:${batchIndex}`.',
792
+ },
793
+ runId: {
794
+ semantics:
795
+ 'ctx.run.id is stable while Deepline retries or resumes one durable run. A separately submitted run receives a new id.',
796
+ use: 'Use it when deriving an external idempotency key for a sequence of batches.',
797
+ },
798
+ } as const;
799
+
746
800
  /** The complete customer-authored `ctx` Interface shared by every Adapter. */
747
801
  export interface PlayAuthoringRuntimeContext {
748
802
  /**
@@ -776,6 +830,12 @@ export interface PlayAuthoringRuntimeContext {
776
830
  >,
777
831
  ): never;
778
832
 
833
+ /**
834
+ * Identity for this durable run. Use this to build a replay-stable external
835
+ * idempotency key, for example when posting a sequence of batches.
836
+ */
837
+ readonly run: PlayAuthoringRunScope;
838
+
779
839
  tools: {
780
840
  /**
781
841
  * Execute a provider tool through the durable receipt contract.
@@ -2294,6 +2354,7 @@ export const PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
2294
2354
  ' csv<T = Record<string, unknown>>(path: string | CsvInput<T & object>, options?: CsvOptions): Promise<PlayDataset<T>>;',
2295
2355
  ' dataset<TSource extends PlayDatasetInput<object>>(key: string, items: TSource): DatasetBuilder<PlayDatasetRow<TSource> & object, PlayDatasetRow<TSource> & object>;',
2296
2356
  ' map<TSource extends PlayDatasetInput<object>>(key: string, items: TSource, options?: DatasetDefinitionOptions<PlayDatasetRow<TSource> & object>): never;',
2357
+ ' readonly run: { readonly id: string };',
2297
2358
  ` runSteps<TInput extends Record<string, unknown>, TOutput>(program: RunnableStepProgram<TInput, TOutput>, input: TInput, options?: { description?: ${cloudReferenceType('ctx.runSteps.options.description')} }): Promise<TOutput>;`,
2298
2359
  ' tools: { execute<K extends string>(request: ToolExecutionRequest<K>): Promise<ToolExecutionOutput<K>> };',
2299
2360
  ` customerDb: { query<TRow extends Record<string, unknown> = Record<string, unknown>>(statement: SqlQuery, options?: { maxRows?: ${cloudReferenceType('ctx.customerDb.query.options.maxRows')}; timeoutMs?: ${cloudReferenceType('ctx.customerDb.query.options.timeoutMs')} }): Promise<TRow[]> };`,
@@ -10,6 +10,7 @@ import {
10
10
  join,
11
11
  relative,
12
12
  resolve,
13
+ sep,
13
14
  } from 'node:path';
14
15
  import { builtinModules } from 'node:module';
15
16
  import { Parser } from 'acorn';
@@ -94,6 +95,8 @@ export type PlayLocalFileDiscoveryResult = {
94
95
 
95
96
  export type PlayBundlingAdapter = {
96
97
  projectRoot: string;
98
+ /** Optional root used only to make source-graph identity independent of temporary absolute paths. */
99
+ sourceIdentityRoot?: string;
97
100
  nodeModulesDir: string;
98
101
  cacheDir?: string;
99
102
  sdkSourceRoot: string;
@@ -179,6 +182,24 @@ function sha256(value: string): string {
179
182
  return createHash('sha256').update(value).digest('hex');
180
183
  }
181
184
 
185
+ function sourceIdentityPath(
186
+ filePath: string,
187
+ adapter: PlayBundlingAdapter,
188
+ ): string {
189
+ if (!adapter.sourceIdentityRoot) return filePath;
190
+ const identityRoot = resolve(adapter.sourceIdentityRoot);
191
+ const logicalPath = relative(identityRoot, resolve(filePath));
192
+ if (
193
+ !logicalPath ||
194
+ logicalPath === '..' ||
195
+ logicalPath.startsWith(`..${sep}`) ||
196
+ isAbsolute(logicalPath)
197
+ ) {
198
+ return filePath;
199
+ }
200
+ return logicalPath.split(/[\\/]+/).join('/');
201
+ }
202
+
182
203
  function formatEsbuildMessage(message: Message): string {
183
204
  const location = message.location
184
205
  ? `${message.location.file}:${message.location.line}:${message.location.column}`
@@ -1598,9 +1619,12 @@ async function analyzeSourceGraph(
1598
1619
  const sourceHash = sha256(sourceCode);
1599
1620
  const graphHash = sha256(
1600
1621
  JSON.stringify({
1601
- entryFile: absoluteEntryFile,
1622
+ entryFile: sourceIdentityPath(absoluteEntryFile, adapter),
1602
1623
  localFiles: [...localFiles.entries()]
1603
- .map(([filePath, contents]) => ({ filePath, hash: sha256(contents) }))
1624
+ .map(([filePath, contents]) => ({
1625
+ filePath: sourceIdentityPath(filePath, adapter),
1626
+ hash: sha256(contents),
1627
+ }))
1604
1628
  .sort((left, right) => left.filePath.localeCompare(right.filePath)),
1605
1629
  nodeBuiltins: [...nodeBuiltins].sort(),
1606
1630
  packages: [...packages.entries()]
@@ -1608,7 +1632,7 @@ async function analyzeSourceGraph(
1608
1632
  .sort((left, right) => left.name.localeCompare(right.name)),
1609
1633
  importedPlayDependencies: [...importedPlayDependencies.values()]
1610
1634
  .map((dependency) => ({
1611
- filePath: dependency.filePath,
1635
+ filePath: sourceIdentityPath(dependency.filePath, adapter),
1612
1636
  playName: dependency.playName,
1613
1637
  }))
1614
1638
  .sort((left, right) => left.filePath.localeCompare(right.filePath)),
@@ -1660,7 +1684,7 @@ function artifactCachePath(
1660
1684
  adapter: PlayBundlingAdapter,
1661
1685
  ): string {
1662
1686
  return join(
1663
- adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR,
1687
+ /* turbopackIgnore: true */ adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR,
1664
1688
  `${graphHash}.${artifactKind}.json`,
1665
1689
  );
1666
1690
  }
@@ -1672,7 +1696,11 @@ async function readArtifactCache(
1672
1696
  ): Promise<PlayBundleArtifact | null> {
1673
1697
  try {
1674
1698
  const serialized = await readFile(
1675
- artifactCachePath(graphHash, artifactKind, adapter),
1699
+ /* turbopackIgnore: true */ artifactCachePath(
1700
+ graphHash,
1701
+ artifactKind,
1702
+ adapter,
1703
+ ),
1676
1704
  'utf-8',
1677
1705
  );
1678
1706
  return JSON.parse(serialized) as PlayBundleArtifact;
@@ -1686,9 +1714,9 @@ async function writeArtifactCache(
1686
1714
  adapter: PlayBundlingAdapter,
1687
1715
  ): Promise<void> {
1688
1716
  const cacheDir = adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR;
1689
- await mkdir(cacheDir, { recursive: true });
1717
+ await mkdir(/* turbopackIgnore: true */ cacheDir, { recursive: true });
1690
1718
  await writeFile(
1691
- artifactCachePath(
1719
+ /* turbopackIgnore: true */ artifactCachePath(
1692
1720
  artifact.graphHash,
1693
1721
  artifact.artifactKind ?? PLAY_ARTIFACT_KINDS.cjsNode20,
1694
1722
  adapter,
@@ -0,0 +1,21 @@
1
+ export const ENRICH_COMPAT_DEFAULT_PLAY_NAME = 'deepline-enrich-v1-compat';
2
+ export const ENRICH_COMPAT_DEFAULT_MAP_NAME = 'deepline_enrich_rows';
3
+
4
+ export type EnrichCompatibilityOptions = {
5
+ playName?: string;
6
+ mapName?: string;
7
+ };
8
+
9
+ export type EnrichCompatibilityPlan = {
10
+ playName: string;
11
+ mapName: string;
12
+ };
13
+
14
+ export function buildEnrichCompatibilityPlan(
15
+ options: EnrichCompatibilityOptions = {},
16
+ ): EnrichCompatibilityPlan {
17
+ return {
18
+ playName: options.playName?.trim() || ENRICH_COMPAT_DEFAULT_PLAY_NAME,
19
+ mapName: options.mapName?.trim() || ENRICH_COMPAT_DEFAULT_MAP_NAME,
20
+ };
21
+ }