@weirdfingers/boards 0.1.4
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/index.d.mts +508 -0
- package/dist/index.d.ts +508 -0
- package/dist/index.js +1150 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1096 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -0
- package/src/auth/context.tsx +104 -0
- package/src/auth/hooks/useAuth.ts +6 -0
- package/src/auth/providers/__tests__/none.test.ts +187 -0
- package/src/auth/providers/base.ts +62 -0
- package/src/auth/providers/none.ts +157 -0
- package/src/auth/types.ts +67 -0
- package/src/config/ApiConfigContext.tsx +47 -0
- package/src/graphql/client.ts +130 -0
- package/src/graphql/operations.ts +293 -0
- package/src/hooks/useBoard.ts +323 -0
- package/src/hooks/useBoards.ts +138 -0
- package/src/hooks/useGeneration.ts +429 -0
- package/src/hooks/useGenerators.ts +44 -0
- package/src/index.test.ts +7 -0
- package/src/index.ts +25 -0
- package/src/providers/BoardsProvider.tsx +68 -0
- package/src/test-setup.ts +29 -0
- package/tsconfig.json +37 -0
- package/tsup.config.ts +11 -0
- package/vitest.config.ts +10 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ADD_BOARD_MEMBER: () => ADD_BOARD_MEMBER,
|
|
24
|
+
ArtifactType: () => ArtifactType,
|
|
25
|
+
AuthProvider: () => AuthProvider,
|
|
26
|
+
BOARD_FRAGMENT: () => BOARD_FRAGMENT,
|
|
27
|
+
BaseAuthProvider: () => BaseAuthProvider,
|
|
28
|
+
BoardRole: () => BoardRole,
|
|
29
|
+
BoardsProvider: () => BoardsProvider,
|
|
30
|
+
CANCEL_GENERATION: () => CANCEL_GENERATION,
|
|
31
|
+
CREATE_BOARD: () => CREATE_BOARD,
|
|
32
|
+
CREATE_GENERATION: () => CREATE_GENERATION,
|
|
33
|
+
DELETE_BOARD: () => DELETE_BOARD,
|
|
34
|
+
GENERATION_FRAGMENT: () => GENERATION_FRAGMENT,
|
|
35
|
+
GET_BOARD: () => GET_BOARD,
|
|
36
|
+
GET_BOARDS: () => GET_BOARDS,
|
|
37
|
+
GET_CURRENT_USER: () => GET_CURRENT_USER,
|
|
38
|
+
GET_GENERATION: () => GET_GENERATION,
|
|
39
|
+
GET_GENERATIONS: () => GET_GENERATIONS,
|
|
40
|
+
GET_GENERATORS: () => GET_GENERATORS,
|
|
41
|
+
GenerationStatus: () => GenerationStatus,
|
|
42
|
+
NoAuthProvider: () => NoAuthProvider,
|
|
43
|
+
REMOVE_BOARD_MEMBER: () => REMOVE_BOARD_MEMBER,
|
|
44
|
+
RETRY_GENERATION: () => RETRY_GENERATION,
|
|
45
|
+
UPDATE_BOARD: () => UPDATE_BOARD,
|
|
46
|
+
UPDATE_BOARD_MEMBER_ROLE: () => UPDATE_BOARD_MEMBER_ROLE,
|
|
47
|
+
USER_FRAGMENT: () => USER_FRAGMENT,
|
|
48
|
+
VERSION: () => VERSION,
|
|
49
|
+
createGraphQLClient: () => createGraphQLClient,
|
|
50
|
+
useApiConfig: () => useApiConfig,
|
|
51
|
+
useAuth: () => useAuth,
|
|
52
|
+
useAuthOptional: () => useAuthOptional,
|
|
53
|
+
useBoard: () => useBoard,
|
|
54
|
+
useBoards: () => useBoards,
|
|
55
|
+
useGeneration: () => useGeneration,
|
|
56
|
+
useGenerators: () => useGenerators
|
|
57
|
+
});
|
|
58
|
+
module.exports = __toCommonJS(index_exports);
|
|
59
|
+
|
|
60
|
+
// src/auth/context.tsx
|
|
61
|
+
var import_react = require("react");
|
|
62
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
63
|
+
var AuthContext = (0, import_react.createContext)(null);
|
|
64
|
+
function AuthProvider({ provider, children }) {
|
|
65
|
+
const [state, setState] = (0, import_react.useState)({
|
|
66
|
+
user: null,
|
|
67
|
+
status: "loading",
|
|
68
|
+
signIn: async () => {
|
|
69
|
+
},
|
|
70
|
+
signOut: async () => {
|
|
71
|
+
},
|
|
72
|
+
getToken: async () => null,
|
|
73
|
+
refreshToken: async () => null
|
|
74
|
+
});
|
|
75
|
+
const [isInitializing, setIsInitializing] = (0, import_react.useState)(true);
|
|
76
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
77
|
+
const clearError = (0, import_react.useCallback)(() => {
|
|
78
|
+
setError(null);
|
|
79
|
+
}, []);
|
|
80
|
+
(0, import_react.useEffect)(() => {
|
|
81
|
+
let mounted = true;
|
|
82
|
+
let unsubscribe = null;
|
|
83
|
+
const initializeAuth = async () => {
|
|
84
|
+
try {
|
|
85
|
+
await provider.initialize();
|
|
86
|
+
if (!mounted) return;
|
|
87
|
+
unsubscribe = provider.onAuthStateChange((newState) => {
|
|
88
|
+
if (mounted) {
|
|
89
|
+
setState(newState);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
const initialState = await provider.getAuthState();
|
|
93
|
+
if (mounted) {
|
|
94
|
+
setState(initialState);
|
|
95
|
+
setIsInitializing(false);
|
|
96
|
+
}
|
|
97
|
+
} catch (err) {
|
|
98
|
+
if (mounted) {
|
|
99
|
+
setError(err instanceof Error ? err : new Error("Auth initialization failed"));
|
|
100
|
+
setIsInitializing(false);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
initializeAuth();
|
|
105
|
+
return () => {
|
|
106
|
+
mounted = false;
|
|
107
|
+
if (unsubscribe) {
|
|
108
|
+
unsubscribe();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}, [provider]);
|
|
112
|
+
(0, import_react.useEffect)(() => {
|
|
113
|
+
return () => {
|
|
114
|
+
provider.destroy();
|
|
115
|
+
};
|
|
116
|
+
}, [provider]);
|
|
117
|
+
const contextValue = {
|
|
118
|
+
...state,
|
|
119
|
+
isInitializing,
|
|
120
|
+
error,
|
|
121
|
+
clearError
|
|
122
|
+
};
|
|
123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthContext.Provider, { value: contextValue, children });
|
|
124
|
+
}
|
|
125
|
+
function useAuth() {
|
|
126
|
+
const context = (0, import_react.useContext)(AuthContext);
|
|
127
|
+
if (!context) {
|
|
128
|
+
throw new Error("useAuth must be used within an AuthProvider");
|
|
129
|
+
}
|
|
130
|
+
return context;
|
|
131
|
+
}
|
|
132
|
+
function useAuthOptional() {
|
|
133
|
+
return (0, import_react.useContext)(AuthContext);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/auth/providers/base.ts
|
|
137
|
+
var BaseAuthProvider = class {
|
|
138
|
+
constructor(config = {}) {
|
|
139
|
+
this.config = config;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get the tenant ID from config.
|
|
143
|
+
*/
|
|
144
|
+
getTenantId() {
|
|
145
|
+
return this.config.tenantId || "default";
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// src/auth/providers/none.ts
|
|
150
|
+
var NoAuthProvider = class extends BaseAuthProvider {
|
|
151
|
+
constructor(config = {}) {
|
|
152
|
+
super(config);
|
|
153
|
+
this.listeners = [];
|
|
154
|
+
const nodeEnv = typeof process !== "undefined" ? process.env?.NODE_ENV : "";
|
|
155
|
+
const isDevelopment = nodeEnv === "development" || nodeEnv === "" || nodeEnv === "test";
|
|
156
|
+
if (!isDevelopment) {
|
|
157
|
+
const error = new Error(
|
|
158
|
+
"NoAuthProvider cannot be used in production environments. Please configure a proper authentication provider (JWT, Supabase, Clerk, etc.)"
|
|
159
|
+
);
|
|
160
|
+
console.error("\u{1F6A8} SECURITY ERROR:", error.message);
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
this.config = {
|
|
164
|
+
defaultUserId: "dev-user",
|
|
165
|
+
defaultEmail: "dev@example.com",
|
|
166
|
+
defaultDisplayName: "Development User",
|
|
167
|
+
...config
|
|
168
|
+
};
|
|
169
|
+
this.defaultUser = {
|
|
170
|
+
id: this.config.defaultUserId,
|
|
171
|
+
email: this.config.defaultEmail,
|
|
172
|
+
name: this.config.defaultDisplayName,
|
|
173
|
+
avatar: void 0,
|
|
174
|
+
metadata: { provider: "none" },
|
|
175
|
+
credits: {
|
|
176
|
+
balance: 1e3,
|
|
177
|
+
reserved: 0
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
this.currentState = {
|
|
181
|
+
user: this.defaultUser,
|
|
182
|
+
status: "authenticated",
|
|
183
|
+
// Always authenticated in no-auth mode
|
|
184
|
+
signIn: this.signIn.bind(this),
|
|
185
|
+
signOut: this.signOut.bind(this),
|
|
186
|
+
getToken: this.getToken.bind(this),
|
|
187
|
+
refreshToken: this.refreshToken.bind(this)
|
|
188
|
+
};
|
|
189
|
+
if (console.warn) {
|
|
190
|
+
console.warn(
|
|
191
|
+
"\u{1F6A8} [AUTH] NoAuthProvider is active - authentication is disabled!",
|
|
192
|
+
{
|
|
193
|
+
message: "This should ONLY be used in development environments",
|
|
194
|
+
environment: nodeEnv || "unknown",
|
|
195
|
+
provider: "none"
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async initialize() {
|
|
201
|
+
this.updateState({ user: this.defaultUser, status: "authenticated" });
|
|
202
|
+
}
|
|
203
|
+
async getAuthState() {
|
|
204
|
+
return this.currentState;
|
|
205
|
+
}
|
|
206
|
+
async signIn() {
|
|
207
|
+
if (console.info) {
|
|
208
|
+
console.info("[AUTH] SignIn called in no-auth mode - no action taken", {
|
|
209
|
+
provider: "none",
|
|
210
|
+
action: "signIn",
|
|
211
|
+
status: "ignored"
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async signOut() {
|
|
216
|
+
if (console.info) {
|
|
217
|
+
console.info("[AUTH] SignOut called in no-auth mode - no action taken", {
|
|
218
|
+
provider: "none",
|
|
219
|
+
action: "signOut",
|
|
220
|
+
status: "ignored"
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async getToken() {
|
|
225
|
+
return "dev-token|no-auth-mode|always-valid";
|
|
226
|
+
}
|
|
227
|
+
async refreshToken() {
|
|
228
|
+
return "dev-token|no-auth-mode|always-valid";
|
|
229
|
+
}
|
|
230
|
+
async getUser() {
|
|
231
|
+
return this.defaultUser;
|
|
232
|
+
}
|
|
233
|
+
onAuthStateChange(callback) {
|
|
234
|
+
callback(this.currentState);
|
|
235
|
+
this.listeners.push(callback);
|
|
236
|
+
return () => {
|
|
237
|
+
const index = this.listeners.indexOf(callback);
|
|
238
|
+
if (index > -1) {
|
|
239
|
+
this.listeners.splice(index, 1);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async destroy() {
|
|
244
|
+
this.listeners = [];
|
|
245
|
+
}
|
|
246
|
+
updateState(updates) {
|
|
247
|
+
this.currentState = { ...this.currentState, ...updates };
|
|
248
|
+
this.listeners.forEach((listener) => listener(this.currentState));
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// src/config/ApiConfigContext.tsx
|
|
253
|
+
var import_react2 = require("react");
|
|
254
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
255
|
+
var ApiConfigContext = (0, import_react2.createContext)(null);
|
|
256
|
+
function ApiConfigProvider({
|
|
257
|
+
children,
|
|
258
|
+
config
|
|
259
|
+
}) {
|
|
260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ApiConfigContext.Provider, { value: config, children });
|
|
261
|
+
}
|
|
262
|
+
function useApiConfig() {
|
|
263
|
+
const context = (0, import_react2.useContext)(ApiConfigContext);
|
|
264
|
+
if (!context) {
|
|
265
|
+
throw new Error("useApiConfig must be used within ApiConfigProvider");
|
|
266
|
+
}
|
|
267
|
+
return context;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// src/graphql/client.ts
|
|
271
|
+
var import_urql = require("urql");
|
|
272
|
+
var import_exchange_auth = require("@urql/exchange-auth");
|
|
273
|
+
var import_graphql_ws = require("graphql-ws");
|
|
274
|
+
function createGraphQLClient({
|
|
275
|
+
url,
|
|
276
|
+
subscriptionUrl,
|
|
277
|
+
auth,
|
|
278
|
+
tenantId
|
|
279
|
+
}) {
|
|
280
|
+
const wsClient = subscriptionUrl ? (0, import_graphql_ws.createClient)({
|
|
281
|
+
url: subscriptionUrl,
|
|
282
|
+
connectionParams: async () => {
|
|
283
|
+
const token = await auth.getToken();
|
|
284
|
+
const headers = {};
|
|
285
|
+
if (token) {
|
|
286
|
+
headers.Authorization = `Bearer ${token}`;
|
|
287
|
+
}
|
|
288
|
+
if (tenantId) {
|
|
289
|
+
headers["X-Tenant"] = tenantId;
|
|
290
|
+
}
|
|
291
|
+
return headers;
|
|
292
|
+
}
|
|
293
|
+
}) : null;
|
|
294
|
+
return (0, import_urql.createClient)({
|
|
295
|
+
url,
|
|
296
|
+
exchanges: [
|
|
297
|
+
import_urql.cacheExchange,
|
|
298
|
+
(0, import_exchange_auth.authExchange)(async () => {
|
|
299
|
+
let token = await auth.getToken();
|
|
300
|
+
return {
|
|
301
|
+
addAuthToOperation: (operation) => {
|
|
302
|
+
const headers = {};
|
|
303
|
+
if (token) {
|
|
304
|
+
headers.Authorization = `Bearer ${token}`;
|
|
305
|
+
}
|
|
306
|
+
if (tenantId) {
|
|
307
|
+
headers["X-Tenant"] = tenantId;
|
|
308
|
+
}
|
|
309
|
+
const fetchOptions = typeof operation.context.fetchOptions === "function" ? operation.context.fetchOptions() : operation.context.fetchOptions || {};
|
|
310
|
+
return (0, import_urql.makeOperation)(operation.kind, operation, {
|
|
311
|
+
...operation.context,
|
|
312
|
+
fetchOptions: {
|
|
313
|
+
...operation.context.fetchOptions,
|
|
314
|
+
headers: {
|
|
315
|
+
...fetchOptions.headers,
|
|
316
|
+
...headers
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
},
|
|
321
|
+
didAuthError: (error) => {
|
|
322
|
+
return error.graphQLErrors.some(
|
|
323
|
+
(e) => e.extensions?.code === "UNAUTHENTICATED" || e.extensions?.code === "UNAUTHORIZED"
|
|
324
|
+
);
|
|
325
|
+
},
|
|
326
|
+
willAuthError: () => {
|
|
327
|
+
return false;
|
|
328
|
+
},
|
|
329
|
+
refreshAuth: async () => {
|
|
330
|
+
token = await auth.getToken();
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}),
|
|
334
|
+
import_urql.fetchExchange,
|
|
335
|
+
...wsClient ? [
|
|
336
|
+
(0, import_urql.subscriptionExchange)({
|
|
337
|
+
forwardSubscription: (operation) => ({
|
|
338
|
+
subscribe: (sink) => ({
|
|
339
|
+
unsubscribe: wsClient.subscribe(
|
|
340
|
+
{
|
|
341
|
+
query: operation.query || "",
|
|
342
|
+
variables: operation.variables
|
|
343
|
+
},
|
|
344
|
+
sink
|
|
345
|
+
)
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
})
|
|
349
|
+
] : []
|
|
350
|
+
]
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// src/graphql/operations.ts
|
|
355
|
+
var import_urql2 = require("urql");
|
|
356
|
+
var USER_FRAGMENT = import_urql2.gql`
|
|
357
|
+
fragment UserFragment on User {
|
|
358
|
+
id
|
|
359
|
+
email
|
|
360
|
+
displayName
|
|
361
|
+
avatarUrl
|
|
362
|
+
createdAt
|
|
363
|
+
}
|
|
364
|
+
`;
|
|
365
|
+
var BOARD_FRAGMENT = import_urql2.gql`
|
|
366
|
+
fragment BoardFragment on Board {
|
|
367
|
+
id
|
|
368
|
+
tenantId
|
|
369
|
+
ownerId
|
|
370
|
+
title
|
|
371
|
+
description
|
|
372
|
+
isPublic
|
|
373
|
+
settings
|
|
374
|
+
metadata
|
|
375
|
+
createdAt
|
|
376
|
+
updatedAt
|
|
377
|
+
generationCount
|
|
378
|
+
}
|
|
379
|
+
`;
|
|
380
|
+
var GENERATION_FRAGMENT = import_urql2.gql`
|
|
381
|
+
fragment GenerationFragment on Generation {
|
|
382
|
+
id
|
|
383
|
+
boardId
|
|
384
|
+
userId
|
|
385
|
+
generatorName
|
|
386
|
+
artifactType
|
|
387
|
+
status
|
|
388
|
+
progress
|
|
389
|
+
storageUrl
|
|
390
|
+
thumbnailUrl
|
|
391
|
+
inputParams
|
|
392
|
+
outputMetadata
|
|
393
|
+
errorMessage
|
|
394
|
+
createdAt
|
|
395
|
+
updatedAt
|
|
396
|
+
completedAt
|
|
397
|
+
}
|
|
398
|
+
`;
|
|
399
|
+
var GET_CURRENT_USER = import_urql2.gql`
|
|
400
|
+
${USER_FRAGMENT}
|
|
401
|
+
query GetCurrentUser {
|
|
402
|
+
me {
|
|
403
|
+
...UserFragment
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
`;
|
|
407
|
+
var GET_BOARDS = import_urql2.gql`
|
|
408
|
+
${BOARD_FRAGMENT}
|
|
409
|
+
${USER_FRAGMENT}
|
|
410
|
+
query GetBoards($limit: Int, $offset: Int) {
|
|
411
|
+
myBoards(limit: $limit, offset: $offset) {
|
|
412
|
+
...BoardFragment
|
|
413
|
+
owner {
|
|
414
|
+
...UserFragment
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
`;
|
|
419
|
+
var GET_BOARD = import_urql2.gql`
|
|
420
|
+
${BOARD_FRAGMENT}
|
|
421
|
+
${USER_FRAGMENT}
|
|
422
|
+
${GENERATION_FRAGMENT}
|
|
423
|
+
query GetBoard($id: UUID!) {
|
|
424
|
+
board(id: $id) {
|
|
425
|
+
...BoardFragment
|
|
426
|
+
owner {
|
|
427
|
+
...UserFragment
|
|
428
|
+
}
|
|
429
|
+
members {
|
|
430
|
+
id
|
|
431
|
+
boardId
|
|
432
|
+
userId
|
|
433
|
+
role
|
|
434
|
+
invitedBy
|
|
435
|
+
joinedAt
|
|
436
|
+
user {
|
|
437
|
+
...UserFragment
|
|
438
|
+
}
|
|
439
|
+
inviter {
|
|
440
|
+
...UserFragment
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
generations(limit: 10) {
|
|
444
|
+
...GenerationFragment
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
`;
|
|
449
|
+
var GET_GENERATORS = import_urql2.gql`
|
|
450
|
+
query GetGenerators($artifactType: String) {
|
|
451
|
+
generators(artifactType: $artifactType) {
|
|
452
|
+
name
|
|
453
|
+
description
|
|
454
|
+
artifactType
|
|
455
|
+
inputSchema
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
`;
|
|
459
|
+
var GET_GENERATIONS = import_urql2.gql`
|
|
460
|
+
${GENERATION_FRAGMENT}
|
|
461
|
+
query GetGenerations($boardId: UUID, $limit: Int, $offset: Int) {
|
|
462
|
+
generations(boardId: $boardId, limit: $limit, offset: $offset) {
|
|
463
|
+
...GenerationFragment
|
|
464
|
+
board {
|
|
465
|
+
id
|
|
466
|
+
title
|
|
467
|
+
}
|
|
468
|
+
user {
|
|
469
|
+
...UserFragment
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
`;
|
|
474
|
+
var GET_GENERATION = import_urql2.gql`
|
|
475
|
+
${GENERATION_FRAGMENT}
|
|
476
|
+
query GetGeneration($id: UUID!) {
|
|
477
|
+
generation(id: $id) {
|
|
478
|
+
...GenerationFragment
|
|
479
|
+
board {
|
|
480
|
+
...BoardFragment
|
|
481
|
+
}
|
|
482
|
+
user {
|
|
483
|
+
...UserFragment
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
`;
|
|
488
|
+
var CREATE_BOARD = import_urql2.gql`
|
|
489
|
+
${BOARD_FRAGMENT}
|
|
490
|
+
${USER_FRAGMENT}
|
|
491
|
+
mutation CreateBoard($input: CreateBoardInput!) {
|
|
492
|
+
createBoard(input: $input) {
|
|
493
|
+
...BoardFragment
|
|
494
|
+
owner {
|
|
495
|
+
...UserFragment
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
`;
|
|
500
|
+
var UPDATE_BOARD = import_urql2.gql`
|
|
501
|
+
${BOARD_FRAGMENT}
|
|
502
|
+
mutation UpdateBoard($id: UUID!, $input: UpdateBoardInput!) {
|
|
503
|
+
updateBoard(id: $id, input: $input) {
|
|
504
|
+
...BoardFragment
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
`;
|
|
508
|
+
var DELETE_BOARD = import_urql2.gql`
|
|
509
|
+
mutation DeleteBoard($id: UUID!) {
|
|
510
|
+
deleteBoard(id: $id) {
|
|
511
|
+
success
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
`;
|
|
515
|
+
var ADD_BOARD_MEMBER = import_urql2.gql`
|
|
516
|
+
mutation AddBoardMember($boardId: UUID!, $email: String!, $role: BoardRole!) {
|
|
517
|
+
addBoardMember(boardId: $boardId, email: $email, role: $role) {
|
|
518
|
+
id
|
|
519
|
+
boardId
|
|
520
|
+
userId
|
|
521
|
+
role
|
|
522
|
+
invitedBy
|
|
523
|
+
joinedAt
|
|
524
|
+
user {
|
|
525
|
+
...UserFragment
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
`;
|
|
530
|
+
var UPDATE_BOARD_MEMBER_ROLE = import_urql2.gql`
|
|
531
|
+
mutation UpdateBoardMemberRole($id: UUID!, $role: BoardRole!) {
|
|
532
|
+
updateBoardMemberRole(id: $id, role: $role) {
|
|
533
|
+
id
|
|
534
|
+
role
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
`;
|
|
538
|
+
var REMOVE_BOARD_MEMBER = import_urql2.gql`
|
|
539
|
+
mutation RemoveBoardMember($id: UUID!) {
|
|
540
|
+
removeBoardMember(id: $id) {
|
|
541
|
+
success
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
`;
|
|
545
|
+
var CREATE_GENERATION = import_urql2.gql`
|
|
546
|
+
${GENERATION_FRAGMENT}
|
|
547
|
+
mutation CreateGeneration($input: CreateGenerationInput!) {
|
|
548
|
+
createGeneration(input: $input) {
|
|
549
|
+
...GenerationFragment
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
`;
|
|
553
|
+
var CANCEL_GENERATION = import_urql2.gql`
|
|
554
|
+
mutation CancelGeneration($id: UUID!) {
|
|
555
|
+
cancelGeneration(id: $id) {
|
|
556
|
+
id
|
|
557
|
+
status
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
`;
|
|
561
|
+
var RETRY_GENERATION = import_urql2.gql`
|
|
562
|
+
${GENERATION_FRAGMENT}
|
|
563
|
+
mutation RetryGeneration($id: UUID!) {
|
|
564
|
+
retryGeneration(id: $id) {
|
|
565
|
+
...GenerationFragment
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
`;
|
|
569
|
+
var BoardRole = /* @__PURE__ */ ((BoardRole2) => {
|
|
570
|
+
BoardRole2["VIEWER"] = "VIEWER";
|
|
571
|
+
BoardRole2["EDITOR"] = "EDITOR";
|
|
572
|
+
BoardRole2["ADMIN"] = "ADMIN";
|
|
573
|
+
return BoardRole2;
|
|
574
|
+
})(BoardRole || {});
|
|
575
|
+
var GenerationStatus = /* @__PURE__ */ ((GenerationStatus2) => {
|
|
576
|
+
GenerationStatus2["PENDING"] = "PENDING";
|
|
577
|
+
GenerationStatus2["RUNNING"] = "RUNNING";
|
|
578
|
+
GenerationStatus2["COMPLETED"] = "COMPLETED";
|
|
579
|
+
GenerationStatus2["FAILED"] = "FAILED";
|
|
580
|
+
GenerationStatus2["CANCELLED"] = "CANCELLED";
|
|
581
|
+
return GenerationStatus2;
|
|
582
|
+
})(GenerationStatus || {});
|
|
583
|
+
var ArtifactType = /* @__PURE__ */ ((ArtifactType4) => {
|
|
584
|
+
ArtifactType4["IMAGE"] = "image";
|
|
585
|
+
ArtifactType4["VIDEO"] = "video";
|
|
586
|
+
ArtifactType4["AUDIO"] = "audio";
|
|
587
|
+
ArtifactType4["TEXT"] = "text";
|
|
588
|
+
ArtifactType4["LORA"] = "lora";
|
|
589
|
+
ArtifactType4["MODEL"] = "model";
|
|
590
|
+
return ArtifactType4;
|
|
591
|
+
})(ArtifactType || {});
|
|
592
|
+
|
|
593
|
+
// src/hooks/useBoards.ts
|
|
594
|
+
var import_react3 = require("react");
|
|
595
|
+
var import_urql3 = require("urql");
|
|
596
|
+
function useBoards(options = {}) {
|
|
597
|
+
const { limit = 50, offset = 0 } = options;
|
|
598
|
+
const [searchQuery, setSearchQuery] = (0, import_react3.useState)("");
|
|
599
|
+
const [{ data, fetching, error }, reexecuteQuery] = (0, import_urql3.useQuery)({
|
|
600
|
+
query: GET_BOARDS,
|
|
601
|
+
variables: { limit, offset }
|
|
602
|
+
});
|
|
603
|
+
const [, createBoardMutation] = (0, import_urql3.useMutation)(CREATE_BOARD);
|
|
604
|
+
const [, deleteBoardMutation] = (0, import_urql3.useMutation)(DELETE_BOARD);
|
|
605
|
+
const boards = (0, import_react3.useMemo)(() => data?.myBoards || [], [data?.myBoards]);
|
|
606
|
+
const createBoard = (0, import_react3.useCallback)(
|
|
607
|
+
async (input) => {
|
|
608
|
+
const result = await createBoardMutation({ input });
|
|
609
|
+
if (result.error) {
|
|
610
|
+
throw new Error(result.error.message);
|
|
611
|
+
}
|
|
612
|
+
if (!result.data?.createBoard) {
|
|
613
|
+
throw new Error("Failed to create board");
|
|
614
|
+
}
|
|
615
|
+
return result.data.createBoard;
|
|
616
|
+
},
|
|
617
|
+
[createBoardMutation]
|
|
618
|
+
);
|
|
619
|
+
const deleteBoard = (0, import_react3.useCallback)(
|
|
620
|
+
async (boardId) => {
|
|
621
|
+
const result = await deleteBoardMutation({ id: boardId });
|
|
622
|
+
if (result.error) {
|
|
623
|
+
throw new Error(result.error.message);
|
|
624
|
+
}
|
|
625
|
+
if (!result.data?.deleteBoard?.success) {
|
|
626
|
+
throw new Error("Failed to delete board");
|
|
627
|
+
}
|
|
628
|
+
reexecuteQuery({ requestPolicy: "network-only" });
|
|
629
|
+
},
|
|
630
|
+
[deleteBoardMutation, reexecuteQuery]
|
|
631
|
+
);
|
|
632
|
+
const searchBoards = (0, import_react3.useCallback)(
|
|
633
|
+
async (query) => {
|
|
634
|
+
setSearchQuery(query);
|
|
635
|
+
return new Promise((resolve) => {
|
|
636
|
+
setTimeout(() => {
|
|
637
|
+
resolve(
|
|
638
|
+
boards.filter(
|
|
639
|
+
(board) => board.title.toLowerCase().includes(query.toLowerCase()) || board.description?.toLowerCase().includes(query.toLowerCase())
|
|
640
|
+
)
|
|
641
|
+
);
|
|
642
|
+
}, 350);
|
|
643
|
+
});
|
|
644
|
+
},
|
|
645
|
+
[boards]
|
|
646
|
+
);
|
|
647
|
+
const refresh = (0, import_react3.useCallback)(async () => {
|
|
648
|
+
await reexecuteQuery({ requestPolicy: "network-only" });
|
|
649
|
+
}, [reexecuteQuery]);
|
|
650
|
+
return {
|
|
651
|
+
boards,
|
|
652
|
+
loading: fetching,
|
|
653
|
+
error: error ? new Error(error.message) : null,
|
|
654
|
+
createBoard,
|
|
655
|
+
deleteBoard,
|
|
656
|
+
searchBoards,
|
|
657
|
+
refresh,
|
|
658
|
+
setSearchQuery,
|
|
659
|
+
searchQuery
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/hooks/useBoard.ts
|
|
664
|
+
var import_react4 = require("react");
|
|
665
|
+
var import_urql4 = require("urql");
|
|
666
|
+
function useBoard(boardId) {
|
|
667
|
+
const { user } = useAuth();
|
|
668
|
+
const [{ data, fetching, error }, reexecuteQuery] = (0, import_urql4.useQuery)({
|
|
669
|
+
query: GET_BOARD,
|
|
670
|
+
variables: { id: boardId },
|
|
671
|
+
pause: !boardId,
|
|
672
|
+
requestPolicy: "cache-and-network"
|
|
673
|
+
// Always fetch fresh data while showing cached data
|
|
674
|
+
});
|
|
675
|
+
const [, updateBoardMutation] = (0, import_urql4.useMutation)(UPDATE_BOARD);
|
|
676
|
+
const [, deleteBoardMutation] = (0, import_urql4.useMutation)(DELETE_BOARD);
|
|
677
|
+
const [, addMemberMutation] = (0, import_urql4.useMutation)(ADD_BOARD_MEMBER);
|
|
678
|
+
const [, updateMemberRoleMutation] = (0, import_urql4.useMutation)(UPDATE_BOARD_MEMBER_ROLE);
|
|
679
|
+
const [, removeMemberMutation] = (0, import_urql4.useMutation)(REMOVE_BOARD_MEMBER);
|
|
680
|
+
const board = (0, import_react4.useMemo)(() => data?.board || null, [data?.board]);
|
|
681
|
+
const members = (0, import_react4.useMemo)(() => board?.members || [], [board?.members]);
|
|
682
|
+
const permissions = (0, import_react4.useMemo)(() => {
|
|
683
|
+
if (!board || !user) {
|
|
684
|
+
return {
|
|
685
|
+
canEdit: false,
|
|
686
|
+
canDelete: false,
|
|
687
|
+
canAddMembers: false,
|
|
688
|
+
canRemoveMembers: false,
|
|
689
|
+
canGenerate: false,
|
|
690
|
+
canExport: false
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
const isOwner = board.ownerId === user.id;
|
|
694
|
+
const userMember = members.find(
|
|
695
|
+
(member) => member.userId === user.id
|
|
696
|
+
);
|
|
697
|
+
const userRole = userMember?.role;
|
|
698
|
+
const isAdmin = userRole === "ADMIN" /* ADMIN */;
|
|
699
|
+
const isEditor = userRole === "EDITOR" /* EDITOR */ || isAdmin;
|
|
700
|
+
const isViewer = userRole === "VIEWER" /* VIEWER */ || isEditor;
|
|
701
|
+
return {
|
|
702
|
+
canEdit: isOwner || isAdmin || isEditor,
|
|
703
|
+
canDelete: isOwner,
|
|
704
|
+
canAddMembers: isOwner || isAdmin,
|
|
705
|
+
canRemoveMembers: isOwner || isAdmin,
|
|
706
|
+
canGenerate: isOwner || isAdmin || isEditor,
|
|
707
|
+
canExport: isViewer
|
|
708
|
+
// Even viewers can export
|
|
709
|
+
};
|
|
710
|
+
}, [board, user, members]);
|
|
711
|
+
const updateBoard = (0, import_react4.useCallback)(
|
|
712
|
+
async (updates) => {
|
|
713
|
+
if (!boardId) {
|
|
714
|
+
throw new Error("Board ID is required");
|
|
715
|
+
}
|
|
716
|
+
const result = await updateBoardMutation({
|
|
717
|
+
id: boardId,
|
|
718
|
+
input: updates
|
|
719
|
+
});
|
|
720
|
+
if (result.error) {
|
|
721
|
+
throw new Error(result.error.message);
|
|
722
|
+
}
|
|
723
|
+
if (!result.data?.updateBoard) {
|
|
724
|
+
throw new Error("Failed to update board");
|
|
725
|
+
}
|
|
726
|
+
return result.data.updateBoard;
|
|
727
|
+
},
|
|
728
|
+
[boardId, updateBoardMutation]
|
|
729
|
+
);
|
|
730
|
+
const deleteBoard = (0, import_react4.useCallback)(async () => {
|
|
731
|
+
if (!boardId) {
|
|
732
|
+
throw new Error("Board ID is required");
|
|
733
|
+
}
|
|
734
|
+
const result = await deleteBoardMutation({ id: boardId });
|
|
735
|
+
if (result.error) {
|
|
736
|
+
throw new Error(result.error.message);
|
|
737
|
+
}
|
|
738
|
+
if (!result.data?.deleteBoard?.success) {
|
|
739
|
+
throw new Error("Failed to delete board");
|
|
740
|
+
}
|
|
741
|
+
}, [boardId, deleteBoardMutation]);
|
|
742
|
+
const addMember = (0, import_react4.useCallback)(
|
|
743
|
+
async (email, role) => {
|
|
744
|
+
if (!boardId) {
|
|
745
|
+
throw new Error("Board ID is required");
|
|
746
|
+
}
|
|
747
|
+
const result = await addMemberMutation({
|
|
748
|
+
boardId,
|
|
749
|
+
email,
|
|
750
|
+
role
|
|
751
|
+
});
|
|
752
|
+
if (result.error) {
|
|
753
|
+
throw new Error(result.error.message);
|
|
754
|
+
}
|
|
755
|
+
if (!result.data?.addBoardMember) {
|
|
756
|
+
throw new Error("Failed to add member");
|
|
757
|
+
}
|
|
758
|
+
reexecuteQuery({ requestPolicy: "network-only" });
|
|
759
|
+
return result.data.addBoardMember;
|
|
760
|
+
},
|
|
761
|
+
[boardId, addMemberMutation, reexecuteQuery]
|
|
762
|
+
);
|
|
763
|
+
const removeMember = (0, import_react4.useCallback)(
|
|
764
|
+
async (memberId) => {
|
|
765
|
+
const result = await removeMemberMutation({ id: memberId });
|
|
766
|
+
if (result.error) {
|
|
767
|
+
throw new Error(result.error.message);
|
|
768
|
+
}
|
|
769
|
+
if (!result.data?.removeBoardMember?.success) {
|
|
770
|
+
throw new Error("Failed to remove member");
|
|
771
|
+
}
|
|
772
|
+
reexecuteQuery({ requestPolicy: "network-only" });
|
|
773
|
+
},
|
|
774
|
+
[removeMemberMutation, reexecuteQuery]
|
|
775
|
+
);
|
|
776
|
+
const updateMemberRole = (0, import_react4.useCallback)(
|
|
777
|
+
async (memberId, role) => {
|
|
778
|
+
const result = await updateMemberRoleMutation({
|
|
779
|
+
id: memberId,
|
|
780
|
+
role
|
|
781
|
+
});
|
|
782
|
+
if (result.error) {
|
|
783
|
+
throw new Error(result.error.message);
|
|
784
|
+
}
|
|
785
|
+
if (!result.data?.updateBoardMemberRole) {
|
|
786
|
+
throw new Error("Failed to update member role");
|
|
787
|
+
}
|
|
788
|
+
reexecuteQuery({ requestPolicy: "network-only" });
|
|
789
|
+
return result.data.updateBoardMemberRole;
|
|
790
|
+
},
|
|
791
|
+
[updateMemberRoleMutation, reexecuteQuery]
|
|
792
|
+
);
|
|
793
|
+
const generateShareLink = (0, import_react4.useCallback)(
|
|
794
|
+
async (_options) => {
|
|
795
|
+
throw new Error("Share links not implemented yet");
|
|
796
|
+
},
|
|
797
|
+
[]
|
|
798
|
+
);
|
|
799
|
+
const revokeShareLink = (0, import_react4.useCallback)(
|
|
800
|
+
async (_linkId) => {
|
|
801
|
+
throw new Error("Share link revocation not implemented yet");
|
|
802
|
+
},
|
|
803
|
+
[]
|
|
804
|
+
);
|
|
805
|
+
const refresh = (0, import_react4.useCallback)(async () => {
|
|
806
|
+
await reexecuteQuery({ requestPolicy: "network-only" });
|
|
807
|
+
}, [reexecuteQuery]);
|
|
808
|
+
return {
|
|
809
|
+
board,
|
|
810
|
+
members,
|
|
811
|
+
permissions,
|
|
812
|
+
loading: fetching,
|
|
813
|
+
error: error ? new Error(error.message) : null,
|
|
814
|
+
updateBoard,
|
|
815
|
+
deleteBoard,
|
|
816
|
+
refresh,
|
|
817
|
+
addMember,
|
|
818
|
+
removeMember,
|
|
819
|
+
updateMemberRole,
|
|
820
|
+
generateShareLink,
|
|
821
|
+
revokeShareLink
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// src/hooks/useGeneration.ts
|
|
826
|
+
var import_react5 = require("react");
|
|
827
|
+
var import_fetch_event_source = require("@microsoft/fetch-event-source");
|
|
828
|
+
var import_urql5 = require("urql");
|
|
829
|
+
function useGeneration() {
|
|
830
|
+
const [progress, setProgress] = (0, import_react5.useState)(null);
|
|
831
|
+
const [result, setResult] = (0, import_react5.useState)(null);
|
|
832
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
833
|
+
const [isGenerating, setIsGenerating] = (0, import_react5.useState)(false);
|
|
834
|
+
const [history, setHistory] = (0, import_react5.useState)([]);
|
|
835
|
+
const { apiUrl } = useApiConfig();
|
|
836
|
+
const auth = useAuth();
|
|
837
|
+
const abortControllers = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
|
|
838
|
+
const [, createGenerationMutation] = (0, import_urql5.useMutation)(CREATE_GENERATION);
|
|
839
|
+
const [, cancelGenerationMutation] = (0, import_urql5.useMutation)(CANCEL_GENERATION);
|
|
840
|
+
const [, retryGenerationMutation] = (0, import_urql5.useMutation)(RETRY_GENERATION);
|
|
841
|
+
(0, import_react5.useEffect)(() => {
|
|
842
|
+
return () => {
|
|
843
|
+
abortControllers.current.forEach((controller) => {
|
|
844
|
+
controller.abort();
|
|
845
|
+
});
|
|
846
|
+
abortControllers.current.clear();
|
|
847
|
+
};
|
|
848
|
+
}, []);
|
|
849
|
+
const connectToSSE = (0, import_react5.useCallback)(
|
|
850
|
+
async (jobId) => {
|
|
851
|
+
const existingController = abortControllers.current.get(jobId);
|
|
852
|
+
if (existingController) {
|
|
853
|
+
existingController.abort();
|
|
854
|
+
}
|
|
855
|
+
const abortController = new AbortController();
|
|
856
|
+
abortControllers.current.set(jobId, abortController);
|
|
857
|
+
const token = await auth.getToken();
|
|
858
|
+
const headers = {
|
|
859
|
+
Accept: "text/event-stream"
|
|
860
|
+
};
|
|
861
|
+
if (token) {
|
|
862
|
+
headers.Authorization = `Bearer ${token}`;
|
|
863
|
+
}
|
|
864
|
+
const sseUrl = `${apiUrl}/api/sse/generations/${jobId}/progress`;
|
|
865
|
+
console.log("SSE: Connecting to", sseUrl, "with headers:", headers);
|
|
866
|
+
try {
|
|
867
|
+
await (0, import_fetch_event_source.fetchEventSource)(sseUrl, {
|
|
868
|
+
headers,
|
|
869
|
+
signal: abortController.signal,
|
|
870
|
+
async onopen(response) {
|
|
871
|
+
console.log(
|
|
872
|
+
"SSE: Connection opened",
|
|
873
|
+
response.status,
|
|
874
|
+
response.statusText
|
|
875
|
+
);
|
|
876
|
+
if (response.ok) {
|
|
877
|
+
console.log("SSE: Connection successful");
|
|
878
|
+
} else {
|
|
879
|
+
console.error("SSE: Connection failed", response.status);
|
|
880
|
+
throw new Error(`SSE connection failed: ${response.statusText}`);
|
|
881
|
+
}
|
|
882
|
+
},
|
|
883
|
+
onmessage(event) {
|
|
884
|
+
console.log("SSE: Raw event received:", event);
|
|
885
|
+
if (!event.data || event.data.trim() === "") {
|
|
886
|
+
console.log("SSE: Skipping empty message");
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
try {
|
|
890
|
+
const progressData = JSON.parse(event.data);
|
|
891
|
+
console.log("SSE: progress data received:", progressData);
|
|
892
|
+
setProgress(progressData);
|
|
893
|
+
if (progressData.status === "completed" || progressData.status === "failed" || progressData.status === "cancelled") {
|
|
894
|
+
setIsGenerating(false);
|
|
895
|
+
if (progressData.status === "completed") {
|
|
896
|
+
const mockResult = {
|
|
897
|
+
id: progressData.jobId,
|
|
898
|
+
jobId: progressData.jobId,
|
|
899
|
+
boardId: "",
|
|
900
|
+
// Would be filled from the original request
|
|
901
|
+
request: {},
|
|
902
|
+
artifacts: [],
|
|
903
|
+
credits: { cost: 0, balanceBefore: 0, balance: 0 },
|
|
904
|
+
performance: {
|
|
905
|
+
queueTime: 0,
|
|
906
|
+
processingTime: 0,
|
|
907
|
+
totalTime: 0
|
|
908
|
+
},
|
|
909
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
910
|
+
};
|
|
911
|
+
setResult(mockResult);
|
|
912
|
+
setHistory((prev) => [...prev, mockResult]);
|
|
913
|
+
} else if (progressData.status === "failed") {
|
|
914
|
+
setError(new Error("Generation failed"));
|
|
915
|
+
}
|
|
916
|
+
abortController.abort();
|
|
917
|
+
abortControllers.current.delete(jobId);
|
|
918
|
+
}
|
|
919
|
+
} catch (err) {
|
|
920
|
+
console.error("Failed to parse SSE message:", err);
|
|
921
|
+
setError(new Error("Failed to parse progress update"));
|
|
922
|
+
setIsGenerating(false);
|
|
923
|
+
abortController.abort();
|
|
924
|
+
abortControllers.current.delete(jobId);
|
|
925
|
+
}
|
|
926
|
+
},
|
|
927
|
+
onerror(err) {
|
|
928
|
+
console.error("SSE connection error:", err);
|
|
929
|
+
console.error("SSE error details:", {
|
|
930
|
+
message: err instanceof Error ? err.message : String(err),
|
|
931
|
+
jobId,
|
|
932
|
+
url: sseUrl
|
|
933
|
+
});
|
|
934
|
+
setError(new Error("Lost connection to generation progress"));
|
|
935
|
+
setIsGenerating(false);
|
|
936
|
+
abortController.abort();
|
|
937
|
+
abortControllers.current.delete(jobId);
|
|
938
|
+
throw err;
|
|
939
|
+
},
|
|
940
|
+
openWhenHidden: true
|
|
941
|
+
// Keep connection open when tab is hidden
|
|
942
|
+
});
|
|
943
|
+
} catch (err) {
|
|
944
|
+
if (abortController.signal.aborted) {
|
|
945
|
+
console.log("SSE connection aborted for job:", jobId);
|
|
946
|
+
} else {
|
|
947
|
+
console.error("SSE connection failed:", err);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
},
|
|
951
|
+
[apiUrl, auth]
|
|
952
|
+
);
|
|
953
|
+
const submit = (0, import_react5.useCallback)(
|
|
954
|
+
async (request) => {
|
|
955
|
+
setError(null);
|
|
956
|
+
setProgress(null);
|
|
957
|
+
setResult(null);
|
|
958
|
+
setIsGenerating(true);
|
|
959
|
+
const input = {
|
|
960
|
+
boardId: request.boardId,
|
|
961
|
+
generatorName: request.model,
|
|
962
|
+
artifactType: request.artifactType,
|
|
963
|
+
inputParams: {
|
|
964
|
+
...request.inputs,
|
|
965
|
+
...request.options
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
let lastError = null;
|
|
969
|
+
const maxRetries = 2;
|
|
970
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
971
|
+
try {
|
|
972
|
+
const result2 = await createGenerationMutation({ input });
|
|
973
|
+
if (result2.error) {
|
|
974
|
+
throw new Error(result2.error.message);
|
|
975
|
+
}
|
|
976
|
+
if (!result2.data?.createGeneration) {
|
|
977
|
+
throw new Error("Failed to create generation");
|
|
978
|
+
}
|
|
979
|
+
const jobId = result2.data.createGeneration.id;
|
|
980
|
+
connectToSSE(jobId);
|
|
981
|
+
setIsGenerating(false);
|
|
982
|
+
return jobId;
|
|
983
|
+
} catch (err) {
|
|
984
|
+
lastError = err instanceof Error ? err : new Error("Failed to submit generation");
|
|
985
|
+
if (lastError.message.includes("insufficient credits") || lastError.message.includes("validation") || lastError.message.includes("unauthorized") || lastError.message.includes("forbidden")) {
|
|
986
|
+
setError(lastError);
|
|
987
|
+
setIsGenerating(false);
|
|
988
|
+
throw lastError;
|
|
989
|
+
}
|
|
990
|
+
if (attempt === maxRetries) {
|
|
991
|
+
setError(lastError);
|
|
992
|
+
setIsGenerating(false);
|
|
993
|
+
throw lastError;
|
|
994
|
+
}
|
|
995
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 * attempt));
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
const finalError = lastError || new Error("Failed to submit generation after retries");
|
|
999
|
+
setError(finalError);
|
|
1000
|
+
setIsGenerating(false);
|
|
1001
|
+
throw finalError;
|
|
1002
|
+
},
|
|
1003
|
+
[createGenerationMutation, connectToSSE]
|
|
1004
|
+
);
|
|
1005
|
+
const cancel = (0, import_react5.useCallback)(
|
|
1006
|
+
async (jobId) => {
|
|
1007
|
+
try {
|
|
1008
|
+
const result2 = await cancelGenerationMutation({ id: jobId });
|
|
1009
|
+
if (result2.error) {
|
|
1010
|
+
throw new Error(result2.error.message);
|
|
1011
|
+
}
|
|
1012
|
+
const controller = abortControllers.current.get(jobId);
|
|
1013
|
+
if (controller) {
|
|
1014
|
+
controller.abort();
|
|
1015
|
+
abortControllers.current.delete(jobId);
|
|
1016
|
+
}
|
|
1017
|
+
setIsGenerating(false);
|
|
1018
|
+
setProgress((prev) => prev ? { ...prev, status: "cancelled" } : null);
|
|
1019
|
+
} catch (err) {
|
|
1020
|
+
setError(
|
|
1021
|
+
err instanceof Error ? err : new Error("Failed to cancel generation")
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
},
|
|
1025
|
+
[cancelGenerationMutation]
|
|
1026
|
+
);
|
|
1027
|
+
const retry = (0, import_react5.useCallback)(
|
|
1028
|
+
async (jobId) => {
|
|
1029
|
+
try {
|
|
1030
|
+
setError(null);
|
|
1031
|
+
setIsGenerating(true);
|
|
1032
|
+
const result2 = await retryGenerationMutation({ id: jobId });
|
|
1033
|
+
if (result2.error) {
|
|
1034
|
+
throw new Error(result2.error.message);
|
|
1035
|
+
}
|
|
1036
|
+
if (!result2.data?.retryGeneration) {
|
|
1037
|
+
throw new Error("Failed to retry generation");
|
|
1038
|
+
}
|
|
1039
|
+
const newJobId = result2.data.retryGeneration.id;
|
|
1040
|
+
connectToSSE(newJobId);
|
|
1041
|
+
} catch (err) {
|
|
1042
|
+
setError(
|
|
1043
|
+
err instanceof Error ? err : new Error("Failed to retry generation")
|
|
1044
|
+
);
|
|
1045
|
+
setIsGenerating(false);
|
|
1046
|
+
}
|
|
1047
|
+
},
|
|
1048
|
+
[retryGenerationMutation, connectToSSE]
|
|
1049
|
+
);
|
|
1050
|
+
const clearHistory = (0, import_react5.useCallback)(() => {
|
|
1051
|
+
setHistory([]);
|
|
1052
|
+
}, []);
|
|
1053
|
+
return {
|
|
1054
|
+
progress,
|
|
1055
|
+
result,
|
|
1056
|
+
error,
|
|
1057
|
+
isGenerating,
|
|
1058
|
+
submit,
|
|
1059
|
+
cancel,
|
|
1060
|
+
retry,
|
|
1061
|
+
history,
|
|
1062
|
+
clearHistory
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// src/hooks/useGenerators.ts
|
|
1067
|
+
var import_react6 = require("react");
|
|
1068
|
+
var import_urql6 = require("urql");
|
|
1069
|
+
function useGenerators(options = {}) {
|
|
1070
|
+
const { artifactType } = options;
|
|
1071
|
+
const [{ data, fetching, error }] = (0, import_urql6.useQuery)({
|
|
1072
|
+
query: GET_GENERATORS,
|
|
1073
|
+
variables: artifactType ? { artifactType } : {}
|
|
1074
|
+
});
|
|
1075
|
+
const generators = (0, import_react6.useMemo)(() => data?.generators || [], [data?.generators]);
|
|
1076
|
+
return {
|
|
1077
|
+
generators,
|
|
1078
|
+
loading: fetching,
|
|
1079
|
+
error: error ? new Error(error.message) : null
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// src/providers/BoardsProvider.tsx
|
|
1084
|
+
var import_urql7 = require("urql");
|
|
1085
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1086
|
+
function BoardsProvider({
|
|
1087
|
+
children,
|
|
1088
|
+
apiUrl,
|
|
1089
|
+
graphqlUrl,
|
|
1090
|
+
subscriptionUrl,
|
|
1091
|
+
authProvider,
|
|
1092
|
+
tenantId
|
|
1093
|
+
}) {
|
|
1094
|
+
const resolvedGraphqlUrl = graphqlUrl || `${apiUrl}/graphql`;
|
|
1095
|
+
const apiConfig = {
|
|
1096
|
+
apiUrl,
|
|
1097
|
+
graphqlUrl: resolvedGraphqlUrl,
|
|
1098
|
+
subscriptionUrl
|
|
1099
|
+
};
|
|
1100
|
+
const client = createGraphQLClient({
|
|
1101
|
+
url: resolvedGraphqlUrl,
|
|
1102
|
+
subscriptionUrl,
|
|
1103
|
+
auth: {
|
|
1104
|
+
getToken: () => authProvider.getAuthState().then((state) => state.getToken())
|
|
1105
|
+
},
|
|
1106
|
+
tenantId
|
|
1107
|
+
});
|
|
1108
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AuthProvider, { provider: authProvider, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ApiConfigProvider, { config: apiConfig, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_urql7.Provider, { value: client, children }) }) });
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/index.ts
|
|
1112
|
+
var VERSION = "0.1.0";
|
|
1113
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1114
|
+
0 && (module.exports = {
|
|
1115
|
+
ADD_BOARD_MEMBER,
|
|
1116
|
+
ArtifactType,
|
|
1117
|
+
AuthProvider,
|
|
1118
|
+
BOARD_FRAGMENT,
|
|
1119
|
+
BaseAuthProvider,
|
|
1120
|
+
BoardRole,
|
|
1121
|
+
BoardsProvider,
|
|
1122
|
+
CANCEL_GENERATION,
|
|
1123
|
+
CREATE_BOARD,
|
|
1124
|
+
CREATE_GENERATION,
|
|
1125
|
+
DELETE_BOARD,
|
|
1126
|
+
GENERATION_FRAGMENT,
|
|
1127
|
+
GET_BOARD,
|
|
1128
|
+
GET_BOARDS,
|
|
1129
|
+
GET_CURRENT_USER,
|
|
1130
|
+
GET_GENERATION,
|
|
1131
|
+
GET_GENERATIONS,
|
|
1132
|
+
GET_GENERATORS,
|
|
1133
|
+
GenerationStatus,
|
|
1134
|
+
NoAuthProvider,
|
|
1135
|
+
REMOVE_BOARD_MEMBER,
|
|
1136
|
+
RETRY_GENERATION,
|
|
1137
|
+
UPDATE_BOARD,
|
|
1138
|
+
UPDATE_BOARD_MEMBER_ROLE,
|
|
1139
|
+
USER_FRAGMENT,
|
|
1140
|
+
VERSION,
|
|
1141
|
+
createGraphQLClient,
|
|
1142
|
+
useApiConfig,
|
|
1143
|
+
useAuth,
|
|
1144
|
+
useAuthOptional,
|
|
1145
|
+
useBoard,
|
|
1146
|
+
useBoards,
|
|
1147
|
+
useGeneration,
|
|
1148
|
+
useGenerators
|
|
1149
|
+
});
|
|
1150
|
+
//# sourceMappingURL=index.js.map
|