deepline 0.3.185 → 0.3.187
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/sdk/src/types.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts +229 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +16 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +54 -160
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-telemetry.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +238 -24
- package/dist/bundling-sources/shared_libs/play-runtime/sheet-attempt-sql.ts +5 -5
- package/dist/cli/index.js +29 -3
- package/dist/cli/index.mjs +29 -3
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/install-integrity.json +1 -0
- 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.187',
|
|
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: {
|
|
@@ -1331,6 +1331,8 @@ export interface PlayDefinitionDetail {
|
|
|
1331
1331
|
cronTimezone?: string | null;
|
|
1332
1332
|
nextScheduledAt?: number | null;
|
|
1333
1333
|
lastScheduledAt?: number | null;
|
|
1334
|
+
blockedAt?: number | null;
|
|
1335
|
+
blockedReasonCode?: string | null;
|
|
1334
1336
|
blockedReason?: string | null;
|
|
1335
1337
|
[key: string]: unknown;
|
|
1336
1338
|
} | null;
|
|
@@ -1403,6 +1405,8 @@ export interface PlayTriggerStatus {
|
|
|
1403
1405
|
cron: string | null;
|
|
1404
1406
|
webhook: string | null;
|
|
1405
1407
|
blockedReason: string | null;
|
|
1408
|
+
blockedReasonCode?: string;
|
|
1409
|
+
blockedAt?: number;
|
|
1406
1410
|
}
|
|
1407
1411
|
|
|
1408
1412
|
export interface ProductNotificationEventDefinition {
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { sha256Hex, stableStringify } from '../plays/row-identity';
|
|
2
|
+
import { LEGACY_MAX_CONCURRENT_EXTERNAL_CALLS } from './governor/policy';
|
|
3
|
+
import type { PlaySchedulerSubmitInput } from './scheduler-backend';
|
|
4
|
+
|
|
5
|
+
/** Optional launch-envelope field used by the mixed-release admission fence. */
|
|
6
|
+
export const PLAY_LAUNCH_IDENTITY_DIGEST_FIELD = 'launchIdentityDigest';
|
|
7
|
+
const PLAY_LAUNCH_IDENTITY_DIGEST_NAMESPACE = 'deepline:play-launch-identity';
|
|
8
|
+
|
|
9
|
+
export type PlayLaunchFieldRole = 'identity' | 'detail';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Keep this list exhaustive over the launch envelope. A newly added field must
|
|
13
|
+
* be classified before it can participate in launch admission.
|
|
14
|
+
*/
|
|
15
|
+
export const PLAY_LAUNCH_ENVELOPE_FIELD_ROLES: {
|
|
16
|
+
readonly [K in keyof PlaySchedulerSubmitInput]-?: PlayLaunchFieldRole;
|
|
17
|
+
} = {
|
|
18
|
+
orgId: 'identity',
|
|
19
|
+
playName: 'identity',
|
|
20
|
+
playReference: 'identity',
|
|
21
|
+
definitionScope: 'identity',
|
|
22
|
+
revisionId: 'identity',
|
|
23
|
+
artifactStorageKey: 'identity',
|
|
24
|
+
artifactHash: 'identity',
|
|
25
|
+
graphHash: 'identity',
|
|
26
|
+
workflowFamilyKey: 'identity',
|
|
27
|
+
inputSha256: 'identity',
|
|
28
|
+
source: 'identity',
|
|
29
|
+
triggerSource: 'identity',
|
|
30
|
+
parentRunId: 'identity',
|
|
31
|
+
rootRunId: 'identity',
|
|
32
|
+
asyncLaunchKey: 'identity',
|
|
33
|
+
asyncInvocationKey: 'identity',
|
|
34
|
+
asyncRequestFingerprint: 'identity',
|
|
35
|
+
force: 'identity',
|
|
36
|
+
forceToolRefresh: 'identity',
|
|
37
|
+
maxConcurrentExternalCalls: 'identity',
|
|
38
|
+
maxConcurrentRows: 'identity',
|
|
39
|
+
integrationMode: 'identity',
|
|
40
|
+
runtimeSandboxPlacementPolicyId: 'identity',
|
|
41
|
+
input: 'identity',
|
|
42
|
+
inputFile: 'identity',
|
|
43
|
+
inlineInputFile: 'identity',
|
|
44
|
+
inlineCsv: 'identity',
|
|
45
|
+
packagedFiles: 'identity',
|
|
46
|
+
runId: 'detail',
|
|
47
|
+
existingOnly: 'detail',
|
|
48
|
+
asyncParentRunAttempt: 'detail',
|
|
49
|
+
asyncParentRunLeaseToken: 'detail',
|
|
50
|
+
asyncParentAttemptRequired: 'detail',
|
|
51
|
+
asyncAncestryPlayIds: 'detail',
|
|
52
|
+
playId: 'detail',
|
|
53
|
+
schedulerSchema: 'detail',
|
|
54
|
+
requiresRunCreatedProjection: 'detail',
|
|
55
|
+
runtimeArtifact: 'detail',
|
|
56
|
+
runtimeProtocolVersion: 'detail',
|
|
57
|
+
staticPipeline: 'detail',
|
|
58
|
+
inputSummary: 'detail',
|
|
59
|
+
inputBytes: 'detail',
|
|
60
|
+
inputFileId: 'detail',
|
|
61
|
+
replayedFromRunId: 'detail',
|
|
62
|
+
totalRows: 'detail',
|
|
63
|
+
contractSnapshot: 'detail',
|
|
64
|
+
executionPlan: 'detail',
|
|
65
|
+
preloadedDbSessions: 'detail',
|
|
66
|
+
preloadedDbSessionUnwrapKey: 'detail',
|
|
67
|
+
executorToken: 'detail',
|
|
68
|
+
runtimeAuthority: 'detail',
|
|
69
|
+
runtimeApiBaseUrl: 'detail',
|
|
70
|
+
runtimeTokenOrigin: 'detail',
|
|
71
|
+
baseUrl: 'detail',
|
|
72
|
+
coordinatorUrl: 'detail',
|
|
73
|
+
coordinatorInternalToken: 'detail',
|
|
74
|
+
runtimeDeployVersion: 'detail',
|
|
75
|
+
absurdReleaseId: 'detail',
|
|
76
|
+
absurdReleaseEnvironment: 'detail',
|
|
77
|
+
vercelProtectionBypassToken: 'detail',
|
|
78
|
+
preferredReceiptGatewayMachineId: 'detail',
|
|
79
|
+
runtimeTestFaultHeader: 'detail',
|
|
80
|
+
testPolicyOverrides: 'detail',
|
|
81
|
+
submittedAtMs: 'detail',
|
|
82
|
+
schedulerBackend: 'detail',
|
|
83
|
+
executionProfile: 'detail',
|
|
84
|
+
runtimeBackend: 'detail',
|
|
85
|
+
queueMaxDelaySeconds: 'detail',
|
|
86
|
+
queuePriority: 'detail',
|
|
87
|
+
userEmail: 'detail',
|
|
88
|
+
userId: 'detail',
|
|
89
|
+
launchIdentityDigest: 'detail',
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const PLAY_LAUNCH_IDENTITY_FIELDS_COMPARED_OUTSIDE_DIGEST: readonly string[] =
|
|
93
|
+
Object.freeze(['runtimeSandboxPlacementPolicyId']);
|
|
94
|
+
|
|
95
|
+
export const PLAY_LAUNCH_IDENTITY_FIELDS: readonly string[] = Object.freeze(
|
|
96
|
+
Object.entries(PLAY_LAUNCH_ENVELOPE_FIELD_ROLES)
|
|
97
|
+
.filter(([, role]) => role === 'identity')
|
|
98
|
+
.map(([field]) => field)
|
|
99
|
+
.sort(),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
export const PLAY_LAUNCH_DETAIL_FIELDS: readonly string[] = Object.freeze(
|
|
103
|
+
Object.entries(PLAY_LAUNCH_ENVELOPE_FIELD_ROLES)
|
|
104
|
+
.filter(([, role]) => role === 'detail')
|
|
105
|
+
.map(([field]) => field)
|
|
106
|
+
.sort(),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
export type PlayLaunchIdentitySource = Readonly<
|
|
110
|
+
Partial<Record<keyof PlaySchedulerSubmitInput, unknown>>
|
|
111
|
+
>;
|
|
112
|
+
|
|
113
|
+
function text(value: unknown): string | null {
|
|
114
|
+
return typeof value === 'string' && value.trim() ? value.trim() : null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function flag(value: unknown): boolean {
|
|
118
|
+
return value === true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function count(value: unknown): number | null {
|
|
122
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function record(value: unknown): Record<string, unknown> | null {
|
|
126
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
127
|
+
? (value as Record<string, unknown>)
|
|
128
|
+
: null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function stagedFileIdentity(value: unknown): Record<string, unknown> | null {
|
|
132
|
+
const file = record(value);
|
|
133
|
+
if (!file) return null;
|
|
134
|
+
return {
|
|
135
|
+
logicalPath:
|
|
136
|
+
text(file.logicalPath) ?? text(file.path) ?? text(file.playPath),
|
|
137
|
+
fileName: text(file.fileName) ?? text(file.name),
|
|
138
|
+
contentType: text(file.contentType),
|
|
139
|
+
bytes: count(file.bytes),
|
|
140
|
+
contentDigest:
|
|
141
|
+
typeof file.contentBase64 === 'string'
|
|
142
|
+
? sha256Hex(file.contentBase64)
|
|
143
|
+
: typeof file.inlineText === 'string'
|
|
144
|
+
? sha256Hex(file.inlineText)
|
|
145
|
+
: null,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function stagedFileListIdentity(
|
|
150
|
+
value: unknown,
|
|
151
|
+
): Array<Record<string, unknown>> {
|
|
152
|
+
if (!Array.isArray(value)) return [];
|
|
153
|
+
return value
|
|
154
|
+
.map((entry) => stagedFileIdentity(entry))
|
|
155
|
+
.filter((entry): entry is Record<string, unknown> => entry !== null)
|
|
156
|
+
.sort((left, right) =>
|
|
157
|
+
stableStringify(left).localeCompare(stableStringify(right)),
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Return only customer intent; transport, authority, and release details are excluded. */
|
|
162
|
+
export function buildPlayLaunchIdentity(
|
|
163
|
+
launch: PlayLaunchIdentitySource,
|
|
164
|
+
): Record<string, unknown> {
|
|
165
|
+
const inlineCsv = record(launch.inlineCsv);
|
|
166
|
+
return {
|
|
167
|
+
orgId: text(launch.orgId),
|
|
168
|
+
playName: text(launch.playName),
|
|
169
|
+
playReference: text(launch.playReference) ?? text(launch.playName),
|
|
170
|
+
definitionScope: text(launch.definitionScope),
|
|
171
|
+
revisionId: text(launch.revisionId),
|
|
172
|
+
artifactStorageKey: text(launch.artifactStorageKey),
|
|
173
|
+
artifactHash: text(launch.artifactHash),
|
|
174
|
+
graphHash: text(launch.graphHash),
|
|
175
|
+
workflowFamilyKey: text(launch.workflowFamilyKey),
|
|
176
|
+
inputSha256: text(launch.inputSha256),
|
|
177
|
+
source: text(launch.source),
|
|
178
|
+
triggerSource: text(launch.triggerSource),
|
|
179
|
+
parentRunId: text(launch.parentRunId),
|
|
180
|
+
rootRunId: text(launch.rootRunId),
|
|
181
|
+
asyncLaunchKey: text(launch.asyncLaunchKey),
|
|
182
|
+
asyncInvocationKey: text(launch.asyncInvocationKey),
|
|
183
|
+
asyncRequestFingerprint: text(launch.asyncRequestFingerprint),
|
|
184
|
+
force: flag(launch.force),
|
|
185
|
+
forceToolRefresh: flag(launch.forceToolRefresh),
|
|
186
|
+
integrationMode: text(launch.integrationMode),
|
|
187
|
+
maxConcurrentExternalCalls:
|
|
188
|
+
count(launch.maxConcurrentExternalCalls) ??
|
|
189
|
+
LEGACY_MAX_CONCURRENT_EXTERNAL_CALLS,
|
|
190
|
+
maxConcurrentRows: count(launch.maxConcurrentRows),
|
|
191
|
+
inputDigest: sha256Hex(stableStringify(launch.input ?? {})),
|
|
192
|
+
inputFile: stagedFileIdentity(launch.inputFile),
|
|
193
|
+
inlineInputFile: stagedFileIdentity(launch.inlineInputFile),
|
|
194
|
+
inlineCsv: inlineCsv
|
|
195
|
+
? {
|
|
196
|
+
name: text(inlineCsv.name),
|
|
197
|
+
rowsDigest: sha256Hex(stableStringify(inlineCsv.rows ?? [])),
|
|
198
|
+
}
|
|
199
|
+
: null,
|
|
200
|
+
packagedFiles: stagedFileListIdentity(launch.packagedFiles),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export const PLAY_LAUNCH_DIGESTED_IDENTITY_FIELDS: readonly string[] =
|
|
205
|
+
Object.freeze(
|
|
206
|
+
PLAY_LAUNCH_IDENTITY_FIELDS.filter(
|
|
207
|
+
(field) =>
|
|
208
|
+
!PLAY_LAUNCH_IDENTITY_FIELDS_COMPARED_OUTSIDE_DIGEST.includes(field),
|
|
209
|
+
),
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
export function buildPlayLaunchIdentityDigest(
|
|
213
|
+
launch: PlayLaunchIdentitySource,
|
|
214
|
+
): string {
|
|
215
|
+
return sha256Hex(
|
|
216
|
+
`${PLAY_LAUNCH_IDENTITY_DIGEST_NAMESPACE}\0${stableStringify(
|
|
217
|
+
buildPlayLaunchIdentity(launch),
|
|
218
|
+
)}`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function withPlayLaunchIdentityDigest<
|
|
223
|
+
T extends PlaySchedulerSubmitInput,
|
|
224
|
+
>(launch: T): T {
|
|
225
|
+
return {
|
|
226
|
+
...launch,
|
|
227
|
+
launchIdentityDigest: buildPlayLaunchIdentityDigest(launch),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
@@ -42,16 +42,31 @@ export type PlayRunAdmissionJob = {
|
|
|
42
42
|
admit(input: PlayRunAdmissionInput): Promise<PlayRunAdmissionOutcome>;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
export type PlayRunLaunchConflictReason = 'launch_identity_mismatch';
|
|
46
|
+
|
|
45
47
|
/** A stable, machine-readable rejection for a reused run id with new intent. */
|
|
46
48
|
export class PlayRunLaunchConflictError extends Error {
|
|
47
49
|
readonly code = 'PLAY_RUN_LAUNCH_CONFLICT';
|
|
50
|
+
readonly conflictReason: PlayRunLaunchConflictReason | undefined;
|
|
51
|
+
readonly conflictingFields: string[] | undefined;
|
|
48
52
|
|
|
49
|
-
constructor(
|
|
53
|
+
constructor(
|
|
54
|
+
runId: string,
|
|
55
|
+
options?: {
|
|
56
|
+
cause?: unknown;
|
|
57
|
+
conflictReason?: PlayRunLaunchConflictReason;
|
|
58
|
+
conflictingFields?: readonly string[];
|
|
59
|
+
},
|
|
60
|
+
) {
|
|
50
61
|
super(
|
|
51
62
|
`Play run "${runId}" already exists with a different launch.`,
|
|
52
63
|
options,
|
|
53
64
|
);
|
|
54
65
|
this.name = 'PlayRunLaunchConflictError';
|
|
66
|
+
this.conflictReason = options?.conflictReason;
|
|
67
|
+
this.conflictingFields = options?.conflictingFields
|
|
68
|
+
? [...options.conflictingFields]
|
|
69
|
+
: undefined;
|
|
55
70
|
}
|
|
56
71
|
}
|
|
57
72
|
|
package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts
CHANGED
|
@@ -54,6 +54,9 @@ export function createPostgresPlayRunAdmissionPorts(input: {
|
|
|
54
54
|
artifactHash: admission.launch.artifactHash,
|
|
55
55
|
graphHash: admission.launch.graphHash,
|
|
56
56
|
inputSha256: admission.launch.inputSha256,
|
|
57
|
+
launchIdentityDigest: admission.launch.launchIdentityDigest,
|
|
58
|
+
conflictReason: conflict.conflictReason ?? null,
|
|
59
|
+
conflictingFields: conflict.conflictingFields ?? null,
|
|
57
60
|
error: conflict,
|
|
58
61
|
});
|
|
59
62
|
throw conflict;
|