@tiangong-lca/cli 0.1.0 → 0.1.2
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/README.md +58 -6
- package/dist/src/batch.d.ts +6 -0
- package/dist/src/batch.js +6 -0
- package/dist/src/batch.js.map +1 -0
- package/dist/src/cli.d.ts +161 -0
- package/dist/src/cli.js +130 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/command-spec.d.ts +90 -0
- package/dist/src/command-spec.js +400 -0
- package/dist/src/command-spec.js.map +1 -0
- package/dist/src/lib/artifacts.d.ts +9 -0
- package/dist/src/lib/auth-identity-receipt.d.ts +160 -0
- package/dist/src/lib/auth-identity-receipt.js +634 -0
- package/dist/src/lib/auth-identity-receipt.js.map +1 -0
- package/dist/src/lib/batch/attempt-recovery.d.ts +12 -0
- package/dist/src/lib/batch/attempt-recovery.js +183 -0
- package/dist/src/lib/batch/attempt-recovery.js.map +1 -0
- package/dist/src/lib/batch/canonical-contracts.d.ts +21 -0
- package/dist/src/lib/batch/canonical-contracts.js +180 -0
- package/dist/src/lib/batch/canonical-contracts.js.map +1 -0
- package/dist/src/lib/batch/engine.d.ts +2 -0
- package/dist/src/lib/batch/engine.js +294 -0
- package/dist/src/lib/batch/engine.js.map +1 -0
- package/dist/src/lib/batch/errors.d.ts +51 -0
- package/dist/src/lib/batch/errors.js +81 -0
- package/dist/src/lib/batch/errors.js.map +1 -0
- package/dist/src/lib/batch/item-projection.d.ts +10 -0
- package/dist/src/lib/batch/item-projection.js +118 -0
- package/dist/src/lib/batch/item-projection.js.map +1 -0
- package/dist/src/lib/batch/run-lock.d.ts +4 -0
- package/dist/src/lib/batch/run-lock.js +155 -0
- package/dist/src/lib/batch/run-lock.js.map +1 -0
- package/dist/src/lib/batch/scheduler-runtime.d.ts +29 -0
- package/dist/src/lib/batch/scheduler-runtime.js +114 -0
- package/dist/src/lib/batch/scheduler-runtime.js.map +1 -0
- package/dist/src/lib/batch/types.d.ts +183 -0
- package/dist/src/lib/batch/types.js +2 -0
- package/dist/src/lib/batch/types.js.map +1 -0
- package/dist/src/lib/dataset-author.d.ts +39 -0
- package/dist/src/lib/dataset-bilingual.d.ts +165 -0
- package/dist/src/lib/dataset-classification.d.ts +279 -0
- package/dist/src/lib/dataset-command.d.ts +53 -0
- package/dist/src/lib/dataset-contract.d.ts +82 -0
- package/dist/src/lib/dataset-curation-queue.d.ts +219 -0
- package/dist/src/lib/dataset-evidence-search.d.ts +134 -0
- package/dist/src/lib/dataset-import-lca.d.ts +136 -0
- package/dist/src/lib/dataset-local.d.ts +23 -0
- package/dist/src/lib/dataset-maintenance-alias-request.d.ts +12 -0
- package/dist/src/lib/dataset-maintenance-alias-rewrite.d.ts +111 -0
- package/dist/src/lib/dataset-maintenance-apply.d.ts +458 -0
- package/dist/src/lib/dataset-maintenance-clear-account.d.ts +161 -0
- package/dist/src/lib/dataset-maintenance-contract.d.ts +317 -0
- package/dist/src/lib/dataset-maintenance-derivatives.d.ts +48 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-approval-claim.d.ts +50 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-capture.d.ts +110 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-command.d.ts +15 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-contract.d.ts +387 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-execution-contract.d.ts +456 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-freeze.d.ts +99 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-plan.d.ts +85 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-recovery.d.ts +268 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-run.d.ts +123 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-seal.d.ts +50 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-verify.d.ts +85 -0
- package/dist/src/lib/dataset-maintenance-flow-identity-wire.d.ts +32 -0
- package/dist/src/lib/dataset-maintenance-pagination.d.ts +58 -0
- package/dist/src/lib/dataset-maintenance-plan.d.ts +40 -0
- package/dist/src/lib/dataset-maintenance-protected-artifacts.d.ts +16 -0
- package/dist/src/lib/dataset-maintenance-protected-before.d.ts +71 -0
- package/dist/src/lib/dataset-maintenance-protected-contract.d.ts +385 -0
- package/dist/src/lib/dataset-maintenance-protected-freeze.d.ts +148 -0
- package/dist/src/lib/dataset-maintenance-protected-preparation.d.ts +76 -0
- package/dist/src/lib/dataset-maintenance-protected-run.d.ts +252 -0
- package/dist/src/lib/dataset-maintenance-protected-seal.d.ts +93 -0
- package/dist/src/lib/dataset-maintenance-protected-toolchain.d.ts +31 -0
- package/dist/src/lib/dataset-maintenance-protected-verify.d.ts +99 -0
- package/dist/src/lib/dataset-maintenance-remote.d.ts +212 -0
- package/dist/src/lib/dataset-maintenance-support-validation.d.ts +18 -0
- package/dist/src/lib/dataset-maintenance-verify.d.ts +102 -0
- package/dist/src/lib/dataset-patch.d.ts +193 -0
- package/dist/src/lib/dataset-references-rewrite.d.ts +77 -0
- package/dist/src/lib/dataset-remote-refresh.d.ts +64 -0
- package/dist/src/lib/dataset-remote-verify.d.ts +168 -0
- package/dist/src/lib/dataset-save-draft-run.d.ts +283 -0
- package/dist/src/lib/dataset-save-draft-run.js +54 -21
- package/dist/src/lib/dataset-save-draft-run.js.map +1 -1
- package/dist/src/lib/dataset-source-upload-attachments.d.ts +109 -0
- package/dist/src/lib/dataset-validate.d.ts +62 -0
- package/dist/src/lib/dotenv.d.ts +6 -0
- package/dist/src/lib/env.d.ts +59 -0
- package/dist/src/lib/errors.d.ts +18 -0
- package/dist/src/lib/flow-build-alias-map.d.ts +80 -0
- package/dist/src/lib/flow-fetch-rows.d.ts +70 -0
- package/dist/src/lib/flow-get.d.ts +35 -0
- package/dist/src/lib/flow-governance.d.ts +22 -0
- package/dist/src/lib/flow-list.d.ts +57 -0
- package/dist/src/lib/flow-materialize-decisions.d.ts +67 -0
- package/dist/src/lib/flow-payload-validation.d.ts +32 -0
- package/dist/src/lib/flow-publish-reviewed-data.d.ts +262 -0
- package/dist/src/lib/flow-publish-version.d.ts +193 -0
- package/dist/src/lib/flow-qa.d.ts +289 -0
- package/dist/src/lib/flow-read.d.ts +70 -0
- package/dist/src/lib/flow-regen-product.d.ts +431 -0
- package/dist/src/lib/flow-remediate.d.ts +133 -0
- package/dist/src/lib/http.d.ts +25 -0
- package/dist/src/lib/http.js.map +1 -1
- package/dist/src/lib/identity-preflight.d.ts +235 -0
- package/dist/src/lib/io.d.ts +2 -0
- package/dist/src/lib/kb-search.d.ts +23 -0
- package/dist/src/lib/lca-release.d.ts +105 -0
- package/dist/src/lib/lifecyclemodel-auto-build.d.ts +223 -0
- package/dist/src/lib/lifecyclemodel-bundle-save.d.ts +71 -0
- package/dist/src/lib/lifecyclemodel-graph.d.ts +91 -0
- package/dist/src/lib/lifecyclemodel-orchestrate.d.ts +349 -0
- package/dist/src/lib/lifecyclemodel-publish-build.d.ts +77 -0
- package/dist/src/lib/lifecyclemodel-publish-resulting-process.d.ts +27 -0
- package/dist/src/lib/lifecyclemodel-qa.d.ts +206 -0
- package/dist/src/lib/lifecyclemodel-resulting-process.d.ts +204 -0
- package/dist/src/lib/lifecyclemodel-save-draft-run.d.ts +96 -0
- package/dist/src/lib/lifecyclemodel-validate-build.d.ts +78 -0
- package/dist/src/lib/llm.d.ts +51 -0
- package/dist/src/lib/package-version.d.ts +3 -0
- package/dist/src/lib/process-auto-build.d.ts +168 -0
- package/dist/src/lib/process-batch-build.d.ts +97 -0
- package/dist/src/lib/process-dedup-review.d.ts +253 -0
- package/dist/src/lib/process-flow-build-plan.d.ts +108 -0
- package/dist/src/lib/process-get.d.ts +26 -0
- package/dist/src/lib/process-list.d.ts +87 -0
- package/dist/src/lib/process-payload-validation.d.ts +27 -0
- package/dist/src/lib/process-publish-build.d.ts +148 -0
- package/dist/src/lib/process-qa.d.ts +243 -0
- package/dist/src/lib/process-refresh-references.d.ts +179 -0
- package/dist/src/lib/process-required-fields.d.ts +142 -0
- package/dist/src/lib/process-resume-build.d.ts +77 -0
- package/dist/src/lib/process-save-draft-run.d.ts +72 -0
- package/dist/src/lib/process-save-draft.d.ts +53 -0
- package/dist/src/lib/process-scope-statistics.d.ts +210 -0
- package/dist/src/lib/process-verify-rows.d.ts +71 -0
- package/dist/src/lib/publish.d.ts +219 -0
- package/dist/src/lib/remote.d.ts +19 -0
- package/dist/src/lib/run.d.ts +60 -0
- package/dist/src/lib/runtime-rulesets.d.ts +29 -0
- package/dist/src/lib/state-lock.d.ts +25 -0
- package/dist/src/lib/state-lock.js +23 -1
- package/dist/src/lib/state-lock.js.map +1 -1
- package/dist/src/lib/supabase-client.d.ts +47 -0
- package/dist/src/lib/supabase-data-api-contract.d.ts +304 -0
- package/dist/src/lib/supabase-data-api-replay.d.ts +74 -0
- package/dist/src/lib/supabase-json-ordered-write.d.ts +65 -0
- package/dist/src/lib/supabase-rest.d.ts +26 -0
- package/dist/src/lib/supabase-session.d.ts +115 -0
- package/dist/src/lib/tidas-languages.d.ts +3 -0
- package/dist/src/lib/tidas-sdk-package-validator.d.ts +111 -0
- package/dist/src/lib/tidas-sdk-validation.d.ts +42 -0
- package/dist/src/lib/unstructured.d.ts +32 -0
- package/dist/src/lib/user-api-key.d.ts +16 -0
- package/dist/src/lib/validation.d.ts +82 -0
- package/dist/src/main.d.ts +4 -0
- package/package.json +17 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"item-projection.js","sourceRoot":"","sources":["../../../../src/lib/batch/item-projection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n MAX_NODE_TIMER_DELAY_MS,\n assertBatchContractMatches,\n createBatchItemContract,\n isRecord,\n parseBatchItemContract,\n parseItemIdentity,\n} from './canonical-contracts.js';\nimport {\n BatchContractError,\n BatchItemIdentityDriftError,\n BatchItemProjectionDriftError,\n BatchItemResourceDriftError,\n BatchItemResumeContractError,\n BatchMutationRetryError,\n} from './errors.js';\nimport { failedResult } from './scheduler-runtime.js';\nimport { MAX_BATCH_CONCURRENCY } from './types.js';\nimport type {\n BatchClock,\n BatchContract,\n BatchItemContract,\n BatchItemFailedResult,\n BatchJsonValue,\n BatchResumeItem,\n BatchResumeState,\n RunBoundedBatchOptions,\n} from './types.js';\n\nexport function validateBatchOptions<\n TInput,\n TOutput,\n TIdentity extends BatchJsonValue,\n TExclusiveKey extends string,\n>(options: RunBoundedBatchOptions<TInput, TOutput, TIdentity, TExclusiveKey>): void {\n if (\n !Number.isSafeInteger(options.maxConcurrency) ||\n options.maxConcurrency < 1 ||\n options.maxConcurrency > MAX_BATCH_CONCURRENCY\n ) {\n throw new BatchContractError(\n `Batch maxConcurrency must be a safe integer from 1 to ${MAX_BATCH_CONCURRENCY}.`,\n );\n }\n if (options.mode !== 'read' && options.mode !== 'mutation') {\n throw new BatchContractError('Batch mode must be read or mutation.');\n }\n if (options.mode === 'mutation' && options.retry) {\n throw new BatchMutationRetryError();\n }\n if (\n options.retry &&\n (!Number.isSafeInteger(options.retry.maxAttempts) ||\n options.retry.maxAttempts < 1 ||\n !Number.isSafeInteger(options.retry.maxDelayMs) ||\n options.retry.maxDelayMs < 0 ||\n options.retry.maxDelayMs > MAX_NODE_TIMER_DELAY_MS)\n ) {\n throw new BatchContractError(\n `Batch retry maxAttempts must be positive and maxDelayMs must be a non-negative safe integer no greater than the maximum supported timer delay (${MAX_NODE_TIMER_DELAY_MS} ms).`,\n );\n }\n}\n\nexport function validateResume<TOutput, TIdentity extends BatchJsonValue>(\n resume: BatchResumeState<TOutput, TIdentity> | undefined,\n contract: BatchContract<TIdentity>,\n itemIds: readonly string[],\n): Map<string, BatchResumeItem<TOutput>> {\n const result = new Map<string, BatchResumeItem<TOutput>>();\n if (!resume) return result;\n assertBatchContractMatches<TIdentity>(contract, resume.contract);\n const currentIds = new Set(itemIds);\n for (const item of resume.items) {\n let itemContract: BatchItemContract;\n try {\n itemContract = parseBatchItemContract(item);\n } catch (error) {\n throw new BatchContractError('Batch resume contains an invalid item contract.', {\n cause: error,\n });\n }\n if (\n !isRecord(item) ||\n !currentIds.has(itemContract.item_id) ||\n !Number.isSafeInteger(item.attempts) ||\n Number(item.attempts) < 1 ||\n !['attempted', 'completed'].includes(String(item.state))\n ) {\n throw new BatchContractError('Batch resume contains an invalid or foreign item.');\n }\n if (result.has(itemContract.item_id)) {\n throw new BatchContractError('Batch resume item identities must be unique.');\n }\n if (item.state === 'completed') {\n if (!['succeeded', 'recovered'].includes(String(item.outcome))) {\n throw new BatchContractError('Completed batch resume items require a successful outcome.');\n }\n result.set(\n itemContract.item_id,\n Object.freeze({\n ...itemContract,\n state: 'completed',\n outcome: item.outcome,\n value: item.value,\n attempts: Number(item.attempts),\n }),\n );\n } else {\n result.set(\n itemContract.item_id,\n Object.freeze({\n ...itemContract,\n state: 'attempted',\n attempts: Number(item.attempts),\n }),\n );\n }\n }\n return result;\n}\n\nexport function projectBatchItemContract<\n TInput,\n TOutput,\n TIdentity extends BatchJsonValue,\n TExclusiveKey extends string,\n>(\n options: RunBoundedBatchOptions<TInput, TOutput, TIdentity, TExclusiveKey>,\n item: TInput,\n index: number,\n itemId: string,\n): BatchItemContract {\n return createBatchItemContract({\n item_id: itemId,\n content: options.projectItemContent(item, index),\n policy: options.projectItemPolicy(item, index),\n });\n}\n\nexport function itemIdentityMatches<\n TInput,\n TOutput,\n TIdentity extends BatchJsonValue,\n TExclusiveKey extends string,\n>(\n options: RunBoundedBatchOptions<TInput, TOutput, TIdentity, TExclusiveKey>,\n item: TInput,\n index: number,\n expectedItemId: string,\n): boolean {\n try {\n const projected = options.getItemIdentity(item, index);\n return parseItemIdentity(projected, index) === expectedItemId;\n } catch {\n return false;\n }\n}\n\nexport function identityDriftFailure<TInput, TOutput>(\n item: TInput,\n itemContract: BatchItemContract,\n exclusiveKey: string | null,\n index: number,\n resumeItem: BatchResumeItem<TOutput> | undefined,\n clock: BatchClock,\n): BatchItemFailedResult<TInput> {\n return failedResult(\n item,\n itemContract,\n index,\n resumeItem?.attempts ?? 0,\n resumeItem !== undefined,\n resumeItem !== undefined,\n clock,\n new BatchItemIdentityDriftError(itemContract.item_id),\n exclusiveKey,\n );\n}\n\nexport function projectExclusiveKey<\n TInput,\n TOutput,\n TIdentity extends BatchJsonValue,\n TExclusiveKey extends string,\n>(\n options: RunBoundedBatchOptions<TInput, TOutput, TIdentity, TExclusiveKey>,\n item: TInput,\n index: number,\n itemContract: BatchItemContract,\n): TExclusiveKey | null {\n if (!options.getExclusiveKey) return null;\n const value = options.getExclusiveKey({\n item,\n item_id: itemContract.item_id,\n item_contract: itemContract,\n input_index: index,\n });\n if (value === null || value === undefined) return null;\n if (typeof value !== 'string' || value.length === 0 || /[\\0\\r\\n]/u.test(value)) {\n throw new BatchContractError(\n 'Batch exclusive resource keys must be non-empty single-line strings.',\n );\n }\n return value;\n}\n\nexport function projectionDriftFailure<TInput, TOutput>(\n item: TInput,\n itemContract: BatchItemContract,\n exclusiveKey: string | null,\n index: number,\n resumeItem: BatchResumeItem<TOutput> | undefined,\n clock: BatchClock,\n): BatchItemFailedResult<TInput> {\n return failedResult(\n item,\n itemContract,\n index,\n resumeItem?.attempts ?? 0,\n resumeItem !== undefined,\n resumeItem !== undefined,\n clock,\n new BatchItemProjectionDriftError(itemContract.item_id),\n exclusiveKey,\n );\n}\n\nexport function resourceDriftFailure<TInput, TOutput>(\n item: TInput,\n itemContract: BatchItemContract,\n exclusiveKey: string | null,\n index: number,\n resumeItem: BatchResumeItem<TOutput> | undefined,\n clock: BatchClock,\n): BatchItemFailedResult<TInput> {\n return failedResult(\n item,\n itemContract,\n index,\n resumeItem?.attempts ?? 0,\n resumeItem !== undefined,\n resumeItem !== undefined,\n clock,\n new BatchItemResourceDriftError(itemContract.item_id),\n exclusiveKey,\n );\n}\n\nexport function resumeContractFailure<TInput>(\n item: TInput,\n itemContract: BatchItemContract,\n exclusiveKey: string | null,\n index: number,\n attempts: number,\n clock: BatchClock,\n): BatchItemFailedResult<TInput> {\n return failedResult(\n item,\n itemContract,\n index,\n attempts,\n true,\n true,\n clock,\n new BatchItemResumeContractError(itemContract.item_id),\n exclusiveKey,\n );\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BatchJsonValue, BatchRunLockOptions, BatchRunLockReceipt } from './types.js';
|
|
2
|
+
export declare function batchRunLockStatePath(runPath: string): string;
|
|
3
|
+
export declare function batchRunLockPath(runPath: string): string;
|
|
4
|
+
export declare function withBatchRunLock<T, TIdentity extends BatchJsonValue>(options: BatchRunLockOptions<TIdentity>, task: (receipt: BatchRunLockReceipt) => Promise<T> | T): Promise<T>;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { StateLockTimeoutError, lockPathForState, withStateFileLock } from '../state-lock.js';
|
|
4
|
+
import { assertBatchTimerDelaySupported, parseBatchRunLockToken, parseBatchRunPath, sha256BatchJson, } from './canonical-contracts.js';
|
|
5
|
+
import { BatchRunLockIdentityConflictError, BatchRunLockTimeoutError } from './errors.js';
|
|
6
|
+
const DEFAULT_BATCH_RUN_LOCK_TIMEOUT_MS = 300_000;
|
|
7
|
+
const ACTIVE_BATCH_RUN_LOCKS = new Map();
|
|
8
|
+
const BATCH_RUN_LOCK_CONTEXT = new AsyncLocalStorage();
|
|
9
|
+
export function batchRunLockStatePath(runPath) {
|
|
10
|
+
return path.join(parseBatchRunPath(runPath), '.tiangong-lca-batch-run.state');
|
|
11
|
+
}
|
|
12
|
+
export function batchRunLockPath(runPath) {
|
|
13
|
+
return lockPathForState(batchRunLockStatePath(runPath));
|
|
14
|
+
}
|
|
15
|
+
export async function withBatchRunLock(options, task) {
|
|
16
|
+
const runPath = parseBatchRunPath(options.runPath);
|
|
17
|
+
const reason = parseBatchRunLockToken(options.reason, 'reason');
|
|
18
|
+
assertBatchTimerDelaySupported(options.timeoutMs, 'timeoutMs');
|
|
19
|
+
assertBatchTimerDelaySupported(options.pollMs, 'pollMs');
|
|
20
|
+
const identitySha256 = sha256BatchJson(options.identity);
|
|
21
|
+
const statePath = batchRunLockStatePath(runPath);
|
|
22
|
+
const lockPath = lockPathForState(statePath);
|
|
23
|
+
const receipt = Object.freeze({
|
|
24
|
+
run_path: runPath,
|
|
25
|
+
state_path: statePath,
|
|
26
|
+
lock_path: lockPath,
|
|
27
|
+
identity_sha256: identitySha256,
|
|
28
|
+
});
|
|
29
|
+
const active = ACTIVE_BATCH_RUN_LOCKS.get(statePath);
|
|
30
|
+
if (active) {
|
|
31
|
+
if (active.identitySha256 !== identitySha256) {
|
|
32
|
+
throw new BatchRunLockIdentityConflictError({
|
|
33
|
+
runPath,
|
|
34
|
+
activeIdentitySha256: active.identitySha256,
|
|
35
|
+
requestedIdentitySha256: identitySha256,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const parentScope = BATCH_RUN_LOCK_CONTEXT.getStore()?.get(statePath);
|
|
39
|
+
if (parentScope?.active && parentScope.owner === active) {
|
|
40
|
+
return runBatchRunLockScope(statePath, active, task);
|
|
41
|
+
}
|
|
42
|
+
await waitForActiveBatchRunLock(active, options, runPath, lockPath, identitySha256);
|
|
43
|
+
return withBatchRunLock(options, task);
|
|
44
|
+
}
|
|
45
|
+
let physicalOwner;
|
|
46
|
+
try {
|
|
47
|
+
const result = await withStateFileLock(statePath, {
|
|
48
|
+
reason: `batch-run:${identitySha256}:${reason}`,
|
|
49
|
+
metadata: {
|
|
50
|
+
batch_identity_sha256: identitySha256,
|
|
51
|
+
batch_run_path: runPath,
|
|
52
|
+
},
|
|
53
|
+
stalePolicy: 'same-host-pid',
|
|
54
|
+
...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
|
|
55
|
+
...(options.pollMs === undefined ? {} : { pollMs: options.pollMs }),
|
|
56
|
+
...(options.sleep === undefined ? {} : { sleep: options.sleep }),
|
|
57
|
+
}, async () => {
|
|
58
|
+
const owner = createActiveBatchRunLock(identitySha256, receipt);
|
|
59
|
+
physicalOwner = owner;
|
|
60
|
+
ACTIVE_BATCH_RUN_LOCKS.set(statePath, owner);
|
|
61
|
+
try {
|
|
62
|
+
return await runBatchRunLockScope(statePath, owner, task);
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
await owner.drained;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (!(error instanceof StateLockTimeoutError))
|
|
72
|
+
throw error;
|
|
73
|
+
const details = error.details;
|
|
74
|
+
throw new BatchRunLockTimeoutError({
|
|
75
|
+
runPath,
|
|
76
|
+
lockPath,
|
|
77
|
+
identitySha256,
|
|
78
|
+
waitedMs: details.waitedMs,
|
|
79
|
+
owner: details.owner ? Object.freeze({ ...details.owner }) : null,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
if (physicalOwner) {
|
|
84
|
+
ACTIVE_BATCH_RUN_LOCKS.delete(statePath);
|
|
85
|
+
physicalOwner.release();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function createActiveBatchRunLock(identitySha256, receipt) {
|
|
90
|
+
let drain = () => undefined;
|
|
91
|
+
const drained = new Promise((resolve) => {
|
|
92
|
+
drain = resolve;
|
|
93
|
+
});
|
|
94
|
+
let release = () => undefined;
|
|
95
|
+
const released = new Promise((resolve) => {
|
|
96
|
+
release = resolve;
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
scopeDepth: 0,
|
|
100
|
+
identitySha256,
|
|
101
|
+
receipt,
|
|
102
|
+
drained,
|
|
103
|
+
drain,
|
|
104
|
+
released,
|
|
105
|
+
release,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
async function runBatchRunLockScope(statePath, owner, task) {
|
|
109
|
+
const scope = { active: true, owner };
|
|
110
|
+
owner.scopeDepth += 1;
|
|
111
|
+
const context = new Map(BATCH_RUN_LOCK_CONTEXT.getStore() ?? []);
|
|
112
|
+
context.set(statePath, scope);
|
|
113
|
+
try {
|
|
114
|
+
return await BATCH_RUN_LOCK_CONTEXT.run(context, () => task(owner.receipt));
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
scope.active = false;
|
|
118
|
+
owner.scopeDepth -= 1;
|
|
119
|
+
if (owner.scopeDepth === 0)
|
|
120
|
+
owner.drain();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async function waitForActiveBatchRunLock(active, options, runPath, lockPath, identitySha256) {
|
|
124
|
+
const timeoutMs = Math.max(options.timeoutMs ?? DEFAULT_BATCH_RUN_LOCK_TIMEOUT_MS, 0);
|
|
125
|
+
if (timeoutMs === 0) {
|
|
126
|
+
throw new BatchRunLockTimeoutError({
|
|
127
|
+
runPath,
|
|
128
|
+
lockPath,
|
|
129
|
+
identitySha256,
|
|
130
|
+
waitedMs: 0,
|
|
131
|
+
owner: null,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const startedAt = Date.now();
|
|
135
|
+
let timer;
|
|
136
|
+
try {
|
|
137
|
+
await Promise.race([
|
|
138
|
+
active.released,
|
|
139
|
+
new Promise((_resolve, reject) => {
|
|
140
|
+
timer = setTimeout(() => reject(new BatchRunLockTimeoutError({
|
|
141
|
+
runPath,
|
|
142
|
+
lockPath,
|
|
143
|
+
identitySha256,
|
|
144
|
+
waitedMs: Date.now() - startedAt,
|
|
145
|
+
owner: null,
|
|
146
|
+
})), timeoutMs);
|
|
147
|
+
}),
|
|
148
|
+
]);
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
if (timer)
|
|
152
|
+
clearTimeout(timer);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=run-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-lock.js","sourceRoot":"","sources":["../../../../src/lib/batch/run-lock.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport path from 'node:path';\n\nimport { StateLockTimeoutError, lockPathForState, withStateFileLock } from '../state-lock.js';\nimport {\n assertBatchTimerDelaySupported,\n parseBatchRunLockToken,\n parseBatchRunPath,\n sha256BatchJson,\n} from './canonical-contracts.js';\nimport { BatchRunLockIdentityConflictError, BatchRunLockTimeoutError } from './errors.js';\nimport type { BatchJsonValue, BatchRunLockOptions, BatchRunLockReceipt } from './types.js';\n\nconst DEFAULT_BATCH_RUN_LOCK_TIMEOUT_MS = 300_000;\n\ntype ActiveBatchRunLock = {\n scopeDepth: number;\n identitySha256: string;\n receipt: BatchRunLockReceipt;\n drained: Promise<void>;\n drain: () => void;\n released: Promise<void>;\n release: () => void;\n};\n\ntype BatchRunLockScope = {\n active: boolean;\n owner: ActiveBatchRunLock;\n};\n\nconst ACTIVE_BATCH_RUN_LOCKS = new Map<string, ActiveBatchRunLock>();\nconst BATCH_RUN_LOCK_CONTEXT = new AsyncLocalStorage<ReadonlyMap<string, BatchRunLockScope>>();\n\nexport function batchRunLockStatePath(runPath: string): string {\n return path.join(parseBatchRunPath(runPath), '.tiangong-lca-batch-run.state');\n}\n\nexport function batchRunLockPath(runPath: string): string {\n return lockPathForState(batchRunLockStatePath(runPath));\n}\n\nexport async function withBatchRunLock<T, TIdentity extends BatchJsonValue>(\n options: BatchRunLockOptions<TIdentity>,\n task: (receipt: BatchRunLockReceipt) => Promise<T> | T,\n): Promise<T> {\n const runPath = parseBatchRunPath(options.runPath);\n const reason = parseBatchRunLockToken(options.reason, 'reason');\n assertBatchTimerDelaySupported(options.timeoutMs, 'timeoutMs');\n assertBatchTimerDelaySupported(options.pollMs, 'pollMs');\n const identitySha256 = sha256BatchJson(options.identity);\n const statePath = batchRunLockStatePath(runPath);\n const lockPath = lockPathForState(statePath);\n const receipt = Object.freeze({\n run_path: runPath,\n state_path: statePath,\n lock_path: lockPath,\n identity_sha256: identitySha256,\n });\n const active = ACTIVE_BATCH_RUN_LOCKS.get(statePath);\n if (active) {\n if (active.identitySha256 !== identitySha256) {\n throw new BatchRunLockIdentityConflictError({\n runPath,\n activeIdentitySha256: active.identitySha256,\n requestedIdentitySha256: identitySha256,\n });\n }\n const parentScope = BATCH_RUN_LOCK_CONTEXT.getStore()?.get(statePath);\n if (parentScope?.active && parentScope.owner === active) {\n return runBatchRunLockScope(statePath, active, task);\n }\n await waitForActiveBatchRunLock(active, options, runPath, lockPath, identitySha256);\n return withBatchRunLock(options, task);\n }\n\n let physicalOwner: ActiveBatchRunLock | undefined;\n try {\n const result = await withStateFileLock(\n statePath,\n {\n reason: `batch-run:${identitySha256}:${reason}`,\n metadata: {\n batch_identity_sha256: identitySha256,\n batch_run_path: runPath,\n },\n stalePolicy: 'same-host-pid',\n ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),\n ...(options.pollMs === undefined ? {} : { pollMs: options.pollMs }),\n ...(options.sleep === undefined ? {} : { sleep: options.sleep }),\n },\n async () => {\n const owner = createActiveBatchRunLock(identitySha256, receipt);\n physicalOwner = owner;\n ACTIVE_BATCH_RUN_LOCKS.set(statePath, owner);\n try {\n return await runBatchRunLockScope(statePath, owner, task);\n } finally {\n await owner.drained;\n }\n },\n );\n return result;\n } catch (error) {\n if (!(error instanceof StateLockTimeoutError)) throw error;\n const details = error.details as {\n waitedMs: number;\n owner: Record<string, unknown> | null;\n };\n throw new BatchRunLockTimeoutError({\n runPath,\n lockPath,\n identitySha256,\n waitedMs: details.waitedMs,\n owner: details.owner ? Object.freeze({ ...details.owner }) : null,\n });\n } finally {\n if (physicalOwner) {\n ACTIVE_BATCH_RUN_LOCKS.delete(statePath);\n physicalOwner.release();\n }\n }\n}\n\nfunction createActiveBatchRunLock(\n identitySha256: string,\n receipt: BatchRunLockReceipt,\n): ActiveBatchRunLock {\n let drain: () => void = () => undefined;\n const drained = new Promise<void>((resolve) => {\n drain = resolve;\n });\n let release: () => void = () => undefined;\n const released = new Promise<void>((resolve) => {\n release = resolve;\n });\n return {\n scopeDepth: 0,\n identitySha256,\n receipt,\n drained,\n drain,\n released,\n release,\n };\n}\n\nasync function runBatchRunLockScope<T>(\n statePath: string,\n owner: ActiveBatchRunLock,\n task: (receipt: BatchRunLockReceipt) => Promise<T> | T,\n): Promise<T> {\n const scope: BatchRunLockScope = { active: true, owner };\n owner.scopeDepth += 1;\n const context = new Map(BATCH_RUN_LOCK_CONTEXT.getStore() ?? []);\n context.set(statePath, scope);\n try {\n return await BATCH_RUN_LOCK_CONTEXT.run(context, () => task(owner.receipt));\n } finally {\n scope.active = false;\n owner.scopeDepth -= 1;\n if (owner.scopeDepth === 0) owner.drain();\n }\n}\n\nasync function waitForActiveBatchRunLock<TIdentity extends BatchJsonValue>(\n active: { released: Promise<void> },\n options: BatchRunLockOptions<TIdentity>,\n runPath: string,\n lockPath: string,\n identitySha256: string,\n): Promise<void> {\n const timeoutMs = Math.max(options.timeoutMs ?? DEFAULT_BATCH_RUN_LOCK_TIMEOUT_MS, 0);\n if (timeoutMs === 0) {\n throw new BatchRunLockTimeoutError({\n runPath,\n lockPath,\n identitySha256,\n waitedMs: 0,\n owner: null,\n });\n }\n const startedAt = Date.now();\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n active.released,\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(\n () =>\n reject(\n new BatchRunLockTimeoutError({\n runPath,\n lockPath,\n identitySha256,\n waitedMs: Date.now() - startedAt,\n owner: null,\n }),\n ),\n timeoutMs,\n );\n }),\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BatchClock, BatchEvent, BatchEventType, BatchItemContract, BatchItemFailedResult, BatchItemResult } from './types.js';
|
|
2
|
+
export declare class MinReadyIndexHeap {
|
|
3
|
+
private readonly values;
|
|
4
|
+
push(value: number): void;
|
|
5
|
+
pop(): number | undefined;
|
|
6
|
+
}
|
|
7
|
+
export type EventEmitter = ReturnType<typeof createEventEmitter>;
|
|
8
|
+
export declare function createEventEmitter(clock: BatchClock, sink: ((event: BatchEvent) => void | Promise<void>) | undefined): {
|
|
9
|
+
events: Readonly<{
|
|
10
|
+
sequence: number;
|
|
11
|
+
timestamp_ms: number;
|
|
12
|
+
type: BatchEventType;
|
|
13
|
+
item_id?: string;
|
|
14
|
+
input_index?: number;
|
|
15
|
+
attempt?: number;
|
|
16
|
+
delay_ms?: number;
|
|
17
|
+
status?: import("./types.js").BatchItemResultStatus | import("./types.js").BatchStatus;
|
|
18
|
+
source?: import("./types.js").BatchRecoverySource;
|
|
19
|
+
exclusive_key?: string;
|
|
20
|
+
}>[];
|
|
21
|
+
emit: (type: BatchEventType, details?: Omit<BatchEvent, 'sequence' | 'timestamp_ms' | 'type'>) => Promise<void>;
|
|
22
|
+
settled: () => Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
export declare function readClock(clock: BatchClock): number;
|
|
25
|
+
export declare function createAsyncLock(onError: (error: unknown) => void): <T>(operation: () => Promise<T>) => Promise<T>;
|
|
26
|
+
export declare function inputOrderedResults<TInput, TOutput>(results: Map<number, BatchItemResult<TInput, TOutput>>): BatchItemResult<TInput, TOutput>[];
|
|
27
|
+
export declare function failedResult<TInput>(item: TInput, itemContract: BatchItemContract, inputIndex: number, attempts: number, attemptConsumed: boolean, resumed: boolean, clock: BatchClock, error: unknown, exclusiveKey?: string | null): BatchItemFailedResult<TInput>;
|
|
28
|
+
export declare function freezeResult<T extends BatchItemResult<unknown, unknown>>(value: T): T;
|
|
29
|
+
export declare function defaultBatchSleep(milliseconds: number): Promise<void>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { BatchContractError } from './errors.js';
|
|
2
|
+
export class MinReadyIndexHeap {
|
|
3
|
+
values = [];
|
|
4
|
+
push(value) {
|
|
5
|
+
this.values.push(value);
|
|
6
|
+
let child = this.values.length - 1;
|
|
7
|
+
while (child > 0) {
|
|
8
|
+
const parent = Math.floor((child - 1) / 2);
|
|
9
|
+
if (this.values[parent] <= this.values[child])
|
|
10
|
+
break;
|
|
11
|
+
[this.values[parent], this.values[child]] = [this.values[child], this.values[parent]];
|
|
12
|
+
child = parent;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
pop() {
|
|
16
|
+
if (this.values.length === 0)
|
|
17
|
+
return undefined;
|
|
18
|
+
const minimum = this.values[0];
|
|
19
|
+
const last = this.values.pop();
|
|
20
|
+
if (this.values.length === 0)
|
|
21
|
+
return minimum;
|
|
22
|
+
this.values[0] = last;
|
|
23
|
+
let parent = 0;
|
|
24
|
+
while (true) {
|
|
25
|
+
const left = parent * 2 + 1;
|
|
26
|
+
if (left >= this.values.length)
|
|
27
|
+
break;
|
|
28
|
+
const right = left + 1;
|
|
29
|
+
const smallest = right < this.values.length && this.values[right] < this.values[left] ? right : left;
|
|
30
|
+
if (this.values[parent] <= this.values[smallest])
|
|
31
|
+
break;
|
|
32
|
+
[this.values[parent], this.values[smallest]] = [this.values[smallest], this.values[parent]];
|
|
33
|
+
parent = smallest;
|
|
34
|
+
}
|
|
35
|
+
return minimum;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function createEventEmitter(clock, sink) {
|
|
39
|
+
const events = [];
|
|
40
|
+
let sequence = 0;
|
|
41
|
+
let lastTimestamp = Number.NEGATIVE_INFINITY;
|
|
42
|
+
let tail = Promise.resolve();
|
|
43
|
+
return {
|
|
44
|
+
events,
|
|
45
|
+
emit: async (type, details = {}) => {
|
|
46
|
+
const timestamp = Math.max(lastTimestamp, readClock(clock));
|
|
47
|
+
lastTimestamp = timestamp;
|
|
48
|
+
const event = Object.freeze({
|
|
49
|
+
sequence: (sequence += 1),
|
|
50
|
+
timestamp_ms: timestamp,
|
|
51
|
+
type,
|
|
52
|
+
...details,
|
|
53
|
+
});
|
|
54
|
+
events.push(event);
|
|
55
|
+
const delivery = tail.then(() => sink?.(event));
|
|
56
|
+
tail = delivery.then(() => undefined, () => undefined);
|
|
57
|
+
await delivery;
|
|
58
|
+
},
|
|
59
|
+
settled: () => tail,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function readClock(clock) {
|
|
63
|
+
const value = clock.now();
|
|
64
|
+
if (!Number.isFinite(value)) {
|
|
65
|
+
throw new BatchContractError('Batch clock must return a finite millisecond value.');
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
export function createAsyncLock(onError) {
|
|
70
|
+
let tail = Promise.resolve();
|
|
71
|
+
return async (operation) => {
|
|
72
|
+
const previous = tail;
|
|
73
|
+
let release = () => undefined;
|
|
74
|
+
tail = new Promise((resolve) => {
|
|
75
|
+
release = resolve;
|
|
76
|
+
});
|
|
77
|
+
await previous;
|
|
78
|
+
try {
|
|
79
|
+
return await operation();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
onError(error);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
release();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export function inputOrderedResults(results) {
|
|
91
|
+
return [...results.entries()].sort(([left], [right]) => left - right).map(([, result]) => result);
|
|
92
|
+
}
|
|
93
|
+
export function failedResult(item, itemContract, inputIndex, attempts, attemptConsumed, resumed, clock, error, exclusiveKey = null) {
|
|
94
|
+
return freezeResult({
|
|
95
|
+
item,
|
|
96
|
+
item_id: itemContract.item_id,
|
|
97
|
+
item_contract: itemContract,
|
|
98
|
+
exclusive_key: exclusiveKey,
|
|
99
|
+
input_index: inputIndex,
|
|
100
|
+
attempts,
|
|
101
|
+
attempt_consumed: attemptConsumed,
|
|
102
|
+
resumed,
|
|
103
|
+
completed_at_ms: readClock(clock),
|
|
104
|
+
status: 'failed',
|
|
105
|
+
error,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
export function freezeResult(value) {
|
|
109
|
+
return Object.freeze(value);
|
|
110
|
+
}
|
|
111
|
+
export function defaultBatchSleep(milliseconds) {
|
|
112
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=scheduler-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler-runtime.js","sourceRoot":"","sources":["../../../../src/lib/batch/scheduler-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAUjD,MAAM,OAAO,iBAAiB;IACX,MAAM,GAAa,EAAE,CAAC;IAEvC,IAAI,CAAC,KAAa;QAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QACnC,OAAO,KAAK,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3C,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAE,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAE;gBAAE,MAAM;YACvD,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAE,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAE,CAAC,CAAC;YACxF,KAAK,GAAG,MAAM,CAAC;QACjB,CAAC;IACH,CAAC;IAED,GAAG;QACD,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAG,CAAC;QAChC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;QACtB,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM;gBAAE,MAAM;YACtC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;YACvB,MAAM,QAAQ,GACZ,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;YACxF,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAE,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAE;gBAAE,MAAM;YAC1D,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAE,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAE,CAAC,CAAC;YAC9F,MAAM,GAAG,QAAQ,CAAC;QACpB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAID,MAAM,UAAU,kBAAkB,CAChC,KAAiB,EACjB,IAA+D;IAE/D,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAC7C,IAAI,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7B,OAAO;QACL,MAAM;QACN,IAAI,EAAE,KAAK,EACT,IAAoB,EACpB,OAAO,GAA2D,EAAE,EACpE,EAAE;YACF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;YAC5D,aAAa,GAAG,SAAS,CAAC;YAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;gBAC1B,QAAQ,EAAE,CAAC,QAAQ,IAAI,CAAC,CAAC;gBACzB,YAAY,EAAE,SAAS;gBACvB,IAAI;gBACJ,GAAG,OAAO;aACX,CAAe,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAChD,IAAI,GAAG,QAAQ,CAAC,IAAI,CAClB,GAAG,EAAE,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,SAAS,CAChB,CAAC;YACF,MAAM,QAAQ,CAAC;QACjB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI;KACpB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAiB;IACzC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;IAC1B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,kBAAkB,CAAC,qDAAqD,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAiC;IAC/D,IAAI,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7B,OAAO,KAAK,EAAK,SAA2B,EAAc,EAAE;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC;QACtB,IAAI,OAAO,GAAe,GAAG,EAAE,CAAC,SAAS,CAAC;QAC1C,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,OAAO,GAAG,OAAO,CAAC;QACpB,CAAC,CAAC,CAAC;QACH,MAAM,QAAQ,CAAC;QACf,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,CAAC;YACf,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,OAAsD;IAEtD,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,YAA+B,EAC/B,UAAkB,EAClB,QAAgB,EAChB,eAAwB,EACxB,OAAgB,EAChB,KAAiB,EACjB,KAAc,EACd,YAAY,GAAkB,IAAI;IAElC,OAAO,YAAY,CAAC;QAClB,IAAI;QACJ,OAAO,EAAE,YAAY,CAAC,OAAO;QAC7B,aAAa,EAAE,YAAY;QAC3B,aAAa,EAAE,YAAY;QAC3B,WAAW,EAAE,UAAU;QACvB,QAAQ;QACR,gBAAgB,EAAE,eAAe;QACjC,OAAO;QACP,eAAe,EAAE,SAAS,CAAC,KAAK,CAAC;QACjC,MAAM,EAAE,QAAQ;QAChB,KAAK;KACN,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY,CAA8C,KAAQ;IAChF,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,YAAoB;IACpD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;AACrE,CAAC","sourcesContent":["import { BatchContractError } from './errors.js';\nimport type {\n BatchClock,\n BatchEvent,\n BatchEventType,\n BatchItemContract,\n BatchItemFailedResult,\n BatchItemResult,\n} from './types.js';\n\nexport class MinReadyIndexHeap {\n private readonly values: number[] = [];\n\n push(value: number): void {\n this.values.push(value);\n let child = this.values.length - 1;\n while (child > 0) {\n const parent = Math.floor((child - 1) / 2);\n if (this.values[parent]! <= this.values[child]!) break;\n [this.values[parent], this.values[child]] = [this.values[child]!, this.values[parent]!];\n child = parent;\n }\n }\n\n pop(): number | undefined {\n if (this.values.length === 0) return undefined;\n const minimum = this.values[0]!;\n const last = this.values.pop()!;\n if (this.values.length === 0) return minimum;\n this.values[0] = last;\n let parent = 0;\n while (true) {\n const left = parent * 2 + 1;\n if (left >= this.values.length) break;\n const right = left + 1;\n const smallest =\n right < this.values.length && this.values[right]! < this.values[left]! ? right : left;\n if (this.values[parent]! <= this.values[smallest]!) break;\n [this.values[parent], this.values[smallest]] = [this.values[smallest]!, this.values[parent]!];\n parent = smallest;\n }\n return minimum;\n }\n}\n\nexport type EventEmitter = ReturnType<typeof createEventEmitter>;\n\nexport function createEventEmitter(\n clock: BatchClock,\n sink: ((event: BatchEvent) => void | Promise<void>) | undefined,\n) {\n const events: BatchEvent[] = [];\n let sequence = 0;\n let lastTimestamp = Number.NEGATIVE_INFINITY;\n let tail = Promise.resolve();\n return {\n events,\n emit: async (\n type: BatchEventType,\n details: Omit<BatchEvent, 'sequence' | 'timestamp_ms' | 'type'> = {},\n ) => {\n const timestamp = Math.max(lastTimestamp, readClock(clock));\n lastTimestamp = timestamp;\n const event = Object.freeze({\n sequence: (sequence += 1),\n timestamp_ms: timestamp,\n type,\n ...details,\n }) as BatchEvent;\n events.push(event);\n const delivery = tail.then(() => sink?.(event));\n tail = delivery.then(\n () => undefined,\n () => undefined,\n );\n await delivery;\n },\n settled: () => tail,\n };\n}\n\nexport function readClock(clock: BatchClock): number {\n const value = clock.now();\n if (!Number.isFinite(value)) {\n throw new BatchContractError('Batch clock must return a finite millisecond value.');\n }\n return value;\n}\n\nexport function createAsyncLock(onError: (error: unknown) => void) {\n let tail = Promise.resolve();\n return async <T>(operation: () => Promise<T>): Promise<T> => {\n const previous = tail;\n let release: () => void = () => undefined;\n tail = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous;\n try {\n return await operation();\n } catch (error) {\n onError(error);\n throw error;\n } finally {\n release();\n }\n };\n}\n\nexport function inputOrderedResults<TInput, TOutput>(\n results: Map<number, BatchItemResult<TInput, TOutput>>,\n): BatchItemResult<TInput, TOutput>[] {\n return [...results.entries()].sort(([left], [right]) => left - right).map(([, result]) => result);\n}\n\nexport function failedResult<TInput>(\n item: TInput,\n itemContract: BatchItemContract,\n inputIndex: number,\n attempts: number,\n attemptConsumed: boolean,\n resumed: boolean,\n clock: BatchClock,\n error: unknown,\n exclusiveKey: string | null = null,\n): BatchItemFailedResult<TInput> {\n return freezeResult({\n item,\n item_id: itemContract.item_id,\n item_contract: itemContract,\n exclusive_key: exclusiveKey,\n input_index: inputIndex,\n attempts,\n attempt_consumed: attemptConsumed,\n resumed,\n completed_at_ms: readClock(clock),\n status: 'failed',\n error,\n });\n}\n\nexport function freezeResult<T extends BatchItemResult<unknown, unknown>>(value: T): T {\n return Object.freeze(value);\n}\n\nexport function defaultBatchSleep(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n"]}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
export declare const MAX_BATCH_CONCURRENCY: 64;
|
|
2
|
+
export type BatchJsonPrimitive = boolean | null | number | string;
|
|
3
|
+
export type BatchJsonValue = BatchJsonPrimitive | BatchJsonValue[] | BatchJsonObject;
|
|
4
|
+
export type BatchJsonObject = {
|
|
5
|
+
[key: string]: BatchJsonValue;
|
|
6
|
+
};
|
|
7
|
+
export type BatchContract<TIdentity extends BatchJsonValue = BatchJsonValue> = {
|
|
8
|
+
identity: TIdentity;
|
|
9
|
+
content_sha256: string;
|
|
10
|
+
policy_sha256: string;
|
|
11
|
+
};
|
|
12
|
+
export type BatchItemContract = Readonly<{
|
|
13
|
+
item_id: string;
|
|
14
|
+
content_sha256: string;
|
|
15
|
+
policy_sha256: string;
|
|
16
|
+
}>;
|
|
17
|
+
export type CreateBatchItemContractOptions = Readonly<{
|
|
18
|
+
item_id: string;
|
|
19
|
+
content: BatchJsonValue;
|
|
20
|
+
policy: BatchJsonValue;
|
|
21
|
+
}>;
|
|
22
|
+
export type CreateBatchContractOptions<TIdentity extends BatchJsonValue> = {
|
|
23
|
+
identity: TIdentity;
|
|
24
|
+
content: BatchJsonValue;
|
|
25
|
+
policy: BatchJsonValue;
|
|
26
|
+
};
|
|
27
|
+
export type BatchMode = 'mutation' | 'read';
|
|
28
|
+
export type BatchStatus = 'completed' | 'paused' | 'stopped';
|
|
29
|
+
export type BatchItemSuccessStatus = 'recovered' | 'succeeded';
|
|
30
|
+
export type BatchEventType = 'attempt_failed' | 'attempt_started' | 'attempt_succeeded' | 'batch_completed' | 'batch_paused' | 'batch_started' | 'batch_stopped' | 'item_claimed' | 'item_completed' | 'item_identity_drift' | 'item_projection_drift' | 'item_resource_acquired' | 'item_resource_drift' | 'item_resource_queued' | 'item_resource_released' | 'item_resume_rejected' | 'item_resumed' | 'recovery_failed' | 'recovery_started' | 'recovery_succeeded' | 'retry_scheduled';
|
|
31
|
+
export type BatchEvent = Readonly<{
|
|
32
|
+
sequence: number;
|
|
33
|
+
timestamp_ms: number;
|
|
34
|
+
type: BatchEventType;
|
|
35
|
+
item_id?: string;
|
|
36
|
+
input_index?: number;
|
|
37
|
+
attempt?: number;
|
|
38
|
+
delay_ms?: number;
|
|
39
|
+
status?: BatchItemResultStatus | BatchStatus;
|
|
40
|
+
source?: BatchRecoverySource;
|
|
41
|
+
exclusive_key?: string;
|
|
42
|
+
}>;
|
|
43
|
+
type BatchItemResultCommon<TInput> = Readonly<{
|
|
44
|
+
item: TInput;
|
|
45
|
+
item_id: string;
|
|
46
|
+
item_contract: BatchItemContract;
|
|
47
|
+
exclusive_key: string | null;
|
|
48
|
+
input_index: number;
|
|
49
|
+
attempts: number;
|
|
50
|
+
attempt_consumed: boolean;
|
|
51
|
+
resumed: boolean;
|
|
52
|
+
completed_at_ms: number;
|
|
53
|
+
}>;
|
|
54
|
+
export type BatchItemSucceededResult<TInput, TOutput> = BatchItemResultCommon<TInput> & Readonly<{
|
|
55
|
+
status: BatchItemSuccessStatus;
|
|
56
|
+
value: TOutput;
|
|
57
|
+
}>;
|
|
58
|
+
export type BatchItemFailedResult<TInput> = BatchItemResultCommon<TInput> & Readonly<{
|
|
59
|
+
status: 'failed';
|
|
60
|
+
error: unknown;
|
|
61
|
+
}>;
|
|
62
|
+
export type BatchItemResultStatus = BatchItemSuccessStatus | 'failed';
|
|
63
|
+
export type BatchItemResult<TInput, TOutput> = BatchItemFailedResult<TInput> | BatchItemSucceededResult<TInput, TOutput>;
|
|
64
|
+
export type BatchRunResult<TInput, TOutput, TIdentity extends BatchJsonValue = BatchJsonValue> = Readonly<{
|
|
65
|
+
contract: BatchContract<TIdentity>;
|
|
66
|
+
status: BatchStatus;
|
|
67
|
+
claim_order: readonly string[];
|
|
68
|
+
completion_order: readonly string[];
|
|
69
|
+
results_input_order: readonly BatchItemResult<TInput, TOutput>[];
|
|
70
|
+
results_completion_order: readonly BatchItemResult<TInput, TOutput>[];
|
|
71
|
+
unclaimed_item_ids: readonly string[];
|
|
72
|
+
events: readonly BatchEvent[];
|
|
73
|
+
}>;
|
|
74
|
+
export type BatchExecutionContext<TInput, TExclusiveKey extends string = string> = Readonly<{
|
|
75
|
+
item: TInput;
|
|
76
|
+
item_id: string;
|
|
77
|
+
item_contract: BatchItemContract;
|
|
78
|
+
exclusive_key: TExclusiveKey | null;
|
|
79
|
+
input_index: number;
|
|
80
|
+
attempt: number;
|
|
81
|
+
mode: BatchMode;
|
|
82
|
+
}>;
|
|
83
|
+
export type BatchRetryContext<TInput, TExclusiveKey extends string = string> = BatchExecutionContext<TInput, TExclusiveKey> & Readonly<{
|
|
84
|
+
error: unknown;
|
|
85
|
+
}>;
|
|
86
|
+
export type BatchRetryPolicy<TInput, TExclusiveKey extends string = string> = Readonly<{
|
|
87
|
+
maxAttempts: number;
|
|
88
|
+
maxDelayMs: number;
|
|
89
|
+
shouldRetry: (context: BatchRetryContext<TInput, TExclusiveKey>) => boolean | Promise<boolean>;
|
|
90
|
+
delayMs: (context: BatchRetryContext<TInput, TExclusiveKey>) => number | Promise<number>;
|
|
91
|
+
}>;
|
|
92
|
+
export type BatchRecoverySource = 'execution_error' | 'resume_incomplete';
|
|
93
|
+
export type BatchMutationRecoveryContext<TInput, TExclusiveKey extends string = string> = Readonly<{
|
|
94
|
+
item: TInput;
|
|
95
|
+
item_id: string;
|
|
96
|
+
item_contract: BatchItemContract;
|
|
97
|
+
exclusive_key: TExclusiveKey | null;
|
|
98
|
+
input_index: number;
|
|
99
|
+
attempts: number;
|
|
100
|
+
error: unknown;
|
|
101
|
+
source: BatchRecoverySource;
|
|
102
|
+
}>;
|
|
103
|
+
export type BatchMutationRecoveryResult<TOutput> = Readonly<{
|
|
104
|
+
status: 'recovered';
|
|
105
|
+
value: TOutput;
|
|
106
|
+
}> | Readonly<{
|
|
107
|
+
status: 'unresolved';
|
|
108
|
+
error?: unknown;
|
|
109
|
+
}>;
|
|
110
|
+
export type BatchCompletedResumeItem<TOutput> = BatchItemContract & Readonly<{
|
|
111
|
+
state: 'completed';
|
|
112
|
+
outcome: BatchItemSuccessStatus;
|
|
113
|
+
value: TOutput;
|
|
114
|
+
attempts: number;
|
|
115
|
+
}>;
|
|
116
|
+
export type BatchAttemptedResumeItem = BatchItemContract & Readonly<{
|
|
117
|
+
state: 'attempted';
|
|
118
|
+
attempts: number;
|
|
119
|
+
}>;
|
|
120
|
+
export type BatchResumeItem<TOutput> = BatchAttemptedResumeItem | BatchCompletedResumeItem<TOutput>;
|
|
121
|
+
export type BatchResumeState<TOutput, TIdentity extends BatchJsonValue = BatchJsonValue> = Readonly<{
|
|
122
|
+
contract: BatchContract<TIdentity>;
|
|
123
|
+
items: readonly BatchResumeItem<TOutput>[];
|
|
124
|
+
}>;
|
|
125
|
+
export type BatchPauseContext<TInput, TOutput> = Readonly<{
|
|
126
|
+
item: TInput;
|
|
127
|
+
item_id: string;
|
|
128
|
+
item_contract: BatchItemContract;
|
|
129
|
+
exclusive_key: string | null;
|
|
130
|
+
input_index: number;
|
|
131
|
+
claimed_count: number;
|
|
132
|
+
results_input_order: readonly BatchItemResult<TInput, TOutput>[];
|
|
133
|
+
}>;
|
|
134
|
+
export type BatchStopContext<TInput, TOutput> = Readonly<{
|
|
135
|
+
last_result: BatchItemResult<TInput, TOutput>;
|
|
136
|
+
claimed_count: number;
|
|
137
|
+
results_input_order: readonly BatchItemResult<TInput, TOutput>[];
|
|
138
|
+
results_completion_order: readonly BatchItemResult<TInput, TOutput>[];
|
|
139
|
+
}>;
|
|
140
|
+
export type BatchClock = Readonly<{
|
|
141
|
+
now: () => number;
|
|
142
|
+
}>;
|
|
143
|
+
export type BatchSleep = (milliseconds: number) => Promise<void>;
|
|
144
|
+
export type BatchRunLockOptions<TIdentity extends BatchJsonValue> = Readonly<{
|
|
145
|
+
runPath: string;
|
|
146
|
+
identity: TIdentity;
|
|
147
|
+
reason: string;
|
|
148
|
+
timeoutMs?: number;
|
|
149
|
+
pollMs?: number;
|
|
150
|
+
sleep?: BatchSleep;
|
|
151
|
+
}>;
|
|
152
|
+
export type BatchRunLockReceipt = Readonly<{
|
|
153
|
+
run_path: string;
|
|
154
|
+
state_path: string;
|
|
155
|
+
lock_path: string;
|
|
156
|
+
identity_sha256: string;
|
|
157
|
+
}>;
|
|
158
|
+
export type BatchExclusiveKeyContext<TInput> = Readonly<{
|
|
159
|
+
item: TInput;
|
|
160
|
+
item_id: string;
|
|
161
|
+
item_contract: BatchItemContract;
|
|
162
|
+
input_index: number;
|
|
163
|
+
}>;
|
|
164
|
+
export type RunBoundedBatchOptions<TInput, TOutput, TIdentity extends BatchJsonValue, TExclusiveKey extends string = string> = Readonly<{
|
|
165
|
+
contract: BatchContract<TIdentity>;
|
|
166
|
+
items: readonly TInput[];
|
|
167
|
+
getItemIdentity: (item: TInput, inputIndex: number) => string;
|
|
168
|
+
projectItemContent: (item: TInput, inputIndex: number) => BatchJsonValue;
|
|
169
|
+
projectItemPolicy: (item: TInput, inputIndex: number) => BatchJsonValue;
|
|
170
|
+
getExclusiveKey?: (context: BatchExclusiveKeyContext<TInput>) => TExclusiveKey | null | undefined;
|
|
171
|
+
mode: BatchMode;
|
|
172
|
+
maxConcurrency: number;
|
|
173
|
+
execute: (context: BatchExecutionContext<TInput, TExclusiveKey>) => TOutput | Promise<TOutput>;
|
|
174
|
+
retry?: BatchRetryPolicy<TInput, TExclusiveKey>;
|
|
175
|
+
recoverMutation?: (context: BatchMutationRecoveryContext<TInput, TExclusiveKey>) => BatchMutationRecoveryResult<TOutput> | Promise<BatchMutationRecoveryResult<TOutput>>;
|
|
176
|
+
resume?: BatchResumeState<TOutput, TIdentity>;
|
|
177
|
+
shouldPauseBeforeClaim?: (context: BatchPauseContext<TInput, TOutput>) => boolean | Promise<boolean>;
|
|
178
|
+
shouldStop?: (context: BatchStopContext<TInput, TOutput>) => boolean | Promise<boolean>;
|
|
179
|
+
eventSink?: (event: BatchEvent) => void | Promise<void>;
|
|
180
|
+
clock?: BatchClock;
|
|
181
|
+
sleep?: BatchSleep;
|
|
182
|
+
}>;
|
|
183
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/batch/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAW,CAAC","sourcesContent":["export const MAX_BATCH_CONCURRENCY = 64 as const;\n\nexport type BatchJsonPrimitive = boolean | null | number | string;\nexport type BatchJsonValue = BatchJsonPrimitive | BatchJsonValue[] | BatchJsonObject;\nexport type BatchJsonObject = { [key: string]: BatchJsonValue };\n\nexport type BatchContract<TIdentity extends BatchJsonValue = BatchJsonValue> = {\n identity: TIdentity;\n content_sha256: string;\n policy_sha256: string;\n};\n\nexport type BatchItemContract = Readonly<{\n item_id: string;\n content_sha256: string;\n policy_sha256: string;\n}>;\n\nexport type CreateBatchItemContractOptions = Readonly<{\n item_id: string;\n content: BatchJsonValue;\n policy: BatchJsonValue;\n}>;\n\nexport type CreateBatchContractOptions<TIdentity extends BatchJsonValue> = {\n identity: TIdentity;\n content: BatchJsonValue;\n policy: BatchJsonValue;\n};\n\nexport type BatchMode = 'mutation' | 'read';\nexport type BatchStatus = 'completed' | 'paused' | 'stopped';\nexport type BatchItemSuccessStatus = 'recovered' | 'succeeded';\n\nexport type BatchEventType =\n | 'attempt_failed'\n | 'attempt_started'\n | 'attempt_succeeded'\n | 'batch_completed'\n | 'batch_paused'\n | 'batch_started'\n | 'batch_stopped'\n | 'item_claimed'\n | 'item_completed'\n | 'item_identity_drift'\n | 'item_projection_drift'\n | 'item_resource_acquired'\n | 'item_resource_drift'\n | 'item_resource_queued'\n | 'item_resource_released'\n | 'item_resume_rejected'\n | 'item_resumed'\n | 'recovery_failed'\n | 'recovery_started'\n | 'recovery_succeeded'\n | 'retry_scheduled';\n\nexport type BatchEvent = Readonly<{\n sequence: number;\n timestamp_ms: number;\n type: BatchEventType;\n item_id?: string;\n input_index?: number;\n attempt?: number;\n delay_ms?: number;\n status?: BatchItemResultStatus | BatchStatus;\n source?: BatchRecoverySource;\n exclusive_key?: string;\n}>;\n\ntype BatchItemResultCommon<TInput> = Readonly<{\n item: TInput;\n item_id: string;\n item_contract: BatchItemContract;\n exclusive_key: string | null;\n input_index: number;\n attempts: number;\n attempt_consumed: boolean;\n resumed: boolean;\n completed_at_ms: number;\n}>;\n\nexport type BatchItemSucceededResult<TInput, TOutput> = BatchItemResultCommon<TInput> &\n Readonly<{\n status: BatchItemSuccessStatus;\n value: TOutput;\n }>;\n\nexport type BatchItemFailedResult<TInput> = BatchItemResultCommon<TInput> &\n Readonly<{\n status: 'failed';\n error: unknown;\n }>;\n\nexport type BatchItemResultStatus = BatchItemSuccessStatus | 'failed';\nexport type BatchItemResult<TInput, TOutput> =\n | BatchItemFailedResult<TInput>\n | BatchItemSucceededResult<TInput, TOutput>;\n\nexport type BatchRunResult<\n TInput,\n TOutput,\n TIdentity extends BatchJsonValue = BatchJsonValue,\n> = Readonly<{\n contract: BatchContract<TIdentity>;\n status: BatchStatus;\n claim_order: readonly string[];\n completion_order: readonly string[];\n results_input_order: readonly BatchItemResult<TInput, TOutput>[];\n results_completion_order: readonly BatchItemResult<TInput, TOutput>[];\n unclaimed_item_ids: readonly string[];\n events: readonly BatchEvent[];\n}>;\n\nexport type BatchExecutionContext<TInput, TExclusiveKey extends string = string> = Readonly<{\n item: TInput;\n item_id: string;\n item_contract: BatchItemContract;\n exclusive_key: TExclusiveKey | null;\n input_index: number;\n attempt: number;\n mode: BatchMode;\n}>;\n\nexport type BatchRetryContext<\n TInput,\n TExclusiveKey extends string = string,\n> = BatchExecutionContext<TInput, TExclusiveKey> &\n Readonly<{\n error: unknown;\n }>;\n\nexport type BatchRetryPolicy<TInput, TExclusiveKey extends string = string> = Readonly<{\n maxAttempts: number;\n maxDelayMs: number;\n shouldRetry: (context: BatchRetryContext<TInput, TExclusiveKey>) => boolean | Promise<boolean>;\n delayMs: (context: BatchRetryContext<TInput, TExclusiveKey>) => number | Promise<number>;\n}>;\n\nexport type BatchRecoverySource = 'execution_error' | 'resume_incomplete';\n\nexport type BatchMutationRecoveryContext<TInput, TExclusiveKey extends string = string> = Readonly<{\n item: TInput;\n item_id: string;\n item_contract: BatchItemContract;\n exclusive_key: TExclusiveKey | null;\n input_index: number;\n attempts: number;\n error: unknown;\n source: BatchRecoverySource;\n}>;\n\nexport type BatchMutationRecoveryResult<TOutput> =\n | Readonly<{ status: 'recovered'; value: TOutput }>\n | Readonly<{ status: 'unresolved'; error?: unknown }>;\n\nexport type BatchCompletedResumeItem<TOutput> = BatchItemContract &\n Readonly<{\n state: 'completed';\n outcome: BatchItemSuccessStatus;\n value: TOutput;\n attempts: number;\n }>;\n\nexport type BatchAttemptedResumeItem = BatchItemContract &\n Readonly<{\n state: 'attempted';\n attempts: number;\n }>;\n\nexport type BatchResumeItem<TOutput> = BatchAttemptedResumeItem | BatchCompletedResumeItem<TOutput>;\n\nexport type BatchResumeState<\n TOutput,\n TIdentity extends BatchJsonValue = BatchJsonValue,\n> = Readonly<{\n contract: BatchContract<TIdentity>;\n items: readonly BatchResumeItem<TOutput>[];\n}>;\n\nexport type BatchPauseContext<TInput, TOutput> = Readonly<{\n item: TInput;\n item_id: string;\n item_contract: BatchItemContract;\n exclusive_key: string | null;\n input_index: number;\n claimed_count: number;\n results_input_order: readonly BatchItemResult<TInput, TOutput>[];\n}>;\n\nexport type BatchStopContext<TInput, TOutput> = Readonly<{\n last_result: BatchItemResult<TInput, TOutput>;\n claimed_count: number;\n results_input_order: readonly BatchItemResult<TInput, TOutput>[];\n results_completion_order: readonly BatchItemResult<TInput, TOutput>[];\n}>;\n\nexport type BatchClock = Readonly<{ now: () => number }>;\nexport type BatchSleep = (milliseconds: number) => Promise<void>;\n\nexport type BatchRunLockOptions<TIdentity extends BatchJsonValue> = Readonly<{\n runPath: string;\n identity: TIdentity;\n reason: string;\n timeoutMs?: number;\n pollMs?: number;\n sleep?: BatchSleep;\n}>;\n\nexport type BatchRunLockReceipt = Readonly<{\n run_path: string;\n state_path: string;\n lock_path: string;\n identity_sha256: string;\n}>;\n\nexport type BatchExclusiveKeyContext<TInput> = Readonly<{\n item: TInput;\n item_id: string;\n item_contract: BatchItemContract;\n input_index: number;\n}>;\n\nexport type RunBoundedBatchOptions<\n TInput,\n TOutput,\n TIdentity extends BatchJsonValue,\n TExclusiveKey extends string = string,\n> = Readonly<{\n contract: BatchContract<TIdentity>;\n items: readonly TInput[];\n getItemIdentity: (item: TInput, inputIndex: number) => string;\n projectItemContent: (item: TInput, inputIndex: number) => BatchJsonValue;\n projectItemPolicy: (item: TInput, inputIndex: number) => BatchJsonValue;\n getExclusiveKey?: (context: BatchExclusiveKeyContext<TInput>) => TExclusiveKey | null | undefined;\n mode: BatchMode;\n maxConcurrency: number;\n execute: (context: BatchExecutionContext<TInput, TExclusiveKey>) => TOutput | Promise<TOutput>;\n retry?: BatchRetryPolicy<TInput, TExclusiveKey>;\n recoverMutation?: (\n context: BatchMutationRecoveryContext<TInput, TExclusiveKey>,\n ) => BatchMutationRecoveryResult<TOutput> | Promise<BatchMutationRecoveryResult<TOutput>>;\n resume?: BatchResumeState<TOutput, TIdentity>;\n shouldPauseBeforeClaim?: (\n context: BatchPauseContext<TInput, TOutput>,\n ) => boolean | Promise<boolean>;\n shouldStop?: (context: BatchStopContext<TInput, TOutput>) => boolean | Promise<boolean>;\n eventSink?: (event: BatchEvent) => void | Promise<void>;\n clock?: BatchClock;\n sleep?: BatchSleep;\n}>;\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { runDatasetContract, type DatasetContractReport } from './dataset-contract.js';
|
|
2
|
+
import { parseUnstructuredDocument } from './unstructured.js';
|
|
3
|
+
import type { FetchLike } from './http.js';
|
|
4
|
+
export type DatasetAuthorReport = {
|
|
5
|
+
schema_version: 1;
|
|
6
|
+
status: 'evidence_ready';
|
|
7
|
+
generated_at_utc: string;
|
|
8
|
+
input_path: string;
|
|
9
|
+
target_types: string[];
|
|
10
|
+
files: {
|
|
11
|
+
source_extract: string;
|
|
12
|
+
authoring_report: string;
|
|
13
|
+
};
|
|
14
|
+
context_packs: Array<{
|
|
15
|
+
type: string;
|
|
16
|
+
report: DatasetContractReport;
|
|
17
|
+
}>;
|
|
18
|
+
next_actions: string[];
|
|
19
|
+
};
|
|
20
|
+
export type RunDatasetAuthorOptions = {
|
|
21
|
+
inputPath: string;
|
|
22
|
+
targetTypes: string | string[] | undefined;
|
|
23
|
+
outDir: string | null | undefined;
|
|
24
|
+
prompt?: string | undefined;
|
|
25
|
+
provider?: string | undefined;
|
|
26
|
+
model?: string | undefined;
|
|
27
|
+
timeoutMs?: number | undefined;
|
|
28
|
+
env: NodeJS.ProcessEnv;
|
|
29
|
+
fetchImpl: FetchLike;
|
|
30
|
+
now?: Date | undefined;
|
|
31
|
+
parseImpl?: typeof parseUnstructuredDocument | undefined;
|
|
32
|
+
contractImpl?: typeof runDatasetContract | undefined;
|
|
33
|
+
};
|
|
34
|
+
export declare function runDatasetAuthor(options: RunDatasetAuthorOptions): Promise<DatasetAuthorReport>;
|
|
35
|
+
declare function normalizeTargetTypes(value: string | string[] | undefined): string[];
|
|
36
|
+
export declare const __testInternals: {
|
|
37
|
+
normalizeTargetTypes: typeof normalizeTargetTypes;
|
|
38
|
+
};
|
|
39
|
+
export {};
|