deepline 0.2.13 → 0.2.14
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/index.ts +3 -0
- package/dist/bundling-sources/sdk/src/play.ts +150 -691
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +7 -1
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +249 -51
- package/dist/bundling-sources/shared_libs/play-runtime/csv-rename.ts +10 -6
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +32 -51
- package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +11 -22
- package/dist/bundling-sources/shared_libs/play-runtime/durable-call-policy.ts +34 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-call-execution.ts +2 -1
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-projection-contract.ts +95 -0
- package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +23 -15
- package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +3 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +2222 -0
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +3 -2
- package/dist/bundling-sources/shared_libs/plays/compiler-manifest.ts +2 -0
- package/dist/bundling-sources/shared_libs/plays/contracts.ts +16 -0
- package/dist/bundling-sources/shared_libs/plays/input-contract-definition.ts +28 -0
- package/dist/bundling-sources/shared_libs/plays/input-contract.ts +3 -3
- package/dist/cli/index.js +5074 -829
- package/dist/cli/index.mjs +5019 -759
- package/dist/compiler-manifest-xFkbJX2B.d.mts +2517 -0
- package/dist/compiler-manifest-xFkbJX2B.d.ts +2517 -0
- package/dist/index.d.mts +36 -1011
- package/dist/index.d.ts +36 -1011
- package/dist/index.js +25 -7
- package/dist/index.mjs +25 -7
- package/dist/plays/bundle-play-file.d.mts +5 -8
- package/dist/plays/bundle-play-file.d.ts +5 -8
- package/dist/plays/bundle-play-file.mjs +3844 -3
- package/package.json +1 -1
- package/dist/bundling-sources/shared_libs/plays/source-metadata.ts +0 -240
- package/dist/tool-execution-error-4-rhemLQ.d.mts +0 -446
- package/dist/tool-execution-error-4-rhemLQ.d.ts +0 -446
|
@@ -3,6 +3,18 @@ import type { PlayBundleArtifact } from '../plays/artifact-types';
|
|
|
3
3
|
import type { PlayRunContractSnapshot } from '../plays/contracts';
|
|
4
4
|
import type { PlayStructuredDefinition } from '../plays/definition';
|
|
5
5
|
import type { PlayStaticPipeline } from '../plays/static-pipeline';
|
|
6
|
+
import type {
|
|
7
|
+
DurableCallStaleAfterSeconds,
|
|
8
|
+
PlayAuthoringCallOptions,
|
|
9
|
+
PlayAuthoringCsvOptions,
|
|
10
|
+
PlayAuthoringFetchOptions,
|
|
11
|
+
PlayAuthoringRuntimeStepOptions,
|
|
12
|
+
PlayAuthoringContractEdition,
|
|
13
|
+
PlayToolCallOptions,
|
|
14
|
+
PlayToolExecutionRequest,
|
|
15
|
+
PlayReceiptWaitMs,
|
|
16
|
+
PlayRuntimeTimeoutMs,
|
|
17
|
+
} from '../plays/authoring-contract';
|
|
6
18
|
import type {
|
|
7
19
|
PlayDataset,
|
|
8
20
|
PlayDatasetInput,
|
|
@@ -208,14 +220,9 @@ export interface HeartbeatRuntimeStepReceiptsInput {
|
|
|
208
220
|
leaseIds?: string[];
|
|
209
221
|
}
|
|
210
222
|
|
|
211
|
-
export
|
|
212
|
-
description?: string;
|
|
213
|
-
columns?: Record<string, string | readonly string[]>;
|
|
214
|
-
rename?: Record<string, string | readonly string[]>;
|
|
215
|
-
required?: readonly string[];
|
|
216
|
-
}
|
|
223
|
+
export type CsvOptions = PlayAuthoringCsvOptions;
|
|
217
224
|
|
|
218
|
-
export interface
|
|
225
|
+
export interface RuntimeDatasetOptions<TItem = Record<string, unknown>> {
|
|
219
226
|
description?: string;
|
|
220
227
|
/**
|
|
221
228
|
* Optional relative cache window for intentional reruns.
|
|
@@ -270,58 +277,30 @@ export interface DatasetOptions<TItem = Record<string, unknown>> {
|
|
|
270
277
|
mode?: 'upsert' | 'net_new';
|
|
271
278
|
}
|
|
272
279
|
|
|
273
|
-
export type
|
|
274
|
-
|
|
275
|
-
'description'
|
|
276
|
-
>;
|
|
280
|
+
export type RuntimeDatasetDefinitionOptions<TItem = Record<string, unknown>> =
|
|
281
|
+
Omit<RuntimeDatasetOptions<TItem>, 'description'>;
|
|
277
282
|
|
|
278
|
-
export type
|
|
279
|
-
|
|
283
|
+
export type RuntimeDatasetRunOptions<TItem = Record<string, unknown>> = Pick<
|
|
284
|
+
RuntimeDatasetOptions<TItem>,
|
|
280
285
|
'description' | 'key' | 'onRowError' | 'mode'
|
|
281
286
|
>;
|
|
282
287
|
|
|
283
|
-
export
|
|
284
|
-
|
|
285
|
-
force?: boolean;
|
|
286
|
-
staleAfterSeconds?: number;
|
|
287
|
-
timeoutMs?: number;
|
|
288
|
-
receiptWaitMs?: number;
|
|
289
|
-
}
|
|
288
|
+
export type ToolCallOptions = PlayToolCallOptions;
|
|
289
|
+
export type ToolExecutionRequest = PlayToolExecutionRequest;
|
|
290
290
|
|
|
291
|
-
export
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
force?: boolean;
|
|
297
|
-
staleAfterSeconds?: number;
|
|
298
|
-
timeoutMs?: number;
|
|
299
|
-
receiptWaitMs?: number;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
export interface PlayCallOptions {
|
|
303
|
-
description?: string;
|
|
304
|
-
/**
|
|
305
|
-
* `child-workflow` is accepted only so the checker/runtime can emit the
|
|
306
|
-
* canonical CTX_RUN_PLAY_INLINE_ONLY migration diagnostic. It never starts a
|
|
307
|
-
* child workflow.
|
|
308
|
-
*/
|
|
291
|
+
export type PlayCallOptions = Omit<
|
|
292
|
+
PlayAuthoringCallOptions,
|
|
293
|
+
'execution' | 'timeoutMs'
|
|
294
|
+
> & {
|
|
295
|
+
/** Legacy invalid spelling retained only for the stable migration error. */
|
|
309
296
|
execution?: PlayCallExecution | 'child-workflow';
|
|
310
|
-
/**
|
|
311
|
-
* Parsed so source preflight and an untyped runtime call can return the
|
|
312
|
-
* canonical CTX_RUN_PLAY_INLINE_ONLY migration error. It is never honored.
|
|
313
|
-
*/
|
|
297
|
+
/** Legacy invalid option retained only for the stable migration error. */
|
|
314
298
|
timeoutMs?: number;
|
|
315
|
-
}
|
|
299
|
+
};
|
|
316
300
|
|
|
317
|
-
export
|
|
318
|
-
semanticKey?: string;
|
|
319
|
-
staleAfterSeconds?: number;
|
|
320
|
-
}
|
|
301
|
+
export type RuntimeStepOptions = PlayAuthoringRuntimeStepOptions;
|
|
321
302
|
|
|
322
|
-
export
|
|
323
|
-
staleAfterSeconds?: number;
|
|
324
|
-
}
|
|
303
|
+
export type FetchOptions = PlayAuthoringFetchOptions;
|
|
325
304
|
|
|
326
305
|
export interface ResolvedPlayExecution {
|
|
327
306
|
playId: string;
|
|
@@ -502,6 +481,8 @@ export type IntegrationEventWaitHandler = {
|
|
|
502
481
|
export interface ContextOptions {
|
|
503
482
|
/** Immutable logical and physical execution identity for this context. */
|
|
504
483
|
executionScope?: RunExecutionScope;
|
|
484
|
+
/** Authoring semantics pinned by the immutable artifact. */
|
|
485
|
+
authoringContractEdition?: PlayAuthoringContractEdition;
|
|
505
486
|
/** Error shape pinned by the immutable play artifact; missing preserves legacy schema 0. */
|
|
506
487
|
toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
|
|
507
488
|
/** Short-lived HMAC-signed internal token for tool callbacks. Required for cloud execution. */
|
|
@@ -589,7 +570,7 @@ export interface ContextOptions {
|
|
|
589
570
|
staticPipeline?: PlayStaticPipeline | null;
|
|
590
571
|
forceRefresh?: boolean;
|
|
591
572
|
inputOffset?: number;
|
|
592
|
-
mode?:
|
|
573
|
+
mode?: RuntimeDatasetRunOptions['mode'];
|
|
593
574
|
},
|
|
594
575
|
) => Promise<MapStartResult>;
|
|
595
576
|
/**
|
|
@@ -6,40 +6,29 @@ import {
|
|
|
6
6
|
// packed SDK's dist/bundling-sources graph, where only relative imports
|
|
7
7
|
// resolve.
|
|
8
8
|
} from '../plays/row-identity';
|
|
9
|
+
import { resolveDurableCallCachePolicy } from './durable-call-policy';
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
DURABLE_CALL_STALE_AFTER_SECONDS_ERROR,
|
|
13
|
+
resolveDurableCallCachePolicy,
|
|
14
|
+
} from './durable-call-policy';
|
|
15
|
+
export type { DurableCallCachePolicy } from './durable-call-policy';
|
|
9
16
|
|
|
10
17
|
export const DURABLE_CALL_CACHE_POLICY_VERSION = 'call-cache-v1';
|
|
11
18
|
|
|
12
19
|
export type DurableCallKind = 'tool' | 'step' | 'fetch';
|
|
13
20
|
|
|
14
|
-
function validateStaleAfterSeconds(staleAfterSeconds?: number | null): void {
|
|
15
|
-
if (staleAfterSeconds === undefined || staleAfterSeconds === null) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
if (
|
|
19
|
-
!Number.isFinite(staleAfterSeconds) ||
|
|
20
|
-
!Number.isInteger(staleAfterSeconds) ||
|
|
21
|
-
staleAfterSeconds <= 0
|
|
22
|
-
) {
|
|
23
|
-
throw new Error(
|
|
24
|
-
'staleAfterSeconds must be a positive whole number of seconds.',
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
21
|
export function durableCacheStaleBucket(input: {
|
|
30
22
|
staleAfterSeconds?: number | null;
|
|
31
23
|
nowMs?: number;
|
|
32
24
|
}): string | null {
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
input.staleAfterSeconds === undefined ||
|
|
36
|
-
input.staleAfterSeconds === null
|
|
37
|
-
) {
|
|
25
|
+
const policy = resolveDurableCallCachePolicy(input.staleAfterSeconds);
|
|
26
|
+
if (policy.staleAfterSeconds === null) {
|
|
38
27
|
return null;
|
|
39
28
|
}
|
|
40
29
|
const nowMs = input.nowMs ?? Date.now();
|
|
41
|
-
return `${
|
|
42
|
-
nowMs / (
|
|
30
|
+
return `${policy.staleAfterSeconds}:${Math.floor(
|
|
31
|
+
nowMs / (policy.staleAfterSeconds * 1000),
|
|
43
32
|
)}`;
|
|
44
33
|
}
|
|
45
34
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PLAY_AUTHORING_FIELD_REGISTRY,
|
|
3
|
+
validatePlayAuthoringField,
|
|
4
|
+
type PlayAuthoringFieldPath,
|
|
5
|
+
} from '../plays/authoring-contract';
|
|
6
|
+
|
|
7
|
+
export const DURABLE_CALL_STALE_AFTER_SECONDS_ERROR =
|
|
8
|
+
PLAY_AUTHORING_FIELD_REGISTRY['ctx.tools.execute.staleAfterSeconds']
|
|
9
|
+
.errorMessage;
|
|
10
|
+
|
|
11
|
+
export type DurableCallCachePolicy = {
|
|
12
|
+
forceRefresh: boolean;
|
|
13
|
+
staleAfterSeconds: number | null;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** Normalize the public freshness contract shared by durable calls. */
|
|
17
|
+
export function resolveDurableCallCachePolicy(
|
|
18
|
+
staleAfterSeconds?: number | null,
|
|
19
|
+
path: Extract<
|
|
20
|
+
PlayAuthoringFieldPath,
|
|
21
|
+
| 'ctx.tools.execute.staleAfterSeconds'
|
|
22
|
+
| 'ctx.step.staleAfterSeconds'
|
|
23
|
+
| 'ctx.fetch.staleAfterSeconds'
|
|
24
|
+
> = 'ctx.tools.execute.staleAfterSeconds',
|
|
25
|
+
): DurableCallCachePolicy {
|
|
26
|
+
if (staleAfterSeconds === undefined || staleAfterSeconds === null) {
|
|
27
|
+
return { forceRefresh: false, staleAfterSeconds: null };
|
|
28
|
+
}
|
|
29
|
+
if (staleAfterSeconds === 0) {
|
|
30
|
+
return { forceRefresh: true, staleAfterSeconds: null };
|
|
31
|
+
}
|
|
32
|
+
validatePlayAuthoringField(path, staleAfterSeconds);
|
|
33
|
+
return { forceRefresh: false, staleAfterSeconds };
|
|
34
|
+
}
|
|
@@ -3,4 +3,5 @@
|
|
|
3
3
|
* recognizes the historical `child-workflow` spelling so preflight can return
|
|
4
4
|
* CTX_RUN_PLAY_INLINE_ONLY, but it is no longer a supported runtime option.
|
|
5
5
|
*/
|
|
6
|
-
export type PlayCallExecution = 'inline'
|
|
6
|
+
export type PlayCallExecution = Extract<PlayAuthoringCallExecution, 'inline'>;
|
|
7
|
+
import type { PlayAuthoringCallExecution } from '../plays/authoring-contract';
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract for idempotent Runtime Postgres -> Convex Run Ledger delivery.
|
|
3
|
+
*
|
|
4
|
+
* Producers must use these builders and API boundaries must use these
|
|
5
|
+
* validators. Keeping the format here prevents the scheduler and runtime route
|
|
6
|
+
* from admitting different lifecycle-event keys.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const UUID_PATTERN =
|
|
10
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
11
|
+
const SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/i;
|
|
12
|
+
|
|
13
|
+
function requireRunId(runId: string): void {
|
|
14
|
+
if (!runId.trim()) {
|
|
15
|
+
throw new Error('Run Ledger projection idempotency key requires a run id.');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function requireDeliveryKey(deliveryKey: string): void {
|
|
20
|
+
if (!UUID_PATTERN.test(deliveryKey)) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
'Run Ledger projection delivery key must be a canonical UUID.',
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function buildRunLedgerStartIdempotencyKey(input: {
|
|
28
|
+
runId: string;
|
|
29
|
+
deliveryKey: string;
|
|
30
|
+
}): string {
|
|
31
|
+
requireRunId(input.runId);
|
|
32
|
+
requireDeliveryKey(input.deliveryKey);
|
|
33
|
+
return `run-started:${input.runId}:${input.deliveryKey}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function buildRunLedgerTerminalIdempotencyKey(input: {
|
|
37
|
+
runId: string;
|
|
38
|
+
deliveryKey: string;
|
|
39
|
+
}): string {
|
|
40
|
+
requireRunId(input.runId);
|
|
41
|
+
requireDeliveryKey(input.deliveryKey);
|
|
42
|
+
return `run-terminal:${input.runId}:${input.deliveryKey}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Compatibility key for the one-row projector. The `run-terminal` prefix was
|
|
47
|
+
* historically used for every non-start row, including lifecycle events, so
|
|
48
|
+
* changing it during a retry could append the same fact twice across deploys.
|
|
49
|
+
*/
|
|
50
|
+
export function buildRunLedgerSingleEventIdempotencyKey(input: {
|
|
51
|
+
runId: string;
|
|
52
|
+
deliveryKey: string;
|
|
53
|
+
}): string {
|
|
54
|
+
return buildRunLedgerTerminalIdempotencyKey(input);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function buildRunLedgerEventsIdempotencyKey(input: {
|
|
58
|
+
runId: string;
|
|
59
|
+
deliveryDigest: string;
|
|
60
|
+
}): string {
|
|
61
|
+
requireRunId(input.runId);
|
|
62
|
+
if (!SHA256_HEX_PATTERN.test(input.deliveryDigest)) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
'Run Ledger projection delivery digest must be a SHA-256 hex value.',
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return `run-events:${input.runId}:${input.deliveryDigest}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function isValidRunLedgerStartIdempotencyKey(input: {
|
|
71
|
+
runId: string;
|
|
72
|
+
idempotencyKey: string;
|
|
73
|
+
}): boolean {
|
|
74
|
+
const prefix = `run-started:${input.runId}:`;
|
|
75
|
+
return (
|
|
76
|
+
input.idempotencyKey.startsWith(prefix) &&
|
|
77
|
+
UUID_PATTERN.test(input.idempotencyKey.slice(prefix.length))
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function isValidRunLedgerAppendIdempotencyKey(input: {
|
|
82
|
+
runId: string;
|
|
83
|
+
idempotencyKey: string;
|
|
84
|
+
}): boolean {
|
|
85
|
+
const terminalPrefix = `run-terminal:${input.runId}:`;
|
|
86
|
+
if (input.idempotencyKey.startsWith(terminalPrefix)) {
|
|
87
|
+
return UUID_PATTERN.test(input.idempotencyKey.slice(terminalPrefix.length));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const eventsPrefix = `run-events:${input.runId}:`;
|
|
91
|
+
return (
|
|
92
|
+
input.idempotencyKey.startsWith(eventsPrefix) &&
|
|
93
|
+
SHA256_HEX_PATTERN.test(input.idempotencyKey.slice(eventsPrefix.length))
|
|
94
|
+
);
|
|
95
|
+
}
|
|
@@ -1,28 +1,36 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
PlaySecretAuth,
|
|
3
|
+
PlaySecretAwareRequestInit,
|
|
4
|
+
PlaySecretHandle,
|
|
5
|
+
} from '../plays/authoring-contract';
|
|
6
|
+
|
|
1
7
|
const SECRET_HANDLE_BRAND = Symbol.for('deepline.secret.handle');
|
|
2
8
|
const SECRET_AUTH_BRAND = Symbol.for('deepline.secret.auth');
|
|
3
9
|
const SECRET_HANDLE_MARKER_RE = /\[secret:[A-Z0-9_ -]+\]/i;
|
|
4
10
|
|
|
5
|
-
export type SecretHandle = {
|
|
11
|
+
export type SecretHandle = PlaySecretHandle & {
|
|
6
12
|
readonly [SECRET_HANDLE_BRAND]: true;
|
|
7
13
|
readonly name: string;
|
|
8
14
|
toString(): string;
|
|
9
15
|
toJSON(): never;
|
|
10
16
|
};
|
|
11
17
|
|
|
12
|
-
export type SecretAuth =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
export type SecretAuth = PlaySecretAuth &
|
|
19
|
+
(
|
|
20
|
+
| {
|
|
21
|
+
readonly [SECRET_AUTH_BRAND]: true;
|
|
22
|
+
readonly kind: 'bearer';
|
|
23
|
+
readonly secret: SecretHandle;
|
|
24
|
+
}
|
|
25
|
+
| {
|
|
26
|
+
readonly [SECRET_AUTH_BRAND]: true;
|
|
27
|
+
readonly kind: 'header';
|
|
28
|
+
readonly header: string;
|
|
29
|
+
readonly secret: SecretHandle;
|
|
30
|
+
}
|
|
31
|
+
);
|
|
24
32
|
|
|
25
|
-
export type SecretAwareRequestInit =
|
|
33
|
+
export type SecretAwareRequestInit = PlaySecretAwareRequestInit & {
|
|
26
34
|
auth?: SecretAuth;
|
|
27
35
|
};
|
|
28
36
|
|
|
@@ -70,7 +78,7 @@ export function createSecretHandle(name: string): SecretHandle {
|
|
|
70
78
|
`Secret ${name} cannot be serialized. Use an approved ctx.secrets helper.`,
|
|
71
79
|
);
|
|
72
80
|
},
|
|
73
|
-
};
|
|
81
|
+
} as unknown as SecretHandle;
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
export function createBearerSecretAuth(secret: SecretHandle): SecretAuth {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ToolExecutionErrorSchemaVersion } from '../tool-execution-error';
|
|
2
|
+
import type { PlayAuthoringContractEdition } from './authoring-contract';
|
|
2
3
|
|
|
3
4
|
export type PlayPackageImport = {
|
|
4
5
|
name: string;
|
|
@@ -25,6 +26,8 @@ export type PlayArtifactCompatibility = {
|
|
|
25
26
|
runtimeBackend?: string | null;
|
|
26
27
|
/** Missing preserves the legacy schema used before this field existed. */
|
|
27
28
|
toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
|
|
29
|
+
/** Missing preserves edition 1 for artifacts created before authoring contracts were pinned. */
|
|
30
|
+
authoringContractEdition?: PlayAuthoringContractEdition;
|
|
28
31
|
};
|
|
29
32
|
|
|
30
33
|
/** The only executable Play artifact contract. */
|