@civitai/blocks-react 0.43.1 → 0.44.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 CHANGED
@@ -237,8 +237,44 @@ try {
237
237
  showError(estimateFailureMessage(err));
238
238
  }
239
239
  if (priced) {
240
- const snap = await submit(body); // status 'submitting' → 'polling'; returns a workflowId
241
- await poll(snap.workflowId); // you loop this on a backoff until terminal
240
+ // 🔴 submit() REJECTS when the reply carries no usable workflow outcome. A
241
+ // priced refusal is different — it RESOLVES.
242
+ try {
243
+ const snap = await submit(body); // status 'submitting' → 'polling'
244
+ if (snap.status === 'failed') {
245
+ // 🔴 A RESOLVED `failed` IS A PRICED SERVER OUTCOME — and only SOME of
246
+ // them are about the viewer's wallet. Affordability (per-call budget, the
247
+ // per-user daily Buzz cap) IS fixable by buying Buzz; the per-app velocity
248
+ // limit, the per-app aggregate daily cap, a fail-closed "temporarily
249
+ // unavailable" deny and a missing price quote are NOT. Selling Buzz for
250
+ // one of those takes money and fixes nothing, so branch before you offer.
251
+ showError(submitOutcomeMessage(snap)); // YOUR app owns this copy
252
+ } else {
253
+ await poll(snap.workflowId); // you loop this on a backoff until terminal
254
+ }
255
+ } catch (err) {
256
+ if (!(err instanceof WorkflowSubmitError)) throw err;
257
+ // Log both for the developer; render neither.
258
+ logForDebugging(err.message, err.snapshot.error);
259
+ // 🔴 TWO SEPARATE QUESTIONS — DO NOT CONJOIN THEM. `code` decides what you may
260
+ // say about MONEY; the id decides only whether there is something to POLL.
261
+ // Folding the id test into the `code` test sends a 'workflow-failed' reply
262
+ // whose id is 'whatif' into the reassuring arm — the exact blind-retry
263
+ // invitation this whole guard exists to remove.
264
+ if (err.code === 'workflow-failed') {
265
+ // 🔴 Spend MAY ALREADY BE COMMITTED. Do not tell the viewer it was free,
266
+ // and do not retry blindly — a retry mints a fresh idempotency key, i.e. a
267
+ // SECOND reservation.
268
+ showError('The generation may have started but did not complete. Check your history.');
269
+ // Only NOW ask about pollability: 'whatif' is a non-workflow sentinel.
270
+ if (err.snapshot.workflowId !== 'whatif') await poll(err.snapshot.workflowId);
271
+ } else {
272
+ // 🔴 'exception' means the host had no workflow to report — USUALLY nothing
273
+ // was queued, but a lost response or an in-progress idempotency conflict
274
+ // reaches this arm too. Retry with the SAME idempotencyKey, not a fresh one.
275
+ showError('Could not start the generation. Please try again.');
276
+ }
277
+ }
242
278
  }
