@nifrajs/coding-agent 3.2.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/EXTENSIONS.md +25 -0
- package/PERFORMANCE.md +19 -0
- package/README.md +69 -0
- package/REGISTRY.md +15 -0
- package/SECURITY.md +32 -0
- package/dist/approvals.d.ts +70 -0
- package/dist/approvals.d.ts.map +1 -0
- package/dist/approvals.js +174 -0
- package/dist/approvals.js.map +1 -0
- package/dist/capabilities.d.ts +20 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +49 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +380 -0
- package/dist/cli.js.map +1 -0
- package/dist/context.d.ts +17 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +66 -0
- package/dist/context.js.map +1 -0
- package/dist/deployment-adapters.d.ts +40 -0
- package/dist/deployment-adapters.d.ts.map +1 -0
- package/dist/deployment-adapters.js +147 -0
- package/dist/deployment-adapters.js.map +1 -0
- package/dist/diff.d.ts +17 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +61 -0
- package/dist/diff.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +35 -0
- package/dist/errors.js.map +1 -0
- package/dist/extensions.d.ts +104 -0
- package/dist/extensions.d.ts.map +1 -0
- package/dist/extensions.js +284 -0
- package/dist/extensions.js.map +1 -0
- package/dist/handoffs.d.ts +97 -0
- package/dist/handoffs.d.ts.map +1 -0
- package/dist/handoffs.js +199 -0
- package/dist/handoffs.js.map +1 -0
- package/dist/healing.d.ts +56 -0
- package/dist/healing.d.ts.map +1 -0
- package/dist/healing.js +54 -0
- package/dist/healing.js.map +1 -0
- package/dist/host.d.ts +61 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +369 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/isolated-worker.d.ts +2 -0
- package/dist/isolated-worker.d.ts.map +1 -0
- package/dist/isolated-worker.js +155 -0
- package/dist/isolated-worker.js.map +1 -0
- package/dist/isolated.d.ts +52 -0
- package/dist/isolated.d.ts.map +1 -0
- package/dist/isolated.js +293 -0
- package/dist/isolated.js.map +1 -0
- package/dist/native.d.ts +92 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +339 -0
- package/dist/native.js.map +1 -0
- package/dist/orchestration/artifact-port.d.ts +30 -0
- package/dist/orchestration/artifact-port.d.ts.map +1 -0
- package/dist/orchestration/artifact-port.js +59 -0
- package/dist/orchestration/artifact-port.js.map +1 -0
- package/dist/orchestration/catalog.d.ts +71 -0
- package/dist/orchestration/catalog.d.ts.map +1 -0
- package/dist/orchestration/catalog.js +46 -0
- package/dist/orchestration/catalog.js.map +1 -0
- package/dist/orchestration/compile.d.ts +59 -0
- package/dist/orchestration/compile.d.ts.map +1 -0
- package/dist/orchestration/compile.js +268 -0
- package/dist/orchestration/compile.js.map +1 -0
- package/dist/orchestration/dispatch.d.ts +115 -0
- package/dist/orchestration/dispatch.d.ts.map +1 -0
- package/dist/orchestration/dispatch.js +220 -0
- package/dist/orchestration/dispatch.js.map +1 -0
- package/dist/orchestration/durable-jobs.d.ts +35 -0
- package/dist/orchestration/durable-jobs.d.ts.map +1 -0
- package/dist/orchestration/durable-jobs.js +273 -0
- package/dist/orchestration/durable-jobs.js.map +1 -0
- package/dist/orchestration/effect-key.d.ts +23 -0
- package/dist/orchestration/effect-key.d.ts.map +1 -0
- package/dist/orchestration/effect-key.js +24 -0
- package/dist/orchestration/effect-key.js.map +1 -0
- package/dist/orchestration/evidence-store.d.ts +75 -0
- package/dist/orchestration/evidence-store.d.ts.map +1 -0
- package/dist/orchestration/evidence-store.js +183 -0
- package/dist/orchestration/evidence-store.js.map +1 -0
- package/dist/orchestration/hash.d.ts +12 -0
- package/dist/orchestration/hash.d.ts.map +1 -0
- package/dist/orchestration/hash.js +43 -0
- package/dist/orchestration/hash.js.map +1 -0
- package/dist/orchestration/host.d.ts +121 -0
- package/dist/orchestration/host.d.ts.map +1 -0
- package/dist/orchestration/host.js +334 -0
- package/dist/orchestration/host.js.map +1 -0
- package/dist/orchestration/index.d.ts +20 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +19 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/policy.d.ts +63 -0
- package/dist/orchestration/policy.d.ts.map +1 -0
- package/dist/orchestration/policy.js +80 -0
- package/dist/orchestration/policy.js.map +1 -0
- package/dist/orchestration/recovery.d.ts +87 -0
- package/dist/orchestration/recovery.d.ts.map +1 -0
- package/dist/orchestration/recovery.js +197 -0
- package/dist/orchestration/recovery.js.map +1 -0
- package/dist/orchestration/tracer.d.ts +31 -0
- package/dist/orchestration/tracer.d.ts.map +1 -0
- package/dist/orchestration/tracer.js +141 -0
- package/dist/orchestration/tracer.js.map +1 -0
- package/dist/plans.d.ts +35 -0
- package/dist/plans.d.ts.map +1 -0
- package/dist/plans.js +63 -0
- package/dist/plans.js.map +1 -0
- package/dist/presets.d.ts +10 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +70 -0
- package/dist/presets.js.map +1 -0
- package/dist/process.d.ts +6 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +42 -0
- package/dist/process.js.map +1 -0
- package/dist/registry.d.ts +37 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +51 -0
- package/dist/registry.js.map +1 -0
- package/dist/replay.d.ts +24 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +154 -0
- package/dist/replay.js.map +1 -0
- package/dist/rpc.d.ts +51 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +412 -0
- package/dist/rpc.js.map +1 -0
- package/dist/session-migration.d.ts +59 -0
- package/dist/session-migration.d.ts.map +1 -0
- package/dist/session-migration.js +315 -0
- package/dist/session-migration.js.map +1 -0
- package/dist/sessions.d.ts +74 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +222 -0
- package/dist/sessions.js.map +1 -0
- package/dist/subagents.d.ts +51 -0
- package/dist/subagents.d.ts.map +1 -0
- package/dist/subagents.js +141 -0
- package/dist/subagents.js.map +1 -0
- package/dist/tools.d.ts +13 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +37 -0
- package/dist/tools.js.map +1 -0
- package/dist/ui.d.ts +42 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +93 -0
- package/dist/ui.js.map +1 -0
- package/dist/verification.d.ts +34 -0
- package/dist/verification.d.ts.map +1 -0
- package/dist/verification.js +91 -0
- package/dist/verification.js.map +1 -0
- package/dist/workflows.d.ts +98 -0
- package/dist/workflows.d.ts.map +1 -0
- package/dist/workflows.js +174 -0
- package/dist/workflows.js.map +1 -0
- package/package.json +84 -0
- package/src/approvals.ts +249 -0
- package/src/capabilities.ts +74 -0
- package/src/cli.ts +405 -0
- package/src/context.ts +81 -0
- package/src/deployment-adapters.ts +181 -0
- package/src/diff.ts +80 -0
- package/src/errors.ts +46 -0
- package/src/extensions.ts +402 -0
- package/src/handoffs.ts +299 -0
- package/src/healing.ts +93 -0
- package/src/host.ts +465 -0
- package/src/index.ts +165 -0
- package/src/isolated-worker.ts +177 -0
- package/src/isolated.ts +344 -0
- package/src/native.ts +478 -0
- package/src/orchestration/artifact-port.ts +75 -0
- package/src/orchestration/catalog.ts +102 -0
- package/src/orchestration/compile.ts +373 -0
- package/src/orchestration/dispatch.ts +383 -0
- package/src/orchestration/durable-jobs.ts +374 -0
- package/src/orchestration/effect-key.ts +35 -0
- package/src/orchestration/evidence-store.ts +233 -0
- package/src/orchestration/hash.ts +43 -0
- package/src/orchestration/host.ts +445 -0
- package/src/orchestration/index.ts +131 -0
- package/src/orchestration/policy.ts +116 -0
- package/src/orchestration/recovery.ts +271 -0
- package/src/orchestration/tracer.ts +177 -0
- package/src/plans.ts +105 -0
- package/src/presets.ts +90 -0
- package/src/process.ts +47 -0
- package/src/registry.ts +80 -0
- package/src/replay.ts +190 -0
- package/src/rpc.ts +598 -0
- package/src/session-migration.ts +401 -0
- package/src/sessions.ts +303 -0
- package/src/subagents.ts +210 -0
- package/src/tools.ts +52 -0
- package/src/ui.ts +137 -0
- package/src/verification.ts +133 -0
- package/src/workflows.ts +279 -0
package/src/workflows.ts
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { publicErrorDetails } from "./errors.ts"
|
|
2
|
+
|
|
3
|
+
export interface WorkflowContext {
|
|
4
|
+
readonly signal: AbortSignal
|
|
5
|
+
readonly values: ReadonlyMap<string, unknown>
|
|
6
|
+
set(name: string, value: unknown): void
|
|
7
|
+
run(step: WorkflowStep): Promise<unknown>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type WorkflowStep =
|
|
11
|
+
| {
|
|
12
|
+
readonly type: "task"
|
|
13
|
+
readonly id: string
|
|
14
|
+
readonly run: (context: WorkflowContext) => unknown | PromiseLike<unknown>
|
|
15
|
+
}
|
|
16
|
+
| { readonly type: "sequence"; readonly steps: readonly WorkflowStep[] }
|
|
17
|
+
| {
|
|
18
|
+
readonly type: "parallel"
|
|
19
|
+
readonly steps: readonly WorkflowStep[]
|
|
20
|
+
readonly maxConcurrency?: number
|
|
21
|
+
}
|
|
22
|
+
| {
|
|
23
|
+
readonly type: "verify"
|
|
24
|
+
readonly id: string
|
|
25
|
+
readonly run: (
|
|
26
|
+
context: WorkflowContext,
|
|
27
|
+
) => unknown | PromiseLike<boolean | { readonly ok: boolean; readonly report?: unknown }>
|
|
28
|
+
}
|
|
29
|
+
| {
|
|
30
|
+
readonly type: "approve"
|
|
31
|
+
readonly id: string
|
|
32
|
+
readonly reason: string
|
|
33
|
+
readonly run: (context: WorkflowContext) => unknown | PromiseLike<boolean>
|
|
34
|
+
}
|
|
35
|
+
| {
|
|
36
|
+
readonly type: "retry"
|
|
37
|
+
readonly step: WorkflowStep
|
|
38
|
+
readonly attempts?: number
|
|
39
|
+
readonly backoffMs?: number
|
|
40
|
+
}
|
|
41
|
+
| {
|
|
42
|
+
readonly type: "branch"
|
|
43
|
+
readonly id: string
|
|
44
|
+
readonly when: (context: WorkflowContext) => boolean | PromiseLike<boolean>
|
|
45
|
+
readonly then: WorkflowStep
|
|
46
|
+
readonly otherwise?: WorkflowStep
|
|
47
|
+
}
|
|
48
|
+
| {
|
|
49
|
+
readonly type: "checkpoint"
|
|
50
|
+
readonly id: string
|
|
51
|
+
readonly run: (context: WorkflowContext) => unknown | PromiseLike<unknown>
|
|
52
|
+
}
|
|
53
|
+
| {
|
|
54
|
+
readonly type: "handoff"
|
|
55
|
+
readonly id: string
|
|
56
|
+
readonly run: (context: WorkflowContext) => unknown | PromiseLike<unknown>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface WorkflowRunnerOptions {
|
|
60
|
+
readonly signal?: AbortSignal
|
|
61
|
+
readonly maxSteps?: number
|
|
62
|
+
readonly maxDepth?: number
|
|
63
|
+
readonly onEvent?: (event: WorkflowEvent) => void | PromiseLike<void>
|
|
64
|
+
readonly exposeErrorStacks?: boolean
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type WorkflowEvent =
|
|
68
|
+
| { readonly type: "step.started"; readonly id: string }
|
|
69
|
+
| { readonly type: "step.completed"; readonly id: string; readonly output?: unknown }
|
|
70
|
+
| {
|
|
71
|
+
readonly type: "step.failed"
|
|
72
|
+
readonly id: string
|
|
73
|
+
readonly error: string
|
|
74
|
+
readonly stack?: string
|
|
75
|
+
}
|
|
76
|
+
| { readonly type: "approval.required"; readonly id: string; readonly reason: string }
|
|
77
|
+
| { readonly type: "checkpoint.created"; readonly id: string }
|
|
78
|
+
|
|
79
|
+
export interface WorkflowResult {
|
|
80
|
+
readonly ok: boolean
|
|
81
|
+
readonly values: ReadonlyMap<string, unknown>
|
|
82
|
+
readonly completed: readonly string[]
|
|
83
|
+
readonly error?: string
|
|
84
|
+
readonly stack?: string
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Bounded orchestration primitives. The kernel knows no provider, UI, or framework package. */
|
|
88
|
+
export class WorkflowRunner {
|
|
89
|
+
private readonly options: Required<Pick<WorkflowRunnerOptions, "maxSteps" | "maxDepth">> &
|
|
90
|
+
WorkflowRunnerOptions
|
|
91
|
+
private readonly values = new Map<string, unknown>()
|
|
92
|
+
private readonly completed: string[] = []
|
|
93
|
+
private steps = 0
|
|
94
|
+
|
|
95
|
+
constructor(options: WorkflowRunnerOptions = {}) {
|
|
96
|
+
this.options = {
|
|
97
|
+
...options,
|
|
98
|
+
maxSteps: options.maxSteps ?? 128,
|
|
99
|
+
maxDepth: options.maxDepth ?? 8,
|
|
100
|
+
}
|
|
101
|
+
if (!Number.isSafeInteger(this.options.maxSteps) || this.options.maxSteps < 1)
|
|
102
|
+
throw new RangeError("workflow: maxSteps must be positive")
|
|
103
|
+
if (!Number.isSafeInteger(this.options.maxDepth) || this.options.maxDepth < 1)
|
|
104
|
+
throw new RangeError("workflow: maxDepth must be positive")
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async run(step: WorkflowStep): Promise<WorkflowResult> {
|
|
108
|
+
try {
|
|
109
|
+
await this.execute(step, 0)
|
|
110
|
+
return {
|
|
111
|
+
ok: true,
|
|
112
|
+
values: new Map(this.values),
|
|
113
|
+
completed: Object.freeze([...this.completed]),
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const details = publicErrorDetails(
|
|
117
|
+
error,
|
|
118
|
+
"workflow failed",
|
|
119
|
+
this.options.exposeErrorStacks === true,
|
|
120
|
+
)
|
|
121
|
+
return {
|
|
122
|
+
ok: false,
|
|
123
|
+
values: new Map(this.values),
|
|
124
|
+
completed: Object.freeze([...this.completed]),
|
|
125
|
+
error: details.message,
|
|
126
|
+
...(details.stack === undefined ? {} : { stack: details.stack }),
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private context(): WorkflowContext {
|
|
132
|
+
return {
|
|
133
|
+
signal: this.options.signal ?? new AbortController().signal,
|
|
134
|
+
values: this.values,
|
|
135
|
+
set: (name, value) => this.values.set(name, value),
|
|
136
|
+
run: (step) => this.execute(step, 1),
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private async execute(step: WorkflowStep, depth: number): Promise<unknown> {
|
|
141
|
+
if (depth > this.options.maxDepth) throw new Error("workflow max depth exceeded")
|
|
142
|
+
if (++this.steps > this.options.maxSteps) throw new Error("workflow max steps exceeded")
|
|
143
|
+
if (this.options.signal?.aborted) throw new Error("workflow cancelled")
|
|
144
|
+
switch (step.type) {
|
|
145
|
+
case "task":
|
|
146
|
+
return this.single(step.id, () => step.run(this.context()))
|
|
147
|
+
case "verify": {
|
|
148
|
+
const result = await this.single(step.id, () => step.run(this.context()))
|
|
149
|
+
const ok = typeof result === "boolean" ? result : isVerificationResult(result) && result.ok
|
|
150
|
+
if (!ok) throw new Error(`verification failed: ${step.id}`)
|
|
151
|
+
return result
|
|
152
|
+
}
|
|
153
|
+
case "approve": {
|
|
154
|
+
await this.emit({ type: "approval.required", id: step.id, reason: step.reason })
|
|
155
|
+
const approved = await this.single(step.id, () => step.run(this.context()))
|
|
156
|
+
if (approved !== true) throw new Error(`approval denied: ${step.id}`)
|
|
157
|
+
return approved
|
|
158
|
+
}
|
|
159
|
+
case "checkpoint": {
|
|
160
|
+
const result = await this.single(step.id, () => step.run(this.context()))
|
|
161
|
+
await this.emit({ type: "checkpoint.created", id: step.id })
|
|
162
|
+
return result
|
|
163
|
+
}
|
|
164
|
+
case "handoff":
|
|
165
|
+
return this.single(step.id, () => step.run(this.context()))
|
|
166
|
+
case "sequence": {
|
|
167
|
+
const results: unknown[] = []
|
|
168
|
+
for (const child of step.steps) results.push(await this.execute(child, depth + 1))
|
|
169
|
+
return results
|
|
170
|
+
}
|
|
171
|
+
case "parallel":
|
|
172
|
+
return this.parallel(step.steps, step.maxConcurrency ?? step.steps.length, depth)
|
|
173
|
+
case "retry": {
|
|
174
|
+
const attempts = step.attempts ?? 3
|
|
175
|
+
if (!Number.isSafeInteger(attempts) || attempts < 1 || attempts > 16)
|
|
176
|
+
throw new RangeError("workflow: attempts must be between 1 and 16")
|
|
177
|
+
let last: unknown
|
|
178
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
179
|
+
try {
|
|
180
|
+
return await this.execute(step.step, depth + 1)
|
|
181
|
+
} catch (error) {
|
|
182
|
+
last = error
|
|
183
|
+
if (attempt + 1 < attempts && (step.backoffMs ?? 0) > 0)
|
|
184
|
+
await delay(Math.min(step.backoffMs! * (attempt + 1), 10_000), this.options.signal)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
throw last instanceof Error ? last : new Error(String(last))
|
|
188
|
+
}
|
|
189
|
+
case "branch": {
|
|
190
|
+
const selected = await this.single(step.id, () => step.when(this.context()))
|
|
191
|
+
return selected === true
|
|
192
|
+
? this.execute(step.then, depth + 1)
|
|
193
|
+
: step.otherwise === undefined
|
|
194
|
+
? undefined
|
|
195
|
+
: this.execute(step.otherwise, depth + 1)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private async single(id: string, run: () => unknown | PromiseLike<unknown>): Promise<unknown> {
|
|
201
|
+
await this.emit({ type: "step.started", id })
|
|
202
|
+
try {
|
|
203
|
+
const output = await run()
|
|
204
|
+
this.completed.push(id)
|
|
205
|
+
await this.emit({ type: "step.completed", id, ...(output === undefined ? {} : { output }) })
|
|
206
|
+
return output
|
|
207
|
+
} catch (error) {
|
|
208
|
+
const details = publicErrorDetails(
|
|
209
|
+
error,
|
|
210
|
+
"workflow step failed",
|
|
211
|
+
this.options.exposeErrorStacks === true,
|
|
212
|
+
)
|
|
213
|
+
await this.emit({
|
|
214
|
+
type: "step.failed",
|
|
215
|
+
id,
|
|
216
|
+
error: details.message,
|
|
217
|
+
...(details.stack === undefined ? {} : { stack: details.stack }),
|
|
218
|
+
})
|
|
219
|
+
throw error
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private async parallel(
|
|
224
|
+
steps: readonly WorkflowStep[],
|
|
225
|
+
maxConcurrency: number,
|
|
226
|
+
depth: number,
|
|
227
|
+
): Promise<readonly unknown[]> {
|
|
228
|
+
if (!Number.isSafeInteger(maxConcurrency) || maxConcurrency < 1)
|
|
229
|
+
throw new RangeError("workflow: maxConcurrency must be positive")
|
|
230
|
+
const outputs: unknown[] = new Array(steps.length)
|
|
231
|
+
let next = 0
|
|
232
|
+
const worker = async (): Promise<void> => {
|
|
233
|
+
for (;;) {
|
|
234
|
+
const index = next++
|
|
235
|
+
if (index >= steps.length) return
|
|
236
|
+
outputs[index] = await this.execute(steps[index]!, depth + 1)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
await Promise.all(
|
|
240
|
+
Array.from({ length: Math.min(maxConcurrency, steps.length) }, () => worker()),
|
|
241
|
+
)
|
|
242
|
+
return outputs
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private async emit(event: WorkflowEvent): Promise<void> {
|
|
246
|
+
await this.options.onEvent?.(event)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async function delay(ms: number, signal: AbortSignal | undefined): Promise<void> {
|
|
251
|
+
await new Promise<void>((resolve, reject) => {
|
|
252
|
+
const timer = setTimeout(resolve, ms)
|
|
253
|
+
if (signal === undefined) return
|
|
254
|
+
if (signal.aborted) {
|
|
255
|
+
clearTimeout(timer)
|
|
256
|
+
reject(new Error("workflow cancelled"))
|
|
257
|
+
return
|
|
258
|
+
}
|
|
259
|
+
signal.addEventListener(
|
|
260
|
+
"abort",
|
|
261
|
+
() => {
|
|
262
|
+
clearTimeout(timer)
|
|
263
|
+
reject(new Error("workflow cancelled"))
|
|
264
|
+
},
|
|
265
|
+
{ once: true },
|
|
266
|
+
)
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function isVerificationResult(
|
|
271
|
+
value: unknown,
|
|
272
|
+
): value is { readonly ok: boolean; readonly report?: unknown } {
|
|
273
|
+
return (
|
|
274
|
+
value !== null &&
|
|
275
|
+
typeof value === "object" &&
|
|
276
|
+
!Array.isArray(value) &&
|
|
277
|
+
typeof (value as { readonly ok?: unknown }).ok === "boolean"
|
|
278
|
+
)
|
|
279
|
+
}
|