@docmana/sdk 0.32.0 → 0.36.0
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/CHANGELOG.md +60 -0
- package/LICENSE +21 -21
- package/README.md +183 -0
- package/dist/cli.mjs +265 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/client.d.ts +4 -0
- package/dist/errors.d.ts +17 -0
- package/dist/execution-events.d.ts +47 -0
- package/dist/http/http-client.d.ts +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +327 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +317 -2
- package/dist/index.mjs.map +1 -1
- package/dist/models/execution-status.enum.d.ts +1 -1
- package/dist/review-events.d.ts +36 -0
- package/dist/reviews.d.ts +188 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { FormulaAuthoring } from "./authoring.js";
|
|
2
|
+
import { Reviews } from "./reviews.js";
|
|
3
|
+
import { ExecutionEvents } from "./execution-events.js";
|
|
2
4
|
import type { AccessibleOrganization, DocmanaConfig, DocmanaExecutionResult, DownloadedOrganizationDocument, ExecutionStatus, FraudDetectionAccepted, FraudDetectionAsyncOptions, FraudDetectionOptions, FraudDetectionParams, FraudDetectionResult, FraudDetectionStatusResult, FlowDefinition, FlowListItem, FlowMetadata, OrganizationDocumentsPayload, RunFlowAsyncParams, RunFlowAsyncOptions, RunFlowOptions, RunFlowParams, RunPartialFlowAsyncParams, RunPartialFlowOptions, RunPartialFlowParams } from "./types.js";
|
|
3
5
|
export declare class Docmana {
|
|
4
6
|
readonly authoring: FormulaAuthoring;
|
|
7
|
+
readonly reviews: Reviews;
|
|
8
|
+
readonly executionEvents: ExecutionEvents;
|
|
5
9
|
private readonly config;
|
|
6
10
|
private readonly http;
|
|
7
11
|
constructor(config: DocmanaConfig);
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
import type { DocmanaExecutionResult } from "./models/docmana-execution-result.model.js";
|
|
2
2
|
import type { FraudDetectionError, FraudDetectionResult } from "./types.js";
|
|
3
|
+
/** Whitelisted metadata returned by Consumer Edge for a review HTTP 409. */
|
|
4
|
+
export interface ReviewConflictDetails {
|
|
5
|
+
currentVersion?: number | null;
|
|
6
|
+
decidedBy?: {
|
|
7
|
+
id?: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
source?: "integrator" | "token";
|
|
10
|
+
} | null;
|
|
11
|
+
decidedAt?: string | null;
|
|
12
|
+
/** @deprecated Use currentVersion. Retained for existing SDK consumers. */
|
|
13
|
+
version: number | null;
|
|
14
|
+
/** @deprecated Use decidedBy. Retained for existing SDK consumers. */
|
|
15
|
+
submittedBy: string | null;
|
|
16
|
+
/** @deprecated Use decidedAt. Retained for existing SDK consumers. */
|
|
17
|
+
submittedAt: string | null;
|
|
18
|
+
}
|
|
3
19
|
export declare class DocmanaError extends Error {
|
|
4
20
|
readonly status?: number;
|
|
5
21
|
readonly requestId?: string;
|
|
6
22
|
readonly code: string;
|
|
7
23
|
/** Public API business code; `code` retains the SDK's existing error category. */
|
|
8
24
|
readonly apiCode?: string;
|
|
25
|
+
readonly reviewConflict?: ReviewConflictDetails;
|
|
9
26
|
constructor(message: string, opts?: {
|
|
10
27
|
status?: number;
|
|
11
28
|
requestId?: string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { HttpClient } from "./http/http-client.js";
|
|
2
|
+
import type { ExecutionStatus } from "./models/execution-status.enum.js";
|
|
3
|
+
import { type ReviewEventCallback, type verifyReviewEventCallback } from "./review-events.js";
|
|
4
|
+
export declare const EXECUTION_NODE_EVENT_TYPES: readonly ["execution.node.started", "execution.node.completed", "execution.node.failed", "execution.node.reused"];
|
|
5
|
+
export interface ExecutionNodeEvent {
|
|
6
|
+
schemaVersion: 1;
|
|
7
|
+
eventId: string;
|
|
8
|
+
type: (typeof EXECUTION_NODE_EVENT_TYPES)[number];
|
|
9
|
+
organization: string;
|
|
10
|
+
executionResultId: string;
|
|
11
|
+
sequence: number;
|
|
12
|
+
occurredAt: string;
|
|
13
|
+
/** Broker publication instant, present only on event callbacks. */
|
|
14
|
+
publishedAt?: string;
|
|
15
|
+
flowId?: string;
|
|
16
|
+
flowVersion?: number;
|
|
17
|
+
nodeId: string;
|
|
18
|
+
nodeType: string;
|
|
19
|
+
documentKeys: string[];
|
|
20
|
+
revision: number;
|
|
21
|
+
attemptId: string;
|
|
22
|
+
}
|
|
23
|
+
export type ExecutionEventCallback = ExecutionNodeEvent | ReviewEventCallback;
|
|
24
|
+
export interface ExecutionEventsPage {
|
|
25
|
+
executionResultId: string;
|
|
26
|
+
executionStatus: ExecutionStatus;
|
|
27
|
+
flowId?: string;
|
|
28
|
+
flowVersion?: number | null;
|
|
29
|
+
events: ExecutionNodeEvent[];
|
|
30
|
+
nextAfter: number | null;
|
|
31
|
+
lastSequence: number;
|
|
32
|
+
truncated: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare function parseExecutionEventCallback(value: unknown): ExecutionEventCallback;
|
|
35
|
+
/** Expanded signature verifier. Existing review-only parser/verifier keep their contract. */
|
|
36
|
+
export declare function verifyExecutionEventCallback(options: Parameters<typeof verifyReviewEventCallback>[0]): ExecutionEventCallback;
|
|
37
|
+
export declare class ExecutionEvents {
|
|
38
|
+
private readonly http;
|
|
39
|
+
constructor(http: HttpClient);
|
|
40
|
+
/** One bounded page; never polls for completion or consumes a final result. */
|
|
41
|
+
list(id: string, options: {
|
|
42
|
+
organization: string;
|
|
43
|
+
after?: number;
|
|
44
|
+
limit?: number;
|
|
45
|
+
signal?: AbortSignal;
|
|
46
|
+
}): Promise<ExecutionEventsPage>;
|
|
47
|
+
}
|
|
@@ -9,6 +9,8 @@ export interface HttpClientOptions {
|
|
|
9
9
|
}
|
|
10
10
|
type FetchBody = NonNullable<Parameters<typeof fetch>[1]>["body"];
|
|
11
11
|
export interface RequestOptions {
|
|
12
|
+
/** Conditional document reads can legitimately return 304 or 416. */
|
|
13
|
+
acceptStatuses?: readonly number[];
|
|
12
14
|
query?: Record<string, string>;
|
|
13
15
|
body?: FetchBody;
|
|
14
16
|
headers?: Record<string, string>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
export { Docmana } from "./client.js";
|
|
2
|
+
export { REVIEW_EVENT_TYPES, parseReviewEventCallback, verifyReviewEventCallback, ReviewEventVerificationError, } from "./review-events.js";
|
|
3
|
+
export type { ReviewEventCallback, ReviewEventType } from "./review-events.js";
|
|
2
4
|
export { FormulaAuthoring } from "./authoring.js";
|
|
5
|
+
export type { ReviewConflictDetails } from "./errors.js";
|
|
3
6
|
export type { AuthoringDocumentTrialNode, AuthoringDocumentTrialSpec, AuthoringDocumentTrialReport, AuthoringSource, AuthoringGitPublication, AuthoringGitProjection, AuthoringPublication, AuthoringConversation, AuthoringConversationInput, AuthoringConversationContext, AuthoringConversationTurn, AuthoringData, AuthoringNode, AuthoringEdge, AuthoringRevisions, AuthoringFlowSummary, AuthoringSnapshot, AuthoringChanges, AuthoringDraft, AuthoringCreate, AuthoringReceipt, AuthoringOptions, AuthoringEditorCatalog, AuthoringPageOptions, } from "./authoring.js";
|
|
4
7
|
export { DocmanaError, DocmanaAuthError, DocmanaRequestError, DocmanaPayloadTooLargeError, DocmanaPermissionError, DocmanaNotFoundError, DocmanaExecutionError, DocmanaFraudDetectionError, DocmanaTimeoutError, DocmanaAbortError, DocmanaServiceUnavailableError, } from "./errors.js";
|
|
5
8
|
export type { AccessibleOrganization, DownloadedOrganizationDocument, DocmanaConfig, FlowDefinition, FlowDefinitionField, FlowDefinitionNode, FlowDefinitionNodeMetadata, FlowDocumentRequirement, FlowListItem, FlowMetadata, FraudDetectionAccepted, FraudDetectionAsyncOptions, FraudDetectionBaseParams, FraudDetectionError, FraudDetectionFileParams, FraudDetectionOptions, FraudDetectionParams, FraudDetectionProcessor, FraudDetectionResult, FraudDetectionStatus, FraudDetectionStatusResult, FraudDetectionSummary, FraudDetectionUrlParams, FraudDetectionVerdict, FraudFinding, FraudFindingLocation, FraudFindingSeverity, FraudSeverityCounts, OrganizationDocument, OrganizationDocumentsPayload, PartialExecutionFlowVersion, PartialExecutionMetadata, PartialExecutionScope, RunFlowAsyncParams, RunFlowAsyncOptions, RunFlowOptions, RunFlowParams, RunPartialFlowAsyncParams, RunPartialFlowOptions, RunPartialFlowParams, FileInput, NamedFileInput, PathFileInput, DocmanaExecutionResult, DocmanaExecutionVerdict, ExecutionStatus, DocmanaDocumentMapping, DocmanaSourceDocument, DocmanaDocumentResult, DocmanaNodeResult, DocmanaScoreNodeResult, DocmanaCrossValidationResult, DocmanaConclusionResult, DocmanaClassificationResult, DocmanaMetadataExtractionResult, DocmanaExtractionResult, DocmanaValidationResult, DocmanaPreprocessingResult, } from "./types.js";
|
|
6
9
|
export type { ExecutionProgress, VirtualDocument, PhysicalDocument, DocumentContent, FlowNodeType, FlowConfigs, FlowNode, FlowEdge, Flow, NodeTranslationResult, DocmanaApiExecutionResult, DocmanaApiNodeResult, DocmanaApiDocumentExecutionResult, DocmanaApiDocumentRequest, DocmanaApiPreprocessDocumentResult, } from "./models/index.js";
|
|
10
|
+
export { Reviews } from "./reviews.js";
|
|
11
|
+
export { ExecutionEvents, EXECUTION_NODE_EVENT_TYPES, parseExecutionEventCallback, verifyExecutionEventCallback, } from "./execution-events.js";
|
|
12
|
+
export type { ExecutionNodeEvent, ExecutionEventCallback, ExecutionEventsPage, } from "./execution-events.js";
|
|
13
|
+
export type { ReviewCalculation, ReviewFlowOutline, ReviewItem, DocumentPreviewManifest, ReviewDocument, ReviewAssessment, ReviewFinding, ReviewTask, ReviewSummary, ReviewDecision, ReviewReadOptions, ReviewDocumentOptions, } from "./reviews.js";
|
package/dist/index.js
CHANGED
|
@@ -32,7 +32,16 @@ __export(sdk_exports, {
|
|
|
32
32
|
DocmanaRequestError: () => DocmanaRequestError,
|
|
33
33
|
DocmanaServiceUnavailableError: () => DocmanaServiceUnavailableError,
|
|
34
34
|
DocmanaTimeoutError: () => DocmanaTimeoutError,
|
|
35
|
-
|
|
35
|
+
EXECUTION_NODE_EVENT_TYPES: () => EXECUTION_NODE_EVENT_TYPES,
|
|
36
|
+
ExecutionEvents: () => ExecutionEvents,
|
|
37
|
+
FormulaAuthoring: () => FormulaAuthoring,
|
|
38
|
+
REVIEW_EVENT_TYPES: () => REVIEW_EVENT_TYPES,
|
|
39
|
+
ReviewEventVerificationError: () => ReviewEventVerificationError,
|
|
40
|
+
Reviews: () => Reviews,
|
|
41
|
+
parseExecutionEventCallback: () => parseExecutionEventCallback,
|
|
42
|
+
parseReviewEventCallback: () => parseReviewEventCallback,
|
|
43
|
+
verifyExecutionEventCallback: () => verifyExecutionEventCallback,
|
|
44
|
+
verifyReviewEventCallback: () => verifyReviewEventCallback
|
|
36
45
|
});
|
|
37
46
|
module.exports = __toCommonJS(sdk_exports);
|
|
38
47
|
|
|
@@ -201,6 +210,276 @@ var FormulaAuthoring = class {
|
|
|
201
210
|
}
|
|
202
211
|
};
|
|
203
212
|
|
|
213
|
+
// src/sdk/reviews.ts
|
|
214
|
+
function segment(value) {
|
|
215
|
+
if (!value || value === "." || value === ".." || /[\\/]/.test(value) || [...value].some((char) => char.charCodeAt(0) < 32))
|
|
216
|
+
throw new Error("Invalid review identifier");
|
|
217
|
+
return encodeURIComponent(value);
|
|
218
|
+
}
|
|
219
|
+
var Reviews = class {
|
|
220
|
+
constructor(http) {
|
|
221
|
+
this.http = http;
|
|
222
|
+
}
|
|
223
|
+
http;
|
|
224
|
+
/** Repeatable metadata read: never consumes the final execution result. */
|
|
225
|
+
calculation(executionId, options) {
|
|
226
|
+
return this.http.requestJson("GET", `/executions/${segment(executionId)}/review/calculation`, {
|
|
227
|
+
signal: options.signal,
|
|
228
|
+
query: { organization: options.organization }
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/** Published formula structure only. Compare its version with the review's flowVersion. */
|
|
232
|
+
outline(flowId, options) {
|
|
233
|
+
return this.http.requestJson("GET", `/flows/${segment(flowId)}/outline`, {
|
|
234
|
+
signal: options.signal,
|
|
235
|
+
query: { organization: options.organization }
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
list(options) {
|
|
239
|
+
return this.http.requestJson("GET", "/reviews", {
|
|
240
|
+
signal: options.signal,
|
|
241
|
+
query: {
|
|
242
|
+
organization: options.organization,
|
|
243
|
+
...options.status ? { status: options.status } : {},
|
|
244
|
+
...options.cursor ? { cursor: options.cursor } : {},
|
|
245
|
+
...options.limit ? { limit: String(options.limit) } : {}
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
get(executionId, options) {
|
|
250
|
+
return this.http.requestJson("GET", `/executions/${segment(executionId)}/review`, {
|
|
251
|
+
signal: options.signal,
|
|
252
|
+
query: { organization: options.organization }
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
decide(executionId, decision, options) {
|
|
256
|
+
return this.http.requestJson("POST", `/executions/${segment(executionId)}/review`, {
|
|
257
|
+
signal: options.signal,
|
|
258
|
+
query: { organization: options.organization },
|
|
259
|
+
headers: { "content-type": "application/json" },
|
|
260
|
+
body: JSON.stringify(decision)
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/** Streaming Response: callers own consumption/cancellation. Never buffers the PDF. */
|
|
264
|
+
document(executionId, docKey, resource, options) {
|
|
265
|
+
if (typeof resource === "object" && (!Number.isSafeInteger(resource.page) || resource.page < 1 || resource.page > 999999))
|
|
266
|
+
throw new Error("Invalid page number");
|
|
267
|
+
const path = typeof resource === "object" ? `pages/${resource.page}` : resource;
|
|
268
|
+
const headers = Object.fromEntries(
|
|
269
|
+
Object.entries({
|
|
270
|
+
range: options.range,
|
|
271
|
+
"if-range": options.ifRange,
|
|
272
|
+
"if-none-match": options.ifNoneMatch,
|
|
273
|
+
"if-modified-since": options.ifModifiedSince
|
|
274
|
+
}).filter((entry) => typeof entry[1] === "string")
|
|
275
|
+
);
|
|
276
|
+
return this.http.requestRaw(
|
|
277
|
+
"GET",
|
|
278
|
+
`/executions/${segment(executionId)}/review/documents/${segment(docKey)}/${path}`,
|
|
279
|
+
{
|
|
280
|
+
signal: options.signal,
|
|
281
|
+
headers,
|
|
282
|
+
acceptStatuses: [304, 416],
|
|
283
|
+
query: {
|
|
284
|
+
organization: options.organization,
|
|
285
|
+
...options.version ? { v: options.version } : {},
|
|
286
|
+
...options.size ? { size: options.size } : {}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// src/sdk/execution-events.ts
|
|
294
|
+
var import_node_crypto2 = require("crypto");
|
|
295
|
+
|
|
296
|
+
// src/sdk/review-events.ts
|
|
297
|
+
var import_node_crypto = require("crypto");
|
|
298
|
+
var REVIEW_EVENT_TYPES = [
|
|
299
|
+
"execution.awaiting_review",
|
|
300
|
+
"execution.review_done",
|
|
301
|
+
"execution.review_closed",
|
|
302
|
+
"execution.review_expired"
|
|
303
|
+
];
|
|
304
|
+
var ReviewEventVerificationError = class extends Error {
|
|
305
|
+
constructor(reason) {
|
|
306
|
+
super(`Invalid review event ${reason}`);
|
|
307
|
+
this.reason = reason;
|
|
308
|
+
this.name = "ReviewEventVerificationError";
|
|
309
|
+
}
|
|
310
|
+
reason;
|
|
311
|
+
};
|
|
312
|
+
function parseReviewEventCallback(value) {
|
|
313
|
+
const fail = () => {
|
|
314
|
+
throw new ReviewEventVerificationError("payload");
|
|
315
|
+
};
|
|
316
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return fail();
|
|
317
|
+
const raw = value;
|
|
318
|
+
const text = (key) => {
|
|
319
|
+
const v = raw[key];
|
|
320
|
+
if (typeof v !== "string" || !v.trim() || v.length > 512 || [...v].some((char) => char.charCodeAt(0) < 32))
|
|
321
|
+
return fail();
|
|
322
|
+
return v;
|
|
323
|
+
};
|
|
324
|
+
if (raw.schemaVersion !== 1 || !REVIEW_EVENT_TYPES.includes(raw.type))
|
|
325
|
+
return fail();
|
|
326
|
+
const event = {
|
|
327
|
+
schemaVersion: 1,
|
|
328
|
+
eventId: text("eventId"),
|
|
329
|
+
type: raw.type,
|
|
330
|
+
organization: text("organization"),
|
|
331
|
+
executionResultId: text("executionResultId"),
|
|
332
|
+
reviewId: text("reviewId"),
|
|
333
|
+
publishedAt: text("publishedAt")
|
|
334
|
+
};
|
|
335
|
+
if (!Number.isFinite(Date.parse(event.publishedAt))) return fail();
|
|
336
|
+
for (const key of ["flowId", "nodeId"])
|
|
337
|
+
if (raw[key] !== void 0) event[key] = text(key);
|
|
338
|
+
for (const key of ["flowVersion", "reviewVersion"]) {
|
|
339
|
+
if (raw[key] === void 0) continue;
|
|
340
|
+
if (!Number.isSafeInteger(raw[key]) || Number(raw[key]) < 1) return fail();
|
|
341
|
+
event[key] = Number(raw[key]);
|
|
342
|
+
}
|
|
343
|
+
if (raw.documentKeys !== void 0) {
|
|
344
|
+
if (!Array.isArray(raw.documentKeys) || raw.documentKeys.length > 1e3 || raw.documentKeys.some((v) => typeof v !== "string" || !v || v.length > 512))
|
|
345
|
+
return fail();
|
|
346
|
+
event.documentKeys = raw.documentKeys;
|
|
347
|
+
}
|
|
348
|
+
if (raw.decision !== void 0) {
|
|
349
|
+
if (!["continue", "exclude", "rerun", "reject"].includes(String(raw.decision))) return fail();
|
|
350
|
+
event.decision = raw.decision;
|
|
351
|
+
}
|
|
352
|
+
if (raw.reviewStatus !== void 0) {
|
|
353
|
+
if (!["completed", "rejected", "failed"].includes(String(raw.reviewStatus))) return fail();
|
|
354
|
+
event.reviewStatus = raw.reviewStatus;
|
|
355
|
+
}
|
|
356
|
+
if (event.type === "execution.review_done" && (!event.decision || !event.reviewVersion))
|
|
357
|
+
return fail();
|
|
358
|
+
if (event.type === "execution.review_closed" && !event.reviewStatus) return fail();
|
|
359
|
+
return event;
|
|
360
|
+
}
|
|
361
|
+
function verifyReviewEventCallback(options) {
|
|
362
|
+
const { body, signature, timestamp, secret } = options;
|
|
363
|
+
if (!timestamp || !/^\d{10,13}$/.test(timestamp))
|
|
364
|
+
throw new ReviewEventVerificationError("timestamp");
|
|
365
|
+
const age = Math.abs((options.nowMs ?? Date.now()) / 1e3 - Number(timestamp));
|
|
366
|
+
if (age > (options.toleranceSeconds ?? 300)) throw new ReviewEventVerificationError("timestamp");
|
|
367
|
+
if (secret.length < 32 || !signature || !/^v1=[a-f0-9]{64}$/.test(signature))
|
|
368
|
+
throw new ReviewEventVerificationError("signature");
|
|
369
|
+
const expected = (0, import_node_crypto.createHmac)("sha256", secret).update(`${timestamp}.${body}`).digest();
|
|
370
|
+
if (!(0, import_node_crypto.timingSafeEqual)(expected, Buffer.from(signature.slice(3), "hex")))
|
|
371
|
+
throw new ReviewEventVerificationError("signature");
|
|
372
|
+
let value;
|
|
373
|
+
try {
|
|
374
|
+
value = JSON.parse(body);
|
|
375
|
+
} catch {
|
|
376
|
+
throw new ReviewEventVerificationError("payload");
|
|
377
|
+
}
|
|
378
|
+
const event = parseReviewEventCallback(value);
|
|
379
|
+
if (options.organization !== void 0 && event.organization !== options.organization)
|
|
380
|
+
throw new ReviewEventVerificationError("organization");
|
|
381
|
+
return event;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/sdk/execution-events.ts
|
|
385
|
+
var EXECUTION_NODE_EVENT_TYPES = [
|
|
386
|
+
"execution.node.started",
|
|
387
|
+
"execution.node.completed",
|
|
388
|
+
"execution.node.failed",
|
|
389
|
+
"execution.node.reused"
|
|
390
|
+
];
|
|
391
|
+
function parseExecutionEventCallback(value) {
|
|
392
|
+
const raw = value;
|
|
393
|
+
if (!raw || !EXECUTION_NODE_EVENT_TYPES.includes(raw.type))
|
|
394
|
+
return parseReviewEventCallback(value);
|
|
395
|
+
const fail = () => {
|
|
396
|
+
throw new ReviewEventVerificationError("payload");
|
|
397
|
+
};
|
|
398
|
+
const text = (key) => {
|
|
399
|
+
const v = raw[key];
|
|
400
|
+
return typeof v === "string" && v.length > 0 && v.length <= 512 && [...v].every((c) => c.charCodeAt(0) >= 32) ? v : fail();
|
|
401
|
+
};
|
|
402
|
+
const integer = (key) => Number.isSafeInteger(raw[key]) && Number(raw[key]) >= 1 ? Number(raw[key]) : fail();
|
|
403
|
+
if (raw.schemaVersion !== 1) return fail();
|
|
404
|
+
const event = {
|
|
405
|
+
schemaVersion: 1,
|
|
406
|
+
eventId: text("eventId"),
|
|
407
|
+
type: raw.type,
|
|
408
|
+
organization: text("organization"),
|
|
409
|
+
executionResultId: text("executionResultId"),
|
|
410
|
+
sequence: integer("sequence"),
|
|
411
|
+
occurredAt: text("occurredAt"),
|
|
412
|
+
nodeId: text("nodeId"),
|
|
413
|
+
nodeType: text("nodeType"),
|
|
414
|
+
revision: integer("revision"),
|
|
415
|
+
attemptId: text("attemptId"),
|
|
416
|
+
documentKeys: []
|
|
417
|
+
};
|
|
418
|
+
if (!Number.isFinite(Date.parse(event.occurredAt))) return fail();
|
|
419
|
+
if (!Array.isArray(raw.documentKeys) || !raw.documentKeys.length || raw.documentKeys.length > 1e3 || raw.documentKeys.some(
|
|
420
|
+
(v) => typeof v !== "string" || !v || v.length > 512 || [...v].some((c) => c.charCodeAt(0) < 32)
|
|
421
|
+
))
|
|
422
|
+
return fail();
|
|
423
|
+
event.documentKeys = raw.documentKeys;
|
|
424
|
+
if (raw.flowId !== void 0) event.flowId = text("flowId");
|
|
425
|
+
if (raw.flowVersion !== void 0) event.flowVersion = integer("flowVersion");
|
|
426
|
+
if (raw.publishedAt !== void 0) {
|
|
427
|
+
event.publishedAt = text("publishedAt");
|
|
428
|
+
if (!Number.isFinite(Date.parse(event.publishedAt))) return fail();
|
|
429
|
+
}
|
|
430
|
+
return event;
|
|
431
|
+
}
|
|
432
|
+
function verifyExecutionEventCallback(options) {
|
|
433
|
+
const { body, signature, timestamp, secret } = options;
|
|
434
|
+
if (!timestamp || !/^\d{10,13}$/.test(timestamp) || Math.abs((options.nowMs ?? Date.now()) / 1e3 - Number(timestamp)) > (options.toleranceSeconds ?? 300))
|
|
435
|
+
throw new ReviewEventVerificationError("timestamp");
|
|
436
|
+
if (secret.length < 32 || !signature || !/^v1=[a-f0-9]{64}$/.test(signature))
|
|
437
|
+
throw new ReviewEventVerificationError("signature");
|
|
438
|
+
const expected = (0, import_node_crypto2.createHmac)("sha256", secret).update(`${timestamp}.${body}`).digest();
|
|
439
|
+
if (!(0, import_node_crypto2.timingSafeEqual)(expected, Buffer.from(signature.slice(3), "hex")))
|
|
440
|
+
throw new ReviewEventVerificationError("signature");
|
|
441
|
+
let value;
|
|
442
|
+
try {
|
|
443
|
+
value = JSON.parse(body);
|
|
444
|
+
} catch {
|
|
445
|
+
throw new ReviewEventVerificationError("payload");
|
|
446
|
+
}
|
|
447
|
+
const event = parseExecutionEventCallback(value);
|
|
448
|
+
if (options.organization !== void 0 && event.organization !== options.organization)
|
|
449
|
+
throw new ReviewEventVerificationError("organization");
|
|
450
|
+
return event;
|
|
451
|
+
}
|
|
452
|
+
var ExecutionEvents = class {
|
|
453
|
+
constructor(http) {
|
|
454
|
+
this.http = http;
|
|
455
|
+
}
|
|
456
|
+
http;
|
|
457
|
+
/** One bounded page; never polls for completion or consumes a final result. */
|
|
458
|
+
async list(id, options) {
|
|
459
|
+
const after = options.after ?? 0, limit = options.limit ?? 100;
|
|
460
|
+
if (!id || id.length > 512 || id === "." || id === ".." || /[\\/]/.test(id) || [...id].some((c) => c.charCodeAt(0) < 32) || !options.organization?.trim() || !Number.isSafeInteger(after) || after < 0 || !Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
461
|
+
throw new Error("Invalid execution event query");
|
|
462
|
+
const page = await this.http.requestJson(
|
|
463
|
+
"GET",
|
|
464
|
+
`/executions/${encodeURIComponent(id)}/events`,
|
|
465
|
+
{
|
|
466
|
+
signal: options.signal,
|
|
467
|
+
query: { organization: options.organization, after: String(after), limit: String(limit) }
|
|
468
|
+
}
|
|
469
|
+
);
|
|
470
|
+
if (page.executionResultId !== id || !Array.isArray(page.events) || page.events.length > limit || !Number.isSafeInteger(page.lastSequence) || page.lastSequence < 0 || typeof page.truncated !== "boolean")
|
|
471
|
+
throw new ReviewEventVerificationError("payload");
|
|
472
|
+
const events = page.events.map((value) => parseExecutionEventCallback(value));
|
|
473
|
+
if (events.some(
|
|
474
|
+
(event, i) => !("sequence" in event) || event.executionResultId !== id || event.organization !== options.organization || event.sequence <= (i ? events[i - 1].sequence : after) || event.sequence > page.lastSequence
|
|
475
|
+
))
|
|
476
|
+
throw new ReviewEventVerificationError("payload");
|
|
477
|
+
if (page.nextAfter !== null && (!Number.isSafeInteger(page.nextAfter) || page.nextAfter <= after || page.nextAfter !== events.at(-1)?.sequence))
|
|
478
|
+
throw new ReviewEventVerificationError("payload");
|
|
479
|
+
return { ...page, events };
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
|
|
204
483
|
// src/sdk/errors.ts
|
|
205
484
|
var DocmanaError = class extends Error {
|
|
206
485
|
status;
|
|
@@ -208,6 +487,7 @@ var DocmanaError = class extends Error {
|
|
|
208
487
|
code;
|
|
209
488
|
/** Public API business code; `code` retains the SDK's existing error category. */
|
|
210
489
|
apiCode;
|
|
490
|
+
reviewConflict;
|
|
211
491
|
constructor(message, opts = {}) {
|
|
212
492
|
super(message);
|
|
213
493
|
this.name = new.target.name;
|
|
@@ -333,7 +613,7 @@ var HttpClient = class {
|
|
|
333
613
|
if (res.status === 401 && this.opts.getAccessToken) {
|
|
334
614
|
res = await this.send(method, path, options, true);
|
|
335
615
|
}
|
|
336
|
-
if (!res.ok) {
|
|
616
|
+
if (!res.ok && !options.acceptStatuses?.includes(res.status)) {
|
|
337
617
|
const requestId = res.headers.get("x-request-id") ?? void 0;
|
|
338
618
|
const message = await this.extractMessage(res);
|
|
339
619
|
const error = errorFromResponse(
|
|
@@ -345,6 +625,11 @@ var HttpClient = class {
|
|
|
345
625
|
const data = await res.clone().json().catch(() => null);
|
|
346
626
|
if (typeof data?.code === "string" && /^[A-Za-z][A-Za-z0-9_]{0,99}$/.test(data.code))
|
|
347
627
|
Object.defineProperty(error, "apiCode", { value: data.code, enumerable: true });
|
|
628
|
+
if (res.status === 409 && isRecord(data?.details))
|
|
629
|
+
Object.defineProperty(error, "reviewConflict", {
|
|
630
|
+
value: reviewConflictDetails(data.details),
|
|
631
|
+
enumerable: true
|
|
632
|
+
});
|
|
348
633
|
throw error;
|
|
349
634
|
}
|
|
350
635
|
return res;
|
|
@@ -388,6 +673,32 @@ var HttpClient = class {
|
|
|
388
673
|
}
|
|
389
674
|
}
|
|
390
675
|
};
|
|
676
|
+
function isRecord(value) {
|
|
677
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
678
|
+
}
|
|
679
|
+
function reviewConflictDetails(raw) {
|
|
680
|
+
const text = (value, limit) => typeof value === "string" ? value.slice(0, limit) : null;
|
|
681
|
+
const version = (value) => Number.isSafeInteger(value) && Number(value) >= 1 ? value : null;
|
|
682
|
+
const actor = isRecord(raw.decidedBy) ? raw.decidedBy : {};
|
|
683
|
+
const id = text(actor.id, 200);
|
|
684
|
+
const name = text(actor.name, 200);
|
|
685
|
+
const source = actor.source === "integrator" || actor.source === "token" ? actor.source : null;
|
|
686
|
+
const decidedBy = id !== null || name !== null || source !== null ? {
|
|
687
|
+
...id !== null ? { id } : {},
|
|
688
|
+
...name !== null ? { name } : {},
|
|
689
|
+
...source ? { source } : {}
|
|
690
|
+
} : null;
|
|
691
|
+
const currentVersion = version(raw.currentVersion) ?? version(raw.version);
|
|
692
|
+
const decidedAt = text(raw.decidedAt, 40) ?? text(raw.submittedAt, 40);
|
|
693
|
+
return {
|
|
694
|
+
currentVersion,
|
|
695
|
+
decidedBy,
|
|
696
|
+
decidedAt,
|
|
697
|
+
version: currentVersion,
|
|
698
|
+
submittedBy: id ?? name ?? text(raw.submittedBy, 200),
|
|
699
|
+
submittedAt: decidedAt
|
|
700
|
+
};
|
|
701
|
+
}
|
|
391
702
|
function parseRetryAfterMs(value) {
|
|
392
703
|
if (!value) return void 0;
|
|
393
704
|
const seconds = Number(value);
|
|
@@ -846,6 +1157,8 @@ function fullJitterDelay(intervalMs, maxIntervalMs, attempt, random) {
|
|
|
846
1157
|
// src/sdk/client.ts
|
|
847
1158
|
var Docmana = class {
|
|
848
1159
|
authoring;
|
|
1160
|
+
reviews;
|
|
1161
|
+
executionEvents;
|
|
849
1162
|
config;
|
|
850
1163
|
http;
|
|
851
1164
|
constructor(config) {
|
|
@@ -858,6 +1171,8 @@ var Docmana = class {
|
|
|
858
1171
|
headers: this.config.headers
|
|
859
1172
|
});
|
|
860
1173
|
this.authoring = new FormulaAuthoring(this.http);
|
|
1174
|
+
this.reviews = new Reviews(this.http);
|
|
1175
|
+
this.executionEvents = new ExecutionEvents(this.http);
|
|
861
1176
|
}
|
|
862
1177
|
async runFlowAsync(flowId, params, options = {}) {
|
|
863
1178
|
const parts = await resolveInputs(params);
|
|
@@ -1044,6 +1359,15 @@ function isTransientPollingError(error) {
|
|
|
1044
1359
|
DocmanaRequestError,
|
|
1045
1360
|
DocmanaServiceUnavailableError,
|
|
1046
1361
|
DocmanaTimeoutError,
|
|
1047
|
-
|
|
1362
|
+
EXECUTION_NODE_EVENT_TYPES,
|
|
1363
|
+
ExecutionEvents,
|
|
1364
|
+
FormulaAuthoring,
|
|
1365
|
+
REVIEW_EVENT_TYPES,
|
|
1366
|
+
ReviewEventVerificationError,
|
|
1367
|
+
Reviews,
|
|
1368
|
+
parseExecutionEventCallback,
|
|
1369
|
+
parseReviewEventCallback,
|
|
1370
|
+
verifyExecutionEventCallback,
|
|
1371
|
+
verifyReviewEventCallback
|
|
1048
1372
|
});
|
|
1049
1373
|
//# sourceMappingURL=index.js.map
|