@cellarnode/ui 0.186.0 → 0.188.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/dist/brand/brand-assets-api.d.ts +58 -0
- package/dist/brand/brand-assets-api.d.ts.map +1 -0
- package/dist/brand/brand-assets-api.js +160 -0
- package/dist/brand/brand-assets-api.js.map +1 -0
- package/dist/brand/brand-generation-api.d.ts +44 -0
- package/dist/brand/brand-generation-api.d.ts.map +1 -0
- package/dist/brand/brand-generation-api.js +2 -0
- package/dist/brand/brand-generation-api.js.map +1 -0
- package/dist/brand/brand-generation-client.d.ts +36 -0
- package/dist/brand/brand-generation-client.d.ts.map +1 -0
- package/dist/brand/brand-generation-client.js +107 -0
- package/dist/brand/brand-generation-client.js.map +1 -0
- package/dist/brand/brand-generation-copy.d.ts +44 -0
- package/dist/brand/brand-generation-copy.d.ts.map +1 -0
- package/dist/brand/brand-generation-copy.js +70 -0
- package/dist/brand/brand-generation-copy.js.map +1 -0
- package/dist/brand/brand-generation-fixtures.d.ts +32 -0
- package/dist/brand/brand-generation-fixtures.d.ts.map +1 -0
- package/dist/brand/brand-generation-fixtures.js +88 -0
- package/dist/brand/brand-generation-fixtures.js.map +1 -0
- package/dist/brand/brand-generation-flow.d.ts +34 -0
- package/dist/brand/brand-generation-flow.d.ts.map +1 -0
- package/dist/brand/brand-generation-flow.js +34 -0
- package/dist/brand/brand-generation-flow.js.map +1 -0
- package/dist/brand/brand-generation-keys.d.ts +16 -0
- package/dist/brand/brand-generation-keys.d.ts.map +1 -0
- package/dist/brand/brand-generation-keys.js +16 -0
- package/dist/brand/brand-generation-keys.js.map +1 -0
- package/dist/brand/brand-generation-progress.d.ts +27 -0
- package/dist/brand/brand-generation-progress.d.ts.map +1 -0
- package/dist/brand/brand-generation-progress.js +61 -0
- package/dist/brand/brand-generation-progress.js.map +1 -0
- package/dist/brand/brand-generation-recovery-error.d.ts +8 -0
- package/dist/brand/brand-generation-recovery-error.d.ts.map +1 -0
- package/dist/brand/brand-generation-recovery-error.js +7 -0
- package/dist/brand/brand-generation-recovery-error.js.map +1 -0
- package/dist/brand/brand-generation-response.d.ts +86 -0
- package/dist/brand/brand-generation-response.d.ts.map +1 -0
- package/dist/brand/brand-generation-response.js +261 -0
- package/dist/brand/brand-generation-response.js.map +1 -0
- package/dist/brand/brand-generation-sse-parser.d.ts +14 -0
- package/dist/brand/brand-generation-sse-parser.d.ts.map +1 -0
- package/dist/brand/brand-generation-sse-parser.js +92 -0
- package/dist/brand/brand-generation-sse-parser.js.map +1 -0
- package/dist/brand/brand-generation-start.d.ts +49 -0
- package/dist/brand/brand-generation-start.d.ts.map +1 -0
- package/dist/brand/brand-generation-start.js +48 -0
- package/dist/brand/brand-generation-start.js.map +1 -0
- package/dist/brand/brand-generation-steps.d.ts +4 -0
- package/dist/brand/brand-generation-steps.d.ts.map +1 -0
- package/dist/brand/brand-generation-steps.js +29 -0
- package/dist/brand/brand-generation-steps.js.map +1 -0
- package/dist/brand/brand-generation-surface.d.ts +50 -0
- package/dist/brand/brand-generation-surface.d.ts.map +1 -0
- package/dist/brand/brand-generation-surface.js +25 -0
- package/dist/brand/brand-generation-surface.js.map +1 -0
- package/dist/brand/brand-generation-url.d.ts +6 -0
- package/dist/brand/brand-generation-url.d.ts.map +1 -0
- package/dist/brand/brand-generation-url.js +4 -0
- package/dist/brand/brand-generation-url.js.map +1 -0
- package/dist/brand/brand-image-chooser.d.ts +3 -1
- package/dist/brand/brand-image-chooser.d.ts.map +1 -1
- package/dist/brand/brand-image-chooser.js +7 -1
- package/dist/brand/brand-image-chooser.js.map +1 -1
- package/dist/brand/brand-image-choosers.d.ts +37 -0
- package/dist/brand/brand-image-choosers.d.ts.map +1 -0
- package/dist/brand/brand-image-choosers.js +76 -0
- package/dist/brand/brand-image-choosers.js.map +1 -0
- package/dist/brand/brand-workspace-change-notice.d.ts +20 -0
- package/dist/brand/brand-workspace-change-notice.d.ts.map +1 -0
- package/dist/brand/brand-workspace-change-notice.js +19 -0
- package/dist/brand/brand-workspace-change-notice.js.map +1 -0
- package/dist/brand/index.d.ts +37 -0
- package/dist/brand/index.d.ts.map +1 -1
- package/dist/brand/index.js +29 -0
- package/dist/brand/index.js.map +1 -1
- package/dist/brand/resume-brand-generation.d.ts +17 -0
- package/dist/brand/resume-brand-generation.d.ts.map +1 -0
- package/dist/brand/resume-brand-generation.js +22 -0
- package/dist/brand/resume-brand-generation.js.map +1 -0
- package/dist/brand/use-brand-generation-discovery.d.ts +14 -0
- package/dist/brand/use-brand-generation-discovery.d.ts.map +1 -0
- package/dist/brand/use-brand-generation-discovery.js +61 -0
- package/dist/brand/use-brand-generation-discovery.js.map +1 -0
- package/dist/brand/use-brand-generation-transport.d.ts +16 -0
- package/dist/brand/use-brand-generation-transport.d.ts.map +1 -0
- package/dist/brand/use-brand-generation-transport.js +182 -0
- package/dist/brand/use-brand-generation-transport.js.map +1 -0
- package/dist/brand/use-brand-generation.d.ts +35 -0
- package/dist/brand/use-brand-generation.d.ts.map +1 -0
- package/dist/brand/use-brand-generation.js +225 -0
- package/dist/brand/use-brand-generation.js.map +1 -0
- package/dist/brand/use-brand-image-operation-result.d.ts +43 -0
- package/dist/brand/use-brand-image-operation-result.d.ts.map +1 -0
- package/dist/brand/use-brand-image-operation-result.js +162 -0
- package/dist/brand/use-brand-image-operation-result.js.map +1 -0
- package/dist/brand/use-brand-profile-acceptance.d.ts +38 -0
- package/dist/brand/use-brand-profile-acceptance.d.ts.map +1 -0
- package/dist/brand/use-brand-profile-acceptance.js +84 -0
- package/dist/brand/use-brand-profile-acceptance.js.map +1 -0
- package/dist/brand/use-brand-public-visibility.d.ts +59 -0
- package/dist/brand/use-brand-public-visibility.d.ts.map +1 -0
- package/dist/brand/use-brand-public-visibility.js +69 -0
- package/dist/brand/use-brand-public-visibility.js.map +1 -0
- package/dist/brand/use-brand-workspace-concurrency.d.ts +132 -0
- package/dist/brand/use-brand-workspace-concurrency.d.ts.map +1 -0
- package/dist/brand/use-brand-workspace-concurrency.js +255 -0
- package/dist/brand/use-brand-workspace-concurrency.js.map +1 -0
- package/dist/brand/use-brand-workspace-image-candidates.d.ts +19 -0
- package/dist/brand/use-brand-workspace-image-candidates.d.ts.map +1 -0
- package/dist/brand/use-brand-workspace-image-candidates.js +39 -0
- package/dist/brand/use-brand-workspace-image-candidates.js.map +1 -0
- package/dist/brand/use-org-scoped-state.d.ts +3 -0
- package/dist/brand/use-org-scoped-state.d.ts.map +1 -0
- package/dist/brand/use-org-scoped-state.js +22 -0
- package/dist/brand/use-org-scoped-state.js.map +1 -0
- package/dist/components/multi-step-loader.d.ts +4 -0
- package/dist/components/multi-step-loader.d.ts.map +1 -1
- package/dist/components/multi-step-loader.js +4 -3
- package/dist/components/multi-step-loader.js.map +1 -1
- package/dist/moderation/moderation-event.d.ts +2 -0
- package/dist/moderation/moderation-event.d.ts.map +1 -1
- package/dist/moderation/moderation-event.js +7 -0
- package/dist/moderation/moderation-event.js.map +1 -1
- package/dist/moderation/moderation-store.d.ts.map +1 -1
- package/dist/moderation/moderation-store.js +4 -2
- package/dist/moderation/moderation-store.js.map +1 -1
- package/dist/realtime/job-status/schemas.d.ts +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BrandGenerationApi, BrandGenerationStreamConfig } from "./brand-generation-api.js";
|
|
2
|
+
import type { BrandGenerationJobStatus as JobStatus } from "./brand-generation-response.js";
|
|
3
|
+
import { type BrandGenerationUpdate } from "./brand-generation-sse-parser.js";
|
|
4
|
+
export type { BrandGenerationUpdate } from "./brand-generation-sse-parser.js";
|
|
5
|
+
interface TransportOptions {
|
|
6
|
+
api: Pick<BrandGenerationApi, "getStatus">;
|
|
7
|
+
stream: BrandGenerationStreamConfig;
|
|
8
|
+
onUpdate: (data: BrandGenerationUpdate) => void;
|
|
9
|
+
onDegraded: () => void;
|
|
10
|
+
isTerminal: (status: JobStatus | undefined) => boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function useBrandGenerationTransport({ api, stream, onUpdate, onDegraded, isTerminal, }: TransportOptions): {
|
|
13
|
+
cleanup: () => void;
|
|
14
|
+
connect: (jobId: string) => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=use-brand-generation-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-brand-generation-transport.d.ts","sourceRoot":"","sources":["../../src/brand/use-brand-generation-transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAC9F,OAAO,KAAK,EAAE,wBAAwB,IAAI,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAS3E,UAAU,gBAAgB;IACxB,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC;IAC3C,MAAM,EAAE,2BAA2B,CAAC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAChD,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,UAAU,EAAE,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,KAAK,OAAO,CAAC;CACxD;AAED,wBAAgB,2BAA2B,CAAC,EAC1C,GAAG,EACH,MAAM,EACN,QAAQ,EACR,UAAU,EACV,UAAU,GACX,EAAE,gBAAgB;;qBA8DD,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;EAwHvC"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { useCallback, useRef } from "react";
|
|
2
|
+
import { dataPayload, parseSseUpdate, } from "./brand-generation-sse-parser.js";
|
|
3
|
+
const DEFAULT_SSE_IDLE_TIMEOUT_MS = 15_000;
|
|
4
|
+
const DEFAULT_POLL_INTERVAL_MS = 2000;
|
|
5
|
+
function errorType(error) {
|
|
6
|
+
return error instanceof Error ? error.name : "UnknownError";
|
|
7
|
+
}
|
|
8
|
+
export function useBrandGenerationTransport({ api, stream, onUpdate, onDegraded, isTerminal, }) {
|
|
9
|
+
// `api`/`stream` are read through refs so `connect`/`cleanup` keep a stable
|
|
10
|
+
// identity even when a consumer passes fresh object literals each render.
|
|
11
|
+
const apiRef = useRef(api);
|
|
12
|
+
apiRef.current = api;
|
|
13
|
+
const streamRef = useRef(stream);
|
|
14
|
+
streamRef.current = stream;
|
|
15
|
+
const pollIntervalRef = useRef(null);
|
|
16
|
+
const idleTimeoutRef = useRef(null);
|
|
17
|
+
const abortControllerRef = useRef(null);
|
|
18
|
+
const connectionGenerationRef = useRef(0);
|
|
19
|
+
const cleanup = useCallback(() => {
|
|
20
|
+
connectionGenerationRef.current += 1;
|
|
21
|
+
abortControllerRef.current?.abort();
|
|
22
|
+
abortControllerRef.current = null;
|
|
23
|
+
if (idleTimeoutRef.current !== null) {
|
|
24
|
+
window.clearTimeout(idleTimeoutRef.current.timerId);
|
|
25
|
+
idleTimeoutRef.current = null;
|
|
26
|
+
}
|
|
27
|
+
if (pollIntervalRef.current !== null) {
|
|
28
|
+
window.clearInterval(pollIntervalRef.current);
|
|
29
|
+
pollIntervalRef.current = null;
|
|
30
|
+
}
|
|
31
|
+
}, []);
|
|
32
|
+
const emitUpdate = useCallback((data) => {
|
|
33
|
+
if (isTerminal(data.status))
|
|
34
|
+
cleanup();
|
|
35
|
+
onUpdate(data);
|
|
36
|
+
}, [cleanup, isTerminal, onUpdate]);
|
|
37
|
+
const startPolling = useCallback((jobId) => {
|
|
38
|
+
cleanup();
|
|
39
|
+
const generation = connectionGenerationRef.current;
|
|
40
|
+
onDegraded();
|
|
41
|
+
const poll = async () => {
|
|
42
|
+
try {
|
|
43
|
+
const update = await apiRef.current.getStatus(jobId);
|
|
44
|
+
if (connectionGenerationRef.current === generation)
|
|
45
|
+
emitUpdate(update);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.warn("[brand-generation] status poll failed; retrying", {
|
|
49
|
+
errorType: errorType(error),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
void poll();
|
|
54
|
+
pollIntervalRef.current = window.setInterval(() => void poll(), streamRef.current.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
55
|
+
}, [cleanup, emitUpdate, onDegraded]);
|
|
56
|
+
const connect = useCallback(async (jobId) => {
|
|
57
|
+
cleanup();
|
|
58
|
+
const generation = connectionGenerationRef.current;
|
|
59
|
+
const isCurrent = () => connectionGenerationRef.current === generation;
|
|
60
|
+
try {
|
|
61
|
+
const config = streamRef.current;
|
|
62
|
+
const token = config.getAccessToken ? await config.getAccessToken() : undefined;
|
|
63
|
+
if (!isCurrent())
|
|
64
|
+
return;
|
|
65
|
+
// Bearer mode with no usable token (null or empty) degrades to polling,
|
|
66
|
+
// like producer; cookie mode (no `getAccessToken`) streams with
|
|
67
|
+
// credentials instead.
|
|
68
|
+
if (config.getAccessToken && !token) {
|
|
69
|
+
startPolling(jobId);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const controller = new AbortController();
|
|
73
|
+
abortControllerRef.current = controller;
|
|
74
|
+
const clearIdleTimeout = () => {
|
|
75
|
+
const idleTimeout = idleTimeoutRef.current;
|
|
76
|
+
if (idleTimeout?.generation !== generation)
|
|
77
|
+
return;
|
|
78
|
+
window.clearTimeout(idleTimeout.timerId);
|
|
79
|
+
idleTimeoutRef.current = null;
|
|
80
|
+
};
|
|
81
|
+
const armIdleTimeout = () => {
|
|
82
|
+
clearIdleTimeout();
|
|
83
|
+
const timerId = window.setTimeout(() => {
|
|
84
|
+
const idleTimeout = idleTimeoutRef.current;
|
|
85
|
+
if (idleTimeout?.generation !== generation || idleTimeout.timerId !== timerId)
|
|
86
|
+
return;
|
|
87
|
+
idleTimeoutRef.current = null;
|
|
88
|
+
if (!isCurrent())
|
|
89
|
+
return;
|
|
90
|
+
controller.abort();
|
|
91
|
+
startPolling(jobId);
|
|
92
|
+
}, config.idleTimeoutMs ?? DEFAULT_SSE_IDLE_TIMEOUT_MS);
|
|
93
|
+
idleTimeoutRef.current = { generation, timerId };
|
|
94
|
+
};
|
|
95
|
+
armIdleTimeout();
|
|
96
|
+
const doFetch = config.fetch ?? fetch;
|
|
97
|
+
const response = await doFetch(`${config.baseUrl.replace(/\/+$/, "")}/brand-profiles/generate/${encodeURIComponent(jobId)}/stream`, {
|
|
98
|
+
headers: {
|
|
99
|
+
Accept: "text/event-stream",
|
|
100
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
101
|
+
},
|
|
102
|
+
...(token ? {} : { credentials: "include" }),
|
|
103
|
+
signal: controller.signal,
|
|
104
|
+
});
|
|
105
|
+
if (!isCurrent()) {
|
|
106
|
+
controller.abort();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
startPolling(jobId);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const reader = response.body?.getReader();
|
|
114
|
+
if (!reader) {
|
|
115
|
+
startPolling(jobId);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const decoder = new TextDecoder();
|
|
119
|
+
let buffer = "";
|
|
120
|
+
let terminalSeen = false;
|
|
121
|
+
try {
|
|
122
|
+
while (true) {
|
|
123
|
+
const { done, value } = await reader.read();
|
|
124
|
+
clearIdleTimeout();
|
|
125
|
+
if (!isCurrent())
|
|
126
|
+
return;
|
|
127
|
+
if (done) {
|
|
128
|
+
if (!terminalSeen)
|
|
129
|
+
startPolling(jobId);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
armIdleTimeout();
|
|
133
|
+
buffer += decoder.decode(value, { stream: true });
|
|
134
|
+
let boundary = buffer.search(/\r?\n\r?\n/);
|
|
135
|
+
while (boundary !== -1) {
|
|
136
|
+
const chunk = buffer.slice(0, boundary);
|
|
137
|
+
const separator = buffer.slice(boundary).match(/^\r?\n\r?\n/)?.[0] ?? "\n\n";
|
|
138
|
+
buffer = buffer.slice(boundary + separator.length);
|
|
139
|
+
const payload = dataPayload(chunk);
|
|
140
|
+
if (payload !== null) {
|
|
141
|
+
const data = parseSseUpdate(payload);
|
|
142
|
+
if (data) {
|
|
143
|
+
const terminal = isTerminal(data.status);
|
|
144
|
+
if (terminal)
|
|
145
|
+
terminalSeen = true;
|
|
146
|
+
emitUpdate(data);
|
|
147
|
+
if (terminal)
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
boundary = buffer.search(/\r?\n\r?\n/);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (!isCurrent())
|
|
157
|
+
return;
|
|
158
|
+
if (error instanceof Error && error.name === "AbortError")
|
|
159
|
+
return;
|
|
160
|
+
console.warn("[brand-generation] SSE read failed; polling", {
|
|
161
|
+
errorType: errorType(error),
|
|
162
|
+
});
|
|
163
|
+
startPolling(jobId);
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
clearIdleTimeout();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
if (!isCurrent())
|
|
171
|
+
return;
|
|
172
|
+
if (error instanceof Error && error.name === "AbortError")
|
|
173
|
+
return;
|
|
174
|
+
console.warn("[brand-generation] SSE connection failed; polling", {
|
|
175
|
+
errorType: errorType(error),
|
|
176
|
+
});
|
|
177
|
+
startPolling(jobId);
|
|
178
|
+
}
|
|
179
|
+
}, [cleanup, emitUpdate, isTerminal, startPolling]);
|
|
180
|
+
return { cleanup, connect };
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=use-brand-generation-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-brand-generation-transport.js","sourceRoot":"","sources":["../../src/brand/use-brand-generation-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type QueryKey } from "@tanstack/react-query";
|
|
2
|
+
import type { BrandGenerationApi, BrandGenerationStreamConfig } from "./brand-generation-api.js";
|
|
3
|
+
import type { BrandGenerationContext, BrandGenerationJob } from "./brand-generation-response.js";
|
|
4
|
+
export interface UseBrandGenerationOptions {
|
|
5
|
+
/** Active org id. Every piece of generation state resets when it changes. */
|
|
6
|
+
readonly orgId: string;
|
|
7
|
+
/** The endpoint seam. See {@link BrandGenerationApi}. */
|
|
8
|
+
readonly api: BrandGenerationApi;
|
|
9
|
+
/** How the SSE stream authenticates. See {@link BrandGenerationStreamConfig}. */
|
|
10
|
+
readonly stream: BrandGenerationStreamConfig;
|
|
11
|
+
/**
|
|
12
|
+
* The consumer's brand-profile query key (prefix) for this org. It is
|
|
13
|
+
* invalidated when a job reaches a terminal state or is accepted, so the
|
|
14
|
+
* consumer's profile/draft queries refetch. Must not live under the
|
|
15
|
+
* `"brand-generation"` namespace.
|
|
16
|
+
*/
|
|
17
|
+
readonly profileQueryKey: QueryKey;
|
|
18
|
+
}
|
|
19
|
+
export type UseBrandGenerationResult = ReturnType<typeof useBrandGeneration>;
|
|
20
|
+
export declare function useBrandGeneration({ orgId, api, stream, profileQueryKey, }: UseBrandGenerationOptions): {
|
|
21
|
+
job: BrandGenerationJob | null;
|
|
22
|
+
isGenerating: boolean;
|
|
23
|
+
isDiscoveringActive: boolean;
|
|
24
|
+
discoveryError: Error | null;
|
|
25
|
+
error: "start" | "resume" | "accept" | "cancel" | "prioritize" | null;
|
|
26
|
+
transportDegraded: boolean;
|
|
27
|
+
eligibility: import("./brand-generation-types.js").BrandGenerationEligibility | null;
|
|
28
|
+
start: (homepageUrl: string, context?: BrandGenerationContext) => Promise<void>;
|
|
29
|
+
resume: (jobId: string) => Promise<void>;
|
|
30
|
+
cancel: () => Promise<void>;
|
|
31
|
+
prioritizeUrl: (url: string) => Promise<void>;
|
|
32
|
+
accept: () => Promise<boolean>;
|
|
33
|
+
reset: () => void;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=use-brand-generation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-brand-generation.d.ts","sourceRoot":"","sources":["../../src/brand/use-brand-generation.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAM9F,OAAO,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAS9F,MAAM,WAAW,yBAAyB;IACxC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,GAAG,EAAE,kBAAkB,CAAC;IACjC,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC;CACpC;AAED,MAAM,MAAM,wBAAwB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE7E,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,GAAG,EACH,MAAM,EACN,eAAe,GAChB,EAAE,yBAAyB;;;;;;;;yBAwEQ,MAAM,YAAY,sBAAsB;oBAkHnD,MAAM;;yBA1EK,MAAM;;;EA8GzC"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { useEffect, useCallback, useRef } from "react";
|
|
2
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { brandGenerationKeys, isTerminalStatus, } from "./brand-generation-keys.js";
|
|
4
|
+
import { resumeBrandGeneration } from "./resume-brand-generation.js";
|
|
5
|
+
import { useBrandGenerationDiscovery } from "./use-brand-generation-discovery.js";
|
|
6
|
+
import { useBrandGenerationTransport, } from "./use-brand-generation-transport.js";
|
|
7
|
+
import { useOrgScopedState } from "./use-org-scoped-state.js";
|
|
8
|
+
export function useBrandGeneration({ orgId, api, stream, profileQueryKey, }) {
|
|
9
|
+
// Read through a ref so a fresh array literal each render cannot churn the callbacks below.
|
|
10
|
+
const profileKeyRef = useRef(profileQueryKey);
|
|
11
|
+
profileKeyRef.current = profileQueryKey;
|
|
12
|
+
const orgEpochRef = useRef(0);
|
|
13
|
+
const renderedOrgIdRef = useRef(orgId);
|
|
14
|
+
if (renderedOrgIdRef.current !== orgId) {
|
|
15
|
+
renderedOrgIdRef.current = orgId;
|
|
16
|
+
orgEpochRef.current += 1;
|
|
17
|
+
}
|
|
18
|
+
const orgEpoch = orgEpochRef.current;
|
|
19
|
+
const queryClient = useQueryClient();
|
|
20
|
+
const { activeQuery, activeJob, terminalQuery, terminalJob, eligibility: discoveryEligibility, needsTerminalHandoff, isDiscoveringActive, discoveryError, } = useBrandGenerationDiscovery(orgId, api, profileKeyRef);
|
|
21
|
+
const [job, setJob, updateJob] = useOrgScopedState(orgId, null);
|
|
22
|
+
const [dismissedTerminalJobId, setDismissedTerminalJobId] = useOrgScopedState(orgId, null);
|
|
23
|
+
const [isGenerating, setIsGenerating] = useOrgScopedState(orgId, false);
|
|
24
|
+
const [error, setError] = useOrgScopedState(orgId, null);
|
|
25
|
+
const [transportDegraded, setTransportDegraded] = useOrgScopedState(orgId, false);
|
|
26
|
+
const clearGenerationState = useCallback(() => {
|
|
27
|
+
setJob(null);
|
|
28
|
+
setIsGenerating(false);
|
|
29
|
+
setError(null);
|
|
30
|
+
setTransportDegraded(false);
|
|
31
|
+
}, [setError, setIsGenerating, setJob, setTransportDegraded]);
|
|
32
|
+
const markTransportDegraded = useCallback(() => {
|
|
33
|
+
if (orgEpochRef.current === orgEpoch)
|
|
34
|
+
setTransportDegraded(true);
|
|
35
|
+
}, [orgEpoch, setTransportDegraded]);
|
|
36
|
+
const invalidateGenerationHandoff = useCallback(() => {
|
|
37
|
+
if (!orgId)
|
|
38
|
+
return;
|
|
39
|
+
queryClient.setQueryData(brandGenerationKeys.active(orgId), null);
|
|
40
|
+
void Promise.all([
|
|
41
|
+
queryClient.invalidateQueries({ queryKey: brandGenerationKeys.active(orgId), exact: true }),
|
|
42
|
+
queryClient.invalidateQueries({ queryKey: profileKeyRef.current }),
|
|
43
|
+
]);
|
|
44
|
+
}, [orgId, queryClient]);
|
|
45
|
+
const handleUpdate = useCallback((data) => {
|
|
46
|
+
if (orgEpochRef.current !== orgEpoch)
|
|
47
|
+
return;
|
|
48
|
+
const { jobId, ...update } = data;
|
|
49
|
+
updateJob((currentJob) => {
|
|
50
|
+
if (!currentJob)
|
|
51
|
+
return currentJob;
|
|
52
|
+
return { ...currentJob, ...update, id: jobId || update.id || currentJob.id };
|
|
53
|
+
});
|
|
54
|
+
if (isTerminalStatus(data.status)) {
|
|
55
|
+
setIsGenerating(false);
|
|
56
|
+
invalidateGenerationHandoff();
|
|
57
|
+
}
|
|
58
|
+
}, [invalidateGenerationHandoff, orgEpoch, setIsGenerating, updateJob]);
|
|
59
|
+
const { cleanup, connect: connectSSE } = useBrandGenerationTransport({
|
|
60
|
+
api,
|
|
61
|
+
stream,
|
|
62
|
+
onUpdate: handleUpdate,
|
|
63
|
+
onDegraded: markTransportDegraded,
|
|
64
|
+
isTerminal: isTerminalStatus,
|
|
65
|
+
});
|
|
66
|
+
// CEL-1679 contract §2: "Retry is a start with amended context" — no
|
|
67
|
+
// separate retry endpoint, so a retry calls this same function again with
|
|
68
|
+
// the operator's amended context from `BrandGenerationContextForm`.
|
|
69
|
+
const start = async (homepageUrl, context) => {
|
|
70
|
+
if (isDiscoveringActive || discoveryError !== null)
|
|
71
|
+
return;
|
|
72
|
+
const actionEpoch = orgEpoch;
|
|
73
|
+
try {
|
|
74
|
+
setError(null);
|
|
75
|
+
setTransportDegraded(false);
|
|
76
|
+
setDismissedTerminalJobId(null);
|
|
77
|
+
setIsGenerating(true);
|
|
78
|
+
const res = await api.start(homepageUrl, context);
|
|
79
|
+
if (orgEpochRef.current !== actionEpoch)
|
|
80
|
+
return;
|
|
81
|
+
setJob({
|
|
82
|
+
id: res.jobId,
|
|
83
|
+
workflowId: res.workflowId,
|
|
84
|
+
status: "pending",
|
|
85
|
+
progress: {},
|
|
86
|
+
error: null,
|
|
87
|
+
createdAt: new Date().toISOString(),
|
|
88
|
+
updatedAt: new Date().toISOString(),
|
|
89
|
+
});
|
|
90
|
+
connectSSE(res.jobId);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
if (orgEpochRef.current !== actionEpoch)
|
|
94
|
+
return;
|
|
95
|
+
setIsGenerating(false);
|
|
96
|
+
setError("start");
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const cancel = async () => {
|
|
100
|
+
if (!job?.id)
|
|
101
|
+
return;
|
|
102
|
+
const actionEpoch = orgEpoch;
|
|
103
|
+
try {
|
|
104
|
+
const res = await api.cancel(job.id);
|
|
105
|
+
if (orgEpochRef.current !== actionEpoch)
|
|
106
|
+
return;
|
|
107
|
+
handleUpdate(res);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
if (orgEpochRef.current !== actionEpoch)
|
|
111
|
+
return;
|
|
112
|
+
setError("cancel");
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const prioritizeUrl = async (url) => {
|
|
116
|
+
if (!job?.id)
|
|
117
|
+
return;
|
|
118
|
+
const actionEpoch = orgEpoch;
|
|
119
|
+
try {
|
|
120
|
+
const res = await api.prioritizeUrl(job.id, url);
|
|
121
|
+
if (orgEpochRef.current !== actionEpoch)
|
|
122
|
+
return;
|
|
123
|
+
handleUpdate(res);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
if (orgEpochRef.current !== actionEpoch)
|
|
127
|
+
return;
|
|
128
|
+
setError("prioritize");
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const accept = async () => {
|
|
132
|
+
if (!job?.id)
|
|
133
|
+
return false;
|
|
134
|
+
const actionEpoch = orgEpoch;
|
|
135
|
+
try {
|
|
136
|
+
await api.accept(job.id);
|
|
137
|
+
if (orgEpochRef.current !== actionEpoch)
|
|
138
|
+
return false;
|
|
139
|
+
invalidateGenerationHandoff();
|
|
140
|
+
if (isTerminalStatus(job.status))
|
|
141
|
+
setDismissedTerminalJobId(job.id);
|
|
142
|
+
setJob(null);
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
if (orgEpochRef.current !== actionEpoch)
|
|
147
|
+
return false;
|
|
148
|
+
setError("accept");
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
const reset = () => {
|
|
153
|
+
cleanup();
|
|
154
|
+
if (job && isTerminalStatus(job.status))
|
|
155
|
+
setDismissedTerminalJobId(job.id);
|
|
156
|
+
clearGenerationState();
|
|
157
|
+
};
|
|
158
|
+
useEffect(() => cleanup, [cleanup]);
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
cleanup();
|
|
161
|
+
}, [cleanup, orgId]);
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (activeQuery.isFetching ||
|
|
164
|
+
(needsTerminalHandoff && terminalQuery.isFetching) ||
|
|
165
|
+
(!activeJob && (!terminalJob || terminalJob.id === dismissedTerminalJobId)) ||
|
|
166
|
+
job ||
|
|
167
|
+
isGenerating)
|
|
168
|
+
return;
|
|
169
|
+
setError(null);
|
|
170
|
+
setTransportDegraded(false);
|
|
171
|
+
setJob(activeJob ?? terminalJob ?? null);
|
|
172
|
+
if (activeJob) {
|
|
173
|
+
setIsGenerating(true);
|
|
174
|
+
void connectSSE(activeJob.id);
|
|
175
|
+
}
|
|
176
|
+
}, [
|
|
177
|
+
activeJob,
|
|
178
|
+
activeQuery.isFetching,
|
|
179
|
+
connectSSE,
|
|
180
|
+
isGenerating,
|
|
181
|
+
job,
|
|
182
|
+
dismissedTerminalJobId,
|
|
183
|
+
needsTerminalHandoff,
|
|
184
|
+
setError,
|
|
185
|
+
setIsGenerating,
|
|
186
|
+
setJob,
|
|
187
|
+
setTransportDegraded,
|
|
188
|
+
terminalJob,
|
|
189
|
+
terminalQuery.isFetching,
|
|
190
|
+
]);
|
|
191
|
+
const resume = (jobId) => resumeBrandGeneration(jobId, {
|
|
192
|
+
api,
|
|
193
|
+
isCurrent: () => orgEpochRef.current === orgEpoch,
|
|
194
|
+
setError,
|
|
195
|
+
setIsGenerating,
|
|
196
|
+
setTransportDegraded,
|
|
197
|
+
setJob,
|
|
198
|
+
handleUpdate,
|
|
199
|
+
connect: connectSSE,
|
|
200
|
+
});
|
|
201
|
+
return {
|
|
202
|
+
job,
|
|
203
|
+
isGenerating,
|
|
204
|
+
isDiscoveringActive,
|
|
205
|
+
discoveryError,
|
|
206
|
+
error,
|
|
207
|
+
transportDegraded,
|
|
208
|
+
// CEL-1682 (contracts §2): prefers the tracked job's own eligibility
|
|
209
|
+
// (populated by GET /:jobId via `resume`, and by GET /active when a job
|
|
210
|
+
// is active — the freshest snapshot once a specific job is in view),
|
|
211
|
+
// falling back to the discovery-level snapshot from
|
|
212
|
+
// `useBrandGenerationDiscovery`'s unconditional `/active` read. This is
|
|
213
|
+
// the fix for the confirmed idle-state gap: `getActiveBrandGeneration`
|
|
214
|
+
// no longer collapses `{ job: null, eligibility }` to a bare `null`, so
|
|
215
|
+
// the cooldown banner has data even when nothing is running.
|
|
216
|
+
eligibility: job?.eligibility ?? discoveryEligibility,
|
|
217
|
+
start,
|
|
218
|
+
resume,
|
|
219
|
+
cancel,
|
|
220
|
+
prioritizeUrl,
|
|
221
|
+
accept,
|
|
222
|
+
reset,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=use-brand-generation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-brand-generation.js","sourceRoot":"","sources":["../../src/brand/use-brand-generation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type ModerationPersistedRead, type ModerationSubjectMatch } from "../moderation/index.js";
|
|
2
|
+
import type { BrandImageOperationResult } from "./brand-image-chooser-types.js";
|
|
3
|
+
export interface BrandImageOperationController {
|
|
4
|
+
/** `null` when no operation has started yet — the chooser's own idle
|
|
5
|
+
* default. */
|
|
6
|
+
readonly operationResult: BrandImageOperationResult | null;
|
|
7
|
+
/**
|
|
8
|
+
* Call once `onApply`'s upload/candidate-select call has been accepted by
|
|
9
|
+
* the backend: a caller-generated id that correlates a later verdict back
|
|
10
|
+
* to THIS call (never a previous operation on the same subject slot), and
|
|
11
|
+
* the subject to watch. The subject is passed HERE rather than fixed at
|
|
12
|
+
* the hook call site because it depends on which slot the upload actually
|
|
13
|
+
* landed in — a candidate's OWN role can route it to a different slot than
|
|
14
|
+
* the chooser instance's own target (e.g. a favicon-role candidate picked
|
|
15
|
+
* through the "profile picture" chooser still saves to the favicon slot;
|
|
16
|
+
* see `candidateAssetSlot` in `useBrandImageCandidates.ts`). Also marks the
|
|
17
|
+
* subject "checking" in the shared moderation store so every OTHER surface
|
|
18
|
+
* watching it (e.g. `BrandAssetsSection`'s `ModerationSurfaceNotice`) sees
|
|
19
|
+
* it too.
|
|
20
|
+
*/
|
|
21
|
+
readonly startOperation: (operationId: string, subject: ModerationSubjectMatch, startSeq?: number) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Call BEFORE issuing the upload request and pass the result to
|
|
24
|
+
* `startOperation`. The backend can publish a verdict for the asset while
|
|
25
|
+
* the upload's HTTP response is still in flight; without this snapshot that
|
|
26
|
+
* event is gated out as "pre-existing" and the operation hangs at
|
|
27
|
+
* `checking` until it gives up.
|
|
28
|
+
*/
|
|
29
|
+
readonly beginOperation: () => number;
|
|
30
|
+
/** Drops tracking — e.g. when the chooser is dismissed/closed. */
|
|
31
|
+
readonly reset: () => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Owns the chooser's current upload identity and adapts the shared moderation
|
|
35
|
+
* operation (including its exact-asset durable read) to the chooser result.
|
|
36
|
+
*/
|
|
37
|
+
export declare function useBrandImageOperationResult(
|
|
38
|
+
/**
|
|
39
|
+
* The durable, asset-id-keyed read (`BrandAssetsApi.fetchModeration`) used
|
|
40
|
+
* when no live verdict event arrives.
|
|
41
|
+
*/
|
|
42
|
+
fetchModeration: (profileId: string, assetId: string) => Promise<ModerationPersistedRead | null>): BrandImageOperationController;
|
|
43
|
+
//# sourceMappingURL=use-brand-image-operation-result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-brand-image-operation-result.d.ts","sourceRoot":"","sources":["../../src/brand/use-brand-image-operation-result.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC5B,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,6BAA6B,CAAC;AAmCrC,MAAM,WAAW,6BAA6B;IAC5C;kBACc;IACd,QAAQ,CAAC,eAAe,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC3D;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,cAAc,EAAE,CACvB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,CAAC,EAAE,MAAM,KACd,IAAI,CAAC;IACV;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,MAAM,CAAC;IACtC,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,4BAA4B;AAC1C;;;GAGG;AACH,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,GAC/F,6BAA6B,CA0I/B"}
|