deepline 0.3.196 → 0.3.198
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/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/docflow-node-io.ts +33 -8
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +183 -50
- package/dist/cli/index.js +24 -4
- package/dist/cli/index.mjs +24 -4
- package/dist/index.js +24 -4
- package/dist/index.mjs +24 -4
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
|
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
|
|
|
200
200
|
// getters keep their established compatibility behavior.
|
|
201
201
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
202
202
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
203
|
-
version: '0.3.
|
|
203
|
+
version: '0.3.198',
|
|
204
204
|
updateSummary:
|
|
205
205
|
'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
|
|
206
206
|
packageCapabilities: {
|
|
@@ -78,19 +78,44 @@ type PreviewOptions = {
|
|
|
78
78
|
|
|
79
79
|
const utf8Encoder = new TextEncoder();
|
|
80
80
|
const PLAY_DATASET_BRAND = Symbol.for('deepline.play.dataset');
|
|
81
|
+
const MAX_CONVEX_PREVIEW_KEY_LENGTH = 1_024;
|
|
81
82
|
|
|
82
83
|
/**
|
|
83
84
|
* Preview-map keys must be persistable everywhere the ledger lands, and Convex
|
|
84
|
-
* reserves
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
85
|
+
* reserves leading '$', non-ASCII/control characters, and keys over 1,024
|
|
86
|
+
* bytes. A rejected preview key poisons the whole ordered terminal batch, even
|
|
87
|
+
* when the terminal result is replaced by a scheduler reference. Keep already
|
|
88
|
+
* valid keys unchanged and encode only invalid bytes, so repeated normalization
|
|
89
|
+
* of durable observations converges on the same key. `$output` remains `output`.
|
|
89
90
|
*/
|
|
90
91
|
export function ledgerSafeDocflowPreviewKey(key: string): string {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
const source = key.startsWith('$')
|
|
93
|
+
? key.replace(/^\$+/, '') || 'output'
|
|
94
|
+
: key || 'output';
|
|
95
|
+
let encoded = '';
|
|
96
|
+
for (const character of source) {
|
|
97
|
+
const code = character.charCodeAt(0);
|
|
98
|
+
if (code >= 32 && code < 127) {
|
|
99
|
+
encoded += character;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
for (const byte of utf8Encoder.encode(character)) {
|
|
103
|
+
encoded += `%${byte.toString(16).toUpperCase().padStart(2, '0')}`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (encoded.length <= MAX_CONVEX_PREVIEW_KEY_LENGTH) return encoded;
|
|
107
|
+
|
|
108
|
+
// Retain a readable prefix while making long, otherwise identical paths
|
|
109
|
+
// distinguishable. The suffix is stable across runtime and app deployments.
|
|
110
|
+
let hashA = 0x811c9dc5;
|
|
111
|
+
let hashB = 0x9e3779b9;
|
|
112
|
+
for (let index = 0; index < encoded.length; index += 1) {
|
|
113
|
+
const code = encoded.charCodeAt(index);
|
|
114
|
+
hashA = Math.imul(hashA ^ code, 0x01000193);
|
|
115
|
+
hashB = Math.imul(hashB ^ code, 0x01000193);
|
|
116
|
+
}
|
|
117
|
+
const suffix = `~${(hashA >>> 0).toString(16).padStart(8, '0')}${(hashB >>> 0).toString(16).padStart(8, '0')}`;
|
|
118
|
+
return `${encoded.slice(0, MAX_CONVEX_PREVIEW_KEY_LENGTH - suffix.length)}${suffix}`;
|
|
94
119
|
}
|
|
95
120
|
|
|
96
121
|
function utf8Bytes(value: string): number {
|
|
@@ -62,6 +62,7 @@ import {
|
|
|
62
62
|
type RuntimeReceiptValueReference,
|
|
63
63
|
} from '../runtime-receipt-value';
|
|
64
64
|
import { PLAY_RUNTIME_WORK_RECEIPT_LEASE_TTL_MS } from '../lease-policy';
|
|
65
|
+
import { RUNTIME_CAPACITY_POLICY } from '../runtime-capacity-policy';
|
|
65
66
|
import { RUNTIME_RELIABILITY_POLICY } from '../runtime-reliability-policy';
|
|
66
67
|
import { COMPLETED_RECEIPT_CACHE_INSERT_LEASE_ID } from '../durable-receipt-execution';
|
|
67
68
|
import {
|
|
@@ -159,6 +160,7 @@ import { requireRuntimeAuthorityDescriptor } from '../execution-capabilities';
|
|
|
159
160
|
import { stringifyPostgresJson } from '../postgres-json';
|
|
160
161
|
import {
|
|
161
162
|
buildPlayLaunchIdentity,
|
|
163
|
+
PLAY_LAUNCH_ENVELOPE_FIELD_ROLES,
|
|
162
164
|
withPlayLaunchIdentityDigest,
|
|
163
165
|
} from '../launch-identity';
|
|
164
166
|
import { PlayRunLaunchConflictError } from '../play-runs/admission/contracts';
|
|
@@ -173,7 +175,10 @@ import {
|
|
|
173
175
|
recordSchedulerLaunchRead,
|
|
174
176
|
type SchedulerLaunchReadCaller,
|
|
175
177
|
} from './scheduler-launch-read-observability';
|
|
176
|
-
import {
|
|
178
|
+
import {
|
|
179
|
+
emitPlayRunLaunchConflictTelemetry,
|
|
180
|
+
emitPlayTelemetry,
|
|
181
|
+
} from '../runtime-telemetry';
|
|
177
182
|
import { buildAbsurdPlayRunTask } from './absurd-play-run-task';
|
|
178
183
|
import {
|
|
179
184
|
buildAbsurdCronFireTask,
|
|
@@ -4509,6 +4514,38 @@ export async function submitPostgresAbsurdPlayRun(
|
|
|
4509
4514
|
};
|
|
4510
4515
|
}
|
|
4511
4516
|
|
|
4517
|
+
function isJsonObject(value: unknown): value is Record<string, unknown> {
|
|
4518
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
4519
|
+
}
|
|
4520
|
+
|
|
4521
|
+
/**
|
|
4522
|
+
* Reasons this build cannot prove a stored launch has the incoming named
|
|
4523
|
+
* intent. Empty only when the stored envelope is readable, contains no field
|
|
4524
|
+
* this build does not know (a newer writer may have added identity), and
|
|
4525
|
+
* every named intent field matches.
|
|
4526
|
+
*/
|
|
4527
|
+
function launchIntentRematchBlockers(
|
|
4528
|
+
existingLaunchJson: unknown,
|
|
4529
|
+
incomingLaunch: PlaySchedulerSubmitInput,
|
|
4530
|
+
): string[] {
|
|
4531
|
+
if (!isJsonObject(existingLaunchJson)) return ['launch'];
|
|
4532
|
+
const unknownFields = Object.keys(existingLaunchJson).filter(
|
|
4533
|
+
(field) =>
|
|
4534
|
+
!Object.prototype.hasOwnProperty.call(
|
|
4535
|
+
PLAY_LAUNCH_ENVELOPE_FIELD_ROLES,
|
|
4536
|
+
field,
|
|
4537
|
+
),
|
|
4538
|
+
);
|
|
4539
|
+
if (unknownFields.length > 0) return unknownFields.sort();
|
|
4540
|
+
return launchIdentityConflictFields(existingLaunchJson, incomingLaunch);
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
function launchIdentityDigestOf(launchJson: unknown): string | null {
|
|
4544
|
+
if (!isJsonObject(launchJson)) return null;
|
|
4545
|
+
const digest = launchJson.launchIdentityDigest;
|
|
4546
|
+
return typeof digest === 'string' && digest.trim() ? digest.trim() : null;
|
|
4547
|
+
}
|
|
4548
|
+
|
|
4512
4549
|
function launchIdentityConflictFields(
|
|
4513
4550
|
existingLaunchJson: unknown,
|
|
4514
4551
|
incomingLaunch: PlaySchedulerSubmitInput,
|
|
@@ -4559,12 +4596,18 @@ async function submitPostgresSchedulerRunTransaction(
|
|
|
4559
4596
|
options: unknown;
|
|
4560
4597
|
recoverExistingTask?: boolean;
|
|
4561
4598
|
},
|
|
4599
|
+
/**
|
|
4600
|
+
* Set only on the single re-admission after the current build proved the
|
|
4601
|
+
* existing Run has the same named launch intent (see the conflict branch).
|
|
4602
|
+
*/
|
|
4603
|
+
existingLaunchIntentMatches = false,
|
|
4562
4604
|
): Promise<{
|
|
4563
4605
|
absurdTaskId: string | null;
|
|
4564
4606
|
runCreated: boolean;
|
|
4565
4607
|
taskCreated: boolean;
|
|
4566
4608
|
taskRecoveryRequired: boolean;
|
|
4567
4609
|
}> {
|
|
4610
|
+
const requestedInput = input;
|
|
4568
4611
|
// Persist the ABI with every new launch. Null is reserved for genuinely
|
|
4569
4612
|
// historic rows already in storage, where readers interpret it as legacy.
|
|
4570
4613
|
input = {
|
|
@@ -4591,6 +4634,9 @@ async function submitPostgresSchedulerRunTransaction(
|
|
|
4591
4634
|
// fields are removed so they can never change the durable launch identity.
|
|
4592
4635
|
input = withPlayLaunchIdentityDigest(durableInput);
|
|
4593
4636
|
const existingOnlySql = requestedExistingOnly === true ? 'true' : 'false';
|
|
4637
|
+
const existingLaunchIntentMatchesSql = existingLaunchIntentMatches
|
|
4638
|
+
? 'true'
|
|
4639
|
+
: 'false';
|
|
4594
4640
|
const releaseId = input.absurdReleaseId?.trim() || null;
|
|
4595
4641
|
const legacyPreviewRelease =
|
|
4596
4642
|
releaseId === 'dev' || releaseId?.startsWith('dev-') === true;
|
|
@@ -4717,9 +4763,12 @@ async function submitPostgresSchedulerRunTransaction(
|
|
|
4717
4763
|
FOR UPDATE
|
|
4718
4764
|
), existing_run AS (
|
|
4719
4765
|
SELECT
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
$
|
|
4766
|
+
(
|
|
4767
|
+
${existingLaunchIntentMatchesSql}
|
|
4768
|
+
OR ${quoteIdent(schemaName(options))}.runtime_launch_admission_matches(
|
|
4769
|
+
coalesce(runs.admission_json, runs.launch_json),
|
|
4770
|
+
$8::jsonb
|
|
4771
|
+
)
|
|
4723
4772
|
) AS matches_launch,
|
|
4724
4773
|
coalesce(runs.admission_json, runs.launch_json) AS launch_json,
|
|
4725
4774
|
runs.absurd_task_id,
|
|
@@ -4985,13 +5034,42 @@ async function submitPostgresSchedulerRunTransaction(
|
|
|
4985
5034
|
);
|
|
4986
5035
|
}
|
|
4987
5036
|
if (row?.accepted === false && row.existing_run && !row.matching_existing) {
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
5037
|
+
const rematchBlockers = launchIntentRematchBlockers(
|
|
5038
|
+
row.existing_launch_json,
|
|
5039
|
+
input,
|
|
5040
|
+
);
|
|
5041
|
+
if (existingLaunchIntentMatches || rematchBlockers.length > 0) {
|
|
5042
|
+
throw new PlayRunLaunchConflictError(input.runId, {
|
|
5043
|
+
conflictReason: 'launch_identity_mismatch',
|
|
5044
|
+
conflictingFields: rematchBlockers,
|
|
5045
|
+
});
|
|
5046
|
+
}
|
|
5047
|
+
// The stored envelope was written by another build (no digest, or a
|
|
5048
|
+
// digest this build cannot reproduce), but every named intent field
|
|
5049
|
+
// matches. Re-admit once as a match so the Run's normal matched path,
|
|
5050
|
+
// including task recovery, runs instead of failing an at-least-once retry.
|
|
5051
|
+
emitPlayTelemetry({
|
|
5052
|
+
level: 'warn',
|
|
5053
|
+
event: 'play.run.admission_intent_rematch',
|
|
5054
|
+
tag: '[play.run.admission_intent_rematch]',
|
|
5055
|
+
fields: {
|
|
5056
|
+
runId: input.runId,
|
|
5057
|
+
orgId: input.orgId,
|
|
5058
|
+
playName: input.playName,
|
|
5059
|
+
triggerSource: input.triggerSource ?? null,
|
|
5060
|
+
existingLaunchIdentityDigest: launchIdentityDigestOf(
|
|
5061
|
+
row.existing_launch_json,
|
|
5062
|
+
),
|
|
5063
|
+
launchIdentityDigest: input.launchIdentityDigest ?? null,
|
|
5064
|
+
},
|
|
4994
5065
|
});
|
|
5066
|
+
return submitPostgresSchedulerRunTransaction(
|
|
5067
|
+
client,
|
|
5068
|
+
requestedInput,
|
|
5069
|
+
options,
|
|
5070
|
+
absurdTask,
|
|
5071
|
+
true,
|
|
5072
|
+
);
|
|
4995
5073
|
}
|
|
4996
5074
|
if (row?.accepted === false && !row?.existing_run && requestedExistingOnly) {
|
|
4997
5075
|
throw new Error(
|
|
@@ -5683,10 +5761,11 @@ export type FirePostgresSchedulerCronScheduleInput = {
|
|
|
5683
5761
|
* cursor and is a harmless `superseded` no-op.
|
|
5684
5762
|
*
|
|
5685
5763
|
* A re-fire of the same occurrence whose deterministic Run already exists is
|
|
5686
|
-
* an idempotent re-fire, not a no-op. The cursor advances
|
|
5687
|
-
*
|
|
5688
|
-
*
|
|
5689
|
-
*
|
|
5764
|
+
* an idempotent re-fire, not a no-op. The cursor advances over any existing
|
|
5765
|
+
* Run, even when a mixed-version or competing launch makes the named identity
|
|
5766
|
+
* comparator disagree. The persisted Run is authoritative for this
|
|
5767
|
+
* deterministic occurrence; a conflict is emitted for owner-visible
|
|
5768
|
+
* diagnosis, never converted into a permanent blocked cursor.
|
|
5690
5769
|
*/
|
|
5691
5770
|
export async function firePostgresSchedulerCronSchedule(
|
|
5692
5771
|
client: PostgresSchedulerQueryClient,
|
|
@@ -5698,6 +5777,7 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5698
5777
|
runId: string;
|
|
5699
5778
|
successorDueAtMs: number;
|
|
5700
5779
|
reused: boolean;
|
|
5780
|
+
conflictingFields?: string[];
|
|
5701
5781
|
}
|
|
5702
5782
|
| { status: 'superseded' }
|
|
5703
5783
|
| { status: 'stalled'; runId: string; reason: string }
|
|
@@ -5772,6 +5852,7 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5772
5852
|
schedule_current: boolean;
|
|
5773
5853
|
existing_run: boolean;
|
|
5774
5854
|
matching_existing: boolean;
|
|
5855
|
+
existing_launch_json: unknown | null;
|
|
5775
5856
|
release_accepting: boolean;
|
|
5776
5857
|
}>(
|
|
5777
5858
|
`
|
|
@@ -5797,6 +5878,7 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5797
5878
|
FOR UPDATE
|
|
5798
5879
|
), existing_run AS MATERIALIZED (
|
|
5799
5880
|
SELECT runs.run_id,
|
|
5881
|
+
coalesce(runs.admission_json, runs.launch_json) AS launch_json,
|
|
5800
5882
|
${quoteIdent(schemaName(options))}.runtime_launch_admission_matches(
|
|
5801
5883
|
coalesce(runs.admission_json, runs.launch_json),
|
|
5802
5884
|
$6::jsonb
|
|
@@ -5864,7 +5946,6 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5864
5946
|
OR (
|
|
5865
5947
|
occurrence.schedule_current
|
|
5866
5948
|
AND occurrence.existing_run
|
|
5867
|
-
AND occurrence.matching_existing
|
|
5868
5949
|
)
|
|
5869
5950
|
), successor_task_request AS (
|
|
5870
5951
|
SELECT $11::text AS queue_name,
|
|
@@ -5953,6 +6034,7 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5953
6034
|
(SELECT schedule_current FROM occurrence) AS schedule_current,
|
|
5954
6035
|
(SELECT existing_run FROM occurrence) AS existing_run,
|
|
5955
6036
|
(SELECT matching_existing FROM occurrence) AS matching_existing,
|
|
6037
|
+
(SELECT launch_json FROM existing_run) AS existing_launch_json,
|
|
5956
6038
|
coalesce(
|
|
5957
6039
|
(SELECT accepting
|
|
5958
6040
|
FROM ${tableName('runtime_release_admission', options)}
|
|
@@ -5986,24 +6068,53 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5986
6068
|
);
|
|
5987
6069
|
}
|
|
5988
6070
|
if (fired.advanced === true) {
|
|
6071
|
+
const conflictingFields =
|
|
6072
|
+
fired.existing_run === true && fired.matching_existing !== true
|
|
6073
|
+
? launchIntentRematchBlockers(fired.existing_launch_json, launch)
|
|
6074
|
+
: [];
|
|
6075
|
+
if (conflictingFields.length === 0 && fired.existing_run === true) {
|
|
6076
|
+
emitPlayTelemetry({
|
|
6077
|
+
level: 'warn',
|
|
6078
|
+
event: 'play.run.admission_intent_rematch',
|
|
6079
|
+
tag: '[play.run.admission_intent_rematch]',
|
|
6080
|
+
fields: {
|
|
6081
|
+
runId: launch.runId,
|
|
6082
|
+
orgId: launch.orgId,
|
|
6083
|
+
playName: launch.playName,
|
|
6084
|
+
triggerSource: 'cron',
|
|
6085
|
+
scheduleId: schedule.scheduleId,
|
|
6086
|
+
existingLaunchIdentityDigest: launchIdentityDigestOf(
|
|
6087
|
+
fired.existing_launch_json,
|
|
6088
|
+
),
|
|
6089
|
+
launchIdentityDigest: launch.launchIdentityDigest ?? null,
|
|
6090
|
+
},
|
|
6091
|
+
});
|
|
6092
|
+
} else if (conflictingFields.length > 0) {
|
|
6093
|
+
const conflict = new Error(
|
|
6094
|
+
`Cron occurrence "${launch.runId}" already exists with a different launch identity: ${conflictingFields.join(', ')}`,
|
|
6095
|
+
);
|
|
6096
|
+
emitPlayRunLaunchConflictTelemetry({
|
|
6097
|
+
orgId: launch.orgId,
|
|
6098
|
+
runId: launch.runId,
|
|
6099
|
+
playName: launch.playName,
|
|
6100
|
+
triggerSource: 'cron',
|
|
6101
|
+
workflowFamilyKey: launch.workflowFamilyKey,
|
|
6102
|
+
revisionId: launch.revisionId,
|
|
6103
|
+
artifactHash: launch.artifactHash,
|
|
6104
|
+
graphHash: launch.graphHash,
|
|
6105
|
+
inputSha256: launch.inputSha256,
|
|
6106
|
+
launchIdentityDigest: launch.launchIdentityDigest,
|
|
6107
|
+
conflictReason: 'launch_identity_mismatch',
|
|
6108
|
+
conflictingFields,
|
|
6109
|
+
error: conflict,
|
|
6110
|
+
});
|
|
6111
|
+
}
|
|
5989
6112
|
return {
|
|
5990
6113
|
status: 'admitted',
|
|
5991
6114
|
runId: launch.runId,
|
|
5992
6115
|
successorDueAtMs,
|
|
5993
6116
|
reused: fired.run_created !== true,
|
|
5994
|
-
|
|
5995
|
-
}
|
|
5996
|
-
if (
|
|
5997
|
-
fired.schedule_current === true &&
|
|
5998
|
-
fired.existing_run === true &&
|
|
5999
|
-
fired.matching_existing !== true
|
|
6000
|
-
) {
|
|
6001
|
-
return {
|
|
6002
|
-
status: 'stalled',
|
|
6003
|
-
runId: launch.runId,
|
|
6004
|
-
reason:
|
|
6005
|
-
`Cron schedule "${schedule.scheduleId}" generation ${schedule.generation} cannot advance past ` +
|
|
6006
|
-
`occurrence ${schedule.dueAtMs}: Run "${launch.runId}" already exists with a different launch identity.`,
|
|
6117
|
+
...(conflictingFields.length > 0 ? { conflictingFields } : {}),
|
|
6007
6118
|
};
|
|
6008
6119
|
}
|
|
6009
6120
|
return { status: 'superseded' };
|
|
@@ -12102,10 +12213,9 @@ export async function cancelPostgresSchedulerRun(
|
|
|
12102
12213
|
engineTaskTable: string | null;
|
|
12103
12214
|
};
|
|
12104
12215
|
/**
|
|
12105
|
-
* Optional control-plane ownership for the pending causal
|
|
12106
|
-
*
|
|
12107
|
-
*
|
|
12108
|
-
* was waiting on its retry schedule.
|
|
12216
|
+
* Optional control-plane ownership for the oldest pending causal fact.
|
|
12217
|
+
* Cancellation makes the remaining prefix due without sharing this lease
|
|
12218
|
+
* across distinct append batches, then the caller drains it after commit.
|
|
12109
12219
|
*/
|
|
12110
12220
|
outboxLease?: { leaseOwner: string; leaseSeconds: number };
|
|
12111
12221
|
},
|
|
@@ -12238,11 +12348,15 @@ export async function cancelPostgresSchedulerRun(
|
|
|
12238
12348
|
AND NULLIF(resource->>'sandboxId', '') IS NOT NULL
|
|
12239
12349
|
ON CONFLICT (provider, sandbox_id, routing_domain_key) DO NOTHING
|
|
12240
12350
|
),
|
|
12241
|
-
--
|
|
12242
|
-
--
|
|
12243
|
-
--
|
|
12351
|
+
-- Revoke any in-flight background lease and make the complete prefix
|
|
12352
|
+
-- due, but reserve only its head. The app-side delivery validator treats
|
|
12353
|
+
-- every row under one lease owner as one exact append batch. Leasing the
|
|
12354
|
+
-- whole prefix here makes the first run.events append fail that check.
|
|
12355
|
+
-- The head lease fences background claims until the direct projector
|
|
12356
|
+
-- acknowledges it, then the next causal head can be claimed normally.
|
|
12244
12357
|
cancellation_outbox_pending AS MATERIALIZED (
|
|
12245
|
-
SELECT pending.event_id
|
|
12358
|
+
SELECT pending.event_id,
|
|
12359
|
+
row_number() OVER (ORDER BY ${runLedgerOrderSql('pending')}) AS position
|
|
12246
12360
|
FROM ${tableName('outbox', options)} AS pending
|
|
12247
12361
|
JOIN cancelled_run ON cancelled_run.run_id = pending.run_id
|
|
12248
12362
|
WHERE pending.delivered_at IS NULL
|
|
@@ -12250,11 +12364,15 @@ export async function cancelPostgresSchedulerRun(
|
|
|
12250
12364
|
),
|
|
12251
12365
|
cancellation_outbox_lease AS (
|
|
12252
12366
|
UPDATE ${tableName('outbox', options)} AS pending
|
|
12253
|
-
SET lease_owner = $6::text,
|
|
12254
|
-
lease_expires_at =
|
|
12367
|
+
SET lease_owner = CASE WHEN prefix.position = 1 THEN $6::text ELSE NULL END,
|
|
12368
|
+
lease_expires_at = CASE
|
|
12369
|
+
WHEN prefix.position = 1 THEN now() + make_interval(secs => $7::integer)
|
|
12370
|
+
ELSE NULL
|
|
12371
|
+
END,
|
|
12255
12372
|
next_attempt_at = NULL
|
|
12373
|
+
FROM cancellation_outbox_pending AS prefix
|
|
12256
12374
|
WHERE $6::text IS NOT NULL
|
|
12257
|
-
AND pending.event_id
|
|
12375
|
+
AND pending.event_id = prefix.event_id
|
|
12258
12376
|
RETURNING pending.event_id
|
|
12259
12377
|
),
|
|
12260
12378
|
terminal_outbox AS (
|
|
@@ -12309,16 +12427,26 @@ export async function cancelPostgresSchedulerRun(
|
|
|
12309
12427
|
// commits so the request can still project the winning terminal state
|
|
12310
12428
|
// without waiting for a background lease.
|
|
12311
12429
|
await client.query(
|
|
12312
|
-
`
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12430
|
+
`WITH terminal_pending AS MATERIALIZED (
|
|
12431
|
+
SELECT pending.event_id,
|
|
12432
|
+
row_number() OVER (ORDER BY ${runLedgerOrderSql('pending')}) AS position
|
|
12433
|
+
FROM ${tableName('outbox', options)} AS pending
|
|
12434
|
+
JOIN ${tableName('runs', options)} AS terminal_run
|
|
12435
|
+
ON terminal_run.run_id = pending.run_id
|
|
12436
|
+
WHERE pending.run_id = $1
|
|
12437
|
+
AND terminal_run.status IN ('completed', 'failed', 'cancelled')
|
|
12438
|
+
AND pending.delivered_at IS NULL
|
|
12439
|
+
AND pending.failed_at IS NULL
|
|
12440
|
+
)
|
|
12441
|
+
UPDATE ${tableName('outbox', options)} AS pending
|
|
12442
|
+
SET lease_owner = CASE WHEN prefix.position = 1 THEN $2 ELSE NULL END,
|
|
12443
|
+
lease_expires_at = CASE
|
|
12444
|
+
WHEN prefix.position = 1 THEN now() + make_interval(secs => $3::integer)
|
|
12445
|
+
ELSE NULL
|
|
12446
|
+
END,
|
|
12447
|
+
next_attempt_at = NULL
|
|
12448
|
+
FROM terminal_pending AS prefix
|
|
12449
|
+
WHERE pending.event_id = prefix.event_id`,
|
|
12322
12450
|
[input.runId, outboxLeaseOwner, outboxLeaseSeconds],
|
|
12323
12451
|
);
|
|
12324
12452
|
}
|
|
@@ -16711,7 +16839,12 @@ export async function listPostgresSchedulerOutboxMaterializationPlans(
|
|
|
16711
16839
|
*/
|
|
16712
16840
|
export type RunLedgerOutboxTokenAuthority = 'local_mint' | 'gateway';
|
|
16713
16841
|
|
|
16714
|
-
const POSTGRES_SCHEDULER_CANCELLATION_OUTBOX_LEASE_SECONDS =
|
|
16842
|
+
const POSTGRES_SCHEDULER_CANCELLATION_OUTBOX_LEASE_SECONDS =
|
|
16843
|
+
// The direct projection can run for the full app-runtime request deadline.
|
|
16844
|
+
// Keep another 30 seconds for dispatch setup and acknowledgement so a
|
|
16845
|
+
// background projector cannot reclaim an append that is still in flight.
|
|
16846
|
+
Math.ceil(RUNTIME_CAPACITY_POLICY.receiptGateway.requestTimeoutMs / 1_000) +
|
|
16847
|
+
30;
|
|
16715
16848
|
|
|
16716
16849
|
/**
|
|
16717
16850
|
* Stable lease identity shared by the atomic scheduler cancellation and the
|
package/dist/cli/index.js
CHANGED
|
@@ -3051,7 +3051,7 @@ var SDK_RELEASE = {
|
|
|
3051
3051
|
// getters keep their established compatibility behavior.
|
|
3052
3052
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
3053
3053
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
3054
|
-
version: "0.3.
|
|
3054
|
+
version: "0.3.198",
|
|
3055
3055
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
3056
3056
|
packageCapabilities: {
|
|
3057
3057
|
updatePreferences: 1
|
|
@@ -4699,10 +4699,30 @@ var DOCFLOW_NODE_IO_LIMITS = {
|
|
|
4699
4699
|
};
|
|
4700
4700
|
var utf8Encoder = new TextEncoder();
|
|
4701
4701
|
var PLAY_DATASET_BRAND = Symbol.for("deepline.play.dataset");
|
|
4702
|
+
var MAX_CONVEX_PREVIEW_KEY_LENGTH = 1024;
|
|
4702
4703
|
function ledgerSafeDocflowPreviewKey(key) {
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4704
|
+
const source = key.startsWith("$") ? key.replace(/^\$+/, "") || "output" : key || "output";
|
|
4705
|
+
let encoded = "";
|
|
4706
|
+
for (const character of source) {
|
|
4707
|
+
const code = character.charCodeAt(0);
|
|
4708
|
+
if (code >= 32 && code < 127) {
|
|
4709
|
+
encoded += character;
|
|
4710
|
+
continue;
|
|
4711
|
+
}
|
|
4712
|
+
for (const byte of utf8Encoder.encode(character)) {
|
|
4713
|
+
encoded += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4716
|
+
if (encoded.length <= MAX_CONVEX_PREVIEW_KEY_LENGTH) return encoded;
|
|
4717
|
+
let hashA = 2166136261;
|
|
4718
|
+
let hashB = 2654435769;
|
|
4719
|
+
for (let index = 0; index < encoded.length; index += 1) {
|
|
4720
|
+
const code = encoded.charCodeAt(index);
|
|
4721
|
+
hashA = Math.imul(hashA ^ code, 16777619);
|
|
4722
|
+
hashB = Math.imul(hashB ^ code, 16777619);
|
|
4723
|
+
}
|
|
4724
|
+
const suffix = `~${(hashA >>> 0).toString(16).padStart(8, "0")}${(hashB >>> 0).toString(16).padStart(8, "0")}`;
|
|
4725
|
+
return `${encoded.slice(0, MAX_CONVEX_PREVIEW_KEY_LENGTH - suffix.length)}${suffix}`;
|
|
4706
4726
|
}
|
|
4707
4727
|
function utf8Bytes(value) {
|
|
4708
4728
|
return utf8Encoder.encode(value).byteLength;
|
package/dist/cli/index.mjs
CHANGED
|
@@ -3046,7 +3046,7 @@ var SDK_RELEASE = {
|
|
|
3046
3046
|
// getters keep their established compatibility behavior.
|
|
3047
3047
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
3048
3048
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
3049
|
-
version: "0.3.
|
|
3049
|
+
version: "0.3.198",
|
|
3050
3050
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
3051
3051
|
packageCapabilities: {
|
|
3052
3052
|
updatePreferences: 1
|
|
@@ -4694,10 +4694,30 @@ var DOCFLOW_NODE_IO_LIMITS = {
|
|
|
4694
4694
|
};
|
|
4695
4695
|
var utf8Encoder = new TextEncoder();
|
|
4696
4696
|
var PLAY_DATASET_BRAND = Symbol.for("deepline.play.dataset");
|
|
4697
|
+
var MAX_CONVEX_PREVIEW_KEY_LENGTH = 1024;
|
|
4697
4698
|
function ledgerSafeDocflowPreviewKey(key) {
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4699
|
+
const source = key.startsWith("$") ? key.replace(/^\$+/, "") || "output" : key || "output";
|
|
4700
|
+
let encoded = "";
|
|
4701
|
+
for (const character of source) {
|
|
4702
|
+
const code = character.charCodeAt(0);
|
|
4703
|
+
if (code >= 32 && code < 127) {
|
|
4704
|
+
encoded += character;
|
|
4705
|
+
continue;
|
|
4706
|
+
}
|
|
4707
|
+
for (const byte of utf8Encoder.encode(character)) {
|
|
4708
|
+
encoded += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
4709
|
+
}
|
|
4710
|
+
}
|
|
4711
|
+
if (encoded.length <= MAX_CONVEX_PREVIEW_KEY_LENGTH) return encoded;
|
|
4712
|
+
let hashA = 2166136261;
|
|
4713
|
+
let hashB = 2654435769;
|
|
4714
|
+
for (let index = 0; index < encoded.length; index += 1) {
|
|
4715
|
+
const code = encoded.charCodeAt(index);
|
|
4716
|
+
hashA = Math.imul(hashA ^ code, 16777619);
|
|
4717
|
+
hashB = Math.imul(hashB ^ code, 16777619);
|
|
4718
|
+
}
|
|
4719
|
+
const suffix = `~${(hashA >>> 0).toString(16).padStart(8, "0")}${(hashB >>> 0).toString(16).padStart(8, "0")}`;
|
|
4720
|
+
return `${encoded.slice(0, MAX_CONVEX_PREVIEW_KEY_LENGTH - suffix.length)}${suffix}`;
|
|
4701
4721
|
}
|
|
4702
4722
|
function utf8Bytes(value) {
|
|
4703
4723
|
return utf8Encoder.encode(value).byteLength;
|
package/dist/index.js
CHANGED
|
@@ -864,7 +864,7 @@ var SDK_RELEASE = {
|
|
|
864
864
|
// getters keep their established compatibility behavior.
|
|
865
865
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
866
866
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
867
|
-
version: "0.3.
|
|
867
|
+
version: "0.3.198",
|
|
868
868
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
869
869
|
packageCapabilities: {
|
|
870
870
|
updatePreferences: 1
|
|
@@ -2460,10 +2460,30 @@ var DOCFLOW_NODE_IO_LIMITS = {
|
|
|
2460
2460
|
};
|
|
2461
2461
|
var utf8Encoder = new TextEncoder();
|
|
2462
2462
|
var PLAY_DATASET_BRAND = Symbol.for("deepline.play.dataset");
|
|
2463
|
+
var MAX_CONVEX_PREVIEW_KEY_LENGTH = 1024;
|
|
2463
2464
|
function ledgerSafeDocflowPreviewKey(key) {
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2465
|
+
const source = key.startsWith("$") ? key.replace(/^\$+/, "") || "output" : key || "output";
|
|
2466
|
+
let encoded = "";
|
|
2467
|
+
for (const character of source) {
|
|
2468
|
+
const code = character.charCodeAt(0);
|
|
2469
|
+
if (code >= 32 && code < 127) {
|
|
2470
|
+
encoded += character;
|
|
2471
|
+
continue;
|
|
2472
|
+
}
|
|
2473
|
+
for (const byte of utf8Encoder.encode(character)) {
|
|
2474
|
+
encoded += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
if (encoded.length <= MAX_CONVEX_PREVIEW_KEY_LENGTH) return encoded;
|
|
2478
|
+
let hashA = 2166136261;
|
|
2479
|
+
let hashB = 2654435769;
|
|
2480
|
+
for (let index = 0; index < encoded.length; index += 1) {
|
|
2481
|
+
const code = encoded.charCodeAt(index);
|
|
2482
|
+
hashA = Math.imul(hashA ^ code, 16777619);
|
|
2483
|
+
hashB = Math.imul(hashB ^ code, 16777619);
|
|
2484
|
+
}
|
|
2485
|
+
const suffix = `~${(hashA >>> 0).toString(16).padStart(8, "0")}${(hashB >>> 0).toString(16).padStart(8, "0")}`;
|
|
2486
|
+
return `${encoded.slice(0, MAX_CONVEX_PREVIEW_KEY_LENGTH - suffix.length)}${suffix}`;
|
|
2467
2487
|
}
|
|
2468
2488
|
function utf8Bytes(value) {
|
|
2469
2489
|
return utf8Encoder.encode(value).byteLength;
|
package/dist/index.mjs
CHANGED
|
@@ -768,7 +768,7 @@ var SDK_RELEASE = {
|
|
|
768
768
|
// getters keep their established compatibility behavior.
|
|
769
769
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
770
770
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
771
|
-
version: "0.3.
|
|
771
|
+
version: "0.3.198",
|
|
772
772
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
773
773
|
packageCapabilities: {
|
|
774
774
|
updatePreferences: 1
|
|
@@ -2364,10 +2364,30 @@ var DOCFLOW_NODE_IO_LIMITS = {
|
|
|
2364
2364
|
};
|
|
2365
2365
|
var utf8Encoder = new TextEncoder();
|
|
2366
2366
|
var PLAY_DATASET_BRAND = Symbol.for("deepline.play.dataset");
|
|
2367
|
+
var MAX_CONVEX_PREVIEW_KEY_LENGTH = 1024;
|
|
2367
2368
|
function ledgerSafeDocflowPreviewKey(key) {
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2369
|
+
const source = key.startsWith("$") ? key.replace(/^\$+/, "") || "output" : key || "output";
|
|
2370
|
+
let encoded = "";
|
|
2371
|
+
for (const character of source) {
|
|
2372
|
+
const code = character.charCodeAt(0);
|
|
2373
|
+
if (code >= 32 && code < 127) {
|
|
2374
|
+
encoded += character;
|
|
2375
|
+
continue;
|
|
2376
|
+
}
|
|
2377
|
+
for (const byte of utf8Encoder.encode(character)) {
|
|
2378
|
+
encoded += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
if (encoded.length <= MAX_CONVEX_PREVIEW_KEY_LENGTH) return encoded;
|
|
2382
|
+
let hashA = 2166136261;
|
|
2383
|
+
let hashB = 2654435769;
|
|
2384
|
+
for (let index = 0; index < encoded.length; index += 1) {
|
|
2385
|
+
const code = encoded.charCodeAt(index);
|
|
2386
|
+
hashA = Math.imul(hashA ^ code, 16777619);
|
|
2387
|
+
hashB = Math.imul(hashB ^ code, 16777619);
|
|
2388
|
+
}
|
|
2389
|
+
const suffix = `~${(hashA >>> 0).toString(16).padStart(8, "0")}${(hashB >>> 0).toString(16).padStart(8, "0")}`;
|
|
2390
|
+
return `${encoded.slice(0, MAX_CONVEX_PREVIEW_KEY_LENGTH - suffix.length)}${suffix}`;
|
|
2371
2391
|
}
|
|
2372
2392
|
function utf8Bytes(value) {
|
|
2373
2393
|
return utf8Encoder.encode(value).byteLength;
|
package/dist/release.d.mts
CHANGED
|
@@ -149,7 +149,7 @@ type SdkRelease = {
|
|
|
149
149
|
supportPolicy: SdkSupportPolicy;
|
|
150
150
|
};
|
|
151
151
|
declare const SDK_RELEASE: {
|
|
152
|
-
readonly version: "0.3.
|
|
152
|
+
readonly version: "0.3.198";
|
|
153
153
|
readonly updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.";
|
|
154
154
|
readonly packageCapabilities: {
|
|
155
155
|
readonly updatePreferences: 1;
|
package/dist/release.d.ts
CHANGED
|
@@ -149,7 +149,7 @@ type SdkRelease = {
|
|
|
149
149
|
supportPolicy: SdkSupportPolicy;
|
|
150
150
|
};
|
|
151
151
|
declare const SDK_RELEASE: {
|
|
152
|
-
readonly version: "0.3.
|
|
152
|
+
readonly version: "0.3.198";
|
|
153
153
|
readonly updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.";
|
|
154
154
|
readonly packageCapabilities: {
|
|
155
155
|
readonly updatePreferences: 1;
|
package/dist/release.js
CHANGED
|
@@ -74,7 +74,7 @@ var SDK_RELEASE = {
|
|
|
74
74
|
// getters keep their established compatibility behavior.
|
|
75
75
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
76
76
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
77
|
-
version: "0.3.
|
|
77
|
+
version: "0.3.198",
|
|
78
78
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
79
79
|
packageCapabilities: {
|
|
80
80
|
updatePreferences: 1
|
package/dist/release.mjs
CHANGED
|
@@ -48,7 +48,7 @@ var SDK_RELEASE = {
|
|
|
48
48
|
// getters keep their established compatibility behavior.
|
|
49
49
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
50
50
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
51
|
-
version: "0.3.
|
|
51
|
+
version: "0.3.198",
|
|
52
52
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
53
53
|
packageCapabilities: {
|
|
54
54
|
updatePreferences: 1
|