unfazed 0.4.0 → 0.6.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/README.md +323 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +25 -0
- package/dist/errors.js +25 -0
- package/dist/errors.js.map +1 -1
- package/dist/generated/gql.d.ts +5 -1
- package/dist/generated/gql.js +2 -1
- package/dist/generated/gql.js.map +1 -1
- package/dist/generated/graphql.d.ts +107 -0
- package/dist/generated/graphql.js +101 -0
- package/dist/generated/graphql.js.map +1 -1
- package/dist/index.d.ts +21 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/operations.d.ts +3 -0
- package/dist/operations.js +23 -0
- package/dist/operations.js.map +1 -1
- package/dist/remote/app.d.ts +18 -0
- package/dist/remote/app.js +76 -0
- package/dist/remote/app.js.map +1 -0
- package/dist/remote/documents.d.ts +175 -0
- package/dist/remote/documents.js +122 -0
- package/dist/remote/documents.js.map +1 -0
- package/dist/remote/values.d.ts +67 -0
- package/dist/remote/values.js +156 -0
- package/dist/remote/values.js.map +1 -0
- package/dist/remote/world.d.ts +50 -0
- package/dist/remote/world.js +612 -0
- package/dist/remote/world.js.map +1 -0
- package/dist/unfazed.d.ts +37 -1
- package/dist/unfazed.js +13 -1
- package/dist/unfazed.js.map +1 -1
- package/dist/workflow/config.d.ts +23 -0
- package/dist/workflow/config.js +48 -0
- package/dist/workflow/config.js.map +1 -0
- package/dist/workflow/errors.d.ts +33 -0
- package/dist/workflow/errors.js +16 -0
- package/dist/workflow/errors.js.map +1 -0
- package/dist/workflow/index.d.ts +30 -0
- package/dist/workflow/index.js +23 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/inspect-render.d.ts +93 -0
- package/dist/workflow/inspect-render.js +302 -0
- package/dist/workflow/inspect-render.js.map +1 -0
- package/dist/workflow/inspect.d.ts +52 -0
- package/dist/workflow/inspect.js +879 -0
- package/dist/workflow/inspect.js.map +1 -0
- package/dist/workflow/migration-files.d.ts +13 -0
- package/dist/workflow/migration-files.js +52 -0
- package/dist/workflow/migration-files.js.map +1 -0
- package/dist/workflow/migration-types.d.ts +19 -0
- package/dist/workflow/migration-types.js +8 -0
- package/dist/workflow/migration-types.js.map +1 -0
- package/dist/workflow/migrations.d.ts +12 -0
- package/dist/workflow/migrations.generated.d.ts +2 -0
- package/dist/workflow/migrations.generated.js +34 -0
- package/dist/workflow/migrations.generated.js.map +1 -0
- package/dist/workflow/migrations.js +94 -0
- package/dist/workflow/migrations.js.map +1 -0
- package/dist/workflow/nitro-flow-guard.d.ts +4 -0
- package/dist/workflow/nitro-flow-guard.js +19 -0
- package/dist/workflow/nitro-flow-guard.js.map +1 -0
- package/dist/workflow/nitro-inspect.d.ts +3 -0
- package/dist/workflow/nitro-inspect.js +19 -0
- package/dist/workflow/nitro-inspect.js.map +1 -0
- package/dist/workflow/nitro-plugin.d.ts +1 -0
- package/dist/workflow/nitro-plugin.js +13 -0
- package/dist/workflow/nitro-plugin.js.map +1 -0
- package/dist/workflow/nitro.d.ts +70 -0
- package/dist/workflow/nitro.js +213 -0
- package/dist/workflow/nitro.js.map +1 -0
- package/dist/workflow/public-url.d.ts +27 -0
- package/dist/workflow/public-url.js +45 -0
- package/dist/workflow/public-url.js.map +1 -0
- package/dist/workflow/queue.d.ts +128 -0
- package/dist/workflow/queue.js +375 -0
- package/dist/workflow/queue.js.map +1 -0
- package/dist/workflow/state.d.ts +25 -0
- package/dist/workflow/state.js +15 -0
- package/dist/workflow/state.js.map +1 -0
- package/dist/workflow/transport.d.ts +12 -0
- package/dist/workflow/transport.js +29 -0
- package/dist/workflow/transport.js.map +1 -0
- package/dist/workflow/world.d.ts +123 -0
- package/dist/workflow/world.js +375 -0
- package/dist/workflow/world.js.map +1 -0
- package/package.json +66 -5
- package/schema/SOURCE.json +4 -4
- package/schema/schema.graphqls +36 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `unfazed/workflow` — the unfazed World for Workflow SDK.
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* import { setWorld } from "workflow/runtime";
|
|
6
|
+
* import { createWorld } from "unfazed/workflow";
|
|
7
|
+
*
|
|
8
|
+
* setWorld(createWorld()); // before the server serves
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* With Nitro, add `"unfazed/workflow/nitro"` to `modules` instead; it does
|
|
12
|
+
* exactly that for you. Requires the optional peers `workflow`,
|
|
13
|
+
* `@workflow/world` and `@workflow/world-postgres`.
|
|
14
|
+
*/
|
|
15
|
+
export { createWorld, LOCAL_DEPLOYMENT_ID } from "./world.js";
|
|
16
|
+
export { UnfazedWorkflowError } from "./errors.js";
|
|
17
|
+
export { DATABASE_URL_VARS, resolveDatabaseUrl, withLibpqCompat } from "./config.js";
|
|
18
|
+
export { applyPublicUrl } from "./public-url.js";
|
|
19
|
+
export { DELIVERY_HEADERS, QUEUE_API_PATH, verifyQueueToken } from "./queue.js";
|
|
20
|
+
export { createInspectHandler, INSPECT_BASE_PATH, INSPECT_CONTRACT_VERSION } from "./inspect.js";
|
|
21
|
+
export { MIGRATIONS_SCHEMA, MIGRATIONS_TABLE } from "./migration-types.js";
|
|
22
|
+
export { embeddedMigrations } from "./migrations.generated.js";
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workflow/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAIjG,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC","sourcesContent":["/**\n * `unfazed/workflow` — the unfazed World for Workflow SDK.\n *\n * ```ts\n * import { setWorld } from \"workflow/runtime\";\n * import { createWorld } from \"unfazed/workflow\";\n *\n * setWorld(createWorld()); // before the server serves\n * ```\n *\n * With Nitro, add `\"unfazed/workflow/nitro\"` to `modules` instead; it does\n * exactly that for you. Requires the optional peers `workflow`,\n * `@workflow/world` and `@workflow/world-postgres`.\n */\nexport { createWorld, LOCAL_DEPLOYMENT_ID } from \"./world.js\";\nexport type { UnfazedWorld, UnfazedWorldOptions } from \"./world.js\";\nexport { UnfazedWorkflowError } from \"./errors.js\";\nexport type { UnfazedWorkflowErrorCode } from \"./errors.js\";\nexport { DATABASE_URL_VARS, resolveDatabaseUrl, withLibpqCompat } from \"./config.js\";\nexport { applyPublicUrl } from \"./public-url.js\";\nexport type { PublicUrlResult } from \"./public-url.js\";\nexport type { WorkflowEnv } from \"./config.js\";\nexport { DELIVERY_HEADERS, QUEUE_API_PATH, verifyQueueToken } from \"./queue.js\";\nexport { createInspectHandler, INSPECT_BASE_PATH, INSPECT_CONTRACT_VERSION } from \"./inspect.js\";\nexport type { InspectHandlerOptions, InspectRunHandle } from \"./inspect.js\";\nexport type { InspectError, InspectValue } from \"./inspect-render.js\";\nexport type { QueueStats, WorkflowFetch } from \"./queue.js\";\nexport { MIGRATIONS_SCHEMA, MIGRATIONS_TABLE } from \"./migration-types.js\";\nexport type { WorkflowMigrations } from \"./migration-types.js\";\nexport { embeddedMigrations } from \"./migrations.generated.js\";\n"]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** A payload as display text (`Value` in the contract). */
|
|
2
|
+
export interface InspectValue {
|
|
3
|
+
text: string;
|
|
4
|
+
/** UTF-8 length of the whole text, before any cut. */
|
|
5
|
+
bytes: number;
|
|
6
|
+
truncated: boolean;
|
|
7
|
+
/** Present (true) only when the payload could not be hydrated; `text` is the reason. */
|
|
8
|
+
error?: true;
|
|
9
|
+
}
|
|
10
|
+
/** A thrown run or step error (`Error` in the contract). */
|
|
11
|
+
export interface InspectError {
|
|
12
|
+
message: string;
|
|
13
|
+
stack: string | null;
|
|
14
|
+
code: string | null;
|
|
15
|
+
truncated: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare const MESSAGE_CAP_BYTES: number;
|
|
18
|
+
export declare const STACK_CAP_BYTES: number;
|
|
19
|
+
export declare const INFO_CAP_BYTES: number;
|
|
20
|
+
export interface DisplayOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Strings to replace with `[redacted]` wherever they occur in a string
|
|
23
|
+
* (hook tokens, so neither a token nor a webhook URL built from one leaves).
|
|
24
|
+
*/
|
|
25
|
+
secrets?: readonly string[];
|
|
26
|
+
/** Drop every object key named `token`, at any depth. */
|
|
27
|
+
dropTokenKeys?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare const REDACTED = "[redacted]";
|
|
30
|
+
/** Workflow SDK's webhook route; the path segment after it is the hook's token. */
|
|
31
|
+
export declare const WEBHOOK_PATH = "/.well-known/workflow/v1/webhook/";
|
|
32
|
+
/**
|
|
33
|
+
* `text` with the token of every Workflow SDK webhook URL in it replaced by
|
|
34
|
+
* `[redacted]`: `https://app.example/.well-known/workflow/v1/webhook/<token>?a=1`
|
|
35
|
+
* reads `https://app.example/.well-known/workflow/v1/webhook/[redacted]?a=1`.
|
|
36
|
+
* A webhook URL is a capability (anyone holding it resumes the run), so none
|
|
37
|
+
* leaves the route, whatever the app wrote it into.
|
|
38
|
+
*/
|
|
39
|
+
export declare function redactWebhookTokens(text: string): string;
|
|
40
|
+
/** UTF-8 length of `text`. */
|
|
41
|
+
export declare function utf8Length(text: string): number;
|
|
42
|
+
/**
|
|
43
|
+
* `text` cut to at most `capBytes` of UTF-8 on a character boundary, and
|
|
44
|
+
* whether it was cut.
|
|
45
|
+
*/
|
|
46
|
+
export declare function cutUtf8(text: string, capBytes: number): {
|
|
47
|
+
text: string;
|
|
48
|
+
truncated: boolean;
|
|
49
|
+
bytes: number;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The contract's replacer, as a walk that builds a JSON-safe tree:
|
|
53
|
+
* `bigint` → `"123n"`, `undefined` → `null`, `Map` → `{"$map": [[k, v], …]}`,
|
|
54
|
+
* `Set` → `{"$set": […]}`, bytes → `{"$bytes": n}`, `Error` →
|
|
55
|
+
* `{"$error": {name, message, stack}}`, a function → `"[function name]"`, a
|
|
56
|
+
* cycle → `"[circular]"`; anything with `toJSON()` (the revivers' display
|
|
57
|
+
* objects, `Date`, `URL`) goes through it first, as `JSON.stringify` does.
|
|
58
|
+
*/
|
|
59
|
+
export declare function toDisplayJson(value: unknown, options?: DisplayOptions): unknown;
|
|
60
|
+
/** `JSON.stringify(value, replacer, 2)` of the contract. */
|
|
61
|
+
export declare function displayText(value: unknown, options?: DisplayOptions): string;
|
|
62
|
+
/** A hydrated payload as a `Value`, cut at `capBytes`; `undefined`/`null` is `null`. */
|
|
63
|
+
export declare function renderValue(value: unknown, capBytes: number, options?: DisplayOptions): InspectValue | null;
|
|
64
|
+
/** A payload that failed to hydrate (or to render): the error's message, flagged. */
|
|
65
|
+
export declare function failedValue(error: unknown, capBytes: number): InspectValue;
|
|
66
|
+
/**
|
|
67
|
+
* A hydrated run or step error as the contract's `Error`: `message` at most
|
|
68
|
+
* 4 KiB, `stack` at most 8 KiB or `null`, `code` as given.
|
|
69
|
+
*/
|
|
70
|
+
export declare function renderError(hydrated: unknown, code: string | null, failure: unknown, options?: DisplayOptions): InspectError;
|
|
71
|
+
type InfoJson = string | number | boolean | null | InfoJson[] | {
|
|
72
|
+
[key: string]: InfoJson;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* An event's `info`: its `eventData` as `resolveData: "none"` leaves it, every
|
|
76
|
+
* `token` key removed at any depth, only strings, numbers, booleans, `null`
|
|
77
|
+
* and objects/arrays of those kept (a `Date` becomes its RFC 3339 string); at
|
|
78
|
+
* most 2 KiB serialized, else `{}` and truncated.
|
|
79
|
+
*/
|
|
80
|
+
export declare function eventInfo(eventData: unknown): {
|
|
81
|
+
info: Record<string, InfoJson>;
|
|
82
|
+
truncated: boolean;
|
|
83
|
+
};
|
|
84
|
+
/** RFC 3339 UTC with milliseconds, or `null`. */
|
|
85
|
+
export declare function isoTime(value: unknown): string | null;
|
|
86
|
+
/**
|
|
87
|
+
* A step's input as the SDK's own inspector shows it: its arguments. Workflow
|
|
88
|
+
* SDK stores a step's input as `{ args, closureVars, thisVal }`; this answers
|
|
89
|
+
* `args` alone, or `{ args, closureVars?, thisVal? }` with only the parts that
|
|
90
|
+
* hold something. Anything not exactly that envelope is returned as it is.
|
|
91
|
+
*/
|
|
92
|
+
export declare function stepInputDisplay(input: unknown): unknown;
|
|
93
|
+
export {};
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the inspection route turns World data into the display JSON of the
|
|
3
|
+
* contract (unfazed docs/workflow-inspect.md, "Values", "Errors", `Event`).
|
|
4
|
+
* Pure functions, no SDK imports: the caller hydrates, this renders.
|
|
5
|
+
*/
|
|
6
|
+
import { Buffer } from "node:buffer";
|
|
7
|
+
export const MESSAGE_CAP_BYTES = 4 * 1024;
|
|
8
|
+
export const STACK_CAP_BYTES = 8 * 1024;
|
|
9
|
+
export const INFO_CAP_BYTES = 2 * 1024;
|
|
10
|
+
export const REDACTED = "[redacted]";
|
|
11
|
+
/** Workflow SDK's webhook route; the path segment after it is the hook's token. */
|
|
12
|
+
export const WEBHOOK_PATH = "/.well-known/workflow/v1/webhook/";
|
|
13
|
+
// The route as written, also with JSON-escaped slashes (`\/`), then its token:
|
|
14
|
+
// one path segment of RFC 3986 characters (what `encodeURIComponent` emits,
|
|
15
|
+
// plus `%`), so a query string, fragment, quote or space after it stays.
|
|
16
|
+
const WEBHOOK_URL = /(\\?\/\.well-known\\?\/workflow\\?\/v1\\?\/webhook\\?\/)[A-Za-z0-9\-._~!$&'()*+,;=:@%]+/g;
|
|
17
|
+
// The same URL percent-encoded inside another URL (`?next=https%3A%2F%2F…`).
|
|
18
|
+
const WEBHOOK_URL_ENCODED = /(%2F\.well-known%2Fworkflow%2Fv1%2Fwebhook%2F)[A-Za-z0-9\-._~!$'()*+,;:@%]+/gi;
|
|
19
|
+
/**
|
|
20
|
+
* `text` with the token of every Workflow SDK webhook URL in it replaced by
|
|
21
|
+
* `[redacted]`: `https://app.example/.well-known/workflow/v1/webhook/<token>?a=1`
|
|
22
|
+
* reads `https://app.example/.well-known/workflow/v1/webhook/[redacted]?a=1`.
|
|
23
|
+
* A webhook URL is a capability (anyone holding it resumes the run), so none
|
|
24
|
+
* leaves the route, whatever the app wrote it into.
|
|
25
|
+
*/
|
|
26
|
+
export function redactWebhookTokens(text) {
|
|
27
|
+
if (!text.includes("well-known"))
|
|
28
|
+
return text;
|
|
29
|
+
return text.replace(WEBHOOK_URL, `$1${REDACTED}`).replace(WEBHOOK_URL_ENCODED, `$1${REDACTED}`);
|
|
30
|
+
}
|
|
31
|
+
/** UTF-8 length of `text`. */
|
|
32
|
+
export function utf8Length(text) {
|
|
33
|
+
return Buffer.byteLength(text, "utf8");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* `text` cut to at most `capBytes` of UTF-8 on a character boundary, and
|
|
37
|
+
* whether it was cut.
|
|
38
|
+
*/
|
|
39
|
+
export function cutUtf8(text, capBytes) {
|
|
40
|
+
const bytes = utf8Length(text);
|
|
41
|
+
if (bytes <= capBytes)
|
|
42
|
+
return { text, truncated: false, bytes };
|
|
43
|
+
const encoded = Buffer.from(text, "utf8");
|
|
44
|
+
let end = capBytes;
|
|
45
|
+
// Back off continuation bytes (10xxxxxx) so no code point is split.
|
|
46
|
+
while (end > 0 && (encoded[end] & 0xc0) === 0x80)
|
|
47
|
+
end--;
|
|
48
|
+
return { text: encoded.subarray(0, end).toString("utf8"), truncated: true, bytes };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The contract's replacer, as a walk that builds a JSON-safe tree:
|
|
52
|
+
* `bigint` → `"123n"`, `undefined` → `null`, `Map` → `{"$map": [[k, v], …]}`,
|
|
53
|
+
* `Set` → `{"$set": […]}`, bytes → `{"$bytes": n}`, `Error` →
|
|
54
|
+
* `{"$error": {name, message, stack}}`, a function → `"[function name]"`, a
|
|
55
|
+
* cycle → `"[circular]"`; anything with `toJSON()` (the revivers' display
|
|
56
|
+
* objects, `Date`, `URL`) goes through it first, as `JSON.stringify` does.
|
|
57
|
+
*/
|
|
58
|
+
export function toDisplayJson(value, options = {}) {
|
|
59
|
+
const secrets = (options.secrets ?? []).filter((s) => s.length > 0);
|
|
60
|
+
const ancestors = new Set();
|
|
61
|
+
const str = (text) => {
|
|
62
|
+
let out = text;
|
|
63
|
+
for (const secret of secrets)
|
|
64
|
+
if (out.includes(secret))
|
|
65
|
+
out = out.split(secret).join(REDACTED);
|
|
66
|
+
return redactWebhookTokens(out);
|
|
67
|
+
};
|
|
68
|
+
const walk = (input, key) => {
|
|
69
|
+
let v = input;
|
|
70
|
+
if (v !== null && typeof v === "object" && !(v instanceof Error) && !ArrayBuffer.isView(v)) {
|
|
71
|
+
const toJSON = v.toJSON;
|
|
72
|
+
if (typeof toJSON === "function") {
|
|
73
|
+
if (ancestors.has(v))
|
|
74
|
+
return "[circular]";
|
|
75
|
+
v = toJSON.call(v, key);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
switch (typeof v) {
|
|
79
|
+
case "undefined":
|
|
80
|
+
return null;
|
|
81
|
+
case "string":
|
|
82
|
+
return str(v);
|
|
83
|
+
case "number":
|
|
84
|
+
return Number.isFinite(v) ? v : null;
|
|
85
|
+
case "boolean":
|
|
86
|
+
return v;
|
|
87
|
+
case "bigint":
|
|
88
|
+
return `${v}n`;
|
|
89
|
+
case "function":
|
|
90
|
+
return `[function ${v.name || "anonymous"}]`;
|
|
91
|
+
case "symbol":
|
|
92
|
+
return str(v.toString());
|
|
93
|
+
}
|
|
94
|
+
if (v === null)
|
|
95
|
+
return null;
|
|
96
|
+
const obj = v;
|
|
97
|
+
if (obj instanceof ArrayBuffer)
|
|
98
|
+
return { $bytes: obj.byteLength };
|
|
99
|
+
if (ArrayBuffer.isView(obj))
|
|
100
|
+
return { $bytes: obj.byteLength };
|
|
101
|
+
if (ancestors.has(obj))
|
|
102
|
+
return "[circular]";
|
|
103
|
+
ancestors.add(obj);
|
|
104
|
+
try {
|
|
105
|
+
if (obj instanceof Error) {
|
|
106
|
+
return {
|
|
107
|
+
$error: {
|
|
108
|
+
name: str(String(obj.name)),
|
|
109
|
+
message: str(String(obj.message)),
|
|
110
|
+
stack: typeof obj.stack === "string" ? str(obj.stack) : null,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (obj instanceof Map) {
|
|
115
|
+
const entries = [];
|
|
116
|
+
for (const [k, item] of obj) {
|
|
117
|
+
if (options.dropTokenKeys && k === "token")
|
|
118
|
+
continue;
|
|
119
|
+
entries.push([walk(k, ""), walk(item, typeof k === "string" ? k : "")]);
|
|
120
|
+
}
|
|
121
|
+
return { $map: entries };
|
|
122
|
+
}
|
|
123
|
+
if (obj instanceof Set)
|
|
124
|
+
return { $set: [...obj].map((item, i) => walk(item, String(i))) };
|
|
125
|
+
if (typeof Headers !== "undefined" && obj instanceof Headers) {
|
|
126
|
+
const out = {};
|
|
127
|
+
obj.forEach((item, name) => {
|
|
128
|
+
out[name] = str(item);
|
|
129
|
+
});
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
if (obj instanceof RegExp)
|
|
133
|
+
return str(String(obj));
|
|
134
|
+
if (Array.isArray(obj))
|
|
135
|
+
return obj.map((item, i) => walk(item, String(i)));
|
|
136
|
+
const out = {};
|
|
137
|
+
for (const k of Object.keys(obj)) {
|
|
138
|
+
if (options.dropTokenKeys && k === "token")
|
|
139
|
+
continue;
|
|
140
|
+
out[str(k)] = walk(obj[k], k);
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
ancestors.delete(obj);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
return walk(value, "");
|
|
149
|
+
}
|
|
150
|
+
/** `JSON.stringify(value, replacer, 2)` of the contract. */
|
|
151
|
+
export function displayText(value, options = {}) {
|
|
152
|
+
return JSON.stringify(toDisplayJson(value, options), null, 2) ?? "null";
|
|
153
|
+
}
|
|
154
|
+
/** A hydrated payload as a `Value`, cut at `capBytes`; `undefined`/`null` is `null`. */
|
|
155
|
+
export function renderValue(value, capBytes, options = {}) {
|
|
156
|
+
if (value === undefined || value === null)
|
|
157
|
+
return null;
|
|
158
|
+
let text;
|
|
159
|
+
try {
|
|
160
|
+
text = displayText(value, options);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
return failedValue(error, capBytes);
|
|
164
|
+
}
|
|
165
|
+
const cut = cutUtf8(text, capBytes);
|
|
166
|
+
return { text: cut.text, bytes: cut.bytes, truncated: cut.truncated };
|
|
167
|
+
}
|
|
168
|
+
/** A payload that failed to hydrate (or to render): the error's message, flagged. */
|
|
169
|
+
export function failedValue(error, capBytes) {
|
|
170
|
+
const message = redactWebhookTokens(error instanceof Error ? error.message : String(error));
|
|
171
|
+
const cut = cutUtf8(message || "the payload could not be read", capBytes);
|
|
172
|
+
return { text: cut.text, bytes: cut.bytes, truncated: false, error: true };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* A hydrated run or step error as the contract's `Error`: `message` at most
|
|
176
|
+
* 4 KiB, `stack` at most 8 KiB or `null`, `code` as given.
|
|
177
|
+
*/
|
|
178
|
+
export function renderError(hydrated, code, failure, options = {}) {
|
|
179
|
+
let message;
|
|
180
|
+
let stack = null;
|
|
181
|
+
if (failure !== undefined) {
|
|
182
|
+
message = `the error could not be read: ${failure instanceof Error ? failure.message : String(failure)}`;
|
|
183
|
+
}
|
|
184
|
+
else if (hydrated === undefined || hydrated === null) {
|
|
185
|
+
message = "(no error recorded)";
|
|
186
|
+
}
|
|
187
|
+
else if (typeof hydrated === "string") {
|
|
188
|
+
message = hydrated;
|
|
189
|
+
}
|
|
190
|
+
else if (hydrated !== null &&
|
|
191
|
+
typeof hydrated === "object" &&
|
|
192
|
+
typeof hydrated.message === "string") {
|
|
193
|
+
message = hydrated.message;
|
|
194
|
+
const rawStack = hydrated.stack;
|
|
195
|
+
stack = typeof rawStack === "string" ? rawStack : null;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
try {
|
|
199
|
+
message = displayText(hydrated, options);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
message = `the error could not be read: ${error instanceof Error ? error.message : String(error)}`;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const secrets = (options.secrets ?? []).filter((s) => s.length > 0);
|
|
206
|
+
const scrub = (text) => redactWebhookTokens(secrets.reduce((out, secret) => out.split(secret).join(REDACTED), text));
|
|
207
|
+
const m = cutUtf8(scrub(message), MESSAGE_CAP_BYTES);
|
|
208
|
+
const s = stack === null ? null : cutUtf8(scrub(stack), STACK_CAP_BYTES);
|
|
209
|
+
return { message: m.text, stack: s ? s.text : null, code, truncated: m.truncated || (s?.truncated ?? false) };
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* An event's `info`: its `eventData` as `resolveData: "none"` leaves it, every
|
|
213
|
+
* `token` key removed at any depth, only strings, numbers, booleans, `null`
|
|
214
|
+
* and objects/arrays of those kept (a `Date` becomes its RFC 3339 string); at
|
|
215
|
+
* most 2 KiB serialized, else `{}` and truncated.
|
|
216
|
+
*/
|
|
217
|
+
export function eventInfo(eventData) {
|
|
218
|
+
const sanitize = (v, depth) => {
|
|
219
|
+
if (v === null)
|
|
220
|
+
return null;
|
|
221
|
+
if (v instanceof Date)
|
|
222
|
+
return Number.isNaN(v.getTime()) ? undefined : v.toISOString();
|
|
223
|
+
switch (typeof v) {
|
|
224
|
+
case "string":
|
|
225
|
+
return redactWebhookTokens(v);
|
|
226
|
+
case "boolean":
|
|
227
|
+
return v;
|
|
228
|
+
case "number":
|
|
229
|
+
return Number.isFinite(v) ? v : undefined;
|
|
230
|
+
case "object": {
|
|
231
|
+
if (depth > 32 || ArrayBuffer.isView(v) || v instanceof ArrayBuffer)
|
|
232
|
+
return undefined;
|
|
233
|
+
if (Array.isArray(v)) {
|
|
234
|
+
return v.map((item) => sanitize(item, depth + 1)).filter((item) => item !== undefined);
|
|
235
|
+
}
|
|
236
|
+
const proto = Object.getPrototypeOf(v);
|
|
237
|
+
if (proto !== Object.prototype && proto !== null)
|
|
238
|
+
return undefined;
|
|
239
|
+
const out = {};
|
|
240
|
+
for (const [k, item] of Object.entries(v)) {
|
|
241
|
+
if (k === "token")
|
|
242
|
+
continue;
|
|
243
|
+
const clean = sanitize(item, depth + 1);
|
|
244
|
+
if (clean !== undefined)
|
|
245
|
+
out[redactWebhookTokens(k)] = clean;
|
|
246
|
+
}
|
|
247
|
+
return out;
|
|
248
|
+
}
|
|
249
|
+
default:
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
const clean = sanitize(eventData ?? {}, 0);
|
|
254
|
+
const info = clean !== null && typeof clean === "object" && !Array.isArray(clean) ? clean : {};
|
|
255
|
+
if (utf8Length(JSON.stringify(info)) > INFO_CAP_BYTES)
|
|
256
|
+
return { info: {}, truncated: true };
|
|
257
|
+
return { info, truncated: false };
|
|
258
|
+
}
|
|
259
|
+
/** RFC 3339 UTC with milliseconds, or `null`. */
|
|
260
|
+
export function isoTime(value) {
|
|
261
|
+
if (value === undefined || value === null)
|
|
262
|
+
return null;
|
|
263
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
264
|
+
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* A step's input as the SDK's own inspector shows it: its arguments. Workflow
|
|
268
|
+
* SDK stores a step's input as `{ args, closureVars, thisVal }`; this answers
|
|
269
|
+
* `args` alone, or `{ args, closureVars?, thisVal? }` with only the parts that
|
|
270
|
+
* hold something. Anything not exactly that envelope is returned as it is.
|
|
271
|
+
*/
|
|
272
|
+
export function stepInputDisplay(input) {
|
|
273
|
+
if (input === null || typeof input !== "object" || Array.isArray(input))
|
|
274
|
+
return input;
|
|
275
|
+
const proto = Object.getPrototypeOf(input);
|
|
276
|
+
if (proto !== Object.prototype && proto !== null)
|
|
277
|
+
return input;
|
|
278
|
+
const keys = Object.keys(input);
|
|
279
|
+
if (!keys.includes("args") || keys.some((k) => k !== "args" && k !== "closureVars" && k !== "thisVal"))
|
|
280
|
+
return input;
|
|
281
|
+
const { args, closureVars, thisVal } = input;
|
|
282
|
+
if (!Array.isArray(args))
|
|
283
|
+
return input;
|
|
284
|
+
const extra = {};
|
|
285
|
+
if (!isEmpty(closureVars))
|
|
286
|
+
extra.closureVars = closureVars;
|
|
287
|
+
if (thisVal !== undefined && thisVal !== null)
|
|
288
|
+
extra.thisVal = thisVal;
|
|
289
|
+
return Object.keys(extra).length === 0 ? args : { args, ...extra };
|
|
290
|
+
}
|
|
291
|
+
function isEmpty(value) {
|
|
292
|
+
if (value === undefined || value === null)
|
|
293
|
+
return true;
|
|
294
|
+
if (Array.isArray(value))
|
|
295
|
+
return value.length === 0;
|
|
296
|
+
if (value instanceof Map || value instanceof Set)
|
|
297
|
+
return value.size === 0;
|
|
298
|
+
if (typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype)
|
|
299
|
+
return Object.keys(value).length === 0;
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=inspect-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect-render.js","sourceRoot":"","sources":["../../src/workflow/inspect-render.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * How the inspection route turns World data into the display JSON of the\n * contract (unfazed docs/workflow-inspect.md, \"Values\", \"Errors\", `Event`).\n * Pure functions, no SDK imports: the caller hydrates, this renders.\n */\nimport { Buffer } from \"node:buffer\";\n\n/** A payload as display text (`Value` in the contract). */\nexport interface InspectValue {\n text: string;\n /** UTF-8 length of the whole text, before any cut. */\n bytes: number;\n truncated: boolean;\n /** Present (true) only when the payload could not be hydrated; `text` is the reason. */\n error?: true;\n}\n\n/** A thrown run or step error (`Error` in the contract). */\nexport interface InspectError {\n message: string;\n stack: string | null;\n code: string | null;\n truncated: boolean;\n}\n\nexport const MESSAGE_CAP_BYTES = 4 * 1024;\nexport const STACK_CAP_BYTES = 8 * 1024;\nexport const INFO_CAP_BYTES = 2 * 1024;\n\nexport interface DisplayOptions {\n /**\n * Strings to replace with `[redacted]` wherever they occur in a string\n * (hook tokens, so neither a token nor a webhook URL built from one leaves).\n */\n secrets?: readonly string[];\n /** Drop every object key named `token`, at any depth. */\n dropTokenKeys?: boolean;\n}\n\nexport const REDACTED = \"[redacted]\";\n\n/** Workflow SDK's webhook route; the path segment after it is the hook's token. */\nexport const WEBHOOK_PATH = \"/.well-known/workflow/v1/webhook/\";\n\n// The route as written, also with JSON-escaped slashes (`\\/`), then its token:\n// one path segment of RFC 3986 characters (what `encodeURIComponent` emits,\n// plus `%`), so a query string, fragment, quote or space after it stays.\nconst WEBHOOK_URL = /(\\\\?\\/\\.well-known\\\\?\\/workflow\\\\?\\/v1\\\\?\\/webhook\\\\?\\/)[A-Za-z0-9\\-._~!$&'()*+,;=:@%]+/g;\n// The same URL percent-encoded inside another URL (`?next=https%3A%2F%2F…`).\nconst WEBHOOK_URL_ENCODED = /(%2F\\.well-known%2Fworkflow%2Fv1%2Fwebhook%2F)[A-Za-z0-9\\-._~!$'()*+,;:@%]+/gi;\n\n/**\n * `text` with the token of every Workflow SDK webhook URL in it replaced by\n * `[redacted]`: `https://app.example/.well-known/workflow/v1/webhook/<token>?a=1`\n * reads `https://app.example/.well-known/workflow/v1/webhook/[redacted]?a=1`.\n * A webhook URL is a capability (anyone holding it resumes the run), so none\n * leaves the route, whatever the app wrote it into.\n */\nexport function redactWebhookTokens(text: string): string {\n if (!text.includes(\"well-known\")) return text;\n return text.replace(WEBHOOK_URL, `$1${REDACTED}`).replace(WEBHOOK_URL_ENCODED, `$1${REDACTED}`);\n}\n\n/** UTF-8 length of `text`. */\nexport function utf8Length(text: string): number {\n return Buffer.byteLength(text, \"utf8\");\n}\n\n/**\n * `text` cut to at most `capBytes` of UTF-8 on a character boundary, and\n * whether it was cut.\n */\nexport function cutUtf8(text: string, capBytes: number): { text: string; truncated: boolean; bytes: number } {\n const bytes = utf8Length(text);\n if (bytes <= capBytes) return { text, truncated: false, bytes };\n const encoded = Buffer.from(text, \"utf8\");\n let end = capBytes;\n // Back off continuation bytes (10xxxxxx) so no code point is split.\n while (end > 0 && (encoded[end]! & 0xc0) === 0x80) end--;\n return { text: encoded.subarray(0, end).toString(\"utf8\"), truncated: true, bytes };\n}\n\n/**\n * The contract's replacer, as a walk that builds a JSON-safe tree:\n * `bigint` → `\"123n\"`, `undefined` → `null`, `Map` → `{\"$map\": [[k, v], …]}`,\n * `Set` → `{\"$set\": […]}`, bytes → `{\"$bytes\": n}`, `Error` →\n * `{\"$error\": {name, message, stack}}`, a function → `\"[function name]\"`, a\n * cycle → `\"[circular]\"`; anything with `toJSON()` (the revivers' display\n * objects, `Date`, `URL`) goes through it first, as `JSON.stringify` does.\n */\nexport function toDisplayJson(value: unknown, options: DisplayOptions = {}): unknown {\n const secrets = (options.secrets ?? []).filter((s) => s.length > 0);\n const ancestors = new Set<object>();\n\n const str = (text: string): string => {\n let out = text;\n for (const secret of secrets) if (out.includes(secret)) out = out.split(secret).join(REDACTED);\n return redactWebhookTokens(out);\n };\n\n const walk = (input: unknown, key: string): unknown => {\n let v = input;\n if (v !== null && typeof v === \"object\" && !(v instanceof Error) && !ArrayBuffer.isView(v)) {\n const toJSON = (v as { toJSON?: unknown }).toJSON;\n if (typeof toJSON === \"function\") {\n if (ancestors.has(v as object)) return \"[circular]\";\n v = (toJSON as (k: string) => unknown).call(v, key);\n }\n }\n switch (typeof v) {\n case \"undefined\":\n return null;\n case \"string\":\n return str(v);\n case \"number\":\n return Number.isFinite(v) ? v : null;\n case \"boolean\":\n return v;\n case \"bigint\":\n return `${v}n`;\n case \"function\":\n return `[function ${(v as { name?: string }).name || \"anonymous\"}]`;\n case \"symbol\":\n return str(v.toString());\n }\n if (v === null) return null;\n const obj = v as object;\n if (obj instanceof ArrayBuffer) return { $bytes: obj.byteLength };\n if (ArrayBuffer.isView(obj)) return { $bytes: obj.byteLength };\n if (ancestors.has(obj)) return \"[circular]\";\n ancestors.add(obj);\n try {\n if (obj instanceof Error) {\n return {\n $error: {\n name: str(String(obj.name)),\n message: str(String(obj.message)),\n stack: typeof obj.stack === \"string\" ? str(obj.stack) : null,\n },\n };\n }\n if (obj instanceof Map) {\n const entries: unknown[] = [];\n for (const [k, item] of obj) {\n if (options.dropTokenKeys && k === \"token\") continue;\n entries.push([walk(k, \"\"), walk(item, typeof k === \"string\" ? k : \"\")]);\n }\n return { $map: entries };\n }\n if (obj instanceof Set) return { $set: [...obj].map((item, i) => walk(item, String(i))) };\n if (typeof Headers !== \"undefined\" && obj instanceof Headers) {\n const out: Record<string, unknown> = {};\n obj.forEach((item, name) => {\n out[name] = str(item);\n });\n return out;\n }\n if (obj instanceof RegExp) return str(String(obj));\n if (Array.isArray(obj)) return obj.map((item, i) => walk(item, String(i)));\n const out: Record<string, unknown> = {};\n for (const k of Object.keys(obj)) {\n if (options.dropTokenKeys && k === \"token\") continue;\n out[str(k)] = walk((obj as Record<string, unknown>)[k], k);\n }\n return out;\n } finally {\n ancestors.delete(obj);\n }\n };\n\n return walk(value, \"\");\n}\n\n/** `JSON.stringify(value, replacer, 2)` of the contract. */\nexport function displayText(value: unknown, options: DisplayOptions = {}): string {\n return JSON.stringify(toDisplayJson(value, options), null, 2) ?? \"null\";\n}\n\n/** A hydrated payload as a `Value`, cut at `capBytes`; `undefined`/`null` is `null`. */\nexport function renderValue(value: unknown, capBytes: number, options: DisplayOptions = {}): InspectValue | null {\n if (value === undefined || value === null) return null;\n let text: string;\n try {\n text = displayText(value, options);\n } catch (error) {\n return failedValue(error, capBytes);\n }\n const cut = cutUtf8(text, capBytes);\n return { text: cut.text, bytes: cut.bytes, truncated: cut.truncated };\n}\n\n/** A payload that failed to hydrate (or to render): the error's message, flagged. */\nexport function failedValue(error: unknown, capBytes: number): InspectValue {\n const message = redactWebhookTokens(error instanceof Error ? error.message : String(error));\n const cut = cutUtf8(message || \"the payload could not be read\", capBytes);\n return { text: cut.text, bytes: cut.bytes, truncated: false, error: true };\n}\n\n/**\n * A hydrated run or step error as the contract's `Error`: `message` at most\n * 4 KiB, `stack` at most 8 KiB or `null`, `code` as given.\n */\nexport function renderError(\n hydrated: unknown,\n code: string | null,\n failure: unknown,\n options: DisplayOptions = {},\n): InspectError {\n let message: string;\n let stack: string | null = null;\n if (failure !== undefined) {\n message = `the error could not be read: ${failure instanceof Error ? failure.message : String(failure)}`;\n } else if (hydrated === undefined || hydrated === null) {\n message = \"(no error recorded)\";\n } else if (typeof hydrated === \"string\") {\n message = hydrated;\n } else if (\n hydrated !== null &&\n typeof hydrated === \"object\" &&\n typeof (hydrated as { message?: unknown }).message === \"string\"\n ) {\n message = (hydrated as { message: string }).message;\n const rawStack = (hydrated as { stack?: unknown }).stack;\n stack = typeof rawStack === \"string\" ? rawStack : null;\n } else {\n try {\n message = displayText(hydrated, options);\n } catch (error) {\n message = `the error could not be read: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n const secrets = (options.secrets ?? []).filter((s) => s.length > 0);\n const scrub = (text: string) =>\n redactWebhookTokens(secrets.reduce((out, secret) => out.split(secret).join(REDACTED), text));\n const m = cutUtf8(scrub(message), MESSAGE_CAP_BYTES);\n const s = stack === null ? null : cutUtf8(scrub(stack), STACK_CAP_BYTES);\n return { message: m.text, stack: s ? s.text : null, code, truncated: m.truncated || (s?.truncated ?? false) };\n}\n\ntype InfoJson = string | number | boolean | null | InfoJson[] | { [key: string]: InfoJson };\n\n/**\n * An event's `info`: its `eventData` as `resolveData: \"none\"` leaves it, every\n * `token` key removed at any depth, only strings, numbers, booleans, `null`\n * and objects/arrays of those kept (a `Date` becomes its RFC 3339 string); at\n * most 2 KiB serialized, else `{}` and truncated.\n */\nexport function eventInfo(eventData: unknown): { info: Record<string, InfoJson>; truncated: boolean } {\n const sanitize = (v: unknown, depth: number): InfoJson | undefined => {\n if (v === null) return null;\n if (v instanceof Date) return Number.isNaN(v.getTime()) ? undefined : v.toISOString();\n switch (typeof v) {\n case \"string\":\n return redactWebhookTokens(v);\n case \"boolean\":\n return v;\n case \"number\":\n return Number.isFinite(v) ? v : undefined;\n case \"object\": {\n if (depth > 32 || ArrayBuffer.isView(v) || v instanceof ArrayBuffer) return undefined;\n if (Array.isArray(v)) {\n return v.map((item) => sanitize(item, depth + 1)).filter((item): item is InfoJson => item !== undefined);\n }\n const proto = Object.getPrototypeOf(v);\n if (proto !== Object.prototype && proto !== null) return undefined;\n const out: Record<string, InfoJson> = {};\n for (const [k, item] of Object.entries(v as Record<string, unknown>)) {\n if (k === \"token\") continue;\n const clean = sanitize(item, depth + 1);\n if (clean !== undefined) out[redactWebhookTokens(k)] = clean;\n }\n return out;\n }\n default:\n return undefined;\n }\n };\n const clean = sanitize(eventData ?? {}, 0);\n const info = clean !== null && typeof clean === \"object\" && !Array.isArray(clean) ? clean : {};\n if (utf8Length(JSON.stringify(info)) > INFO_CAP_BYTES) return { info: {}, truncated: true };\n return { info, truncated: false };\n}\n\n/** RFC 3339 UTC with milliseconds, or `null`. */\nexport function isoTime(value: unknown): string | null {\n if (value === undefined || value === null) return null;\n const date = value instanceof Date ? value : new Date(value as string | number);\n return Number.isNaN(date.getTime()) ? null : date.toISOString();\n}\n\n/**\n * A step's input as the SDK's own inspector shows it: its arguments. Workflow\n * SDK stores a step's input as `{ args, closureVars, thisVal }`; this answers\n * `args` alone, or `{ args, closureVars?, thisVal? }` with only the parts that\n * hold something. Anything not exactly that envelope is returned as it is.\n */\nexport function stepInputDisplay(input: unknown): unknown {\n if (input === null || typeof input !== \"object\" || Array.isArray(input)) return input;\n const proto = Object.getPrototypeOf(input);\n if (proto !== Object.prototype && proto !== null) return input;\n const keys = Object.keys(input);\n if (!keys.includes(\"args\") || keys.some((k) => k !== \"args\" && k !== \"closureVars\" && k !== \"thisVal\")) return input;\n const { args, closureVars, thisVal } = input as { args: unknown; closureVars?: unknown; thisVal?: unknown };\n if (!Array.isArray(args)) return input;\n const extra: Record<string, unknown> = {};\n if (!isEmpty(closureVars)) extra.closureVars = closureVars;\n if (thisVal !== undefined && thisVal !== null) extra.thisVal = thisVal;\n return Object.keys(extra).length === 0 ? args : { args, ...extra };\n}\n\nfunction isEmpty(value: unknown): boolean {\n if (value === undefined || value === null) return true;\n if (Array.isArray(value)) return value.length === 0;\n if (value instanceof Map || value instanceof Set) return value.size === 0;\n if (typeof value === \"object\" && Object.getPrototypeOf(value) === Object.prototype) return Object.keys(value).length === 0;\n return false;\n}\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type World } from "@workflow/world";
|
|
2
|
+
import { type WorkflowEnv } from "./config.js";
|
|
3
|
+
/** Where `unfazed/workflow/nitro` mounts the route; other frameworks mount {@link createInspectHandler} here. */
|
|
4
|
+
export declare const INSPECT_BASE_PATH = "/.well-known/workflow/v1/unfazed/inspect/v1";
|
|
5
|
+
export declare const INSPECT_CONTRACT_VERSION = 1;
|
|
6
|
+
/** The slice of Workflow SDK's `Run` the actions use (`getRun(id)` from `workflow/api`). */
|
|
7
|
+
export interface InspectRunHandle {
|
|
8
|
+
wakeUp(options?: {
|
|
9
|
+
correlationIds?: string[];
|
|
10
|
+
}): Promise<{
|
|
11
|
+
stoppedCount: number;
|
|
12
|
+
}>;
|
|
13
|
+
cancel(options?: {
|
|
14
|
+
cancelReason?: string;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export interface InspectHandlerOptions {
|
|
18
|
+
/** The World to read. Default: Workflow SDK's `getWorld()`, the World installed with `setWorld()`. */
|
|
19
|
+
getWorld?: () => World | Promise<World>;
|
|
20
|
+
/** Default: Workflow SDK's `getRun()` (`workflow/api`). */
|
|
21
|
+
getRun?: (runId: string) => InspectRunHandle;
|
|
22
|
+
/** The token the platform sends. Default: `UNFZ_STATE_TOKEN`, read per request. */
|
|
23
|
+
stateToken?: string;
|
|
24
|
+
/** Where `UNFZ_STATE_TOKEN` is read from. Default: `process.env`. */
|
|
25
|
+
env?: WorkflowEnv;
|
|
26
|
+
/** The build's workflow machine names (`workflow//./src/x//name`), for `info`. Default: none. */
|
|
27
|
+
workflows?: readonly string[];
|
|
28
|
+
/** The Workflow SDK version the app was built with, for `info`. Default: `"unknown"`. */
|
|
29
|
+
workflowVersion?: string;
|
|
30
|
+
/** How long a request may take before it answers with an error. Default 19 s (the contract allows 20). */
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The reason as Workflow SDK stores it: its schema takes at most 512 UTF-16
|
|
35
|
+
* units, so a reason of 512 characters that holds astral-plane ones (emoji)
|
|
36
|
+
* is cut on a character boundary to fit, rather than failing the cancel.
|
|
37
|
+
*/
|
|
38
|
+
export declare function sdkCancelReason(reason: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Creates the inspection route's handler: `(request) => Response` for every
|
|
41
|
+
* request under {@link INSPECT_BASE_PATH}.
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* // e.g. a catch-all route at /.well-known/workflow/v1/unfazed/inspect/v1/*
|
|
45
|
+
* import { createInspectHandler } from "unfazed/workflow";
|
|
46
|
+
* const inspect = createInspectHandler();
|
|
47
|
+
* export const GET = inspect, POST = inspect;
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* `unfazed/workflow/nitro` mounts it for you.
|
|
51
|
+
*/
|
|
52
|
+
export declare function createInspectHandler(options?: InspectHandlerOptions): (request: Request) => Promise<Response>;
|