@burojs/react 0.4.0 → 0.5.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.
@@ -0,0 +1,1157 @@
1
+ 'use client';
2
+ "use client";
3
+ import { $ as readPermissions, $t as useApp, At as useCurrentUIActivation, B as resourceDescriptorBase, Bn as executeMutation, Cr as executeQuery, E as registerFlowRun, Ft as useOptionalPresentationMount, G as EMPTY_COUNTED, Hn as resolveCountExecution, J as hopId, K as EMPTY_ROWS, L as createRuntimeActionDataAccess, Lt as FLOW_COMPONENT, N as useFrameworkAudit, Q as projectRows, Qn as useLocale, Qt as useUIPresentationRuntime, R as createUnavailableActionDataAccess, Rt as FlowScreenEntry, U as useFlowAttemptsStore, W as useCurrentUserId, X as listValue, Y as isSignedOut, Z as projectRow, at as whereValueUsable, bt as useDispatcherEffects, d as useProjectedTitle, fn as DismissRegistryContext, ft as useFlowRowResolver, hn as useDismissPending, i as conjoinHostPage, k as useOptionalVisibilityCtx, ln as useNavigationHold, lt as disposeWhenIdle, mr as useFlowFormCatalog, n as usePresentFlow, nn as useRouteNavigate, nt as useContextSnapshot, o as hostPageRef, ot as withRowId, pn as DismissScopeContext, pr as useApplicationSnapshot, qn as buildStandardQueryDescriptor, r as usePageFlowGate, rr as useTranslate, s as useHostPage, t as reportMissingFlowHost, v as useFormController, xr as useOptionalDataRuntime, z as customMutationDescriptor } from "./present-flow-pFzbn0cZ.js";
4
+ import { FLOW_SETTLE_MS, LIST_SOURCE_DEFAULT_LIMIT, attemptKey, attemptSlot, compileFlow, createCustomQueryDescriptor, createIdempotencyKey, createMutationDescriptor, createQueryDescriptor, dtoFields, fnv1a, formatEntityRef, hrefFor, humanizeKey, isDataError, isFlowRef, lowerVia, normalizeDataError, normalizeEntityRef, projectSource, relationAmbiguousError, resolveDataCapability, resolveFieldAccess, resolveFlowGate, ruleContextFor, runThenEffects, snapshotResourceFields, trustedFlowAttachments } from "@burojs/core";
5
+ import { useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
6
+ import { fieldEntriesToMap } from "@burojs/core/internal";
7
+ import { createFlowFormPort, createFlowRun, createMemoryAttempts, hashCanonical } from "@burojs/core/flows";
8
+ //#region src/flows/source-reader.ts
9
+ const resource = (target) => ({
10
+ kind: "resource",
11
+ ref: target
12
+ });
13
+ function ownData(value, key) {
14
+ if (value === null || typeof value !== "object") return void 0;
15
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
16
+ return descriptor !== void 0 && "value" in descriptor ? descriptor.value : void 0;
17
+ }
18
+ function operand(value, sources) {
19
+ if (value.kind !== "ref") return value.value;
20
+ let current = sources[value.source];
21
+ for (const segment of value.path) {
22
+ current = ownData(current, segment);
23
+ if (current === void 0) return void 0;
24
+ }
25
+ return current;
26
+ }
27
+ const isMissing = (error) => error.kind === "not-found" || error.kind === "forbidden";
28
+ function configuration(code, message) {
29
+ return normalizeDataError(Object.assign(new Error(message), {
30
+ kind: "configuration",
31
+ code
32
+ }));
33
+ }
34
+ function createFlowSourceReader(input) {
35
+ const { runtime } = input;
36
+ const app = runtime.app;
37
+ const registryDef = (target) => app.registry.get(resource(target));
38
+ const idFieldOf = (target) => {
39
+ const idField = registryDef(target)?.data?.idField;
40
+ return typeof idField === "string" && idField !== "" ? idField : void 0;
41
+ };
42
+ const recordDto = (target) => {
43
+ const def = registryDef(target);
44
+ return def === void 0 ? void 0 : dtoFields(def, "record");
45
+ };
46
+ const listDto = (target) => {
47
+ const def = registryDef(target);
48
+ return def === void 0 ? void 0 : dtoFields(def, "list");
49
+ };
50
+ const context = async () => ({
51
+ runtime,
52
+ snapshot: app.runtime.getSnapshot(),
53
+ session: await runtime.waitUntilReady(),
54
+ locale: input.inputs().locale
55
+ });
56
+ const run = async (descriptor, signal) => {
57
+ if (isDataError(descriptor)) throw descriptor;
58
+ return await executeQuery({
59
+ descriptor,
60
+ runtime,
61
+ signal
62
+ });
63
+ };
64
+ const row = async (target, key, by, signal) => {
65
+ const ctx = await context();
66
+ const projection = recordDto(target);
67
+ const idField = idFieldOf(target) ?? "id";
68
+ const dto = projection === void 0 || projection.includes(idField) ? projection : [...projection, idField];
69
+ try {
70
+ if (by === void 0) {
71
+ const answer = await run(buildStandardQueryDescriptor(ctx, resource(target), {
72
+ kind: "one",
73
+ id: key,
74
+ ...projection === void 0 ? {} : { projection }
75
+ }), signal);
76
+ return withRowId(projectRow(answer?.data ?? null, dto), idField, key);
77
+ }
78
+ const answer = await run(buildStandardQueryDescriptor(ctx, resource(target), {
79
+ kind: "list",
80
+ filter: {
81
+ field: by,
82
+ op: "eq",
83
+ value: key
84
+ },
85
+ pagination: {
86
+ kind: "offset",
87
+ page: 1,
88
+ pageSize: 2
89
+ },
90
+ ...projection === void 0 ? {} : { projection }
91
+ }), signal);
92
+ const rows = Array.isArray(answer?.data) ? answer.data : [];
93
+ if (rows.length === 0) return null;
94
+ if (rows.length === 1) return projectRow(rows[0], dto);
95
+ throw relationAmbiguousError(formatEntityRef(target), by, String(key));
96
+ } catch (error) {
97
+ const failure = normalizeDataError(error);
98
+ if (isMissing(failure)) return null;
99
+ throw failure;
100
+ }
101
+ };
102
+ const list = async (entry, sources, signal) => {
103
+ const fieldKind = (field) => {
104
+ const found = snapshotResourceFields(app.runtime.getSnapshot())(entry.target)?.find((candidate) => candidate.name === field);
105
+ return typeof found?.kind === "string" ? found.kind : void 0;
106
+ };
107
+ const conditions = [];
108
+ for (const condition of entry.where) {
109
+ const value = operand(condition.value, sources);
110
+ if (!whereValueUsable(value, fieldKind(condition.field))) return entry.count === true ? EMPTY_COUNTED : EMPTY_ROWS;
111
+ conditions.push({
112
+ field: condition.field,
113
+ op: condition.op,
114
+ value
115
+ });
116
+ }
117
+ const filter = conditions.length === 0 ? void 0 : conditions.length === 1 ? conditions[0] : { and: conditions };
118
+ const ctx = await context();
119
+ const projection = listDto(entry.target);
120
+ const answer = await run(buildStandardQueryDescriptor(ctx, resource(entry.target), {
121
+ kind: "list",
122
+ ...filter === void 0 ? {} : { filter },
123
+ ...entry.sort === void 0 ? {} : { sort: entry.sort },
124
+ pagination: {
125
+ kind: "offset",
126
+ page: 1,
127
+ pageSize: entry.limit ?? LIST_SOURCE_DEFAULT_LIMIT
128
+ },
129
+ ...projection === void 0 ? {} : { projection }
130
+ }), signal);
131
+ const rows = projectRows(answer?.data, projection);
132
+ if (entry.count !== true) return listValue(rows);
133
+ const inline = typeof answer?.total === "number" ? answer.total : void 0;
134
+ const execution = resolveCountExecution("auto", inline, {
135
+ query: true,
136
+ live: false
137
+ });
138
+ if (isDataError(execution)) throw execution;
139
+ if (execution.kind === "inline") return listValue(rows, execution.total);
140
+ const counted = await run(buildStandardQueryDescriptor(ctx, resource(entry.target), {
141
+ kind: "count",
142
+ ...filter === void 0 ? {} : { filter }
143
+ }), signal);
144
+ if (typeof counted?.total !== "number") throw configuration("count-missing", "The count read returned no total.");
145
+ return listValue(rows, counted.total);
146
+ };
147
+ const query = async (entry, sources, signal) => {
148
+ const values = {};
149
+ for (const [key, value] of Object.entries(entry.input)) {
150
+ const resolved = operand(value, sources);
151
+ values[key] = resolved === void 0 ? null : resolved;
152
+ }
153
+ const ctx = await context();
154
+ return run(createCustomQueryDescriptor({
155
+ snapshot: ctx.snapshot,
156
+ session: ctx.session,
157
+ locale: ctx.locale,
158
+ ref: entry.query,
159
+ input: values
160
+ }), signal);
161
+ };
162
+ const via = async (entry, sources, signal) => {
163
+ if (input.owner === null) throw configuration("via-invalid", "An app flow has no record for a 'via' source.");
164
+ let hops;
165
+ try {
166
+ hops = lowerVia(normalizeEntityRef(input.owner), {
167
+ path: entry.path,
168
+ ...entry.to === void 0 ? {} : { to: entry.to },
169
+ ...entry.by === void 0 ? {} : { by: entry.by }
170
+ }, snapshotResourceFields(app.runtime.getSnapshot()), idFieldOf);
171
+ } catch (error) {
172
+ const code = error.code;
173
+ throw configuration(typeof code === "string" ? code : "via-invalid", error instanceof Error ? error.message : String(error));
174
+ }
175
+ let current = sources.record ?? null;
176
+ for (const hop of hops) {
177
+ const key = hopId(ownData(current, hop.field));
178
+ if (key === null) return null;
179
+ current = await row(hop.target, key, hop.by, signal);
180
+ if (current === null) return null;
181
+ }
182
+ return current;
183
+ };
184
+ return async (source, signal) => {
185
+ const { record, args, scope } = input.inputs();
186
+ const sources = {
187
+ record,
188
+ args,
189
+ scope
190
+ };
191
+ switch (source.kind) {
192
+ case "one": {
193
+ const key = hopId(operand(source.key, sources));
194
+ if (key === null) return null;
195
+ return row(source.target, key, source.by, signal);
196
+ }
197
+ case "list": return list(source, sources, signal);
198
+ case "query": return query(source, sources, signal);
199
+ case "via": return via(source, sources, signal);
200
+ }
201
+ };
202
+ }
203
+ //#endregion
204
+ //#region src/flows/ports.ts
205
+ const resourceHandle = (resource) => ({
206
+ kind: "resource",
207
+ ref: normalizeEntityRef(resource)
208
+ });
209
+ function validKey(value) {
210
+ if (typeof value === "string") return value === "" ? void 0 : value;
211
+ if (typeof value === "number" && Number.isFinite(value)) return value;
212
+ }
213
+ function settleQueries(runtime) {
214
+ const client = runtime.queryClient;
215
+ return new Promise((resolve) => {
216
+ let done = false;
217
+ let unsubscribe;
218
+ const finish = () => {
219
+ if (done) return;
220
+ done = true;
221
+ clearTimeout(timer);
222
+ unsubscribe?.();
223
+ resolve();
224
+ };
225
+ const timer = setTimeout(finish, FLOW_SETTLE_MS);
226
+ Promise.resolve().then(() => {
227
+ if (client.isFetching() === 0) {
228
+ finish();
229
+ return;
230
+ }
231
+ unsubscribe = client.getQueryCache().subscribe(() => {
232
+ if (client.isFetching() === 0) finish();
233
+ });
234
+ });
235
+ });
236
+ }
237
+ function createRuntimeFlowPorts(input) {
238
+ const { runtime, app, flow } = input;
239
+ const projectSourceValue = (name, value) => {
240
+ if (value === null || typeof value !== "object") return value;
241
+ const owner = flow.resource === null ? void 0 : normalizeEntityRef(flow.resource);
242
+ let target;
243
+ let shape = "row";
244
+ if (name === "record") target = owner;
245
+ else {
246
+ const withs = flow.flow.with ?? {};
247
+ const entry = Object.hasOwn(withs, name) ? withs[name] : void 0;
248
+ if (entry?.kind === "one") target = entry.target;
249
+ else if (entry?.kind === "list") {
250
+ target = entry.target;
251
+ shape = "rows";
252
+ } else if (entry?.kind === "via" && owner !== void 0) try {
253
+ const fieldsOf = snapshotResourceFields(app.runtime.getSnapshot());
254
+ target = lowerVia(owner, {
255
+ path: entry.path,
256
+ ...entry.to === void 0 ? {} : { to: entry.to },
257
+ ...entry.by === void 0 ? {} : { by: entry.by }
258
+ }, fieldsOf).at(-1)?.target;
259
+ } catch {
260
+ return null;
261
+ }
262
+ }
263
+ if (target === void 0) return value;
264
+ const def = app.registry.get({
265
+ kind: "resource",
266
+ ref: target
267
+ });
268
+ if (def === void 0) return value;
269
+ const context = input.context();
270
+ const resource = formatEntityRef(target);
271
+ const decisions = resolveFieldAccess({
272
+ rules: app.ruleSource.rules(resource),
273
+ fields: dtoFields(def, shape === "row" ? "record" : "list"),
274
+ context: ruleContextFor({
275
+ user: context.user,
276
+ scope: context.scope,
277
+ ...context.permissions === void 0 ? {} : { permissions: context.permissions },
278
+ ...shape === "row" ? { record: value } : {},
279
+ mode: shape === "row" ? "show" : "list",
280
+ resource
281
+ }),
282
+ permissions: context.permissions,
283
+ reach: shape === "row" ? "record" : "every"
284
+ });
285
+ const closed = Object.fromEntries(Object.entries(decisions).map(([field, decision]) => [field, decision.view === "visible" ? decision : {
286
+ ...decision,
287
+ view: "hidden"
288
+ }]));
289
+ const idField = def.data?.idField;
290
+ const projected = projectSource({
291
+ status: "ready",
292
+ value,
293
+ refreshing: false
294
+ }, closed, shape, typeof idField === "string" && idField !== "" ? idField : "id");
295
+ return projected.status === "ready" ? projected.value : value;
296
+ };
297
+ const describe = async (call) => {
298
+ if (call.op === "custom") return customMutationDescriptor(runtime, normalizeEntityRef(call.target), call.input);
299
+ const base = await resourceDescriptorBase(runtime, resourceHandle(call.target));
300
+ const kind = call.op === "create" ? "createOne" : call.op === "update" ? "updateOne" : "deleteOne";
301
+ return createMutationDescriptor({
302
+ ...base,
303
+ kind,
304
+ ...call.id === void 0 ? {} : { id: call.id },
305
+ ...call.op === "delete" || call.input === void 0 ? {} : { input: call.input }
306
+ });
307
+ };
308
+ const queryOne = async (resource, id, signal) => {
309
+ const base = await resourceDescriptorBase(runtime, resourceHandle(resource));
310
+ return (await executeQuery({
311
+ descriptor: createQueryDescriptor({
312
+ ...base,
313
+ kind: "one",
314
+ id
315
+ }),
316
+ runtime,
317
+ signal
318
+ })).data;
319
+ };
320
+ const hasOne = (resource) => {
321
+ try {
322
+ const binding = app.resolveDataBinding(resourceHandle(resource));
323
+ const service = runtime.providers.resolve(binding.providerId);
324
+ return typeof resolveDataCapability(service.provider, {
325
+ lifecycle: "query",
326
+ kind: "one"
327
+ }) === "function";
328
+ } catch {
329
+ return false;
330
+ }
331
+ };
332
+ const replaySafe = () => {
333
+ if (flow.op !== "custom") return false;
334
+ try {
335
+ const value = app.runtime.getSnapshot().getProjection({
336
+ kind: "custom-mutation",
337
+ ref: normalizeEntityRef(flow.target)
338
+ })?.value;
339
+ const replay = value?.replay;
340
+ if ((replay?.capability === "mutation-replay-policy" && typeof replay.id === "string" ? app.getPluginCapability("mutation-replay-policy", replay.id) : void 0) !== "once-after-auth-refresh" || value?.binding?.provider === void 0) return false;
341
+ const service = runtime.providers.resolve(value.binding.provider);
342
+ return resolveDataCapability(service.provider, {
343
+ lifecycle: "mutation",
344
+ kind: "custom"
345
+ }).replay?.idempotency === "keyed-replay-once";
346
+ } catch {
347
+ return false;
348
+ }
349
+ };
350
+ const readSource = createFlowSourceReader({
351
+ runtime,
352
+ owner: flow.resource,
353
+ inputs: () => {
354
+ const context = input.context();
355
+ return {
356
+ record: input.record,
357
+ args: input.args ?? {},
358
+ scope: context.scope,
359
+ locale: context.locale
360
+ };
361
+ }
362
+ });
363
+ return {
364
+ gate() {
365
+ const context = input.context();
366
+ return resolveFlowGate({
367
+ app,
368
+ resource: flow.resource,
369
+ flow,
370
+ ctx: ruleContextFor({
371
+ ...input.record === void 0 ? {} : { record: input.record },
372
+ ...flow.resource === null ? {} : { resource: flow.resource },
373
+ mode: input.record === void 0 ? "list" : "show",
374
+ user: context.user,
375
+ scope: context.scope,
376
+ ...context.permissions === void 0 ? {} : { permissions: context.permissions }
377
+ }),
378
+ permissionsStatus: context.permissions?.status
379
+ });
380
+ },
381
+ read(_name, source, signal) {
382
+ return readSource(source, signal);
383
+ },
384
+ async reread(resource, ids, signal) {
385
+ const clean = ids.filter((id) => validKey(id) !== void 0);
386
+ if (clean.length === 0) return [];
387
+ if (clean.length === 1 && hasOne(resource)) {
388
+ const row = await queryOne(resource, clean[0], signal);
389
+ return row === null || row === void 0 ? [] : [row];
390
+ }
391
+ const base = await resourceDescriptorBase(runtime, resourceHandle(resource));
392
+ return (await executeQuery({
393
+ descriptor: createQueryDescriptor({
394
+ ...base,
395
+ kind: "many",
396
+ ids: clean
397
+ }),
398
+ runtime,
399
+ signal
400
+ })).data ?? [];
401
+ },
402
+ async mutate(call) {
403
+ const descriptor = await describe(call);
404
+ const output = await executeMutation({
405
+ descriptor,
406
+ runtime,
407
+ idempotencyKey: call.key,
408
+ ...call.replay === "never" ? { replay: "never" } : {}
409
+ });
410
+ await settleQueries(runtime);
411
+ return output;
412
+ },
413
+ attempts: input.attempts,
414
+ audit(event) {
415
+ input.context().audit?.emit(event, { initiates: true });
416
+ },
417
+ checks: {
418
+ source: (resource) => app.checkSource.checks(resource),
419
+ data: input.data,
420
+ get ctx() {
421
+ return input.context().visibility;
422
+ },
423
+ t: (key, params, defaultValue) => input.context().t(key, params, defaultValue)
424
+ },
425
+ form: input.form,
426
+ project: projectSourceValue,
427
+ attachment: trustedFlowAttachments(app.runtime, flow),
428
+ clock: {
429
+ now: () => Date.now(),
430
+ uuid: () => createIdempotencyKey(),
431
+ wait: (ms, signal) => new Promise((resolve, reject) => {
432
+ const timer = setTimeout(resolve, ms);
433
+ signal.addEventListener("abort", () => {
434
+ clearTimeout(timer);
435
+ reject(signal.reason);
436
+ }, { once: true });
437
+ })
438
+ },
439
+ hash: hashCanonical,
440
+ user: input.user,
441
+ get replaySafe() {
442
+ return replaySafe();
443
+ }
444
+ };
445
+ }
446
+ //#endregion
447
+ //#region src/flows/use-flow-run.ts
448
+ const IDLE = Object.freeze({
449
+ step: "gate",
450
+ history: Object.freeze([]),
451
+ control: "undecided",
452
+ values: Object.freeze({}),
453
+ issues: Object.freeze([]),
454
+ warnings: Object.freeze([]),
455
+ key: null,
456
+ attempt: null,
457
+ canResend: false,
458
+ formStep: null
459
+ });
460
+ const ABSENT = Object.freeze({
461
+ ...IDLE,
462
+ control: "absent"
463
+ });
464
+ const NO_SUBSCRIBE = () => () => {};
465
+ function compileTarget(app, target) {
466
+ const named = isFlowRef(target) ? target.target : target;
467
+ try {
468
+ if ("appAction" in named) {
469
+ const def = app.registry.appActions.get(named.appAction);
470
+ return def === void 0 ? null : compileFlow(def, named.appAction);
471
+ }
472
+ const def = app.registry.get(named.resource);
473
+ return def === void 0 ? null : compileFlow(def, named.action);
474
+ } catch {
475
+ return null;
476
+ }
477
+ }
478
+ const keyOfTarget = (target) => {
479
+ const named = isFlowRef(target) ? target.target : target;
480
+ return "appAction" in named ? `app:${named.appAction}` : `r:${named.resource}/${named.action}`;
481
+ };
482
+ let warnedNoUser = false;
483
+ const isObject$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
484
+ const idOf = (value) => typeof value === "string" && value !== "" ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : void 0;
485
+ function flowAttemptKey(compiled, user, record, args, selection) {
486
+ const recordId = idOf(record?.[compiled.idField] ?? record?.id);
487
+ return attemptKey({
488
+ user,
489
+ flow: compiled.flowId,
490
+ slot: attemptSlot({
491
+ ...recordId === void 0 ? {} : { record: recordId },
492
+ ...args === void 0 || Object.keys(args).length === 0 ? {} : { argsHash: fnv1a(args) },
493
+ ...selection === void 0 || compiled.each ? {} : { selectionHash: fnv1a([...selection].sort()) }
494
+ })
495
+ });
496
+ }
497
+ function thenFor(compiled, effects, record) {
498
+ let open;
499
+ const target = effects.open;
500
+ if (isObject$1(target) && !Object.hasOwn(target, "block")) {
501
+ const resource = typeof target.resource === "string" ? target.resource : compiled.resource ?? void 0;
502
+ const id = idOf(target.id) ?? idOf(record?.[compiled.idField] ?? record?.id);
503
+ if (resource !== void 0 && id !== void 0) open = {
504
+ kind: "record",
505
+ resource,
506
+ id,
507
+ mode: target.mode === "edit" ? "edit" : "show",
508
+ quick: target.quick === true
509
+ };
510
+ }
511
+ const then = {
512
+ ...effects.notify === void 0 ? {} : { notify: effects.notify },
513
+ ...effects.redirect === void 0 ? {} : { redirect: effects.redirect },
514
+ ...open === void 0 ? {} : { open }
515
+ };
516
+ return Object.keys(then).length === 0 ? null : then;
517
+ }
518
+ function useFlowRun(target, opts = {}) {
519
+ const app = useApp();
520
+ const runtime = useOptionalDataRuntime();
521
+ const appSnapshot = useApplicationSnapshot();
522
+ const targetKey = keyOfTarget(target);
523
+ const compiled = useMemo(() => compileTarget(app, target), [
524
+ app,
525
+ targetKey,
526
+ appSnapshot
527
+ ]);
528
+ const userId = useCurrentUserId();
529
+ const store = useFlowAttemptsStore();
530
+ const context = useContextSnapshot();
531
+ const signedOut = isSignedOut(context);
532
+ const visibility = useOptionalVisibilityCtx();
533
+ const translate = useTranslate();
534
+ const locale = useLocale();
535
+ const audit = useFrameworkAudit();
536
+ const latest = useRef(null);
537
+ latest.current = {
538
+ user: context.user,
539
+ scope: context.scope,
540
+ permissions: readPermissions(context),
541
+ visibility,
542
+ t: (key, params, defaultValue) => {
543
+ const text = translate(key, params === void 0 ? void 0 : { params });
544
+ return text === key ? defaultValue ?? key : text;
545
+ },
546
+ audit,
547
+ locale
548
+ };
549
+ const data = useMemo(() => runtime === null ? createUnavailableActionDataAccess("A flow needs a data runtime; none is mounted.") : createRuntimeActionDataAccess(runtime), [runtime]);
550
+ const liveRecordKey = opts.record === void 0 ? "" : JSON.stringify(opts.record);
551
+ const heldRecordKey = useRef(liveRecordKey);
552
+ const writing = useRef(false);
553
+ if (!writing.current) heldRecordKey.current = liveRecordKey;
554
+ const recordKey = heldRecordKey.current;
555
+ const argsKey = opts.args === void 0 ? "" : JSON.stringify(opts.args);
556
+ const selectionKey = opts.selection === void 0 ? "" : [...opts.selection.ids].sort().join("\0");
557
+ const latestOpts = useRef(opts);
558
+ latestOpts.current = opts;
559
+ const [generation, setGeneration] = useState(0);
560
+ const carried = useRef(void 0);
561
+ const restart = useCallback(() => {
562
+ const lease = latestOpts.current.lease;
563
+ if (lease?.run != null) {
564
+ disposeWhenIdle(lease.run);
565
+ lease.run = null;
566
+ lease.deps = null;
567
+ }
568
+ setGeneration((value) => value + 1);
569
+ }, []);
570
+ const attempts = useMemo(() => {
571
+ if (compiled === null) return null;
572
+ if (userId === null) return signedOut ? createMemoryAttempts() : null;
573
+ return store === null || store.user !== userId ? null : store.port;
574
+ }, [
575
+ compiled,
576
+ userId,
577
+ signedOut,
578
+ store,
579
+ generation
580
+ ]);
581
+ const run = useMemo(() => {
582
+ if (compiled === null || runtime === null || attempts === null) return null;
583
+ if (latestOpts.current.linkOnly === true && (compiled.flow.host === "page" || compiled.flow.host !== void 0 && typeof compiled.flow.host === "object")) return null;
584
+ const { record, args, selection, lease } = latestOpts.current;
585
+ const leaseDeps = lease === void 0 ? null : [
586
+ compiled.flowId,
587
+ userId,
588
+ lease.record,
589
+ argsKey
590
+ ].join("\0");
591
+ if (lease?.run != null && lease.deps === leaseDeps) return lease.run;
592
+ const ports = createRuntimeFlowPorts({
593
+ runtime,
594
+ app,
595
+ flow: compiled,
596
+ ...record === void 0 ? {} : { record },
597
+ ...args === void 0 ? {} : { args },
598
+ attempts,
599
+ form: createFlowFormPort(compiled.flow, app, { i18nPrefix: compiled.formId }),
600
+ user: userId,
601
+ data,
602
+ context: () => latest.current
603
+ });
604
+ const created = createFlowRun({
605
+ flow: compiled,
606
+ ...record === void 0 ? {} : { record },
607
+ ...args === void 0 ? {} : { args },
608
+ ...selection === void 0 ? {} : { selection },
609
+ ports
610
+ });
611
+ registerFlowRun(created, compiled.formId);
612
+ if (carried.current !== void 0) created.setValues(carried.current);
613
+ carried.current = void 0;
614
+ if (lease !== void 0) {
615
+ lease.run = created;
616
+ lease.deps = leaseDeps;
617
+ lease.opened = false;
618
+ }
619
+ return created;
620
+ }, [
621
+ compiled,
622
+ runtime,
623
+ attempts,
624
+ app,
625
+ userId,
626
+ data,
627
+ recordKey,
628
+ argsKey,
629
+ selectionKey,
630
+ generation
631
+ ]);
632
+ useEffect(() => {
633
+ if (!signedOut || compiled === null || warnedNoUser) return;
634
+ if (process.env.NODE_ENV === "production") return;
635
+ warnedNoUser = true;
636
+ console.warn(`[burojs] ${compiled.flowId} runs without a signed-in user: its attempts are kept in memory for this run only, and its form keeps no draft.`);
637
+ }, [signedOut, compiled]);
638
+ useEffect(() => {
639
+ if (run === null) return;
640
+ const lease = latestOpts.current.lease;
641
+ if (lease === void 0) {
642
+ run.open();
643
+ return () => run.dispose();
644
+ }
645
+ if (lease.opened) return;
646
+ lease.opened = true;
647
+ run.open();
648
+ }, [run]);
649
+ const permissionsStatus = readPermissions(context)?.status;
650
+ useEffect(() => {
651
+ if (run === null || permissionsStatus === "loading") return;
652
+ if (run.getSnapshot().control === "undecided") run.open();
653
+ }, [run, permissionsStatus]);
654
+ const snapshot = useSyncExternalStore(run?.subscribe ?? NO_SUBSCRIBE, () => run?.getSnapshot() ?? (compiled === null ? ABSENT : IDLE), () => run?.getSnapshot() ?? (compiled === null ? ABSENT : IDLE));
655
+ const locked = snapshot.control === "running";
656
+ writing.current = locked;
657
+ useDismissPending(locked);
658
+ useNavigationHold(locked);
659
+ const scopeEffects = useDispatcherEffects();
660
+ const effectsOf = opts.thenEffects ?? scopeEffects;
661
+ const ranThen = useRef(null);
662
+ const outcome = snapshot.outcome;
663
+ const thenEffects = snapshot.effects;
664
+ const thenHeld = useRef(false);
665
+ const thenOf = useRef({
666
+ run,
667
+ compiled
668
+ });
669
+ thenOf.current = {
670
+ run,
671
+ compiled
672
+ };
673
+ const runThen = useCallback(() => {
674
+ const { run: current, compiled: flow } = thenOf.current;
675
+ if (current === null || flow === null) return;
676
+ const now = current.getSnapshot();
677
+ if (now.outcome?.outcome !== "success" || now.effects === void 0) return;
678
+ if (ranThen.current === now.outcome) return;
679
+ ranThen.current = now.outcome;
680
+ const then = thenFor(flow, now.effects, latestOpts.current.record);
681
+ if (then === null) return;
682
+ runThenEffects(effectsOf(), then).catch((error) => {
683
+ if (process.env.NODE_ENV !== "production") console.error(`[burojs] ${flow.flowId}: a then effect threw.`, error);
684
+ });
685
+ }, [effectsOf]);
686
+ const holdThen = useCallback((hold) => {
687
+ thenHeld.current = hold;
688
+ }, []);
689
+ useEffect(() => {
690
+ if (thenHeld.current) return;
691
+ runThen();
692
+ }, [
693
+ run,
694
+ compiled,
695
+ outcome,
696
+ thenEffects,
697
+ runThen
698
+ ]);
699
+ const lockedRef = useRef(locked);
700
+ lockedRef.current = locked;
701
+ useEffect(() => {
702
+ if (run === null || store === null || compiled === null || compiled.each) return;
703
+ const { record, args, selection } = latestOpts.current;
704
+ const key = flowAttemptKey(compiled, userId, record, args, selection?.ids);
705
+ return store.subscribe(() => {
706
+ if (lockedRef.current) return;
707
+ const now = run.getSnapshot();
708
+ const held = now.outcome?.outcome === "unknown" ? now.key : null;
709
+ if ((store.port.read(key)?.key ?? null) === held) return;
710
+ carried.current = now.values;
711
+ restart();
712
+ });
713
+ }, [
714
+ run,
715
+ store,
716
+ compiled,
717
+ userId,
718
+ restart
719
+ ]);
720
+ const reset = useCallback(() => {
721
+ if (lockedRef.current) return;
722
+ carried.current = void 0;
723
+ restart();
724
+ }, [restart]);
725
+ return useMemo(() => ({
726
+ run,
727
+ snapshot,
728
+ compiled,
729
+ reset,
730
+ holdThen,
731
+ runThen
732
+ }), [
733
+ run,
734
+ snapshot,
735
+ compiled,
736
+ reset,
737
+ holdThen,
738
+ runThen
739
+ ]);
740
+ }
741
+ //#endregion
742
+ //#region src/hooks/use-action.ts
743
+ const isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
744
+ const isStandard = (value) => isObject(value) && isObject(value["~standard"]) && typeof value["~standard"].validate === "function";
745
+ function schemaOf(declared, attachment) {
746
+ if (isStandard(declared)) return declared;
747
+ if (!isObject(declared)) return void 0;
748
+ const schema = declared.schema;
749
+ if (isStandard(schema)) return schema;
750
+ if (isObject(schema) && typeof schema.capability === "string" && typeof schema.id === "string") {
751
+ const resolved = attachment(schema.capability, schema.id);
752
+ if (isStandard(resolved)) return resolved;
753
+ if (isObject(resolved) && isStandard(resolved.schema)) return resolved.schema;
754
+ }
755
+ }
756
+ async function invalidArg(compiled, args, attachment) {
757
+ const declared = compiled.flow.args;
758
+ for (const [name, entry] of Object.entries(declared ?? {})) {
759
+ const optional = isObject(entry) && (entry.optional === true || entry.isOptional === true);
760
+ if (args[name] === void 0 && optional) continue;
761
+ const schema = schemaOf(entry, attachment);
762
+ if (schema === void 0) continue;
763
+ if ((await schema["~standard"].validate(args[name])).issues !== void 0) return name;
764
+ }
765
+ return null;
766
+ }
767
+ function useAction(target, opts = {}) {
768
+ const app = useApp();
769
+ const navigate = useRouteNavigate();
770
+ const { run, snapshot, compiled } = useFlowRun(target, {
771
+ ...opts.record === void 0 ? {} : { record: opts.record },
772
+ ...opts.args === void 0 ? {} : { args: opts.args },
773
+ surface: "code",
774
+ linkOnly: true
775
+ });
776
+ const named = isFlowRef(target) ? target.target : target;
777
+ const resolveRow = useFlowRowResolver("resource" in named ? named.resource : "");
778
+ const pageHosted = compiled?.flow.host === "page";
779
+ const hostPage = useHostPage(compiled?.flow.host);
780
+ const hosted = hostPageRef(compiled?.flow.host) !== void 0;
781
+ const hostGate = usePageFlowGate(named);
782
+ const pageControl = pageHosted ? resolveRow(compiled.name, opts.record) : void 0;
783
+ const title = useProjectedTitle(compiled?.resource ?? void 0, compiled === null ? void 0 : opts.record?.[compiled.idField] ?? opts.record?.id, opts.record);
784
+ const present = usePresentFlow();
785
+ const presentInput = {
786
+ label: compiled === null ? "" : typeof compiled.flow.label === "string" ? compiled.flow.label : humanizeKey(compiled.name),
787
+ ...opts.record === void 0 || title === "" ? {} : { title },
788
+ ...opts.record === void 0 ? {} : { record: opts.record },
789
+ ...opts.args === void 0 ? {} : { args: opts.args }
790
+ };
791
+ const hostRef = useRef({
792
+ present,
793
+ presentInput,
794
+ target
795
+ });
796
+ hostRef.current = {
797
+ present,
798
+ presentInput,
799
+ target
800
+ };
801
+ const inflight = useRef(null);
802
+ const hostState = hosted ? conjoinHostPage(hostGate.answer.state === "available" ? "ready" : hostGate.answer.state === "hidden" ? "absent" : hostGate.answer.state, hostPage) : void 0;
803
+ const hostLink = hostState === void 0 ? void 0 : {
804
+ state: hostState,
805
+ href: hostPage?.href ?? ""
806
+ };
807
+ const latest = useRef({
808
+ run,
809
+ snapshot,
810
+ compiled,
811
+ args: opts.args,
812
+ pageControl,
813
+ hostLink
814
+ });
815
+ latest.current = {
816
+ run,
817
+ snapshot,
818
+ compiled,
819
+ args: opts.args,
820
+ pageControl,
821
+ hostLink
822
+ };
823
+ const pageOf = useRef({
824
+ navigate,
825
+ app,
826
+ record: opts.record
827
+ });
828
+ pageOf.current = {
829
+ navigate,
830
+ app,
831
+ record: opts.record
832
+ };
833
+ const attachments = useMemo(() => compiled === null ? () => void 0 : trustedFlowAttachments(app.runtime, compiled), [app, compiled]);
834
+ const runNow = useCallback(() => {
835
+ if (inflight.current !== null) return inflight.current;
836
+ const { run: current, snapshot: now, compiled: flow, args, pageControl: link, hostLink: pageLink } = latest.current;
837
+ if (pageLink !== void 0) {
838
+ if (pageLink.state !== "ready" || pageLink.href === "") return Promise.resolve(Object.freeze({
839
+ outcome: "unavailable",
840
+ state: pageLink.state
841
+ }));
842
+ pageOf.current.navigate(pageLink.href);
843
+ return Promise.resolve(Object.freeze({ outcome: "navigated" }));
844
+ }
845
+ if (flow !== null && link !== void 0) {
846
+ if (link.state !== "ready") return Promise.resolve(Object.freeze({
847
+ outcome: "unavailable",
848
+ state: link.state
849
+ }));
850
+ const { navigate: go, app: owner, record } = pageOf.current;
851
+ const id = record?.[flow.idField] ?? record?.id;
852
+ if (typeof id !== "string" && typeof id !== "number" || String(id) === "" || flow.resource === null) {
853
+ if (process.env.NODE_ENV !== "production") console.error(`[burojs] useAction(${flow.flowId}): a page-hosted flow needs the record it runs on; nothing was opened.`);
854
+ return Promise.resolve(Object.freeze({ outcome: "failed" }));
855
+ }
856
+ go(hrefFor(owner.registry, flow.resource, {
857
+ action: "flow",
858
+ id: String(id),
859
+ flow: flow.name
860
+ }));
861
+ return Promise.resolve(Object.freeze({ outcome: "navigated" }));
862
+ }
863
+ if (current === null || flow === null || now.control === "undecided" || now.control === "absent") return Promise.resolve(Object.freeze({
864
+ outcome: "unavailable",
865
+ state: current === null && flow !== null ? "undecided" : now.control
866
+ }));
867
+ const started = (async () => {
868
+ const invalid = await invalidArg(flow, args ?? {}, attachments);
869
+ if (invalid !== null) {
870
+ if (process.env.NODE_ENV !== "production") console.error(`[burojs] useAction(${flow.flowId}): args.${invalid} does not match the flow's declared args; nothing was run.`);
871
+ return Object.freeze({ outcome: "failed" });
872
+ }
873
+ if (flow.hasHost) {
874
+ const { present: open, presentInput: given, target: what } = hostRef.current;
875
+ const closed = open({
876
+ ...given,
877
+ target: what,
878
+ host: flow.flow.host === "sheet" ? "sheet" : "dialog"
879
+ });
880
+ if (closed !== null) return closed;
881
+ }
882
+ return current.submit();
883
+ })();
884
+ inflight.current = started;
885
+ started.finally(() => {
886
+ if (inflight.current === started) inflight.current = null;
887
+ });
888
+ return started;
889
+ }, [attachments]);
890
+ const state = hostState ?? (pageControl === void 0 ? snapshot.control : pageControl.state);
891
+ const reason = hosted ? hostGate.answer.state === "disabled" ? hostGate.answer.reason : void 0 : pageControl === void 0 ? snapshot.reason : pageControl.reason;
892
+ return useMemo(() => Object.freeze({
893
+ state,
894
+ ...reason === void 0 ? {} : { reason },
895
+ run: runNow
896
+ }), [
897
+ state,
898
+ reason,
899
+ runNow
900
+ ]);
901
+ }
902
+ //#endregion
903
+ //#region src/flows/use-flow-form.ts
904
+ const NO_FIELDS = Object.freeze({});
905
+ function useFlowForm(run, compiled, snapshot, opts = {}) {
906
+ const form = compiled?.flow.form;
907
+ const userId = useCurrentUserId();
908
+ const fields = useMemo(() => form === void 0 ? NO_FIELDS : fieldEntriesToMap(form.fields), [compiled]);
909
+ const tree = form?.body;
910
+ const body = useMemo(() => tree === void 0 ? void 0 : () => tree, [compiled]);
911
+ const recordId = opts.record === void 0 || compiled === null ? void 0 : opts.record[compiled.idField] ?? opts.record.id;
912
+ const flowDraft = useMemo(() => ({
913
+ ...typeof recordId === "string" || typeof recordId === "number" ? { recordId: String(recordId) } : {},
914
+ ...opts.args === void 0 || Object.keys(opts.args).length === 0 ? {} : { argsHash: fnv1a(opts.args) },
915
+ ...opts.selection === void 0 || compiled?.each === true ? {} : { selectionHash: fnv1a([...opts.selection].sort()) },
916
+ ...compiled === null ? {} : { attempt: flowAttemptKey(compiled, userId, opts.record, opts.args, opts.selection) }
917
+ }), [
918
+ String(recordId),
919
+ JSON.stringify(opts.args ?? null),
920
+ (opts.selection ?? []).join("\0"),
921
+ compiled,
922
+ userId
923
+ ]);
924
+ const onChange = useCallback((values) => run?.setValues(values), [run]);
925
+ const blocks = useFlowFormCatalog();
926
+ const metaSources = useMemo(() => Object.freeze({
927
+ record: Object.freeze({
928
+ status: "ready",
929
+ value: opts.record ?? null,
930
+ refreshing: false
931
+ }),
932
+ args: Object.freeze({
933
+ status: "ready",
934
+ value: opts.args ?? {},
935
+ refreshing: false
936
+ })
937
+ }), [opts.record, opts.args]);
938
+ const controller = useFormController({
939
+ blocks,
940
+ metaSources,
941
+ fields,
942
+ ...body === void 0 ? {} : { body },
943
+ mode: "create",
944
+ surface: "create",
945
+ ...compiled === null ? {} : {
946
+ formId: compiled.formId,
947
+ i18nPrefix: compiled.resource === null ? `appActions.${compiled.name}` : `${compiled.resource}.actions.${compiled.name}`
948
+ },
949
+ ...form?.draft === void 0 || run === null ? {} : { draft: form.draft },
950
+ ...run === null ? {} : { flowRun: run },
951
+ flowDraft,
952
+ flowIssues: snapshot.issues,
953
+ value: snapshot.values,
954
+ onChange
955
+ });
956
+ const seeded = useRef(null);
957
+ const opened = snapshot.history.includes("open");
958
+ useEffect(() => {
959
+ if (run === null || !opened || seeded.current === run) return;
960
+ seeded.current = run;
961
+ controller.reset(run.getSnapshot().values);
962
+ }, [
963
+ run,
964
+ opened,
965
+ controller
966
+ ]);
967
+ const succeeded = snapshot.outcome?.outcome === "success";
968
+ const outcome = snapshot.outcome;
969
+ const cleared = useRef(null);
970
+ useEffect(() => {
971
+ if (!succeeded || cleared.current === outcome) return;
972
+ cleared.current = outcome;
973
+ controller.reset(snapshot.values);
974
+ controller.draft.discard();
975
+ }, [
976
+ succeeded,
977
+ outcome,
978
+ snapshot.values,
979
+ controller
980
+ ]);
981
+ return controller;
982
+ }
983
+ //#endregion
984
+ //#region src/flows/use-flow-host.ts
985
+ function useFlowHost(flow, opts) {
986
+ const runtime = useUIPresentationRuntime();
987
+ const mount = useOptionalPresentationMount();
988
+ const registry = useContext(DismissRegistryContext);
989
+ const enclosing = useContext(DismissScopeContext);
990
+ const activation = useCurrentUIActivation();
991
+ const [openId, setOpenId] = useState(null);
992
+ const [closed, setClosed] = useState(0);
993
+ const current = useRef(null);
994
+ const latest = useRef({
995
+ flow,
996
+ opts
997
+ });
998
+ latest.current = {
999
+ flow,
1000
+ opts
1001
+ };
1002
+ const open = useCallback((hostOverride) => {
1003
+ const { flow: now, opts: given } = latest.current;
1004
+ const { run, compiled } = now;
1005
+ if (run === null || compiled === null || mount === null) return null;
1006
+ if (current.current !== null) return null;
1007
+ const host = hostOverride ?? (compiled.flow.host === "sheet" ? "sheet" : "dialog");
1008
+ if (mount.mode === "app" && !mount.registry.isMounted()) {
1009
+ console.error(`[burojs] ${compiled.flowId} opened nothing: BuroProvider is in presentations="app" mode but no <BuroPresentationOutlet/> is mounted.`);
1010
+ return null;
1011
+ }
1012
+ if (mount.hosts[host] === void 0) {
1013
+ reportMissingFlowHost(mount.registry, host);
1014
+ return null;
1015
+ }
1016
+ if (mount.hosts.screens?.flow === void 0) {
1017
+ reportMissingFlowHost(mount.registry, "screens.flow");
1018
+ return null;
1019
+ }
1020
+ const props = {
1021
+ run,
1022
+ host,
1023
+ label: given.label,
1024
+ compiled,
1025
+ ...given.title === void 0 ? {} : { title: given.title },
1026
+ ...given.record === void 0 ? {} : { record: given.record },
1027
+ ...given.args === void 0 ? {} : { args: given.args },
1028
+ ...given.selection === void 0 ? {} : { selection: given.selection }
1029
+ };
1030
+ const result = runtime.present({
1031
+ component: FLOW_COMPONENT,
1032
+ host,
1033
+ props: { entry: new FlowScreenEntry(props) },
1034
+ options: {
1035
+ ownTitle: true,
1036
+ wrapper: false
1037
+ },
1038
+ activation
1039
+ });
1040
+ if (!result.ok) return null;
1041
+ if (registry !== null && enclosing !== null) registry.recordParent(result.instance.id, enclosing.id);
1042
+ let settle = () => void 0;
1043
+ const closed = new Promise((resolve) => {
1044
+ settle = resolve;
1045
+ });
1046
+ current.current = {
1047
+ id: result.instance.id,
1048
+ settle,
1049
+ run
1050
+ };
1051
+ now.holdThen(true);
1052
+ setOpenId(result.instance.id);
1053
+ return closed;
1054
+ }, [
1055
+ runtime,
1056
+ mount,
1057
+ registry,
1058
+ enclosing,
1059
+ activation
1060
+ ]);
1061
+ useEffect(() => {
1062
+ if (openId === null) return;
1063
+ const check = () => {
1064
+ const open = current.current;
1065
+ if (open === null || open.id !== openId) return;
1066
+ if (runtime.getSnapshot().some((descriptor) => descriptor.id === openId)) return;
1067
+ current.current = null;
1068
+ const snapshot = open.run.getSnapshot();
1069
+ open.settle(snapshot.outcome ?? Object.freeze({
1070
+ outcome: "halted",
1071
+ step: snapshot.step
1072
+ }));
1073
+ setOpenId(null);
1074
+ setClosed((value) => value + 1);
1075
+ };
1076
+ check();
1077
+ return runtime.subscribe(check);
1078
+ }, [runtime, openId]);
1079
+ useEffect(() => {
1080
+ if (closed === 0) return;
1081
+ latest.current.flow.holdThen(false);
1082
+ latest.current.flow.runThen();
1083
+ latest.current.flow.reset();
1084
+ }, [closed]);
1085
+ useEffect(() => () => {
1086
+ const open = current.current;
1087
+ if (open === null) return;
1088
+ current.current = null;
1089
+ runtime.dismiss(open.id);
1090
+ const snapshot = open.run.getSnapshot();
1091
+ open.settle(snapshot.outcome ?? Object.freeze({
1092
+ outcome: "halted",
1093
+ step: snapshot.step
1094
+ }));
1095
+ }, [runtime]);
1096
+ return useMemo(() => ({
1097
+ open,
1098
+ isOpen: openId !== null
1099
+ }), [open, openId]);
1100
+ }
1101
+ //#endregion
1102
+ //#region src/flows/forget-each.ts
1103
+ function useForgetEachAttempt(target) {
1104
+ const app = useApp();
1105
+ const userId = useCurrentUserId();
1106
+ const store = useFlowAttemptsStore();
1107
+ const audit = useFrameworkAudit();
1108
+ const latest = useRef({
1109
+ app,
1110
+ userId,
1111
+ store,
1112
+ audit,
1113
+ target
1114
+ });
1115
+ latest.current = {
1116
+ app,
1117
+ userId,
1118
+ store,
1119
+ audit,
1120
+ target
1121
+ };
1122
+ return useCallback(async (id) => {
1123
+ const { app: now, userId: user, store: tab, audit: sink, target: what } = latest.current;
1124
+ if (user === null || tab === null || tab.user !== user || id === "") return false;
1125
+ const named = isFlowRef(what) ? what.target : what;
1126
+ if ("appAction" in named) return false;
1127
+ const def = now.registry.get(named.resource);
1128
+ if (def === void 0) return false;
1129
+ const compiled = compileFlow(def, named.action);
1130
+ const key = attemptKey({
1131
+ user,
1132
+ flow: compiled.flowId,
1133
+ slot: attemptSlot({ record: id })
1134
+ });
1135
+ const stored = tab.port.read(key) ?? await tab.port.ask(key);
1136
+ if (stored === null || stored.flow !== compiled.flowId) return false;
1137
+ tab.port.drop(key);
1138
+ sink?.emit(Object.freeze({
1139
+ type: "flow.submit",
1140
+ flow: compiled.flowId,
1141
+ ...compiled.resource === null ? {} : { resource: compiled.resource },
1142
+ recordId: id,
1143
+ mutation: compiled.mutationRef,
1144
+ idempotencyKey: stored.key,
1145
+ attempt: 1,
1146
+ outcome: "unknown",
1147
+ resolvedBy: "user",
1148
+ acceptedWarnings: Object.freeze([]),
1149
+ diff: Object.freeze({})
1150
+ }), { initiates: true });
1151
+ return true;
1152
+ }, []);
1153
+ }
1154
+ //#endregion
1155
+ export { useAction, useFlowForm, useFlowHost, useFlowRun, useForgetEachAttempt };
1156
+
1157
+ //# sourceMappingURL=flows-runtime.js.map