243
279
  ```
244
280
 
@@ -252,10 +288,55 @@ if (priced) {
252
288
  - The hook does **not** auto-poll. After `submit` flips status to `'polling'`,
253
289
  the **caller** runs a `useEffect` that calls `poll(workflowId)` on a backoff
254
290
  until the snapshot is terminal (`succeeded | failed | canceled | expired`).
255
- - An over-budget / rejected **submit** comes back as a **resolved** snapshot with
256
- `status: 'failed'` + an `error` string — the transport resolves the reply, it
257
- doesn't throw. Check `snap.status`, not just `try/catch`.
258
- - **`estimate` is the exception to that rule** (`@civitai/blocks-react@0.43.0+`).
291
+ - A **priced** submit refusal comes back as a **resolved** snapshot with
292
+ `status: 'failed'`, an `error` string, **and a numeric `cost.total`** — the
293
+ price the server refused to charge. That is a workflow *outcome*, not an error.
294
+ Check `snap.status`, not just `try/catch`.
295
+ 🔴 **Not all of them are affordability.** Only the per-call `buzzBudget` gate
296
+ and the per-user daily Buzz cap are about the wallet. The per-app **velocity**
297
+ limit, the per-app **aggregate daily** cap, a fail-closed **"temporarily
298
+ unavailable"** deny and a **missing price quote** are priced outcomes too, and
299
+ buying Buzz fixes none of them. Branch before you offer a top-up.
300
+ - **`submit` REJECTS when the reply carries no usable workflow outcome**
301
+ (`@civitai/blocks-react@0.44.0+`). Every failure-shaped reply reports
302
+ `status: 'failed'`, so `status` cannot tell them apart — **`cost` presence
303
+ decides resolve-vs-reject, and `workflowId` decides which rejection**:
304
+ - **priced refusal** → carries `cost`. **Resolves**, as above.
305
+ - **a reply the host built itself** (`failureSnapshot(err)`, which stamps the
306
+ literal `workflowId: 'failed'` — from a `catch` or a short-circuit such as
307
+ the moderator-review nack) → no `cost`. **Rejects** with
308
+ `err.code === 'exception'`, which means *the host had no workflow to report*.
309
+ 🔴 **Not the same as "nothing happened."** Usually nothing was queued or
310
+ charged and a retry is fine, but a **lost response**, an **in-progress
311
+ idempotency conflict**, or a **transient 5xx/408/429/401** also land here,
312
+ and a workflow may have been created and charged. Prefer reusing the same
313
+ `idempotencyKey` on retry, and don't render "nothing was charged" as fact.
314
+ - **a failed, unpriced reply whose id is NOT that sentinel** (normally a
315
+ genuine orchestrator id) → no `cost`. **Rejects** with
316
+ `err.code === 'workflow-failed'`.
317
+ 🔴 **Money may already be committed.** Server-side, *any* resolved submit
318
+ keeps its Buzz reservation "regardless of snapshot status", with no refund on
319
+ a non-throwing failed snapshot. So do not tell the viewer it was free, and do
320
+ not retry blindly — `submit()` mints a fresh `idempotencyKey` per call, so an
321
+ automatic retry is a second reservation. Read `err.snapshot.workflowId` (a
322
+ usually-pollable id) and `watch`/`poll` it to learn the workflow's actual
323
+ fate — guarding with `err.snapshot.workflowId !== 'whatif'` first, since the
324
+ server treats both `'failed'` and `'whatif'` as non-workflow sentinels.
325
+
326
+ Before that version everything resolved, so a block branching on
327
+ `snap.status === 'failed'` could not tell "you can't afford this" from "the
328
+ request failed", and one gating a money control on
329
+ `typeof snap.cost?.total === 'number'` saw the same dead-control shape
330
+ civitai/civitai#4159 describes. An ordinary in-flight reply
331
+ (`{ status: 'pending' }`) is cost-less too and still resolves — and so are
332
+ cost-less `succeeded` / `canceled` / `expired` replies. Only a *failure-shaped*
333
+ reply with no price rejects. `err.message` is a generic developer-facing
334
+ constant that makes **no claim about money** (the two codes differ on that) and
335
+ the server's words stay on `err.snapshot.error`, exactly as on
336
+ `WorkflowEstimateError` below. Note this also fires in **moderator review
337
+ preview**. To exercise your `catch` locally, set the mock host's
338
+ `generation.failSubmitException: true`.
339
+ - **`estimate` follows the same rule for a different question** (`@civitai/blocks-react@0.43.0+`).
259
340
  It **rejects** with a `WorkflowEstimateError` when the reply carries no usable
260
341
  price, rather than resolving a snapshot with no `cost`. Two things produce
261
342
  that, and `err.code` tells them apart: `'failed'` (the estimate errored
@@ -1 +1 @@
1
- {"version":3,"file":"useAppStorage.d.ts","sourceRoot":"","sources":["../../src/hooks/useAppStorage.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACjD;;;;OAIG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnF;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC7D;;;OAGG;IACH,IAAI,CAAC,IAAI,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAClC;;;OAGG;IACH,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,IAAI,aAAa,CAyE7C"}
1
+ {"version":3,"file":"useAppStorage.d.ts","sourceRoot":"","sources":["../../src/hooks/useAppStorage.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACjD;;;;OAIG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnF;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC7D;;;OAGG;IACH,IAAI,CAAC,IAAI,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAClC;;;OAGG;IACH,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,IAAI,aAAa,CAsF7C"}
@@ -35,15 +35,28 @@ export function useAppStorage() {
35
35
  },
36
36
  async set(key, value) {
37
37
  const result = await sendTypedRequest(transport, { type: 'APP_STORAGE_SET', payload: { key, value } }, 'APP_STORAGE_SET_RESULT');
38
- if (!result.ok || result.error) {
39
- throw new Error(result.error ?? 'storage set failed');
38
+ // A PRESENT `error` is the reject signal, not a TRUTHY one: the reply
39
+ // validator early-accepts anything carrying an `error` key, so
40
+ // `error: ''` reaches here having skipped the success-field checks.
41
+ // `||` (not `??`) so an empty error string still yields readable copy.
42
+ if (!result.ok || result.error !== undefined) {
43
+ throw new Error(result.error || 'storage set failed');
40
44
  }
41
45
  return { ok: true, sizeBytes: result.sizeBytes };
42
46
  },
43
47
  async delete(key) {
44
48
  const result = await sendTypedRequest(transport, { type: 'APP_STORAGE_DELETE', payload: { key } }, 'APP_STORAGE_DELETE_RESULT');
45
- if (!result.ok || result.error) {
46
- throw new Error(result.error ?? 'storage delete failed');
49
+ // PRESENT, not truthy — see `set()` above.
50
+ if (!result.ok || result.error !== undefined) {
51
+ throw new Error(result.error || 'storage delete failed');
52
+ }
53
+ // `deleted` is optional on the wire type because an error reply omits
54
+ // it. On the success path the validator requires a boolean, so this is
55
+ // defence in depth rather than a reachable branch through the real
56
+ // transport — but it is what makes the `boolean` we return honest,
57
+ // instead of a cast asserting a guarantee this function cannot see.
58
+ if (typeof result.deleted !== 'boolean') {
59
+ throw new Error('storage delete failed: reply carried no `deleted` flag');
47
60
  }
48
61
  return { ok: true, deleted: result.deleted };
49
62
  },
@@ -1 +1 @@
1
- {"version":3,"file":"useAppStorage.js","sourceRoot":"","sources":["../../src/hooks/useAppStorage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useAppStorage.js","sourceRoot":"","sources":["../../src/hooks/useAppStorage.ts"],"names":[],"mappings":"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"}
@@ -143,20 +143,13 @@ export interface WatchWorkflowOptions {
143
143
  * off a third party's default-printed surface. `test/useBuzzWorkflow.test.tsx`
144
144
  * pins it with a realistic `Unique constraint failed: Key (email)=(…)` fixture.
145
145
  *
146
- * 🔴 NOT APPLIED TO `submit`, and the reason is narrower than it looks. On
147
- * `WORKFLOW_SUBMITTED` there are likewise TWO producers, indistinguishable by
148
- * `status`: budget/cap REJECTIONS, which are a documented outcome the block
149
- * recovers from (open a top-up flow) and which carry a `cost`; and caught server
150
- * exceptions posted via the SAME `failureSnapshot(err)` used above, which do not.
151
- * The `#4159` defect is therefore live on `submit` too, discriminated by `cost`
152
- * presence rather than by `status`. Fixing it there is a separate change with its
153
- * own blast radius on the recovery path (a fix MUST keep the budget-rejection arm
154
- * RESOLVING, or the top-up flow breaks) and is deliberately NOT attempted here —
155
- * so `submit` is left resolving BOTH, and the accompanying test pins only the
156
- * budget-rejection producer, not a claim that submit is correct.
157
- *
158
- * 🔴 TRACKED, NOT FORGOTTEN: civitai/civitai-app-starters#251. Read it before
159
- * touching `submit`'s failure handling.
146
+ * 🔴 `submit` HAS ITS OWN CLASS — {@link WorkflowSubmitError} — BECAUSE ITS
147
+ * DISCRIMINATOR IS DIFFERENT. On `WORKFLOW_SUBMITTED` both producers report
148
+ * `status:'failed'`, so `status` separates nothing there and `cost` presence is
149
+ * what does. Do not merge the two classes or reuse this one for submit: the
150
+ * question each answers is different ("was a usable price returned?" vs "was a
151
+ * workflow actually queued?") and so is the arm that must keep resolving.
152
+ * (civitai/civitai-app-starters#251, the `submit` half of civitai/civitai#4159.)
160
153
  */
161
154
  export declare class WorkflowEstimateError extends Error {
162
155
  /**
@@ -199,6 +192,170 @@ export declare class WorkflowEstimateError extends Error {
199
192
  readonly snapshot: BlockWorkflowSnapshot;
200
193
  constructor(snapshot: BlockWorkflowSnapshot, code: 'failed' | 'no-cost');
201
194
  }
195
+ /**
196
+ * Why {@link UseBuzzWorkflowReturn.submit} rejected. **The two differ on whether
197
+ * money may already have moved** — see {@link WorkflowSubmitError.code}.
198
+ */
199
+ export type WorkflowSubmitErrorCode = 'exception' | 'workflow-failed';
200
+ /**
201
+ * Thrown by {@link UseBuzzWorkflowReturn.submit} when the host's reply carries no
202
+ * usable workflow outcome — either the submit ERRORED before anything was queued,
203
+ * or a workflow-shaped reply came back already failed with no price.
204
+ *
205
+ * 🔴 READ {@link WorkflowSubmitError.code} BEFORE SAYING ANYTHING ABOUT MONEY.
206
+ * The two codes differ on exactly that, and getting it wrong is expensive in both
207
+ * directions — see the per-code notes below.
208
+ *
209
+ * 🔴 WHY THIS EXISTS — civitai/civitai-app-starters#251, the `submit` half of
210
+ * civitai/civitai#4159. A server-side `blocks.submitWorkflow` throw cannot reach
211
+ * the block as a rejection; the reply crosses `postMessage`. The host instead
212
+ * posts a well-formed `WORKFLOW_SUBMITTED` carrying its `failureSnapshot(err)` —
213
+ * `{ workflowId: 'failed', status: 'failed', error: '<server message>' }`, with
214
+ * **no `cost`**. That snapshot is perfectly legal, so `submit()` resolved it and
215
+ * moved the hook to `'done'`, handing the caller a "workflow" that does not
216
+ * exist.
217
+ *
218
+ * 🔴 TWO PRODUCERS, ONE `status` — AND HERE `status` DISCRIMINATES NOTHING. This
219
+ * is what makes submit's version of the defect different from estimate's, and
220
+ * why {@link WorkflowEstimateError}'s guard could not simply be copied:
221
+ *
222
+ * - **budget / spend-cap REJECTION** — a legitimate OUTCOME. The server quotes
223
+ * the price it refused to charge, so the snapshot carries a numeric
224
+ * `cost.total`. Blocks recover from it (open a top-up flow), so it MUST keep
225
+ * RESOLVING. Every such exit on the server attaches a cost: the per-call
226
+ * `buzzBudget` gate, the per-user daily Buzz cap, the per-app aggregate and
227
+ * velocity caps, and the dev-tunnel session cap — on all three body kinds.
228
+ * - **caught server EXCEPTION** — `failureSnapshot(err)`, no `cost`, and the
229
+ * `'failed'` sentinel id. The host had no workflow to report — usually
230
+ * nothing was queued, but a lost response or an in-progress idempotency
231
+ * conflict lands here too. Rejects as `'exception'`.
232
+ * - **a reply that came back failed and unpriced with a NON-sentinel id** —
233
+ * normally a genuine orchestrator id, no `cost` (the server's
234
+ * `snapshotFromWorkflow` omits the key whenever `workflow.cost?.total` is not
235
+ * numeric). Rejects as `'workflow-failed'`, and **money may already be
236
+ * committed** — see that code's note.
237
+ *
238
+ * So the rule is `cost` presence, and ONLY among failure-shaped replies: an
239
+ * ordinary in-flight submit (`{ workflowId:'wf_…', status:'pending' }`) is
240
+ * cost-less too and must keep resolving, which is why the guard is not keyed on
241
+ * `cost` alone either. Both clauses are load-bearing; each has its own control
242
+ * in `test/useBuzzWorkflow.test.tsx`.
243
+ *
244
+ * 🔴 THE GUARD IS DELIBERATELY NOT WIDENED TO ALL TERMINAL STATUSES. A cost-less
245
+ * `succeeded` / `canceled` / `expired` reply is a legitimate outcome and must
246
+ * RESOLVE; only `'failed'` is unusable. Swapping the clause for
247
+ * `TERMINAL_STATUSES.has(...)` is a silent WIDENING that a delete-only mutation
248
+ * sweep cannot see — `test/useBuzzWorkflow.test.tsx` pins each of those three
249
+ * statuses explicitly for exactly that reason.
250
+ *
251
+ * 🔴 THREE FIELDS, THREE AUDIENCES — AND **NONE OF THEM IS VIEWER-FACING COPY**,
252
+ * exactly as on {@link WorkflowEstimateError}. Two apps migrating to `0.43.0`
253
+ * piped that class's `err.message` straight into rendered UI
254
+ * (civitai/civitai-app-starters#253); the same split applies here so the same
255
+ * mistake is not re-enabled on the submit path.
256
+ *
257
+ * - {@link WorkflowSubmitError.snapshot}`.error` — **the DIAGNOSTIC read.** The
258
+ * server's own words, verbatim. **Server-authored and UNSANITISED**:
259
+ * civitai's `errorHandling.ts` documents that raw upstream text —
260
+ * Prisma/`pg` column and constraint names among it — can reach this field.
261
+ * Log it, or show it in a developer-facing error surface. **NEVER render it
262
+ * verbatim into markup**, and think before shipping it to a third-party
263
+ * error tracker.
264
+ * - {@link WorkflowSubmitError.message} — **DEVELOPER-FACING.** A CONSTANT
265
+ * template with only `code` interpolated. It contains no server text, so it
266
+ * is safe to LOG and safe to let a stack trace print — deliberate, because
267
+ * `message` is what an uncaught rejection prints and what a third-party
268
+ * block's error reporter ships upstream by default. **It is NOT intended for
269
+ * display to viewers** and **its exact wording is NOT a contract.**
270
+ * - {@link WorkflowSubmitError.code} — **the BRANCH TARGET**, and the only
271
+ * stable one.
272
+ *
273
+ * 🔴 DO NOT "SIMPLIFY" THIS BY PUTTING `snapshot.error` BACK ON `message`, and do
274
+ * not widen the guard to reject a budget rejection. The first re-opens #253; the
275
+ * second breaks the top-up recovery flow, which is the one thing #251 says must
276
+ * not break.
277
+ */
278
+ export declare class WorkflowSubmitError extends Error {
279
+ /**
280
+ * WHICH PRODUCER this was, structurally — so a caller branches on an enum
281
+ * rather than on prose. It is the ONLY stable branch target here:
282
+ * `snapshot.error` is server-authored and can change without notice, and
283
+ * {@link WorkflowSubmitError.message} is a generic developer-facing summary
284
+ * whose exact wording is not a contract either.
285
+ *
286
+ * 🔴 THE TWO CODES DIFFER ON WHETHER MONEY MOVED. Do not collapse them, and do
287
+ * not write recovery copy that ignores the distinction.
288
+ *
289
+ * - `'exception'` — the host built this reply itself
290
+ * (`failureSnapshot(err)`, id {@link HOST_SYNTHESISED_WORKFLOW_ID}), from a
291
+ * `catch` OR from a non-catch short-circuit such as the moderator-review
292
+ * nack. **It means the host had no workflow to report — NOT that nothing
293
+ * happened.**
294
+ *
295
+ * 🔴 USUALLY nothing was queued and nothing was charged, and a retry is the
296
+ * sensible recovery. But the same shape is reachable when a workflow MAY have
297
+ * been created and charged, because the failure happened after the request
298
+ * left the block:
299
+ * - a **lost response** — the server's own catch concedes that "the
300
+ * orchestrator externalId dedupe still protects a retry that DID create a
301
+ * workflow server-side despite a lost response". What that path refunds
302
+ * is its own reservation and cap counters; the Buzz debit happens inside
303
+ * the orchestrator's submit.
304
+ * - an **in-progress idempotency CONFLICT** — a concurrent first attempt is
305
+ * still in flight and may be committing right now. Retrying blind is the
306
+ * worst option there.
307
+ * - a **transient transport failure** (5xx / 408 / 429 / 401), which the
308
+ * `dev:live` host collapses into this same shape.
309
+ *
310
+ * So prefer **reusing the same {@link SubmitWorkflowOptions.idempotencyKey}**
311
+ * on retry rather than letting a fresh one be minted, and do not render
312
+ * "nothing was charged" to a viewer as a certainty. There is no workflow id
313
+ * on this arm to poll.
314
+ *
315
+ * - `'workflow-failed'` — the id was NOT the host's sentinel, so the reply came
316
+ * from the server's `snapshotFromWorkflow`: normally a real orchestrator id,
317
+ * already `'failed'` and with no price.
318
+ *
319
+ * 🔴 **DO NOT TELL THE VIEWER NOTHING WAS CHARGED, AND DO NOT BLIND-RETRY.**
320
+ * Server-side, `blocks.submitWorkflow` treats *any resolved* submit as
321
+ * money-COMMITTED: its own comment is "A resolved submit is money-COMMITTED
322
+ * (the reservation is kept regardless of snapshot status)… we do NOT refund
323
+ * on a non-throwing failed snapshot", and `finalizeGenIdempotency` runs on
324
+ * that path. So Buzz may already be spent for this call.
325
+ *
326
+ * A retry is a SECOND reservation unless you reuse the same
327
+ * {@link SubmitWorkflowOptions.idempotencyKey} — `submit()` mints a fresh key
328
+ * per call by default, so an automatic retry double-reserves.
329
+ *
330
+ * 🔴 `err.snapshot.workflowId` IS USUALLY POLLABLE, BUT CHECK IT FIRST — this
331
+ * arm is defined by what the id is NOT. The server emits `workflow.id ??
332
+ * 'whatif'`, and it treats **both** `'failed'` and `'whatif'` as non-workflow
333
+ * sentinels (it skips its own persistence and settle steps on either). So
334
+ * `'whatif'` lands here — correctly, because the cautious money reading still
335
+ * applies — but there is nothing to poll. Guard with
336
+ * `err.snapshot.workflowId !== 'whatif'` before calling
337
+ * {@link UseBuzzWorkflowReturn.watch} / {@link UseBuzzWorkflowReturn.poll} to
338
+ * learn the workflow's actual fate before spending again.
339
+ *
340
+ * A union rather than a boolean so a future producer gets its own code without
341
+ * breaking a caller's `switch`.
342
+ *
343
+ * 🔴 A BUDGET REJECTION NEVER ARRIVES HERE. It resolves, and is read off the
344
+ * returned snapshot as `status === 'failed'` with a numeric `cost.total`.
345
+ */
346
+ readonly code: WorkflowSubmitErrorCode;
347
+ /**
348
+ * The snapshot the host replied with, VERBATIM — including `snapshot.error`,
349
+ * the server's own words, when there are any.
350
+ *
351
+ * 🔴 `snapshot.error` IS SERVER-AUTHORED AND UNSANITISED. It is where the
352
+ * reason lives, but raw upstream text — Prisma/`pg` column and constraint
353
+ * names among it — can reach that field. Log it, show it in a developer-facing
354
+ * error surface, **NEVER render it verbatim into markup**.
355
+ */
356
+ readonly snapshot: BlockWorkflowSnapshot;
357
+ constructor(snapshot: BlockWorkflowSnapshot, code: WorkflowSubmitErrorCode);
358
+ }
202
359
  /** Optional per-submit controls. */
203
360
  export interface SubmitWorkflowOptions {
204
361
  /**
@@ -207,6 +364,11 @@ export interface SubmitWorkflowOptions {
207
364
  * host+orchestrator collapse it to ONE Buzz charge instead of double-charging.
208
365
  * Omit → the hook generates a fresh key per `submit()` call (each call is a new
209
366
  * logical submit); pass a stable id (e.g. a grid-cell id) to make a retry safe.
367
+ *
368
+ * 🔴 THIS IS THE FIELD THAT MAKES A RETRY AFTER A `'workflow-failed'` REJECTION
369
+ * SAFE. That code means a workflow probably exists and its spend may already
370
+ * be committed server-side; retrying WITHOUT reusing the key mints a fresh one
371
+ * and therefore a SECOND reservation. See {@link WorkflowSubmitError.code}.
210
372
  */
211
373
  idempotencyKey?: string;
212
374
  }
@@ -234,6 +396,43 @@ interface UseBuzzWorkflowReturn {
234
396
  * estimate's price sitting in `result` for a Confirm gate to read.
235
397
  */
236
398
  estimate: (body: WorkflowBody) => Promise<BlockWorkflowSnapshot>;
399
+ /**
400
+ * Queue a workflow. Resolves ONLY with a reply that represents a real workflow
401
+ * OUTCOME — one that was queued, or one the server priced and then refused.
402
+ *
403
+ * 🔴 REJECTS with {@link WorkflowSubmitError} when the reply is failure-shaped
404
+ * and carries no price. Wrap every call in `try/catch`; see that class for why
405
+ * resolving such a reply was the `submit` half of civitai/civitai#4159.
406
+ * **Check `err.code` before saying anything about money** — and note that
407
+ * NEITHER code guarantees nothing was spent. `'exception'` usually means
408
+ * nothing was queued or charged, but a lost response or an in-progress
409
+ * idempotency conflict reaches it too; `'workflow-failed'` means a workflow
410
+ * PROBABLY exists (the `'whatif'` sentinel lands here too and has nothing to
411
+ * poll — guard before polling) and its spend may already be committed. Do not
412
+ * tell the viewer it was free, and on either code prefer reusing the same
413
+ * {@link SubmitWorkflowOptions.idempotencyKey}.
414
+ *
415
+ * 🔴 A BUDGET / SPEND-CAP REJECTION STILL RESOLVES, and that is deliberate. It
416
+ * is a documented outcome, not an error: the server quotes what it refused to
417
+ * charge, so the resolved snapshot has `status === 'failed'` AND a numeric
418
+ * `cost.total`. THAT is the shape to branch on when offering a top-up —
419
+ * `useBuzzPurchase().openPurchaseModal()` — not a `catch`.
420
+ *
421
+ * 🔴 BUT A RESOLVED `'failed'` IS NOT ALWAYS AN AFFORDABILITY PROBLEM, so do not
422
+ * wire every one of them to a purchase modal. The per-app **velocity** limit,
423
+ * the per-app **aggregate daily** cap, a fail-closed "temporarily unavailable"
424
+ * deny and a **missing price quote** are all priced, resolving outcomes that
425
+ * buying Buzz cannot fix.
426
+ *
427
+ * 🔴 THIS ALSO INCLUDES MODERATOR REVIEW PREVIEW. While an app is under review
428
+ * the host short-circuits every workflow request with
429
+ * `failureSnapshot('not available in review preview')`, so `submit()` rejects
430
+ * there where it used to resolve — the correct reading (no workflow was
431
+ * queued), and why the catch is not optional.
432
+ *
433
+ * `result` is updated to the returned snapshot BEFORE any rejection, so a
434
+ * failed submit can never leave a previous submit's workflow in `result`.
435
+ */
237
436
  submit: (body: WorkflowBody, options?: SubmitWorkflowOptions) => Promise<BlockWorkflowSnapshot>;
238
437
  /**
239
438
  * ONE host round-trip. The low-level pull primitive — you almost certainly
@@ -282,10 +481,20 @@ interface UseBuzzWorkflowReturn {
282
481
  * Orchestrates the estimate → confirm → submit → poll dance through the
283
482
  * host-mediated `postMessage` path.
284
483
  *
285
- * The host enforces budget rules (`cost_estimate <= token.buzzBudget`)
286
- * before forwarding to the orchestrator; submit() will reject if the host
287
- * refuses. Block apps should call `useBuzzPurchase().openPurchaseModal()`
288
- * when that happens.
484
+ * The host enforces budget rules (`cost_estimate <= token.buzzBudget`) before
485
+ * forwarding to the orchestrator.
486
+ *
487
+ * 🔴 A BUDGET REFUSAL DOES **NOT** REJECT — IT RESOLVES. It comes back as a
488
+ * snapshot with `status: 'failed'`, an `error` string and the `cost` the server
489
+ * declined to charge, and THAT resolved shape is the cue to call
490
+ * `useBuzzPurchase().openPurchaseModal()`. What DOES reject is a submit with no
491
+ * usable outcome — see {@link WorkflowSubmitError}. Routing a rejection into a
492
+ * top-up sells Buzz for a failure Buzz cannot fix.
493
+ *
494
+ * 🔴 NOR IS EVERY RESOLVED `'failed'` AN AFFORDABILITY PROBLEM. The per-app
495
+ * velocity limit, the per-app aggregate daily cap, a fail-closed "temporarily
496
+ * unavailable" deny and a missing price quote are all priced, resolving outcomes
497
+ * too. Branch on the message/your own policy before offering to sell anything.
289
498
  *
290
499
  * AFTER `submit` FLIPS `status` TO `'polling'`, USE `watch(workflowId)`. It owns
291
500
  * the loop, resolves on the terminal snapshot, and pushes every intermediate
@@ -347,8 +556,39 @@ interface UseBuzzWorkflowReturn {
347
556
  * logForDebugging(err.message, err.snapshot.error); // developer-facing: LOG only
348
557
  * showError(estimateFailureMessage(err)); // viewer-facing: app-owned
349
558
  * }
350
- * const snap = await submit(body); // status 'submitting' → 'polling'; returns a workflowId
351
- * const done = await watch(snap.workflowId, { onUpdate: render }); // → terminal
559
+ * // 🔴 submit() REJECTS when the reply carries no usable workflow outcome, so it
560
+ * // needs a catch too — and the two codes differ on whether MONEY MOVED.
561
+ * try {
562
+ * const snap = await submit(body); // status 'submitting' → 'polling'
563
+ * if (snap.status === 'failed') {
564
+ * // RESOLVED + priced = a server outcome (affordability, a cap, a velocity
565
+ * // limit, a transient deny). Only some of those are fixable by buying Buzz.
566
+ * showError(submitOutcomeMessage(snap));
567
+ * } else {
568
+ * const done = await watch(snap.workflowId, { onUpdate: render }); // → terminal
569
+ * if (done.status === 'succeeded') setImages(done.imageUrls ?? []);
570
+ * }
571
+ * } catch (err) {
572
+ * if (!(err instanceof WorkflowSubmitError)) throw err;
573
+ * logForDebugging(err.message, err.snapshot.error); // developer-facing: LOG only
574
+ * // 🔴 TWO SEPARATE QUESTIONS: `code` decides what you may say about MONEY,
575
+ * // the id decides only whether there is anything to POLL. Conjoining them
576
+ * // sends a 'whatif' id into the reassuring arm.
577
+ * if (err.code === 'workflow-failed') {
578
+ * // Spend may already be committed. Do NOT retry blindly (that mints a new
579
+ * // idempotency key = a second reservation) and do NOT claim nothing was
580
+ * // charged.
581
+ * showError('The generation may have started but did not complete.');
582
+ * // 'whatif' is a non-workflow sentinel — nothing behind it to poll.
583
+ * if (err.snapshot.workflowId !== 'whatif') {
584
+ * await watch(err.snapshot.workflowId, { onUpdate: render });
585
+ * }
586
+ * } else {
587
+ * // 'exception' — usually nothing was queued. Retry, but reuse the SAME
588
+ * // idempotencyKey: a lost response can also land here.
589
+ * showError('Could not start the generation. Please try again.');
590
+ * }
591
+ * }
352
592
  */
353
593
  export declare function useBuzzWorkflow(): UseBuzzWorkflowReturn;
354
594
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"useBuzzWorkflow.d.ts","sourceRoot":"","sources":["../../src/hooks/useBuzzWorkflow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AA8BnG;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAW7C,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACrD;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAyBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAEpC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;gBAE7B,QAAQ,EAAE,qBAAqB,EAAE,IAAI,EAAE,QAAQ,GAAG,SAAS;CAoBxE;AAED,oCAAoC;AACpC,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,qBAAqB;IAC7B;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACjE,MAAM,EAAE,CACN,IAAI,EAAE,YAAY,EAClB,OAAO,CAAC,EAAE,qBAAqB,KAC5B,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACpC;;;OAGG;IACH,IAAI,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC7D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,KAAK,EAAE,CACL,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,oBAAoB,KAC3B,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACpC;;;;;;OAMG;IACH,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC/D,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACrC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,wBAAgB,eAAe,IAAI,qBAAqB,CAkPvD"}
1
+ {"version":3,"file":"useBuzzWorkflow.d.ts","sourceRoot":"","sources":["../../src/hooks/useBuzzWorkflow.ts"],"names":[],"mappings":"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"}