@xemahq/dsl 0.8.0 → 0.8.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/dist/payload-codec/lib/blob-store.js +0 -0
- package/dist/payload-codec/lib/blob-store.js.map +1 -1
- package/package.json +3 -4
- package/src/deliverable-spec/index.ts +0 -19
- package/src/deliverable-spec/lib/schema.ts +0 -270
- package/src/deliverable-spec/lib/types.ts +0 -26
- package/src/payload-codec/index.ts +0 -44
- package/src/payload-codec/lib/blob-store.ts +0 -0
- package/src/payload-codec/lib/codec-context.ts +0 -38
- package/src/payload-codec/lib/codec.ts +0 -605
- package/src/payload-codec/lib/enums.ts +0 -58
- package/src/payload-codec/lib/errors.ts +0 -54
- package/src/payload-codec/lib/http-blob-store.ts +0 -267
- package/src/payload-codec/lib/lru-cache.ts +0 -81
- package/src/payload-codec/lib/payload.ts +0 -26
- package/src/payload-codec/temporal/index.ts +0 -36
- package/src/workflow/index.ts +0 -108
- package/src/workflow/lib/action-input-validator.ts +0 -160
- package/src/workflow/lib/compiler/action-shape.ts +0 -71
- package/src/workflow/lib/compiler/canonical-json.ts +0 -66
- package/src/workflow/lib/compiler/compile.ts +0 -1742
- package/src/workflow/lib/compiler/concurrency.ts +0 -223
- package/src/workflow/lib/compiler/dag.ts +0 -108
- package/src/workflow/lib/compiler/gate-defaults.ts +0 -153
- package/src/workflow/lib/compiler/index.ts +0 -11
- package/src/workflow/lib/compiler/inputs.ts +0 -254
- package/src/workflow/lib/compiler/installation-resource-validator.ts +0 -114
- package/src/workflow/lib/compiler/manifest-source.ts +0 -71
- package/src/workflow/lib/compiler/matrix.ts +0 -135
- package/src/workflow/lib/compiler/mount-plan.ts +0 -190
- package/src/workflow/lib/compiler/payload-reach-in.ts +0 -497
- package/src/workflow/lib/compiler/permissions.ts +0 -64
- package/src/workflow/lib/compiler/retry-timeout.ts +0 -105
- package/src/workflow/lib/compiler/review-step.ts +0 -548
- package/src/workflow/lib/compiler/types.ts +0 -172
- package/src/workflow/lib/compiler/variable-requirements.ts +0 -208
- package/src/workflow/lib/deliverable-spec-introspection-error.ts +0 -63
- package/src/workflow/lib/deliverable-spec-keys.ts +0 -147
- package/src/workflow/lib/deliverable-spec-source-scan.ts +0 -280
- package/src/workflow/lib/dispatch-inputs/index.ts +0 -160
- package/src/workflow/lib/dispatch-inputs/to-json-schema.ts +0 -60
- package/src/workflow/lib/duration.ts +0 -43
- package/src/workflow/lib/errors.ts +0 -37
- package/src/workflow/lib/expression/ast.ts +0 -108
- package/src/workflow/lib/expression/context.ts +0 -148
- package/src/workflow/lib/expression/evaluator.ts +0 -492
- package/src/workflow/lib/expression/index.ts +0 -28
- package/src/workflow/lib/expression/interpolation.ts +0 -84
- package/src/workflow/lib/expression/parser.ts +0 -264
- package/src/workflow/lib/expression/template.ts +0 -117
- package/src/workflow/lib/expression/tokenizer.ts +0 -200
- package/src/workflow/lib/expression/tokens.ts +0 -30
- package/src/workflow/lib/expression/walk-artifact-refs.ts +0 -232
- package/src/workflow/lib/installation-resource-kind.ts +0 -107
- package/src/workflow/lib/schemas-loader.ts +0 -64
- package/src/workflow/lib/serializer.ts +0 -30
- package/src/workflow/lib/types.ts +0 -417
- package/src/workflow/lib/validate.ts +0 -199
- package/src/workspace-manifest/index.ts +0 -27
- package/src/workspace-manifest/lib/compile.ts +0 -619
- package/src/workspace-manifest/lib/interpolate.ts +0 -166
- package/src/workspace-manifest/lib/resolve-extends.ts +0 -260
- package/src/workspace-manifest/lib/schema.ts +0 -692
- package/src/workspace-manifest/lib/types.ts +0 -446
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Typed error codes emitted by the spill codec. Callers MUST branch on
|
|
3
|
-
* `.code` — free-form message matching is forbidden, because these errors
|
|
4
|
-
* travel across process + network boundaries (Temporal workflow ↔ engine)
|
|
5
|
-
* and need a stable identity.
|
|
6
|
-
*/
|
|
7
|
-
export enum PayloadCodecErrorCode {
|
|
8
|
-
/** Input payload shape is invalid (e.g. missing data). */
|
|
9
|
-
INVALID_PAYLOAD = 'INVALID_PAYLOAD',
|
|
10
|
-
/** BlobStore.put failed during encode. */
|
|
11
|
-
BLOB_PUT_FAILED = 'BLOB_PUT_FAILED',
|
|
12
|
-
/** BlobStore.get failed during decode. */
|
|
13
|
-
BLOB_GET_FAILED = 'BLOB_GET_FAILED',
|
|
14
|
-
/** Received a spilled payload but no BlobStore is configured. */
|
|
15
|
-
NO_BLOB_STORE_CONFIGURED = 'NO_BLOB_STORE_CONFIGURED',
|
|
16
|
-
/** Spill envelope is malformed or uses an unknown version. */
|
|
17
|
-
MALFORMED_ENVELOPE = 'MALFORMED_ENVELOPE',
|
|
18
|
-
/** Envelope declares a store kind this codec doesn't know. */
|
|
19
|
-
UNKNOWN_STORE_KIND = 'UNKNOWN_STORE_KIND',
|
|
20
|
-
/** sha256 mismatch between envelope declaration and fetched blob. */
|
|
21
|
-
SHA256_MISMATCH = 'SHA256_MISMATCH',
|
|
22
|
-
/** orgIdProvider returned no orgId at encode time (fail-fast — no silent fallback). */
|
|
23
|
-
ORG_ID_REQUIRED = 'ORG_ID_REQUIRED',
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class PayloadCodecError extends Error {
|
|
27
|
-
readonly code: PayloadCodecErrorCode;
|
|
28
|
-
readonly details: Readonly<Record<string, unknown>>;
|
|
29
|
-
|
|
30
|
-
constructor(
|
|
31
|
-
code: PayloadCodecErrorCode,
|
|
32
|
-
message: string,
|
|
33
|
-
details: Readonly<Record<string, unknown>> = {},
|
|
34
|
-
) {
|
|
35
|
-
super(message);
|
|
36
|
-
this.name = 'PayloadCodecError';
|
|
37
|
-
this.code = code;
|
|
38
|
-
this.details = details;
|
|
39
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
toJSON(): Readonly<Record<string, unknown>> {
|
|
43
|
-
return {
|
|
44
|
-
name: this.name,
|
|
45
|
-
code: this.code,
|
|
46
|
-
message: this.message,
|
|
47
|
-
details: this.details,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function isPayloadCodecError(err: unknown): err is PayloadCodecError {
|
|
53
|
-
return err instanceof PayloadCodecError;
|
|
54
|
-
}
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import type { Response as UndiciResponse } from 'undici-types';
|
|
2
|
-
|
|
3
|
-
import { BlobStoreKind } from './enums';
|
|
4
|
-
import { PayloadCodecError, PayloadCodecErrorCode } from './errors';
|
|
5
|
-
import {
|
|
6
|
-
type BlobRef,
|
|
7
|
-
type BlobStore,
|
|
8
|
-
type StoredBlob,
|
|
9
|
-
sha256Hex,
|
|
10
|
-
} from './blob-store';
|
|
11
|
-
|
|
12
|
-
export interface HttpBlobStoreOptions {
|
|
13
|
-
/**
|
|
14
|
-
* Resolves the `artifact-store-api` base URL. Invoked PER REQUEST so the
|
|
15
|
-
* store is boot-order-safe (no URL is needed at construction time) and
|
|
16
|
-
* topology-safe under horizontal scaling — wire it to the service
|
|
17
|
-
* registry, e.g.
|
|
18
|
-
* `() => resolveHttpUrl(registry, ServiceName.ARTIFACT_STORE_API)`.
|
|
19
|
-
* Resolution is a cheap in-memory registry-cache read, so per-request
|
|
20
|
-
* resolution is correct rather than caching a possibly-stale instance URL.
|
|
21
|
-
*/
|
|
22
|
-
readonly resolveBaseUrl: () => string | Promise<string>;
|
|
23
|
-
/**
|
|
24
|
-
* Async provider for the service identity JWT. The codec mints new
|
|
25
|
-
* requests on every put/get so the token can expire without a restart.
|
|
26
|
-
*/
|
|
27
|
-
readonly tokenProvider: () => Promise<string>;
|
|
28
|
-
/** Optional correlation id; appended to `X-Correlation-Id`. */
|
|
29
|
-
readonly correlationIdProvider?: () => string | null;
|
|
30
|
-
/** Absolute timeout for an individual put/get request (ms). */
|
|
31
|
-
readonly requestTimeoutMs?: number;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
35
|
-
const PUT_PATH = '/blobs';
|
|
36
|
-
const GET_PATH_PREFIX = '/blobs/';
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* BlobStore backed by `artifact-store-api`. Contract the service exposes:
|
|
40
|
-
*
|
|
41
|
-
* POST /blobs Content-Type: any
|
|
42
|
-
* headers: Authorization: Bearer <jwt>; X-Xema-Org-Id: <tenant>
|
|
43
|
-
* body: raw bytes
|
|
44
|
-
* response: { data: { sha256, sizeBytes, contentType, createdAt } }
|
|
45
|
-
*
|
|
46
|
-
* GET /blobs/:sha256
|
|
47
|
-
* headers: Authorization: Bearer <jwt>; X-Xema-Org-Id: <tenant>
|
|
48
|
-
* response: raw bytes, Content-Type header from the upload
|
|
49
|
-
*
|
|
50
|
-
* `X-Xema-Org-Id` is required on every call — the artifact-store-api scopes
|
|
51
|
-
* blob rows by `(orgId, sha256)`, so reads/writes must declare a tenant.
|
|
52
|
-
* The codec passes the orgId at the call site (encode reads it from the
|
|
53
|
-
* configured orgIdProvider; decode reads it from the spill envelope).
|
|
54
|
-
*
|
|
55
|
-
* Authentication is service-to-service — the caller provides a bearer
|
|
56
|
-
* token (minted via `identity-api`). Idempotent: the server dedupes by
|
|
57
|
-
* `(orgId, sha256)`.
|
|
58
|
-
*/
|
|
59
|
-
export class HttpBlobStore implements BlobStore {
|
|
60
|
-
readonly kind = BlobStoreKind.ARTIFACT_STORE;
|
|
61
|
-
|
|
62
|
-
constructor(private readonly options: HttpBlobStoreOptions) {}
|
|
63
|
-
|
|
64
|
-
async put(
|
|
65
|
-
bytes: Uint8Array,
|
|
66
|
-
contentType: string,
|
|
67
|
-
orgId: string,
|
|
68
|
-
): Promise<StoredBlob> {
|
|
69
|
-
assertOrgId(orgId);
|
|
70
|
-
const token = await this.options.tokenProvider();
|
|
71
|
-
const controller = new AbortController();
|
|
72
|
-
const timer = setTimeout(
|
|
73
|
-
() => controller.abort(),
|
|
74
|
-
this.options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
75
|
-
);
|
|
76
|
-
try {
|
|
77
|
-
// Node's undici fetch accepts Uint8Array directly; Buffer is a
|
|
78
|
-
// Uint8Array subclass AND a documented BodyInit in @types/node's
|
|
79
|
-
// ambient fetch types, so wrap once to keep TS happy without `any`.
|
|
80
|
-
const response = (await fetch(await this.resolveUrl(PUT_PATH), {
|
|
81
|
-
method: 'POST',
|
|
82
|
-
headers: this.buildHeaders(token, contentType, orgId),
|
|
83
|
-
body: Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength),
|
|
84
|
-
signal: controller.signal,
|
|
85
|
-
})) as unknown as UndiciResponse;
|
|
86
|
-
if (!response.ok) {
|
|
87
|
-
throw new PayloadCodecError(
|
|
88
|
-
PayloadCodecErrorCode.BLOB_PUT_FAILED,
|
|
89
|
-
`artifact-store-api POST /blobs failed: ${response.status} ${response.statusText}`,
|
|
90
|
-
{ status: response.status, orgId },
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
const parsed = (await response.json()) as {
|
|
94
|
-
data?: {
|
|
95
|
-
sha256?: unknown;
|
|
96
|
-
sizeBytes?: unknown;
|
|
97
|
-
contentType?: unknown;
|
|
98
|
-
createdAt?: unknown;
|
|
99
|
-
uri?: unknown;
|
|
100
|
-
};
|
|
101
|
-
};
|
|
102
|
-
const data = parsed.data;
|
|
103
|
-
if (!data || typeof data.sha256 !== 'string') {
|
|
104
|
-
throw new PayloadCodecError(
|
|
105
|
-
PayloadCodecErrorCode.BLOB_PUT_FAILED,
|
|
106
|
-
'artifact-store-api POST /blobs: malformed response envelope.',
|
|
107
|
-
{ received: parsed },
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
const expectedSha = sha256Hex(bytes);
|
|
111
|
-
if (data.sha256 !== expectedSha) {
|
|
112
|
-
throw new PayloadCodecError(
|
|
113
|
-
PayloadCodecErrorCode.SHA256_MISMATCH,
|
|
114
|
-
'artifact-store-api returned a different sha256 than the client computed.',
|
|
115
|
-
{ expected: expectedSha, received: data.sha256 },
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
// The current artifact-store BlobResponseDto omits `uri`; the (orgId,
|
|
119
|
-
// sha256) pair is canonical for retrieval, so we synthesize a
|
|
120
|
-
// stable handle for diagnostics.
|
|
121
|
-
const uri =
|
|
122
|
-
typeof data.uri === 'string' && data.uri.length > 0
|
|
123
|
-
? data.uri
|
|
124
|
-
: `artifact-store://${orgId}/${data.sha256}`;
|
|
125
|
-
const sizeBytes =
|
|
126
|
-
typeof data.sizeBytes === 'number' ? data.sizeBytes : bytes.byteLength;
|
|
127
|
-
const contentTypeOut =
|
|
128
|
-
typeof data.contentType === 'string' ? data.contentType : contentType;
|
|
129
|
-
const createdAt =
|
|
130
|
-
typeof data.createdAt === 'string'
|
|
131
|
-
? data.createdAt
|
|
132
|
-
: new Date().toISOString();
|
|
133
|
-
return {
|
|
134
|
-
store: this.kind,
|
|
135
|
-
uri,
|
|
136
|
-
sha256: data.sha256,
|
|
137
|
-
orgId,
|
|
138
|
-
sizeBytes,
|
|
139
|
-
contentType: contentTypeOut,
|
|
140
|
-
createdAt,
|
|
141
|
-
};
|
|
142
|
-
} finally {
|
|
143
|
-
clearTimeout(timer);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async get(ref: BlobRef): Promise<Uint8Array> {
|
|
148
|
-
if (ref.store !== this.kind) {
|
|
149
|
-
throw new PayloadCodecError(
|
|
150
|
-
PayloadCodecErrorCode.UNKNOWN_STORE_KIND,
|
|
151
|
-
`HttpBlobStore cannot read blobs from store '${ref.store}'.`,
|
|
152
|
-
{ expected: this.kind, received: ref.store },
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
assertOrgId(ref.orgId);
|
|
156
|
-
const token = await this.options.tokenProvider();
|
|
157
|
-
const controller = new AbortController();
|
|
158
|
-
const timer = setTimeout(
|
|
159
|
-
() => controller.abort(),
|
|
160
|
-
this.options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
161
|
-
);
|
|
162
|
-
try {
|
|
163
|
-
const response = (await fetch(
|
|
164
|
-
await this.resolveUrl(`${GET_PATH_PREFIX}${encodeURIComponent(ref.sha256)}`),
|
|
165
|
-
{
|
|
166
|
-
method: 'GET',
|
|
167
|
-
headers: this.buildHeaders(token, 'application/octet-stream', ref.orgId),
|
|
168
|
-
signal: controller.signal,
|
|
169
|
-
},
|
|
170
|
-
)) as unknown as UndiciResponse;
|
|
171
|
-
if (!response.ok) {
|
|
172
|
-
throw new PayloadCodecError(
|
|
173
|
-
PayloadCodecErrorCode.BLOB_GET_FAILED,
|
|
174
|
-
`artifact-store-api GET /blobs/${ref.sha256} failed: ${response.status} ${response.statusText}`,
|
|
175
|
-
{ status: response.status, sha256: ref.sha256, orgId: ref.orgId },
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
179
|
-
const actualSha = sha256Hex(buffer);
|
|
180
|
-
if (actualSha !== ref.sha256) {
|
|
181
|
-
throw new PayloadCodecError(
|
|
182
|
-
PayloadCodecErrorCode.SHA256_MISMATCH,
|
|
183
|
-
'Blob fetched from artifact-store-api does not match the requested sha256.',
|
|
184
|
-
{ expected: ref.sha256, actual: actualSha },
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
return buffer;
|
|
188
|
-
} finally {
|
|
189
|
-
clearTimeout(timer);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async delete(
|
|
194
|
-
ref: Pick<BlobRef, 'sha256' | 'orgId'>,
|
|
195
|
-
): Promise<{ deleted: boolean }> {
|
|
196
|
-
assertOrgId(ref.orgId);
|
|
197
|
-
const token = await this.options.tokenProvider();
|
|
198
|
-
const controller = new AbortController();
|
|
199
|
-
const timer = setTimeout(
|
|
200
|
-
() => controller.abort(),
|
|
201
|
-
this.options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
202
|
-
);
|
|
203
|
-
try {
|
|
204
|
-
const response = (await fetch(
|
|
205
|
-
await this.resolveUrl(`${GET_PATH_PREFIX}${encodeURIComponent(ref.sha256)}`),
|
|
206
|
-
{
|
|
207
|
-
method: 'DELETE',
|
|
208
|
-
headers: this.buildHeaders(token, 'application/octet-stream', ref.orgId),
|
|
209
|
-
signal: controller.signal,
|
|
210
|
-
},
|
|
211
|
-
)) as unknown as UndiciResponse;
|
|
212
|
-
if (response.status === 204) {
|
|
213
|
-
// artifact-store-api returns 204 whether or not the row existed
|
|
214
|
-
// (idempotent). We log the call site's perspective ("requested
|
|
215
|
-
// delete completed") rather than the row-existed dimension —
|
|
216
|
-
// the sweeper persists the actual deletion count from its own
|
|
217
|
-
// database delete in the SnapshotPointer table.
|
|
218
|
-
return { deleted: true };
|
|
219
|
-
}
|
|
220
|
-
if (response.status === 404) {
|
|
221
|
-
// Defensive: some auth proxies surface 404 for cross-tenant
|
|
222
|
-
// misses. Treat as "already gone" so retries don't loop.
|
|
223
|
-
return { deleted: false };
|
|
224
|
-
}
|
|
225
|
-
throw new PayloadCodecError(
|
|
226
|
-
PayloadCodecErrorCode.BLOB_GET_FAILED,
|
|
227
|
-
`artifact-store-api DELETE /blobs/${ref.sha256} failed: ${response.status} ${response.statusText}`,
|
|
228
|
-
{ status: response.status, sha256: ref.sha256, orgId: ref.orgId },
|
|
229
|
-
);
|
|
230
|
-
} finally {
|
|
231
|
-
clearTimeout(timer);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
private async resolveUrl(path: string): Promise<string> {
|
|
236
|
-
const raw = await this.options.resolveBaseUrl();
|
|
237
|
-
if (!raw) {
|
|
238
|
-
throw new Error(
|
|
239
|
-
'HttpBlobStore: resolveBaseUrl() returned an empty URL — the ' +
|
|
240
|
-
'artifact-store-api peer could not be resolved.',
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
return `${raw.replace(/\/+$/, '')}${path}`;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
private buildHeaders(token: string, contentType: string, orgId: string): Headers {
|
|
247
|
-
const headers = new Headers({
|
|
248
|
-
Authorization: `Bearer ${token}`,
|
|
249
|
-
'Content-Type': contentType,
|
|
250
|
-
'X-Xema-Org-Id': orgId,
|
|
251
|
-
});
|
|
252
|
-
const correlationId = this.options.correlationIdProvider?.();
|
|
253
|
-
if (correlationId) {
|
|
254
|
-
headers.set('X-Correlation-Id', correlationId);
|
|
255
|
-
}
|
|
256
|
-
return headers;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function assertOrgId(orgId: string): void {
|
|
261
|
-
if (typeof orgId !== 'string' || orgId.length === 0) {
|
|
262
|
-
throw new PayloadCodecError(
|
|
263
|
-
PayloadCodecErrorCode.ORG_ID_REQUIRED,
|
|
264
|
-
'HttpBlobStore operations require a non-empty orgId for X-Xema-Org-Id.',
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tiny byte-capacity LRU cache keyed by string (sha256). Kept intentionally
|
|
3
|
-
* dependency-free — adding a full LRU lib for this alone would bloat the
|
|
4
|
-
* package. Map's insertion-order iteration gives us O(1) recency tracking:
|
|
5
|
-
* re-insert on access, evict from the front when over budget.
|
|
6
|
-
*
|
|
7
|
-
* Entries that exceed the cache's total capacity are refused outright
|
|
8
|
-
* (returned bytes bypass the cache). This avoids the anti-pattern where
|
|
9
|
-
* inserting a single huge value evicts everything else.
|
|
10
|
-
*/
|
|
11
|
-
export class BytesLruCache {
|
|
12
|
-
private readonly entries = new Map<string, Uint8Array>();
|
|
13
|
-
private totalBytes = 0;
|
|
14
|
-
|
|
15
|
-
constructor(private readonly capacityBytes: number) {
|
|
16
|
-
if (!Number.isFinite(capacityBytes) || capacityBytes < 0) {
|
|
17
|
-
throw new Error(`BytesLruCache: capacityBytes must be a non-negative finite number, got ${capacityBytes}.`);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Return cached bytes for `key`, or null if absent. Accessing an entry
|
|
23
|
-
* marks it most-recently-used (moves to the back of the Map).
|
|
24
|
-
*/
|
|
25
|
-
get(key: string): Uint8Array | null {
|
|
26
|
-
const found = this.entries.get(key);
|
|
27
|
-
if (found === undefined) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
// Refresh LRU position.
|
|
31
|
-
this.entries.delete(key);
|
|
32
|
-
this.entries.set(key, found);
|
|
33
|
-
return found;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Insert `value` under `key`. If `value` is larger than the total
|
|
38
|
-
* capacity, the cache skips insertion and the caller receives the
|
|
39
|
-
* untouched bytes. Evicts oldest entries until under capacity.
|
|
40
|
-
*/
|
|
41
|
-
put(key: string, value: Uint8Array): void {
|
|
42
|
-
if (value.byteLength > this.capacityBytes) {
|
|
43
|
-
return; // Too big; don't thrash the cache.
|
|
44
|
-
}
|
|
45
|
-
if (this.entries.has(key)) {
|
|
46
|
-
const prev = this.entries.get(key)!;
|
|
47
|
-
this.totalBytes -= prev.byteLength;
|
|
48
|
-
this.entries.delete(key);
|
|
49
|
-
}
|
|
50
|
-
this.entries.set(key, value);
|
|
51
|
-
this.totalBytes += value.byteLength;
|
|
52
|
-
while (this.totalBytes > this.capacityBytes) {
|
|
53
|
-
const oldest = this.entries.keys().next();
|
|
54
|
-
if (oldest.done === true) {
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
const evicted = this.entries.get(oldest.value);
|
|
58
|
-
if (evicted === undefined) {
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
this.totalBytes -= evicted.byteLength;
|
|
62
|
-
this.entries.delete(oldest.value);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Clears the cache. Used by tests. */
|
|
67
|
-
clear(): void {
|
|
68
|
-
this.entries.clear();
|
|
69
|
-
this.totalBytes = 0;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Current occupancy in bytes. Used by tests + instrumentation. */
|
|
73
|
-
get size(): number {
|
|
74
|
-
return this.totalBytes;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Current number of entries. Used by tests. */
|
|
78
|
-
get count(): number {
|
|
79
|
-
return this.entries.size;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Engine-agnostic payload shapes used by the spill codec.
|
|
3
|
-
*
|
|
4
|
-
* These mirror the structural shape of a workflow-engine payload and codec —
|
|
5
|
-
* a `data` byte buffer plus string→bytes `metadata`, and an encode/decode pair
|
|
6
|
-
* over payload batches. Defining them here keeps the codec free of any direct
|
|
7
|
-
* workflow-engine dependency. The binding to a concrete engine (currently
|
|
8
|
-
* Temporal) lives in a separate adapter — see
|
|
9
|
-
* `@xemahq/dsl/payload-codec/temporal` — so switching engines means adding a
|
|
10
|
-
* sibling adapter, not changing the codec core.
|
|
11
|
-
*
|
|
12
|
-
* The shapes are intentionally structural: any codec implementing this
|
|
13
|
-
* interface is assignable to a matching engine `PayloadCodec` interface.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/** A single payload: optional raw bytes plus optional string→bytes metadata. */
|
|
17
|
-
export interface Payload {
|
|
18
|
-
metadata?: Record<string, Uint8Array> | null;
|
|
19
|
-
data?: Uint8Array | null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Symmetric encode/decode over batches of {@link Payload}s. */
|
|
23
|
-
export interface PayloadCodec {
|
|
24
|
-
encode(payloads: Payload[]): Promise<Payload[]>;
|
|
25
|
-
decode(payloads: Payload[]): Promise<Payload[]>;
|
|
26
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Temporal binding for the spill payload codec.
|
|
3
|
-
*
|
|
4
|
-
* This is the ONLY module in `payload-codec` that references
|
|
5
|
-
* `@temporalio/common`; everything else is engine-agnostic (see
|
|
6
|
-
* `../lib/payload`). To target a different workflow engine, add a sibling
|
|
7
|
-
* adapter — the codec core does not change.
|
|
8
|
-
*
|
|
9
|
-
* `@temporalio/common` is an OPTIONAL peer dependency: install it only if you
|
|
10
|
-
* import this adapter. Consumers using just the engine-agnostic codec core
|
|
11
|
-
* (`@xemahq/dsl/payload-codec`) do not need Temporal at all.
|
|
12
|
-
*/
|
|
13
|
-
import type {
|
|
14
|
-
Payload as TemporalPayload,
|
|
15
|
-
PayloadCodec as TemporalPayloadCodec,
|
|
16
|
-
} from '@temporalio/common';
|
|
17
|
-
|
|
18
|
-
import type { PayloadCodec } from '../lib/payload';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Present an engine-agnostic {@link PayloadCodec} (e.g. `SpillPayloadCodec`)
|
|
22
|
-
* as a Temporal `PayloadCodec` for registration on a Temporal Client/Worker.
|
|
23
|
-
*
|
|
24
|
-
* This is a typed pass-through with no runtime cost. Its signature also serves
|
|
25
|
-
* as a compile-time guarantee that the engine-agnostic shapes remain
|
|
26
|
-
* structurally compatible with Temporal's: if a future Temporal release
|
|
27
|
-
* diverges, this module fails to build — a signal to update the adapter, not
|
|
28
|
-
* the codec core.
|
|
29
|
-
*/
|
|
30
|
-
export function asTemporalPayloadCodec(
|
|
31
|
-
codec: PayloadCodec,
|
|
32
|
-
): TemporalPayloadCodec {
|
|
33
|
-
return codec;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export type { TemporalPayload, TemporalPayloadCodec };
|
package/src/workflow/index.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
-
// ── Xema Workflow DSL — Barrel Export ──
|
|
3
|
-
//
|
|
4
|
-
// Pure TypeScript package (no NestJS, no Temporal, no DB access). Exposes:
|
|
5
|
-
// - JSON Schema Draft 2020-12 validation for workflow / reusable-workflow
|
|
6
|
-
// / action documents.
|
|
7
|
-
// - A deterministic expression engine (no `eval`, closed grammar).
|
|
8
|
-
// - A semantic compiler that produces CompiledRun structures consumed by
|
|
9
|
-
// workflow-engine-api and workflow-runtime-worker.
|
|
10
|
-
//
|
|
11
|
-
// Consumers: `workflow-engine-api` (compile + seed), `workflow-runtime-worker`
|
|
12
|
-
// (evaluate `if`/outputs/matrix-from/mount-plan at dispatch), and CI scripts
|
|
13
|
-
// that validate authored YAML in `biomes/software-dev/workflow-config/`.
|
|
14
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
15
|
-
|
|
16
|
-
export { WorkflowDslError, isWorkflowDslError } from './lib/errors';
|
|
17
|
-
export {
|
|
18
|
-
validateActionInputs,
|
|
19
|
-
type ActionInputValidationFailure,
|
|
20
|
-
type ActionInputValidationResult,
|
|
21
|
-
} from './lib/action-input-validator';
|
|
22
|
-
export {
|
|
23
|
-
InstallationResourceKind,
|
|
24
|
-
collectInstallationResourceHints,
|
|
25
|
-
type InstallationResourceFieldHint,
|
|
26
|
-
} from './lib/installation-resource-kind';
|
|
27
|
-
export type { InstallationCompileScope } from './lib/compiler/types';
|
|
28
|
-
export {
|
|
29
|
-
parseAndValidateActionYaml,
|
|
30
|
-
parseAndValidateReusableWorkflowYaml,
|
|
31
|
-
parseAndValidateWorkflowYaml,
|
|
32
|
-
validateActionManifest,
|
|
33
|
-
validateReusableWorkflowDocument,
|
|
34
|
-
validateWorkflowDocument,
|
|
35
|
-
} from './lib/validate';
|
|
36
|
-
export {
|
|
37
|
-
EMPTY_CONTEXT_SEEDS,
|
|
38
|
-
ExpressionFunction,
|
|
39
|
-
ExpressionNodeKind,
|
|
40
|
-
ExpressionRoot,
|
|
41
|
-
compileExpression,
|
|
42
|
-
evaluateExpression,
|
|
43
|
-
extractInterpolations,
|
|
44
|
-
isInterpolationWrapped,
|
|
45
|
-
stripInterpolation,
|
|
46
|
-
type ExpressionContext,
|
|
47
|
-
type ExpressionNode,
|
|
48
|
-
type NeedsEntry,
|
|
49
|
-
} from './lib/expression';
|
|
50
|
-
export { parseDurationMs } from './lib/duration';
|
|
51
|
-
export {
|
|
52
|
-
DispatchInputFieldType,
|
|
53
|
-
DispatchInputStringFormat,
|
|
54
|
-
extractDispatchInputDescriptors,
|
|
55
|
-
type DispatchInputDescriptor,
|
|
56
|
-
} from './lib/dispatch-inputs';
|
|
57
|
-
export { dispatchInputsToJsonSchema } from './lib/dispatch-inputs/to-json-schema';
|
|
58
|
-
export { serializeWorkflowDocument } from './lib/serializer';
|
|
59
|
-
export {
|
|
60
|
-
DECISION_GATE_ACTION_ID,
|
|
61
|
-
applyGateDefaults,
|
|
62
|
-
canonicalJsonSha256,
|
|
63
|
-
canonicalJsonStringify,
|
|
64
|
-
compileManifestSource,
|
|
65
|
-
compileWorkflow,
|
|
66
|
-
getWorkspaceManifestContract,
|
|
67
|
-
isAgentShapedAction,
|
|
68
|
-
type CompileInput,
|
|
69
|
-
type ResolvedAgentMeta,
|
|
70
|
-
type ResolvedDeliverableSpec,
|
|
71
|
-
type ResolvedRef,
|
|
72
|
-
} from './lib/compiler';
|
|
73
|
-
export {
|
|
74
|
-
extractZodTopLevelObjectKeys,
|
|
75
|
-
extractJsonSchemaTopLevelKeys,
|
|
76
|
-
} from './lib/deliverable-spec-keys';
|
|
77
|
-
export {
|
|
78
|
-
DeliverableSpecIntrospectionError,
|
|
79
|
-
DeliverableSpecIntrospectionFailure,
|
|
80
|
-
isDeliverableSpecIntrospectionError,
|
|
81
|
-
} from './lib/deliverable-spec-introspection-error';
|
|
82
|
-
export { scanTopLevelZodObjectDeclarations } from './lib/deliverable-spec-source-scan';
|
|
83
|
-
export type { TopLevelZodObjectDeclaration } from './lib/deliverable-spec-source-scan';
|
|
84
|
-
export type {
|
|
85
|
-
ActionContract,
|
|
86
|
-
ActionManifest,
|
|
87
|
-
ActionManifestMetadata,
|
|
88
|
-
ActionManifestRetryDefaults,
|
|
89
|
-
ActionManifestSpec,
|
|
90
|
-
ActionManifestTimeoutDefaults,
|
|
91
|
-
WorkspaceManifestActionContract,
|
|
92
|
-
ScheduleDeclaration,
|
|
93
|
-
WebhookDeclaration,
|
|
94
|
-
WorkflowCallDeclaration,
|
|
95
|
-
WorkflowConcurrencyDeclaration,
|
|
96
|
-
WorkflowDefaults,
|
|
97
|
-
WorkflowGateDefaults,
|
|
98
|
-
WorkflowDispatchDeclaration,
|
|
99
|
-
WorkflowDocument,
|
|
100
|
-
WorkflowDynamicStrategyDeclaration,
|
|
101
|
-
WorkflowInputDeclaration,
|
|
102
|
-
WorkflowJobDeclaration,
|
|
103
|
-
WorkflowMetadata,
|
|
104
|
-
WorkflowPermissions,
|
|
105
|
-
WorkflowRetryDeclaration,
|
|
106
|
-
WorkflowStrategyDeclaration,
|
|
107
|
-
WorkflowTriggerDeclarations,
|
|
108
|
-
} from './lib/types';
|