@weirdfingers/boards 0.6.2 → 0.8.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/index.d.mts CHANGED
@@ -389,6 +389,7 @@ declare const REMOVE_BOARD_MEMBER: urql.TypedDocumentNode<any, urql.AnyVariables
389
389
  declare const CREATE_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
390
390
  declare const CANCEL_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
391
391
  declare const RETRY_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
392
+ declare const DELETE_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
392
393
  declare const UPLOAD_ARTIFACT_FROM_URL: urql.TypedDocumentNode<any, urql.AnyVariables>;
393
394
  interface CreateBoardInput {
394
395
  title: string;
@@ -652,6 +653,7 @@ interface GenerationHook {
652
653
  submit: (request: GenerationRequest) => Promise<string>;
653
654
  cancel: (jobId: string) => Promise<void>;
654
655
  retry: (jobId: string) => Promise<void>;
656
+ deleteGeneration: (jobId: string) => Promise<void>;
655
657
  history: GenerationResult[];
656
658
  clearHistory: () => void;
657
659
  }
@@ -679,17 +681,17 @@ interface GeneratorsHook {
679
681
  declare function useGenerators(options?: UseGeneratorsOptions): GeneratorsHook;
680
682
 
681
683
  /**
682
- * Hook for uploading artifacts (images, videos, audio, text).
684
+ * Hook for uploading multiple artifacts concurrently with individual progress tracking.
683
685
  */
684
686
 
685
- interface UploadRequest {
687
+ interface MultiUploadRequest {
686
688
  boardId: string;
687
689
  artifactType: ArtifactType;
688
690
  source: File | string;
689
691
  userDescription?: string;
690
692
  parentGenerationId?: string;
691
693
  }
692
- interface UploadResult {
694
+ interface MultiUploadResult {
693
695
  id: string;
694
696
  storageUrl: string;
695
697
  thumbnailUrl?: string;
@@ -697,13 +699,25 @@ interface UploadResult {
697
699
  artifactType: ArtifactType;
698
700
  generatorName: string;
699
701
  }
700
- interface UploadHook {
701
- upload: (request: UploadRequest) => Promise<UploadResult>;
702
- isUploading: boolean;
702
+ type UploadStatus = "pending" | "uploading" | "completed" | "failed";
703
+ interface UploadItem {
704
+ id: string;
705
+ file: File | string;
706
+ fileName: string;
707
+ status: UploadStatus;
703
708
  progress: number;
704
- error: Error | null;
709
+ result?: MultiUploadResult;
710
+ error?: Error;
711
+ }
712
+ interface MultiUploadHook {
713
+ uploadMultiple: (requests: MultiUploadRequest[]) => Promise<MultiUploadResult[]>;
714
+ uploads: UploadItem[];
715
+ isUploading: boolean;
716
+ overallProgress: number;
717
+ clearUploads: () => void;
718
+ cancelUpload: (uploadId: string) => void;
705
719
  }
706
- declare function useUpload(): UploadHook;
720
+ declare function useMultiUpload(): MultiUploadHook;
707
721
 
708
722
  /**
709
723
  * Hook for accessing generation lineage (ancestry and descendants).
@@ -908,4 +922,4 @@ declare function BoardsProvider({ children, apiUrl, graphqlUrl, subscriptionUrl,
908
922
 
909
923
  declare const VERSION = "0.1.0";
910
924
 
911
- export { ADD_BOARD_MEMBER, ANCESTRY_NODE_FRAGMENT, ARTIFACT_LINEAGE_FRAGMENT, type AncestryNode, type ApiConfig, type Artifact$1 as Artifact, type ArtifactLineage, type ArtifactSlot, type ArtifactSlotInfo, ArtifactType, type AuthContextValue, AuthProvider, type AuthProviderConfig, type AuthState$1 as AuthState, BOARD_FRAGMENT, BaseAuthProvider, BoardRole, BoardsProvider, CANCEL_GENERATION, CREATE_BOARD, CREATE_GENERATION, type CreateBoardInput, type CreateGenerationInput, DELETE_BOARD, DESCENDANT_NODE_FRAGMENT, type DescendantNode, type DropdownField, GENERATION_FRAGMENT, GET_ANCESTRY, GET_BOARD, GET_BOARDS, GET_CURRENT_USER, GET_DESCENDANTS, GET_GENERATION, GET_GENERATIONS, GET_GENERATORS, GET_INPUT_ARTIFACTS, GenerationStatus, type Generator, type GeneratorInfo, type GeneratorSelectionContextValue, GeneratorSelectionProvider, NoAuthProvider, type NumberInputField, type ParsedGeneratorSchema, type PromptField, REMOVE_BOARD_MEMBER, RETRY_GENERATION, type SettingsField, type SignInOptions, type SliderField, type TextInputField, UPDATE_BOARD, UPDATE_BOARD_MEMBER_ROLE, UPLOAD_ARTIFACT_FROM_URL, USER_FRAGMENT, type UpdateBoardInput, type UploadArtifactInput, type UploadHook, type UploadRequest, type UploadResult, type User$1 as User, VERSION, createGraphQLClient, getArtifactType, isArtifactReference, parseArtifactSlot, parseGeneratorSchema, parseSettingsField, useAncestry, useApiConfig, useAuth, useAuthOptional, useBoard, useBoards, useDescendants, useGeneration, useGeneratorSelection, useGenerators, useInputArtifacts, useLineage, useUpload };
925
+ export { ADD_BOARD_MEMBER, ANCESTRY_NODE_FRAGMENT, ARTIFACT_LINEAGE_FRAGMENT, type AncestryNode, type ApiConfig, type Artifact$1 as Artifact, type ArtifactLineage, type ArtifactSlot, type ArtifactSlotInfo, ArtifactType, type AuthContextValue, AuthProvider, type AuthProviderConfig, type AuthState$1 as AuthState, BOARD_FRAGMENT, BaseAuthProvider, BoardRole, BoardsProvider, CANCEL_GENERATION, CREATE_BOARD, CREATE_GENERATION, type CreateBoardInput, type CreateGenerationInput, DELETE_BOARD, DELETE_GENERATION, DESCENDANT_NODE_FRAGMENT, type DescendantNode, type DropdownField, GENERATION_FRAGMENT, GET_ANCESTRY, GET_BOARD, GET_BOARDS, GET_CURRENT_USER, GET_DESCENDANTS, GET_GENERATION, GET_GENERATIONS, GET_GENERATORS, GET_INPUT_ARTIFACTS, GenerationStatus, type Generator, type GeneratorInfo, type GeneratorSelectionContextValue, GeneratorSelectionProvider, type MultiUploadHook, type MultiUploadRequest, type MultiUploadResult, NoAuthProvider, type NumberInputField, type ParsedGeneratorSchema, type PromptField, REMOVE_BOARD_MEMBER, RETRY_GENERATION, type SettingsField, type SignInOptions, type SliderField, type TextInputField, UPDATE_BOARD, UPDATE_BOARD_MEMBER_ROLE, UPLOAD_ARTIFACT_FROM_URL, USER_FRAGMENT, type UpdateBoardInput, type UploadArtifactInput, type UploadItem, type UploadStatus, type User$1 as User, VERSION, createGraphQLClient, getArtifactType, isArtifactReference, parseArtifactSlot, parseGeneratorSchema, parseSettingsField, useAncestry, useApiConfig, useAuth, useAuthOptional, useBoard, useBoards, useDescendants, useGeneration, useGeneratorSelection, useGenerators, useInputArtifacts, useLineage, useMultiUpload };
package/dist/index.d.ts CHANGED
@@ -389,6 +389,7 @@ declare const REMOVE_BOARD_MEMBER: urql.TypedDocumentNode<any, urql.AnyVariables
389
389
  declare const CREATE_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
390
390
  declare const CANCEL_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
391
391
  declare const RETRY_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
392
+ declare const DELETE_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
392
393
  declare const UPLOAD_ARTIFACT_FROM_URL: urql.TypedDocumentNode<any, urql.AnyVariables>;
393
394
  interface CreateBoardInput {
394
395
  title: string;
@@ -652,6 +653,7 @@ interface GenerationHook {
652
653
  submit: (request: GenerationRequest) => Promise<string>;
653
654
  cancel: (jobId: string) => Promise<void>;
654
655
  retry: (jobId: string) => Promise<void>;
656
+ deleteGeneration: (jobId: string) => Promise<void>;
655
657
  history: GenerationResult[];
656
658
  clearHistory: () => void;
657
659
  }
@@ -679,17 +681,17 @@ interface GeneratorsHook {
679
681
  declare function useGenerators(options?: UseGeneratorsOptions): GeneratorsHook;
680
682
 
681
683
  /**
682
- * Hook for uploading artifacts (images, videos, audio, text).
684
+ * Hook for uploading multiple artifacts concurrently with individual progress tracking.
683
685
  */
684
686
 
685
- interface UploadRequest {
687
+ interface MultiUploadRequest {
686
688
  boardId: string;
687
689
  artifactType: ArtifactType;
688
690
  source: File | string;
689
691
  userDescription?: string;
690
692
  parentGenerationId?: string;
691
693
  }
692
- interface UploadResult {
694
+ interface MultiUploadResult {
693
695
  id: string;
694
696
  storageUrl: string;
695
697
  thumbnailUrl?: string;
@@ -697,13 +699,25 @@ interface UploadResult {
697
699
  artifactType: ArtifactType;
698
700
  generatorName: string;
699
701
  }
700
- interface UploadHook {
701
- upload: (request: UploadRequest) => Promise<UploadResult>;
702
- isUploading: boolean;
702
+ type UploadStatus = "pending" | "uploading" | "completed" | "failed";
703
+ interface UploadItem {
704
+ id: string;
705
+ file: File | string;
706
+ fileName: string;
707
+ status: UploadStatus;
703
708
  progress: number;
704
- error: Error | null;
709
+ result?: MultiUploadResult;
710
+ error?: Error;
711
+ }
712
+ interface MultiUploadHook {
713
+ uploadMultiple: (requests: MultiUploadRequest[]) => Promise<MultiUploadResult[]>;
714
+ uploads: UploadItem[];
715
+ isUploading: boolean;
716
+ overallProgress: number;
717
+ clearUploads: () => void;
718
+ cancelUpload: (uploadId: string) => void;
705
719
  }
706
- declare function useUpload(): UploadHook;
720
+ declare function useMultiUpload(): MultiUploadHook;
707
721
 
708
722
  /**
709
723
  * Hook for accessing generation lineage (ancestry and descendants).
@@ -908,4 +922,4 @@ declare function BoardsProvider({ children, apiUrl, graphqlUrl, subscriptionUrl,
908
922
 
909
923
  declare const VERSION = "0.1.0";
910
924
 
911
- export { ADD_BOARD_MEMBER, ANCESTRY_NODE_FRAGMENT, ARTIFACT_LINEAGE_FRAGMENT, type AncestryNode, type ApiConfig, type Artifact$1 as Artifact, type ArtifactLineage, type ArtifactSlot, type ArtifactSlotInfo, ArtifactType, type AuthContextValue, AuthProvider, type AuthProviderConfig, type AuthState$1 as AuthState, BOARD_FRAGMENT, BaseAuthProvider, BoardRole, BoardsProvider, CANCEL_GENERATION, CREATE_BOARD, CREATE_GENERATION, type CreateBoardInput, type CreateGenerationInput, DELETE_BOARD, DESCENDANT_NODE_FRAGMENT, type DescendantNode, type DropdownField, GENERATION_FRAGMENT, GET_ANCESTRY, GET_BOARD, GET_BOARDS, GET_CURRENT_USER, GET_DESCENDANTS, GET_GENERATION, GET_GENERATIONS, GET_GENERATORS, GET_INPUT_ARTIFACTS, GenerationStatus, type Generator, type GeneratorInfo, type GeneratorSelectionContextValue, GeneratorSelectionProvider, NoAuthProvider, type NumberInputField, type ParsedGeneratorSchema, type PromptField, REMOVE_BOARD_MEMBER, RETRY_GENERATION, type SettingsField, type SignInOptions, type SliderField, type TextInputField, UPDATE_BOARD, UPDATE_BOARD_MEMBER_ROLE, UPLOAD_ARTIFACT_FROM_URL, USER_FRAGMENT, type UpdateBoardInput, type UploadArtifactInput, type UploadHook, type UploadRequest, type UploadResult, type User$1 as User, VERSION, createGraphQLClient, getArtifactType, isArtifactReference, parseArtifactSlot, parseGeneratorSchema, parseSettingsField, useAncestry, useApiConfig, useAuth, useAuthOptional, useBoard, useBoards, useDescendants, useGeneration, useGeneratorSelection, useGenerators, useInputArtifacts, useLineage, useUpload };
925
+ export { ADD_BOARD_MEMBER, ANCESTRY_NODE_FRAGMENT, ARTIFACT_LINEAGE_FRAGMENT, type AncestryNode, type ApiConfig, type Artifact$1 as Artifact, type ArtifactLineage, type ArtifactSlot, type ArtifactSlotInfo, ArtifactType, type AuthContextValue, AuthProvider, type AuthProviderConfig, type AuthState$1 as AuthState, BOARD_FRAGMENT, BaseAuthProvider, BoardRole, BoardsProvider, CANCEL_GENERATION, CREATE_BOARD, CREATE_GENERATION, type CreateBoardInput, type CreateGenerationInput, DELETE_BOARD, DELETE_GENERATION, DESCENDANT_NODE_FRAGMENT, type DescendantNode, type DropdownField, GENERATION_FRAGMENT, GET_ANCESTRY, GET_BOARD, GET_BOARDS, GET_CURRENT_USER, GET_DESCENDANTS, GET_GENERATION, GET_GENERATIONS, GET_GENERATORS, GET_INPUT_ARTIFACTS, GenerationStatus, type Generator, type GeneratorInfo, type GeneratorSelectionContextValue, GeneratorSelectionProvider, type MultiUploadHook, type MultiUploadRequest, type MultiUploadResult, NoAuthProvider, type NumberInputField, type ParsedGeneratorSchema, type PromptField, REMOVE_BOARD_MEMBER, RETRY_GENERATION, type SettingsField, type SignInOptions, type SliderField, type TextInputField, UPDATE_BOARD, UPDATE_BOARD_MEMBER_ROLE, UPLOAD_ARTIFACT_FROM_URL, USER_FRAGMENT, type UpdateBoardInput, type UploadArtifactInput, type UploadItem, type UploadStatus, type User$1 as User, VERSION, createGraphQLClient, getArtifactType, isArtifactReference, parseArtifactSlot, parseGeneratorSchema, parseSettingsField, useAncestry, useApiConfig, useAuth, useAuthOptional, useBoard, useBoards, useDescendants, useGeneration, useGeneratorSelection, useGenerators, useInputArtifacts, useLineage, useMultiUpload };
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  CREATE_BOARD: () => CREATE_BOARD,
34
34
  CREATE_GENERATION: () => CREATE_GENERATION,
35
35
  DELETE_BOARD: () => DELETE_BOARD,
36
+ DELETE_GENERATION: () => DELETE_GENERATION,
36
37
  DESCENDANT_NODE_FRAGMENT: () => DESCENDANT_NODE_FRAGMENT,
37
38
  GENERATION_FRAGMENT: () => GENERATION_FRAGMENT,
38
39
  GET_ANCESTRY: () => GET_ANCESTRY,
@@ -72,7 +73,7 @@ __export(index_exports, {
72
73
  useGenerators: () => useGenerators,
73
74
  useInputArtifacts: () => useInputArtifacts,
74
75
  useLineage: () => useLineage,
75
- useUpload: () => useUpload
76
+ useMultiUpload: () => useMultiUpload
76
77
  });
77
78
  module.exports = __toCommonJS(index_exports);
78
79
 
@@ -887,6 +888,11 @@ var RETRY_GENERATION = import_urql2.gql`
887
888
  }
888
889
  }
889
890
  `;
891
+ var DELETE_GENERATION = import_urql2.gql`
892
+ mutation DeleteGeneration($id: UUID!) {
893
+ deleteGeneration(id: $id)
894
+ }
895
+ `;
890
896
  var UPLOAD_ARTIFACT_FROM_URL = import_urql2.gql`
891
897
  ${GENERATION_FRAGMENT}
892
898
  mutation UploadArtifactFromUrl($input: UploadArtifactInput!) {
@@ -1175,6 +1181,7 @@ function useGeneration() {
1175
1181
  const [, createGenerationMutation] = (0, import_urql5.useMutation)(CREATE_GENERATION);
1176
1182
  const [, cancelGenerationMutation] = (0, import_urql5.useMutation)(CANCEL_GENERATION);
1177
1183
  const [, retryGenerationMutation] = (0, import_urql5.useMutation)(RETRY_GENERATION);
1184
+ const [, deleteGenerationMutation] = (0, import_urql5.useMutation)(DELETE_GENERATION);
1178
1185
  (0, import_react6.useEffect)(() => {
1179
1186
  return () => {
1180
1187
  abortControllers.current.forEach((controller) => {
@@ -1384,6 +1391,36 @@ function useGeneration() {
1384
1391
  },
1385
1392
  [retryGenerationMutation, connectToSSE]
1386
1393
  );
1394
+ const deleteGeneration = (0, import_react6.useCallback)(
1395
+ async (jobId) => {
1396
+ try {
1397
+ const result2 = await deleteGenerationMutation({ id: jobId });
1398
+ if (result2.error) {
1399
+ throw new Error(result2.error.message);
1400
+ }
1401
+ if (!result2.data?.deleteGeneration) {
1402
+ throw new Error("Failed to delete generation");
1403
+ }
1404
+ const controller = abortControllers.current.get(jobId);
1405
+ if (controller) {
1406
+ controller.abort();
1407
+ abortControllers.current.delete(jobId);
1408
+ }
1409
+ if (progress?.jobId === jobId) {
1410
+ setProgress(null);
1411
+ setResult(null);
1412
+ setIsGenerating(false);
1413
+ }
1414
+ setHistory((prev) => prev.filter((item) => item.jobId !== jobId));
1415
+ } catch (err) {
1416
+ setError(
1417
+ err instanceof Error ? err : new Error("Failed to delete generation")
1418
+ );
1419
+ throw err;
1420
+ }
1421
+ },
1422
+ [deleteGenerationMutation, progress]
1423
+ );
1387
1424
  const clearHistory = (0, import_react6.useCallback)(() => {
1388
1425
  setHistory([]);
1389
1426
  }, []);
@@ -1395,6 +1432,7 @@ function useGeneration() {
1395
1432
  submit,
1396
1433
  cancel,
1397
1434
  retry,
1435
+ deleteGeneration,
1398
1436
  history,
1399
1437
  clearHistory
1400
1438
  };
@@ -1417,21 +1455,44 @@ function useGenerators(options = {}) {
1417
1455
  };
1418
1456
  }
1419
1457
 
1420
- // src/hooks/useUpload.ts
1458
+ // src/hooks/useMultiUpload.ts
1421
1459
  var import_react8 = require("react");
1422
1460
  var import_urql7 = require("urql");
1423
- function useUpload() {
1424
- const [isUploading, setIsUploading] = (0, import_react8.useState)(false);
1425
- const [progress, setProgress] = (0, import_react8.useState)(0);
1426
- const [error, setError] = (0, import_react8.useState)(null);
1461
+ var uploadIdCounter = 0;
1462
+ function generateUploadId() {
1463
+ return `upload-${Date.now()}-${++uploadIdCounter}`;
1464
+ }
1465
+ function getFileName(source) {
1466
+ if (typeof source === "string") {
1467
+ try {
1468
+ const url = new URL(source);
1469
+ const pathParts = url.pathname.split("/");
1470
+ return pathParts[pathParts.length - 1] || source;
1471
+ } catch {
1472
+ return source;
1473
+ }
1474
+ }
1475
+ return source.name;
1476
+ }
1477
+ function useMultiUpload() {
1478
+ const [uploads, setUploads] = (0, import_react8.useState)([]);
1479
+ const abortControllersRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
1427
1480
  const { apiUrl } = useApiConfig();
1428
1481
  const auth = useAuth();
1429
1482
  const [, uploadFromUrlMutation] = (0, import_urql7.useMutation)(UPLOAD_ARTIFACT_FROM_URL);
1430
- const upload = (0, import_react8.useCallback)(
1431
- async (request) => {
1432
- setError(null);
1433
- setProgress(0);
1434
- setIsUploading(true);
1483
+ const updateUpload = (0, import_react8.useCallback)(
1484
+ (uploadId, updates) => {
1485
+ setUploads(
1486
+ (prev) => prev.map(
1487
+ (item) => item.id === uploadId ? { ...item, ...updates } : item
1488
+ )
1489
+ );
1490
+ },
1491
+ []
1492
+ );
1493
+ const uploadSingle = (0, import_react8.useCallback)(
1494
+ async (uploadId, request) => {
1495
+ updateUpload(uploadId, { status: "uploading", progress: 0 });
1435
1496
  try {
1436
1497
  if (typeof request.source === "string") {
1437
1498
  const result2 = await uploadFromUrlMutation({
@@ -1449,9 +1510,7 @@ function useUpload() {
1449
1510
  if (!result2.data?.uploadArtifact) {
1450
1511
  throw new Error("Upload failed");
1451
1512
  }
1452
- setProgress(100);
1453
- setIsUploading(false);
1454
- return {
1513
+ const uploadResult = {
1455
1514
  id: result2.data.uploadArtifact.id,
1456
1515
  storageUrl: result2.data.uploadArtifact.storageUrl,
1457
1516
  thumbnailUrl: result2.data.uploadArtifact.thumbnailUrl,
@@ -1459,6 +1518,12 @@ function useUpload() {
1459
1518
  artifactType: result2.data.uploadArtifact.artifactType,
1460
1519
  generatorName: result2.data.uploadArtifact.generatorName
1461
1520
  };
1521
+ updateUpload(uploadId, {
1522
+ status: "completed",
1523
+ progress: 100,
1524
+ result: uploadResult
1525
+ });
1526
+ return uploadResult;
1462
1527
  }
1463
1528
  const formData = new FormData();
1464
1529
  formData.append("board_id", request.boardId);
@@ -1475,68 +1540,128 @@ function useUpload() {
1475
1540
  if (token) {
1476
1541
  headers.Authorization = `Bearer ${token}`;
1477
1542
  }
1478
- const result = await new Promise((resolve, reject) => {
1479
- const xhr = new XMLHttpRequest();
1480
- xhr.upload.addEventListener("progress", (e) => {
1481
- if (e.lengthComputable) {
1482
- const percentComplete = e.loaded / e.total * 100;
1483
- setProgress(percentComplete);
1484
- }
1485
- });
1486
- xhr.addEventListener("load", () => {
1487
- if (xhr.status === 200) {
1488
- try {
1489
- const data = JSON.parse(xhr.responseText);
1490
- resolve({
1491
- id: data.id,
1492
- storageUrl: data.storageUrl,
1493
- thumbnailUrl: data.thumbnailUrl,
1494
- status: "completed",
1495
- artifactType: data.artifactType,
1496
- generatorName: data.generatorName
1497
- });
1498
- } catch (err) {
1499
- reject(new Error("Failed to parse response"));
1543
+ const result = await new Promise(
1544
+ (resolve, reject) => {
1545
+ const xhr = new XMLHttpRequest();
1546
+ abortControllersRef.current.set(uploadId, () => xhr.abort());
1547
+ const cleanup = () => {
1548
+ abortControllersRef.current.delete(uploadId);
1549
+ };
1550
+ xhr.upload.addEventListener("progress", (e) => {
1551
+ if (e.lengthComputable) {
1552
+ const percentComplete = e.loaded / e.total * 100;
1553
+ updateUpload(uploadId, { progress: percentComplete });
1500
1554
  }
1501
- } else {
1502
- try {
1503
- const errorData = JSON.parse(xhr.responseText);
1504
- reject(new Error(errorData.detail || `Upload failed: ${xhr.statusText}`));
1505
- } catch {
1506
- reject(new Error(`Upload failed: ${xhr.statusText}`));
1555
+ });
1556
+ xhr.addEventListener("load", () => {
1557
+ cleanup();
1558
+ if (xhr.status === 200) {
1559
+ try {
1560
+ const data = JSON.parse(xhr.responseText);
1561
+ resolve({
1562
+ id: data.id,
1563
+ storageUrl: data.storageUrl,
1564
+ thumbnailUrl: data.thumbnailUrl,
1565
+ status: "completed",
1566
+ artifactType: data.artifactType,
1567
+ generatorName: data.generatorName
1568
+ });
1569
+ } catch (err) {
1570
+ reject(new Error("Failed to parse response"));
1571
+ }
1572
+ } else {
1573
+ try {
1574
+ const errorData = JSON.parse(xhr.responseText);
1575
+ reject(
1576
+ new Error(
1577
+ errorData.detail || `Upload failed: ${xhr.statusText}`
1578
+ )
1579
+ );
1580
+ } catch {
1581
+ reject(new Error(`Upload failed: ${xhr.statusText}`));
1582
+ }
1507
1583
  }
1508
- }
1509
- });
1510
- xhr.addEventListener("error", () => {
1511
- reject(new Error("Upload failed: Network error"));
1512
- });
1513
- xhr.addEventListener("abort", () => {
1514
- reject(new Error("Upload cancelled"));
1515
- });
1516
- xhr.open("POST", `${apiUrl}/api/uploads/artifact`);
1517
- Object.entries(headers).forEach(([key, value]) => {
1518
- xhr.setRequestHeader(key, value);
1519
- });
1520
- xhr.send(formData);
1584
+ });
1585
+ xhr.addEventListener("error", () => {
1586
+ cleanup();
1587
+ reject(new Error("Upload failed: Network error"));
1588
+ });
1589
+ xhr.addEventListener("abort", () => {
1590
+ cleanup();
1591
+ reject(new Error("Upload cancelled"));
1592
+ });
1593
+ xhr.addEventListener("loadend", () => {
1594
+ cleanup();
1595
+ });
1596
+ xhr.open("POST", `${apiUrl}/api/uploads/artifact`);
1597
+ Object.entries(headers).forEach(([key, value]) => {
1598
+ xhr.setRequestHeader(key, value);
1599
+ });
1600
+ xhr.send(formData);
1601
+ }
1602
+ );
1603
+ updateUpload(uploadId, {
1604
+ status: "completed",
1605
+ progress: 100,
1606
+ result
1521
1607
  });
1522
- setProgress(100);
1523
- setIsUploading(false);
1524
1608
  return result;
1525
1609
  } catch (err) {
1526
1610
  const uploadError = err instanceof Error ? err : new Error("Upload failed");
1527
- setError(uploadError);
1528
- setIsUploading(false);
1529
- setProgress(0);
1611
+ updateUpload(uploadId, {
1612
+ status: "failed",
1613
+ error: uploadError
1614
+ });
1530
1615
  throw uploadError;
1531
1616
  }
1532
1617
  },
1533
- [uploadFromUrlMutation, apiUrl, auth]
1618
+ [uploadFromUrlMutation, apiUrl, auth, updateUpload]
1534
1619
  );
1620
+ const uploadMultiple = (0, import_react8.useCallback)(
1621
+ async (requests) => {
1622
+ const newUploads = requests.map((request) => ({
1623
+ id: generateUploadId(),
1624
+ file: request.source,
1625
+ fileName: getFileName(request.source),
1626
+ status: "pending",
1627
+ progress: 0
1628
+ }));
1629
+ setUploads((prev) => [...prev, ...newUploads]);
1630
+ const results = await Promise.allSettled(
1631
+ requests.map(
1632
+ (request, index) => uploadSingle(newUploads[index].id, request)
1633
+ )
1634
+ );
1635
+ const successfulResults = [];
1636
+ results.forEach((result) => {
1637
+ if (result.status === "fulfilled") {
1638
+ successfulResults.push(result.value);
1639
+ }
1640
+ });
1641
+ return successfulResults;
1642
+ },
1643
+ [uploadSingle]
1644
+ );
1645
+ const clearUploads = (0, import_react8.useCallback)(() => {
1646
+ abortControllersRef.current.forEach((abort) => abort());
1647
+ abortControllersRef.current.clear();
1648
+ setUploads([]);
1649
+ }, []);
1650
+ const cancelUpload = (0, import_react8.useCallback)((uploadId) => {
1651
+ const abort = abortControllersRef.current.get(uploadId);
1652
+ if (abort) {
1653
+ abort();
1654
+ }
1655
+ }, []);
1656
+ const isUploading = uploads.some((u) => u.status === "uploading");
1657
+ const overallProgress = uploads.length > 0 ? uploads.reduce((sum, u) => sum + u.progress, 0) / uploads.length : 0;
1535
1658
  return {
1536
- upload,
1659
+ uploadMultiple,
1660
+ uploads,
1537
1661
  isUploading,
1538
- progress,
1539
- error
1662
+ overallProgress,
1663
+ clearUploads,
1664
+ cancelUpload
1540
1665
  };
1541
1666
  }
1542
1667
 
@@ -1654,6 +1779,7 @@ var VERSION = "0.1.0";
1654
1779
  CREATE_BOARD,
1655
1780
  CREATE_GENERATION,
1656
1781
  DELETE_BOARD,
1782
+ DELETE_GENERATION,
1657
1783
  DESCENDANT_NODE_FRAGMENT,
1658
1784
  GENERATION_FRAGMENT,
1659
1785
  GET_ANCESTRY,
@@ -1693,6 +1819,6 @@ var VERSION = "0.1.0";
1693
1819
  useGenerators,
1694
1820
  useInputArtifacts,
1695
1821
  useLineage,
1696
- useUpload
1822
+ useMultiUpload
1697
1823
  });
1698
1824
  //# sourceMappingURL=index.js.map