@adminide-stack/yantra-mobile 12.0.121 → 12.0.123

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.
Files changed (175) hide show
  1. package/lib/features/apps/appArt.js +1 -1
  2. package/lib/features/apps/appArt.js.map +1 -1
  3. package/lib/features/apps/mobileAppCatalog.js +15 -11
  4. package/lib/features/apps/mobileAppCatalog.js.map +1 -1
  5. package/lib/features/canvas/CanvasAgentChatPane.js +82 -20
  6. package/lib/features/canvas/CanvasAgentChatPane.js.map +1 -1
  7. package/lib/features/canvas/CanvasBoardsGrid.js +291 -100
  8. package/lib/features/canvas/CanvasBoardsGrid.js.map +1 -1
  9. package/lib/features/canvas/CanvasEditToolsPanel.js +105 -12
  10. package/lib/features/canvas/CanvasEditToolsPanel.js.map +1 -1
  11. package/lib/features/canvas/CanvasExperience.js +266 -68
  12. package/lib/features/canvas/CanvasExperience.js.map +1 -1
  13. package/lib/features/canvas/CanvasGeneratePanel.js +204 -66
  14. package/lib/features/canvas/CanvasGeneratePanel.js.map +1 -1
  15. package/lib/features/canvas/CanvasLibrarySheet.js +31 -13
  16. package/lib/features/canvas/CanvasLibrarySheet.js.map +1 -1
  17. package/lib/features/canvas/CanvasModelPicker.js +176 -0
  18. package/lib/features/canvas/CanvasModelPicker.js.map +1 -0
  19. package/lib/features/canvas/CanvasTasksPanel.js +325 -29
  20. package/lib/features/canvas/CanvasTasksPanel.js.map +1 -1
  21. package/lib/features/canvas/CanvasTemplatesPanel.js +5 -4
  22. package/lib/features/canvas/CanvasTemplatesPanel.js.map +1 -1
  23. package/lib/features/canvas/CanvasToolDock.js +137 -61
  24. package/lib/features/canvas/CanvasToolDock.js.map +1 -1
  25. package/lib/features/canvas/FrameExtractorExperience.js +33 -2
  26. package/lib/features/canvas/FrameExtractorExperience.js.map +1 -1
  27. package/lib/features/canvas/GeneratorReferenceSlots.js +197 -0
  28. package/lib/features/canvas/GeneratorReferenceSlots.js.map +1 -0
  29. package/lib/features/canvas/NativeCanvasViewer.js +89 -11
  30. package/lib/features/canvas/NativeCanvasViewer.js.map +1 -1
  31. package/lib/features/canvas/PromoContextFields.js +55 -2
  32. package/lib/features/canvas/PromoContextFields.js.map +1 -1
  33. package/lib/features/canvas/SetStudioExperience.js +323 -13
  34. package/lib/features/canvas/SetStudioExperience.js.map +1 -1
  35. package/lib/features/canvas/VideoEditExperience.js +1 -53
  36. package/lib/features/canvas/VideoEditExperience.js.map +1 -1
  37. package/lib/features/canvas/VideoEditorExperience.js +697 -506
  38. package/lib/features/canvas/VideoEditorExperience.js.map +1 -1
  39. package/lib/features/canvas/VideoGeneratorExperience.js +22 -5
  40. package/lib/features/canvas/VideoGeneratorExperience.js.map +1 -1
  41. package/lib/features/canvas/canvasAgentChat.js +125 -11
  42. package/lib/features/canvas/canvasAgentChat.js.map +1 -1
  43. package/lib/features/canvas/canvasCore.js +117 -12
  44. package/lib/features/canvas/canvasCore.js.map +1 -1
  45. package/lib/features/canvas/canvasEditOps.js +148 -111
  46. package/lib/features/canvas/canvasEditOps.js.map +1 -1
  47. package/lib/features/canvas/canvasTaskSync.js +235 -0
  48. package/lib/features/canvas/canvasTaskSync.js.map +1 -0
  49. package/lib/features/canvas/canvasTasks.js +98 -11
  50. package/lib/features/canvas/canvasTasks.js.map +1 -1
  51. package/lib/features/canvas/createTiles.js +247 -0
  52. package/lib/features/canvas/createTiles.js.map +1 -0
  53. package/lib/features/canvas/deepLinks.js +83 -0
  54. package/lib/features/canvas/deepLinks.js.map +1 -0
  55. package/lib/features/canvas/frameExtract.js +13 -1
  56. package/lib/features/canvas/frameExtract.js.map +1 -1
  57. package/lib/features/canvas/generationModels.js +36 -8
  58. package/lib/features/canvas/generationModels.js.map +1 -1
  59. package/lib/features/canvas/generatorCommands.js +106 -0
  60. package/lib/features/canvas/generatorCommands.js.map +1 -0
  61. package/lib/features/canvas/generatorReferences.js +82 -0
  62. package/lib/features/canvas/generatorReferences.js.map +1 -0
  63. package/lib/features/canvas/homeWork.js +74 -0
  64. package/lib/features/canvas/homeWork.js.map +1 -0
  65. package/lib/features/canvas/linksRpc.js +130 -0
  66. package/lib/features/canvas/linksRpc.js.map +1 -0
  67. package/lib/features/canvas/mediaRecheck.js +176 -0
  68. package/lib/features/canvas/mediaRecheck.js.map +1 -0
  69. package/lib/features/canvas/mediaUrls.js +258 -0
  70. package/lib/features/canvas/mediaUrls.js.map +1 -0
  71. package/lib/features/canvas/nativeViewerRegistry.js.map +1 -1
  72. package/lib/features/canvas/promoProjectImport.js +80 -13
  73. package/lib/features/canvas/promoProjectImport.js.map +1 -1
  74. package/lib/features/canvas/promoVideo.js +106 -15
  75. package/lib/features/canvas/promoVideo.js.map +1 -1
  76. package/lib/features/canvas/reframe.js +228 -0
  77. package/lib/features/canvas/reframe.js.map +1 -0
  78. package/lib/features/canvas/serverTasks.js +697 -0
  79. package/lib/features/canvas/serverTasks.js.map +1 -0
  80. package/lib/features/canvas/set/SetViewportWebView.js +207 -28
  81. package/lib/features/canvas/set/SetViewportWebView.js.map +1 -1
  82. package/lib/features/canvas/set/agent/prompt.js +66 -0
  83. package/lib/features/canvas/set/agent/prompt.js.map +1 -0
  84. package/lib/features/canvas/set/agent/setOps.js +203 -0
  85. package/lib/features/canvas/set/agent/setOps.js.map +1 -0
  86. package/lib/features/canvas/set/agent/setTurn.js +128 -0
  87. package/lib/features/canvas/set/agent/setTurn.js.map +1 -0
  88. package/lib/features/canvas/set/agent/snapshot.js +43 -0
  89. package/lib/features/canvas/set/agent/snapshot.js.map +1 -0
  90. package/lib/features/canvas/set/agent/tools.js +580 -0
  91. package/lib/features/canvas/set/agent/tools.js.map +1 -0
  92. package/lib/features/canvas/set/setProject.js +43 -4
  93. package/lib/features/canvas/set/setProject.js.map +1 -1
  94. package/lib/features/canvas/set/supplyLibrary.js +397 -0
  95. package/lib/features/canvas/set/supplyLibrary.js.map +1 -0
  96. package/lib/features/canvas/storageLibrary.js +113 -52
  97. package/lib/features/canvas/storageLibrary.js.map +1 -1
  98. package/lib/features/canvas/studioCatalog.js +15 -2
  99. package/lib/features/canvas/studioCatalog.js.map +1 -1
  100. package/lib/features/canvas/studioLooks.js +1 -8
  101. package/lib/features/canvas/studioLooks.js.map +1 -1
  102. package/lib/features/canvas/useBoardMediaRefresh.js +66 -0
  103. package/lib/features/canvas/useBoardMediaRefresh.js.map +1 -0
  104. package/lib/features/canvas/useMediaSource.js +84 -0
  105. package/lib/features/canvas/useMediaSource.js.map +1 -0
  106. package/lib/features/canvas/video3d.js +11 -10
  107. package/lib/features/canvas/video3d.js.map +1 -1
  108. package/lib/features/canvas/videoEditor/BlurBoxOverlay.js +46 -0
  109. package/lib/features/canvas/videoEditor/BlurBoxOverlay.js.map +1 -0
  110. package/lib/features/canvas/videoEditor/ExportTaskCard.js +134 -0
  111. package/lib/features/canvas/videoEditor/ExportTaskCard.js.map +1 -0
  112. package/lib/features/canvas/videoEditor/agent/AgentCutPane.js +45 -7
  113. package/lib/features/canvas/videoEditor/agent/AgentCutPane.js.map +1 -1
  114. package/lib/features/canvas/videoEditor/agent/agentLoop.js +4 -2
  115. package/lib/features/canvas/videoEditor/agent/agentLoop.js.map +1 -1
  116. package/lib/features/canvas/videoEditor/agent/attachments.js +304 -0
  117. package/lib/features/canvas/videoEditor/agent/attachments.js.map +1 -0
  118. package/lib/features/canvas/videoEditor/agent/brainClient.js +3 -2
  119. package/lib/features/canvas/videoEditor/agent/brainClient.js.map +1 -1
  120. package/lib/features/canvas/videoEditor/agent/cutTools.js +207 -7
  121. package/lib/features/canvas/videoEditor/agent/cutTools.js.map +1 -1
  122. package/lib/features/canvas/videoEditor/blurBox.js +34 -0
  123. package/lib/features/canvas/videoEditor/blurBox.js.map +1 -0
  124. package/lib/features/canvas/videoEditor/compileTimeline.js +668 -0
  125. package/lib/features/canvas/videoEditor/compileTimeline.js.map +1 -0
  126. package/lib/features/canvas/videoEditor/editorModel.js +56 -22
  127. package/lib/features/canvas/videoEditor/editorModel.js.map +1 -1
  128. package/lib/features/canvas/videoEditor/exportPipeline.js +77 -0
  129. package/lib/features/canvas/videoEditor/exportPipeline.js.map +1 -0
  130. package/lib/features/canvas/videoEditor/exportRenderer.js +19 -12
  131. package/lib/features/canvas/videoEditor/exportRenderer.js.map +1 -1
  132. package/lib/features/canvas/videoEditor/exportTask.js +216 -0
  133. package/lib/features/canvas/videoEditor/exportTask.js.map +1 -0
  134. package/lib/features/canvas/videoEditor/formWidgets.js +142 -0
  135. package/lib/features/canvas/videoEditor/formWidgets.js.map +1 -0
  136. package/lib/features/canvas/videoEditor/produce/ProduceVideoSheet.js +195 -0
  137. package/lib/features/canvas/videoEditor/produce/ProduceVideoSheet.js.map +1 -0
  138. package/lib/features/canvas/videoEditor/produce/produceScenes.js +158 -0
  139. package/lib/features/canvas/videoEditor/produce/produceScenes.js.map +1 -0
  140. package/lib/features/canvas/videoEditor/remoteMediaClient.js +17 -5
  141. package/lib/features/canvas/videoEditor/remoteMediaClient.js.map +1 -1
  142. package/lib/features/canvas/videoEditor/renderTimeline.js +207 -0
  143. package/lib/features/canvas/videoEditor/renderTimeline.js.map +1 -0
  144. package/lib/features/canvas/videoEditor/renewLinks.js +64 -0
  145. package/lib/features/canvas/videoEditor/renewLinks.js.map +1 -0
  146. package/lib/features/canvas/videoEditor/sceneLayers.js +101 -0
  147. package/lib/features/canvas/videoEditor/sceneLayers.js.map +1 -0
  148. package/lib/features/canvas/videoEditor/tools/ToolsDrawer.js +283 -0
  149. package/lib/features/canvas/videoEditor/tools/ToolsDrawer.js.map +1 -0
  150. package/lib/features/canvas/videoEditor/tools/catalog.js +576 -0
  151. package/lib/features/canvas/videoEditor/tools/catalog.js.map +1 -0
  152. package/lib/features/canvas/videoEditor/videoProjectsStore.js +27 -3
  153. package/lib/features/canvas/videoEditor/videoProjectsStore.js.map +1 -1
  154. package/lib/features/webbuilder/WebBuilderExperience.js +29 -1
  155. package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -1
  156. package/lib/features/webbuilder/buildFragments.js +8 -4
  157. package/lib/features/webbuilder/buildFragments.js.map +1 -1
  158. package/lib/features/webbuilder/codezenHandoff.js +108 -0
  159. package/lib/features/webbuilder/codezenHandoff.js.map +1 -0
  160. package/lib/features/webbuilder/workflow.js.map +1 -1
  161. package/lib/hooks/useChatApi.js +1 -2
  162. package/lib/hooks/useChatApi.js.map +1 -1
  163. package/lib/screens/CanvasBoard/index.js +12 -1
  164. package/lib/screens/CanvasBoard/index.js.map +1 -1
  165. package/lib/screens/Home/HomeScreen.js.map +1 -1
  166. package/lib/screens/Home/components/HomeSuggestions.js +3 -3
  167. package/lib/screens/Home/components/HomeSuggestions.js.map +1 -1
  168. package/lib/screens/WebBuilder/index.js +4 -2
  169. package/lib/screens/WebBuilder/index.js.map +1 -1
  170. package/lib/screens/WebBuilderNative/index.js +29 -2
  171. package/lib/screens/WebBuilderNative/index.js.map +1 -1
  172. package/lib/screens/WebBuilderNative/useWebBuilderHost.js +30 -6
  173. package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -1
  174. package/package.json +3 -3
  175. /package/lib/assets/apps/{paper2poster.webp → poster.webp} +0 -0
@@ -1,4 +1,4 @@
1
- var __defProp = Object.defineProperty;
1
+ import {isPresignedMediaUrl,ensureFetchableMediaUrl,downloadLinkParams,downloadUrlFromResult}from'./mediaUrls.js';var __defProp = Object.defineProperty;
2
2
  var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -56,6 +56,18 @@ function nameFromUrl(url) {
56
56
  return path.slice(path.lastIndexOf("/") + 1) || "Untitled";
57
57
  }
58
58
  }
59
+ function objectKeyOf(row, url) {
60
+ const explicit = str(row.key);
61
+ if (explicit) return explicit.replace(/^\/+/, "");
62
+ const m = /^https?:\/\/([^/?#]+)([^?#]*)/i.exec(url);
63
+ if (!m) return url.replace(/^\/+/, "");
64
+ const path = m[2].replace(/^\/+/, "");
65
+ if (m[1].toLowerCase() === "storage.googleapis.com") {
66
+ const slash = path.indexOf("/");
67
+ return slash >= 0 ? path.slice(slash + 1) : path;
68
+ }
69
+ return path;
70
+ }
59
71
  function normalizeStorageFiles(raw) {
60
72
  var _a, _b, _c;
61
73
  const outer = raw != null ? raw : {};
@@ -76,27 +88,58 @@ function normalizeStorageFiles(raw) {
76
88
  }
77
89
  if (rows.length) break;
78
90
  }
79
- return rows.map((row) => {
91
+ const files = [];
92
+ for (const row of rows) {
80
93
  const url = str(row.url) || str(row.downloadUrl) || str(row.signedUrl) || str(row.location) || str(row.publicUrl);
81
- if (!url) return null;
94
+ if (!url) continue;
82
95
  const mimeType = str(row.mimeType) || str(row.contentType) || str(row.type);
83
96
  const kind = classifyKind(mimeType, str(row.extension) ? `.${str(row.extension)}` : url);
84
- if (!kind) return null;
85
- const objectKey = str(row.key);
86
- return __spreadValues({
87
- id: str(row.id) || str(row._id) || objectKey || url,
88
- fileInfoId: str(row.id) || str(row._id) || void 0,
97
+ if (!kind) continue;
98
+ const fileInfoId = str(row.id) || str(row._id);
99
+ const explicitKey = str(row.key);
100
+ const objectKey = objectKeyOf(row, url);
101
+ const createdAt = str(row.createdAt) || str(row.uploadedAt) || str(row.lastModified);
102
+ files.push(__spreadValues(__spreadValues(__spreadProps(__spreadValues({
103
+ id: fileInfoId || explicitKey || url
104
+ }, fileInfoId ? {
105
+ fileInfoId
106
+ } : {}), {
89
107
  name: str(row.name) || str(row.filename) || str(row.fileName) || nameFromUrl(url),
90
108
  url,
91
109
  kind
92
- }, objectKey ? {
110
+ }), objectKey ? {
93
111
  objectKey
94
- } : {});
95
- }).filter((f) => f !== null);
112
+ } : {}), createdAt ? {
113
+ createdAt
114
+ } : {}));
115
+ }
116
+ return files;
117
+ }
118
+ const identityOf = (file) => file.objectKey || file.id;
119
+ function mergeStorageFiles(rows) {
120
+ const byIdentity = /* @__PURE__ */ new Map();
121
+ for (const row of rows) {
122
+ const identity = identityOf(row);
123
+ const seen = byIdentity.get(identity);
124
+ if (!seen) {
125
+ byIdentity.set(identity, row);
126
+ continue;
127
+ }
128
+ const merged = __spreadValues({}, seen);
129
+ for (const [k, v] of Object.entries(row)) {
130
+ if (v !== void 0 && merged[k] === void 0) merged[k] = v;
131
+ }
132
+ byIdentity.set(identity, merged);
133
+ }
134
+ return [...byIdentity.values()];
96
135
  }
97
- function unwrap(result) {
136
+ const byNewest = (a, b) => {
137
+ var _a, _b;
138
+ return ((_a = b.createdAt) != null ? _a : "").localeCompare((_b = a.createdAt) != null ? _b : "");
139
+ };
140
+ function unwrap(result, failure = "yantra-storage could not list your files") {
98
141
  if (result.successful === false) {
99
- throw new Error(str(result.error) || "yantra-storage could not list your files");
142
+ throw new Error(str(result.error) || failure);
100
143
  }
101
144
  return result.data && typeof result.data === "object" ? result.data : result;
102
145
  }
@@ -114,71 +157,89 @@ async function listObjects(run, provider) {
114
157
  },
115
158
  limit: 40
116
159
  }));
117
- const outer = unwrap(result);
160
+ const outer = unwrap(result, `yantra-storage could not list your ${provider} objects`);
118
161
  const page = (_b = (_a = outer.storageObjects) != null ? _a : outer) != null ? _b : {};
119
162
  const items = Array.isArray(page.items) ? page.items : [];
120
163
  return normalizeStorageFiles({
121
- data: items.map((item) => ({
122
- url: str(item.publicUrl) || str(item.url) || str(item.signedUrl),
123
- key: str(item.key),
124
- name: str(item.key).split("/").pop(),
125
- lastModified: item.lastModified
126
- }))
127
- });
164
+ data: items.filter((item) => !item.isFolder).map((item) => {
165
+ const key = str(item.key);
166
+ return {
167
+ url: str(item.url) || str(item.publicUrl) || str(item.signedUrl),
168
+ key,
169
+ name: key.slice(key.lastIndexOf("/") + 1),
170
+ extension: key.includes(".") ? key.slice(key.lastIndexOf(".") + 1) : "",
171
+ createdAt: str(item.lastModified)
172
+ };
173
+ })
174
+ }).map((file) => __spreadProps(__spreadValues({}, file), {
175
+ provider
176
+ }));
128
177
  }
129
178
  async function deleteStorageFile(run, fileInfoId) {
130
- const result = unwrap(await run(STORAGE, "YANTRA_STORAGE_DELETE_FILE", {
179
+ var _a;
180
+ const data = unwrap(await run(STORAGE, "YANTRA_STORAGE_DELETE_FILE", {
131
181
  id: fileInfoId
132
- }));
133
- if (result.successful === false) {
134
- throw new Error(str(result.error) || "Could not delete that file");
135
- }
182
+ }), "Could not delete that file");
183
+ const nested = (_a = data.deleteFileInfo) != null ? _a : {};
184
+ if (nested.success === false) throw new Error(str(nested.message) || "The file could not be deleted");
185
+ }
186
+ async function deleteStorageObject(run, objectKey, provider) {
187
+ var _a;
188
+ const data = unwrap(await run(STORAGE, "YANTRA_STORAGE_DELETE_OBJECT", __spreadValues({
189
+ key: objectKey
190
+ }, provider ? {
191
+ provider
192
+ } : {})), "yantra-storage could not delete that object");
193
+ const nested = (_a = data.deleteStorageObject) != null ? _a : {};
194
+ if (nested.success === false) throw new Error(str(nested.message) || "The object could not be deleted");
195
+ }
196
+ const canDeleteLibraryFile = (file) => Boolean(file.fileInfoId || file.objectKey);
197
+ async function deleteLibraryFile(run, file) {
198
+ if (file.fileInfoId) return deleteStorageFile(run, file.fileInfoId);
199
+ if (file.objectKey) return deleteStorageObject(run, file.objectKey, file.provider);
200
+ throw new Error("This file carries no storage id or object key, so it cannot be deleted from here.");
136
201
  }
137
202
  async function listStorageLibraryPage(run, opts = {}) {
138
203
  var _a, _b;
139
204
  const limit = (_a = opts.limit) != null ? _a : 40;
140
205
  const skip = (_b = opts.skip) != null ? _b : 0;
141
- const index = unwrap(await run(STORAGE, "YANTRA_STORAGE_LIST_FILES", {
206
+ const indexRun = run(STORAGE, "YANTRA_STORAGE_LIST_FILES", {
142
207
  limit,
143
208
  skip,
144
209
  sort: {
145
210
  key: "createdAt",
146
211
  value: "DESC"
147
212
  }
148
- }));
149
- const fromIndex = normalizeStorageFiles(index).map((f) => {
150
- const row = f;
151
- return __spreadProps(__spreadValues({}, f), {
152
- fileInfoId: row.fileInfoId || (f.id.startsWith("http") ? void 0 : f.id)
153
- });
154
- });
213
+ }).then((result) => normalizeStorageFiles(unwrap(result)));
155
214
  if (skip > 0) {
215
+ const fromIndex2 = await indexRun;
156
216
  return {
157
- files: fromIndex,
158
- hasMore: fromIndex.length >= limit
217
+ files: fromIndex2,
218
+ hasMore: fromIndex2.length >= limit
159
219
  };
160
220
  }
161
- const buckets = await Promise.allSettled([listObjects(run, "gcs"), listObjects(run, "aws")]);
162
- const seen = /* @__PURE__ */ new Set();
163
- const files = [];
164
- for (const file of [...fromIndex, ...buckets.flatMap((lane) => lane.status === "fulfilled" ? lane.value : [])]) {
165
- const key = file.objectKey || file.url.split("?")[0];
166
- if (seen.has(key)) continue;
167
- seen.add(key);
168
- files.push(file);
221
+ const [indexLane, ...buckets] = await Promise.allSettled([indexRun, listObjects(run, "gcs"), listObjects(run, "aws")]);
222
+ const lanes = [indexLane, ...buckets];
223
+ if (lanes.every((lane) => lane.status === "rejected")) {
224
+ const reason = indexLane.reason;
225
+ throw reason instanceof Error ? reason : new Error(String(reason));
169
226
  }
227
+ const fromIndex = indexLane.status === "fulfilled" ? indexLane.value : [];
228
+ const fromBuckets = buckets.flatMap((lane) => lane.status === "fulfilled" ? lane.value : []);
229
+ const files = mergeStorageFiles([...fromBuckets, ...fromIndex]).sort(byNewest);
170
230
  return {
171
231
  files,
172
- hasMore: fromIndex.length >= limit
232
+ hasMore: indexLane.status === "fulfilled" && fromIndex.length >= limit
173
233
  };
174
234
  }
175
235
  async function createStorageDownloadUrl(run, s3KeyOrUrl) {
176
- var _a;
177
- const result = unwrap(await run(STORAGE, "YANTRA_STORAGE_CREATE_DOWNLOAD_LINK", {
178
- s3KeyOrUrl
179
- }));
180
- const nested = (_a = result.createDownloadLink) != null ? _a : {};
181
- const url = str(result.downloadUrl) || str(nested.downloadUrl) || str(result.url);
236
+ const result = await run(STORAGE, "YANTRA_STORAGE_CREATE_DOWNLOAD_LINK", downloadLinkParams(s3KeyOrUrl));
237
+ const url = downloadUrlFromResult(unwrap(result, "yantra-storage returned no download URL"));
182
238
  if (!url) throw new Error("yantra-storage returned no download URL");
183
239
  return url;
184
- }export{createStorageDownloadUrl,deleteStorageFile,listStorageLibraryPage,normalizeStorageFiles};//# sourceMappingURL=storageLibrary.js.map
240
+ }
241
+ async function fetchableLibraryUrl(run, url) {
242
+ if (isPresignedMediaUrl(url)) return ensureFetchableMediaUrl(run, url).catch(() => url);
243
+ if (!run) return url;
244
+ return createStorageDownloadUrl(run, url).catch(() => url);
245
+ }export{byNewest,canDeleteLibraryFile,createStorageDownloadUrl,deleteLibraryFile,deleteStorageFile,deleteStorageObject,fetchableLibraryUrl,listStorageLibraryPage,mergeStorageFiles,normalizeStorageFiles,objectKeyOf};//# sourceMappingURL=storageLibrary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"storageLibrary.js","sources":["../../../src/features/canvas/storageLibrary.ts"],"sourcesContent":["/**\n * Native twin of canvas-surface `rpc/storageRpc` — Your library is the\n * storage index + buckets, not whatever happens to sit on the open board.\n */\nimport type { RunMediaAction } from './videoEditor/mediaActions';\n\nexport type StorageKind = 'image' | 'video' | 'audio';\n\nexport interface StorageFile {\n id: string;\n /** Index id for delete — absent when the row came only from a bucket listing. */\n fileInfoId?: string;\n name: string;\n url: string;\n kind: StorageKind;\n objectKey?: string;\n}\n\nconst STORAGE = 'yantra-storage' as const;\nconst EXTENSION_KIND: Record<string, StorageKind> = {\n png: 'image',\n jpg: 'image',\n jpeg: 'image',\n webp: 'image',\n gif: 'image',\n avif: 'image',\n svg: 'image',\n mp4: 'video',\n webm: 'video',\n mov: 'video',\n m4v: 'video',\n mp3: 'audio',\n wav: 'audio',\n ogg: 'audio',\n m4a: 'audio',\n flac: 'audio',\n aac: 'audio',\n};\n\nconst str = (v: unknown): string => (typeof v === 'string' ? v : '');\n\nfunction classifyKind(mimeType: string, url: string): StorageKind | null {\n const mime = mimeType.split(';')[0].trim().toLowerCase();\n if (mime.startsWith('image/')) return 'image';\n if (mime.startsWith('video/')) return 'video';\n if (mime.startsWith('audio/')) return 'audio';\n const path = url.split('?')[0];\n const ext = path.slice(path.lastIndexOf('.') + 1).toLowerCase();\n return EXTENSION_KIND[ext] ?? null;\n}\n\nfunction nameFromUrl(url: string): string {\n const path = url.split('?')[0];\n try {\n return decodeURIComponent(path.slice(path.lastIndexOf('/') + 1)) || 'Untitled';\n } catch {\n return path.slice(path.lastIndexOf('/') + 1) || 'Untitled';\n }\n}\n\nexport function normalizeStorageFiles(raw: unknown): StorageFile[] {\n const outer = (raw ?? {}) as Record<string, unknown>;\n const inner = (outer.data ?? outer) as Record<string, unknown>;\n const holders = [\n (inner.filesInfo ?? {}) as Record<string, unknown>,\n inner,\n (inner.listFiles ?? {}) as Record<string, unknown>,\n ];\n let rows: Array<Record<string, unknown>> = [];\n for (const holder of holders) {\n if (Array.isArray(holder)) {\n rows = holder as Array<Record<string, unknown>>;\n break;\n }\n for (const key of ['data', 'files', 'items', 'nodes', 'results']) {\n const v = holder[key];\n if (Array.isArray(v)) {\n rows = v as Array<Record<string, unknown>>;\n break;\n }\n }\n if (rows.length) break;\n }\n return rows\n .map((row) => {\n const url =\n str(row.url) || str(row.downloadUrl) || str(row.signedUrl) || str(row.location) || str(row.publicUrl);\n if (!url) return null;\n const mimeType = str(row.mimeType) || str(row.contentType) || str(row.type);\n const kind = classifyKind(mimeType, str(row.extension) ? `.${str(row.extension)}` : url);\n if (!kind) return null;\n const objectKey = str(row.key);\n return {\n id: str(row.id) || str(row._id) || objectKey || url,\n fileInfoId: str(row.id) || str(row._id) || undefined,\n name: str(row.name) || str(row.filename) || str(row.fileName) || nameFromUrl(url),\n url,\n kind,\n ...(objectKey ? { objectKey } : {}),\n };\n })\n .filter((f): f is StorageFile => f !== null);\n}\n\nfunction unwrap(result: Record<string, unknown>): Record<string, unknown> {\n if (result.successful === false) {\n throw new Error(str(result.error) || 'yantra-storage could not list your files');\n }\n return (result.data && typeof result.data === 'object' ? result.data : result) as Record<string, unknown>;\n}\n\nasync function listObjects(run: RunMediaAction, provider: 'gcs' | 'aws'): Promise<StorageFile[]> {\n const result = await run(STORAGE, 'YANTRA_STORAGE_LIST_OBJECTS', {\n provider,\n scope: 'user',\n ...(provider === 'gcs' ? { signUrls: true } : {}),\n sort: { key: 'lastModified', value: 'DESC' },\n limit: 40,\n });\n const outer = unwrap(result);\n const page = (outer.storageObjects ?? outer ?? {}) as Record<string, unknown>;\n const items = Array.isArray(page.items) ? (page.items as Array<Record<string, unknown>>) : [];\n return normalizeStorageFiles({\n data: items.map((item) => ({\n url: str(item.publicUrl) || str(item.url) || str(item.signedUrl),\n key: str(item.key),\n name: str(item.key).split('/').pop(),\n lastModified: item.lastModified,\n })),\n });\n}\n\nexport async function deleteStorageFile(run: RunMediaAction, fileInfoId: string): Promise<void> {\n const result = unwrap(await run(STORAGE, 'YANTRA_STORAGE_DELETE_FILE', { id: fileInfoId }));\n if ((result as { successful?: boolean }).successful === false) {\n throw new Error(str((result as { error?: unknown }).error) || 'Could not delete that file');\n }\n}\n\nexport async function listStorageLibraryPage(\n run: RunMediaAction,\n opts: { limit?: number; skip?: number } = {},\n): Promise<{ files: StorageFile[]; hasMore: boolean }> {\n const limit = opts.limit ?? 40;\n const skip = opts.skip ?? 0;\n const index = unwrap(\n await run(STORAGE, 'YANTRA_STORAGE_LIST_FILES', {\n limit,\n skip,\n sort: { key: 'createdAt', value: 'DESC' },\n }),\n );\n const fromIndex = normalizeStorageFiles(index).map((f) => {\n const row = f as StorageFile & { fileInfoId?: string };\n return {\n ...f,\n fileInfoId: row.fileInfoId || (f.id.startsWith('http') ? undefined : f.id),\n };\n });\n if (skip > 0) {\n return { files: fromIndex, hasMore: fromIndex.length >= limit };\n }\n const buckets = await Promise.allSettled([listObjects(run, 'gcs'), listObjects(run, 'aws')]);\n const seen = new Set<string>();\n const files: StorageFile[] = [];\n for (const file of [...fromIndex, ...buckets.flatMap((lane) => (lane.status === 'fulfilled' ? lane.value : []))]) {\n const key = file.objectKey || file.url.split('?')[0];\n if (seen.has(key)) continue;\n seen.add(key);\n files.push(file);\n }\n return { files, hasMore: fromIndex.length >= limit };\n}\n\nexport async function listStorageLibrary(run: RunMediaAction): Promise<StorageFile[]> {\n const page = await listStorageLibraryPage(run, { limit: 40, skip: 0 });\n return page.files;\n}\n\nexport async function createStorageDownloadUrl(run: RunMediaAction, s3KeyOrUrl: string): Promise<string> {\n const result = unwrap(await run(STORAGE, 'YANTRA_STORAGE_CREATE_DOWNLOAD_LINK', { s3KeyOrUrl }));\n const nested = (result.createDownloadLink ?? {}) as Record<string, unknown>;\n const url = str(result.downloadUrl) || str(nested.downloadUrl) || str(result.url);\n if (!url) throw new Error('yantra-storage returned no download URL');\n return url;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAeA,MAAM,OAAU,GAAA,gBAAA;AAChB,MAAM,cAA8C,GAAA;AAAA,EAClD,GAAK,EAAA,OAAA;AAAA,EACL,GAAK,EAAA,OAAA;AAAA,EACL,IAAM,EAAA,OAAA;AAAA,EACN,IAAM,EAAA,OAAA;AAAA,EACN,GAAK,EAAA,OAAA;AAAA,EACL,IAAM,EAAA,OAAA;AAAA,EACN,GAAK,EAAA,OAAA;AAAA,EACL,GAAK,EAAA,OAAA;AAAA,EACL,IAAM,EAAA,OAAA;AAAA,EACN,GAAK,EAAA,OAAA;AAAA,EACL,GAAK,EAAA,OAAA;AAAA,EACL,GAAK,EAAA,OAAA;AAAA,EACL,GAAK,EAAA,OAAA;AAAA,EACL,GAAK,EAAA,OAAA;AAAA,EACL,GAAK,EAAA,OAAA;AAAA,EACL,IAAM,EAAA,OAAA;AAAA,EACN,GAAK,EAAA;AACP,CAAA;AACA,MAAM,MAAM,CAAC,CAAA,KAAuB,OAAO,CAAA,KAAM,WAAW,CAAI,GAAA,EAAA;AAChE,SAAS,YAAA,CAAa,UAAkB,GAAiC,EAAA;AApCzE,EAAA,IAAA,EAAA;AAqCE,EAAM,MAAA,IAAA,GAAO,SAAS,KAAM,CAAA,GAAG,EAAE,CAAC,CAAA,CAAE,IAAK,EAAA,CAAE,WAAY,EAAA;AACvD,EAAA,IAAI,IAAK,CAAA,UAAA,CAAW,QAAQ,CAAA,EAAU,OAAA,OAAA;AACtC,EAAA,IAAI,IAAK,CAAA,UAAA,CAAW,QAAQ,CAAA,EAAU,OAAA,OAAA;AACtC,EAAA,IAAI,IAAK,CAAA,UAAA,CAAW,QAAQ,CAAA,EAAU,OAAA,OAAA;AACtC,EAAA,MAAM,IAAO,GAAA,GAAA,CAAI,KAAM,CAAA,GAAG,EAAE,CAAC,CAAA;AAC7B,EAAM,MAAA,GAAA,GAAM,KAAK,KAAM,CAAA,IAAA,CAAK,YAAY,GAAG,CAAA,GAAI,CAAC,CAAA,CAAE,WAAY,EAAA;AAC9D,EAAO,OAAA,CAAA,EAAA,GAAA,cAAA,CAAe,GAAG,CAAA,KAAlB,IAAuB,GAAA,EAAA,GAAA,IAAA;AAChC;AACA,SAAS,YAAY,GAAqB,EAAA;AACxC,EAAA,MAAM,IAAO,GAAA,GAAA,CAAI,KAAM,CAAA,GAAG,EAAE,CAAC,CAAA;AAC7B,EAAI,IAAA;AACF,IAAO,OAAA,kBAAA,CAAmB,KAAK,KAAM,CAAA,IAAA,CAAK,YAAY,GAAG,CAAA,GAAI,CAAC,CAAC,CAAK,IAAA,UAAA;AAAA,GAC9D,CAAA,OAAA,CAAA,EAAA;AACN,IAAA,OAAO,KAAK,KAAM,CAAA,IAAA,CAAK,YAAY,GAAG,CAAA,GAAI,CAAC,CAAK,IAAA,UAAA;AAAA;AAEpD;AACO,SAAS,sBAAsB,GAA6B,EAAA;AArDnE,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAsDE,EAAM,MAAA,KAAA,GAAS,oBAAO,EAAC;AACvB,EAAM,MAAA,KAAA,GAAA,CAAS,EAAM,GAAA,KAAA,CAAA,IAAA,KAAN,IAAc,GAAA,EAAA,GAAA,KAAA;AAC7B,EAAA,MAAM,OAAU,GAAA,CAAA,CAAE,EAAM,GAAA,KAAA,CAAA,SAAA,KAAN,IAAmB,GAAA,EAAA,GAAA,EAAgC,EAAA,KAAA,EAAA,CAAQ,EAAM,GAAA,KAAA,CAAA,SAAA,KAAN,IAAmB,GAAA,EAAA,GAAA,EAA8B,CAAA;AAC9H,EAAA,IAAI,OAAuC,EAAC;AAC5C,EAAA,KAAA,MAAW,UAAU,OAAS,EAAA;AAC5B,IAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,MAAM,CAAG,EAAA;AACzB,MAAO,IAAA,GAAA,MAAA;AACP,MAAA;AAAA;AAEF,IAAA,KAAA,MAAW,OAAO,CAAC,MAAA,EAAQ,SAAS,OAAS,EAAA,OAAA,EAAS,SAAS,CAAG,EAAA;AAChE,MAAM,MAAA,CAAA,GAAI,OAAO,GAAG,CAAA;AACpB,MAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,CAAC,CAAG,EAAA;AACpB,QAAO,IAAA,GAAA,CAAA;AACP,QAAA;AAAA;AACF;AAEF,IAAA,IAAI,KAAK,MAAQ,EAAA;AAAA;AAEnB,EAAO,OAAA,IAAA,CAAK,IAAI,CAAO,GAAA,KAAA;AACrB,IAAA,MAAM,MAAM,GAAI,CAAA,GAAA,CAAI,GAAG,CAAK,IAAA,GAAA,CAAI,IAAI,WAAW,CAAA,IAAK,IAAI,GAAI,CAAA,SAAS,KAAK,GAAI,CAAA,GAAA,CAAI,QAAQ,CAAK,IAAA,GAAA,CAAI,IAAI,SAAS,CAAA;AAChH,IAAI,IAAA,CAAC,KAAY,OAAA,IAAA;AACjB,IAAM,MAAA,QAAA,GAAW,GAAI,CAAA,GAAA,CAAI,QAAQ,CAAA,IAAK,GAAI,CAAA,GAAA,CAAI,WAAW,CAAA,IAAK,GAAI,CAAA,GAAA,CAAI,IAAI,CAAA;AAC1E,IAAA,MAAM,IAAO,GAAA,YAAA,CAAa,QAAU,EAAA,GAAA,CAAI,GAAI,CAAA,SAAS,CAAI,GAAA,CAAA,CAAA,EAAI,GAAI,CAAA,GAAA,CAAI,SAAS,CAAC,KAAK,GAAG,CAAA;AACvF,IAAI,IAAA,CAAC,MAAa,OAAA,IAAA;AAClB,IAAM,MAAA,SAAA,GAAY,GAAI,CAAA,GAAA,CAAI,GAAG,CAAA;AAC7B,IAAO,OAAA,cAAA,CAAA;AAAA,MACL,EAAA,EAAI,IAAI,GAAI,CAAA,EAAE,KAAK,GAAI,CAAA,GAAA,CAAI,GAAG,CAAA,IAAK,SAAa,IAAA,GAAA;AAAA,MAChD,UAAA,EAAY,IAAI,GAAI,CAAA,EAAE,KAAK,GAAI,CAAA,GAAA,CAAI,GAAG,CAAK,IAAA,MAAA;AAAA,MAC3C,IAAM,EAAA,GAAA,CAAI,GAAI,CAAA,IAAI,KAAK,GAAI,CAAA,GAAA,CAAI,QAAQ,CAAA,IAAK,GAAI,CAAA,GAAA,CAAI,QAAQ,CAAA,IAAK,YAAY,GAAG,CAAA;AAAA,MAChF,GAAA;AAAA,MACA;AAAA,KAAA,EACI,SAAY,GAAA;AAAA,MACd;AAAA,QACE,EAAC,CAAA;AAAA,GAER,CAAE,CAAA,MAAA,CAAO,CAAC,CAAA,KAAwB,MAAM,IAAI,CAAA;AAC/C;AACA,SAAS,OAAO,MAA0D,EAAA;AACxE,EAAI,IAAA,MAAA,CAAO,eAAe,KAAO,EAAA;AAC/B,IAAA,MAAM,IAAI,KAAM,CAAA,GAAA,CAAI,MAAO,CAAA,KAAK,KAAK,0CAA0C,CAAA;AAAA;AAEjF,EAAA,OAAQ,OAAO,IAAQ,IAAA,OAAO,OAAO,IAAS,KAAA,QAAA,GAAW,OAAO,IAAO,GAAA,MAAA;AACzE;AACA,eAAe,WAAA,CAAY,KAAqB,QAAiD,EAAA;AAjGjG,EAAA,IAAA,EAAA,EAAA,EAAA;AAkGE,EAAA,MAAM,MAAS,GAAA,MAAM,GAAI,CAAA,OAAA,EAAS,6BAA+B,EAAA,aAAA,CAAA,cAAA,CAAA;AAAA,IAC/D,QAAA;AAAA,IACA,KAAO,EAAA;AAAA,GAAA,EACH,aAAa,KAAQ,GAAA;AAAA,IACvB,QAAU,EAAA;AAAA,GACZ,GAAI,EAL2D,CAAA,EAAA;AAAA,IAM/D,IAAM,EAAA;AAAA,MACJ,GAAK,EAAA,cAAA;AAAA,MACL,KAAO,EAAA;AAAA,KACT;AAAA,IACA,KAAO,EAAA;AAAA,GACR,CAAA,CAAA;AACD,EAAM,MAAA,KAAA,GAAQ,OAAO,MAAM,CAAA;AAC3B,EAAA,MAAM,QAAQ,EAAM,GAAA,CAAA,EAAA,GAAA,KAAA,CAAA,cAAA,KAAN,IAAwB,GAAA,EAAA,GAAA,KAAA,KAAxB,YAAiC,EAAC;AAChD,EAAM,MAAA,KAAA,GAAQ,MAAM,OAAQ,CAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAK,QAA0C,EAAC;AAC1F,EAAA,OAAO,qBAAsB,CAAA;AAAA,IAC3B,IAAA,EAAM,KAAM,CAAA,GAAA,CAAI,CAAS,IAAA,MAAA;AAAA,MACvB,GAAA,EAAK,GAAI,CAAA,IAAA,CAAK,SAAS,CAAA,IAAK,GAAI,CAAA,IAAA,CAAK,GAAG,CAAA,IAAK,GAAI,CAAA,IAAA,CAAK,SAAS,CAAA;AAAA,MAC/D,GAAA,EAAK,GAAI,CAAA,IAAA,CAAK,GAAG,CAAA;AAAA,MACjB,IAAA,EAAM,IAAI,IAAK,CAAA,GAAG,EAAE,KAAM,CAAA,GAAG,EAAE,GAAI,EAAA;AAAA,MACnC,cAAc,IAAK,CAAA;AAAA,KACnB,CAAA;AAAA,GACH,CAAA;AACH;AACsB,eAAA,iBAAA,CAAkB,KAAqB,UAAmC,EAAA;AAC9F,EAAA,MAAM,MAAS,GAAA,MAAA,CAAO,MAAM,GAAA,CAAI,SAAS,4BAA8B,EAAA;AAAA,IACrE,EAAI,EAAA;AAAA,GACL,CAAC,CAAA;AACF,EAAK,IAAA,MAAA,CAEF,eAAe,KAAO,EAAA;AACvB,IAAA,MAAM,IAAI,KAAM,CAAA,GAAA,CAAK,MAElB,CAAA,KAAK,KAAK,4BAA4B,CAAA;AAAA;AAE7C;AACA,eAAsB,sBAAuB,CAAA,GAAA,EAAqB,IAG9D,GAAA,EAGD,EAAA;AA5IH,EAAA,IAAA,EAAA,EAAA,EAAA;AA6IE,EAAM,MAAA,KAAA,GAAA,CAAQ,EAAK,GAAA,IAAA,CAAA,KAAA,KAAL,IAAc,GAAA,EAAA,GAAA,EAAA;AAC5B,EAAM,MAAA,IAAA,GAAA,CAAO,EAAK,GAAA,IAAA,CAAA,IAAA,KAAL,IAAa,GAAA,EAAA,GAAA,CAAA;AAC1B,EAAA,MAAM,KAAQ,GAAA,MAAA,CAAO,MAAM,GAAA,CAAI,SAAS,2BAA6B,EAAA;AAAA,IACnE,KAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAM,EAAA;AAAA,MACJ,GAAK,EAAA,WAAA;AAAA,MACL,KAAO,EAAA;AAAA;AACT,GACD,CAAC,CAAA;AACF,EAAA,MAAM,SAAY,GAAA,qBAAA,CAAsB,KAAK,CAAA,CAAE,IAAI,CAAK,CAAA,KAAA;AACtD,IAAA,MAAM,GAAM,GAAA,CAAA;AAGZ,IAAA,OAAO,iCACF,CADE,CAAA,EAAA;AAAA,MAEL,UAAA,EAAY,IAAI,UAAe,KAAA,CAAA,CAAE,GAAG,UAAW,CAAA,MAAM,CAAI,GAAA,MAAA,GAAY,CAAE,CAAA,EAAA;AAAA,KACzE,CAAA;AAAA,GACD,CAAA;AACD,EAAA,IAAI,OAAO,CAAG,EAAA;AACZ,IAAO,OAAA;AAAA,MACL,KAAO,EAAA,SAAA;AAAA,MACP,OAAA,EAAS,UAAU,MAAU,IAAA;AAAA,KAC/B;AAAA;AAEF,EAAA,MAAM,OAAU,GAAA,MAAM,OAAQ,CAAA,UAAA,CAAW,CAAC,WAAA,CAAY,GAAK,EAAA,KAAK,CAAG,EAAA,WAAA,CAAY,GAAK,EAAA,KAAK,CAAC,CAAC,CAAA;AAC3F,EAAM,MAAA,IAAA,uBAAW,GAAY,EAAA;AAC7B,EAAA,MAAM,QAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,QAAQ,CAAC,GAAG,SAAW,EAAA,GAAG,QAAQ,OAAQ,CAAA,CAAA,IAAA,KAAQ,IAAK,CAAA,MAAA,KAAW,cAAc,IAAK,CAAA,KAAA,GAAQ,EAAE,CAAC,CAAG,EAAA;AAC5G,IAAM,MAAA,GAAA,GAAM,KAAK,SAAa,IAAA,IAAA,CAAK,IAAI,KAAM,CAAA,GAAG,EAAE,CAAC,CAAA;AACnD,IAAI,IAAA,IAAA,CAAK,GAAI,CAAA,GAAG,CAAG,EAAA;AACnB,IAAA,IAAA,CAAK,IAAI,GAAG,CAAA;AACZ,IAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA;AAEjB,EAAO,OAAA;AAAA,IACL,KAAA;AAAA,IACA,OAAA,EAAS,UAAU,MAAU,IAAA;AAAA,GAC/B;AACF;AAQsB,eAAA,wBAAA,CAAyB,KAAqB,UAAqC,EAAA;AA3LzG,EAAA,IAAA,EAAA;AA4LE,EAAA,MAAM,MAAS,GAAA,MAAA,CAAO,MAAM,GAAA,CAAI,SAAS,qCAAuC,EAAA;AAAA,IAC9E;AAAA,GACD,CAAC,CAAA;AACF,EAAA,MAAM,MAAU,GAAA,CAAA,EAAA,GAAA,MAAA,CAAO,kBAAP,KAAA,IAAA,GAAA,EAAA,GAA6B,EAAC;AAC9C,EAAM,MAAA,GAAA,GAAM,GAAI,CAAA,MAAA,CAAO,WAAW,CAAA,IAAK,GAAI,CAAA,MAAA,CAAO,WAAW,CAAA,IAAK,GAAI,CAAA,MAAA,CAAO,GAAG,CAAA;AAChF,EAAA,IAAI,CAAC,GAAA,EAAW,MAAA,IAAI,MAAM,yCAAyC,CAAA;AACnE,EAAO,OAAA,GAAA;AACT"}
1
+ {"version":3,"file":"storageLibrary.js","sources":["../../../src/features/canvas/storageLibrary.ts"],"sourcesContent":["/**\n * Native twin of canvas-surface `rpc/storageRpc` — Your library is the\n * storage index + buckets, not whatever happens to sit on the open board.\n */\nimport { downloadLinkParams, downloadUrlFromResult, ensureFetchableMediaUrl, isPresignedMediaUrl } from './mediaUrls';\nimport type { RunMediaAction } from './videoEditor/mediaActions';\n\nexport type StorageKind = 'image' | 'video' | 'audio';\n\n/** The two object stores the platform writes to (GCS: agent output, AWS: uploads). */\nexport type StorageProvider = 'gcs' | 'aws';\n\nexport interface StorageFile {\n id: string;\n /** Index id for delete — absent when the row came only from a bucket listing. */\n fileInfoId?: string;\n name: string;\n url: string;\n kind: StorageKind;\n /**\n * The object's key in its bucket. The same file reaches the library as an\n * index row and as a bucket object with different ids; the key is what\n * they agree on, so it is what merges them.\n */\n objectKey?: string;\n /** Which store a bucket row came from - deleting by key has to name it. */\n provider?: StorageProvider;\n createdAt?: string;\n}\n\nconst STORAGE = 'yantra-storage' as const;\nconst EXTENSION_KIND: Record<string, StorageKind> = {\n png: 'image',\n jpg: 'image',\n jpeg: 'image',\n webp: 'image',\n gif: 'image',\n avif: 'image',\n svg: 'image',\n mp4: 'video',\n webm: 'video',\n mov: 'video',\n m4v: 'video',\n mp3: 'audio',\n wav: 'audio',\n ogg: 'audio',\n m4a: 'audio',\n flac: 'audio',\n aac: 'audio',\n};\n\nconst str = (v: unknown): string => (typeof v === 'string' ? v : '');\n\nfunction classifyKind(mimeType: string, url: string): StorageKind | null {\n const mime = mimeType.split(';')[0].trim().toLowerCase();\n if (mime.startsWith('image/')) return 'image';\n if (mime.startsWith('video/')) return 'video';\n if (mime.startsWith('audio/')) return 'audio';\n const path = url.split('?')[0];\n const ext = path.slice(path.lastIndexOf('.') + 1).toLowerCase();\n return EXTENSION_KIND[ext] ?? null;\n}\n\nfunction nameFromUrl(url: string): string {\n const path = url.split('?')[0];\n try {\n return decodeURIComponent(path.slice(path.lastIndexOf('/') + 1)) || 'Untitled';\n } catch {\n return path.slice(path.lastIndexOf('/') + 1) || 'Untitled';\n }\n}\n\n/**\n * The bare object key behind a row, from an explicit key or out of its URL.\n * A GCS URL carries the bucket as its first path segment and an AWS/CDN one\n * does not, so only the former is stripped (the connector's extractS3Key).\n */\nexport function objectKeyOf(row: Record<string, unknown>, url: string): string {\n const explicit = str(row.key);\n if (explicit) return explicit.replace(/^\\/+/, '');\n const m = /^https?:\\/\\/([^/?#]+)([^?#]*)/i.exec(url);\n if (!m) return url.replace(/^\\/+/, '');\n const path = m[2].replace(/^\\/+/, '');\n if (m[1].toLowerCase() === 'storage.googleapis.com') {\n const slash = path.indexOf('/');\n return slash >= 0 ? path.slice(slash + 1) : path;\n }\n return path;\n}\n\nexport function normalizeStorageFiles(raw: unknown): StorageFile[] {\n const outer = (raw ?? {}) as Record<string, unknown>;\n const inner = (outer.data ?? outer) as Record<string, unknown>;\n const holders = [\n (inner.filesInfo ?? {}) as Record<string, unknown>,\n inner,\n (inner.listFiles ?? {}) as Record<string, unknown>,\n ];\n let rows: Array<Record<string, unknown>> = [];\n for (const holder of holders) {\n if (Array.isArray(holder)) {\n rows = holder as Array<Record<string, unknown>>;\n break;\n }\n for (const key of ['data', 'files', 'items', 'nodes', 'results']) {\n const v = holder[key];\n if (Array.isArray(v)) {\n rows = v as Array<Record<string, unknown>>;\n break;\n }\n }\n if (rows.length) break;\n }\n const files: StorageFile[] = [];\n for (const row of rows) {\n const url =\n str(row.url) || str(row.downloadUrl) || str(row.signedUrl) || str(row.location) || str(row.publicUrl);\n if (!url) continue;\n const mimeType = str(row.mimeType) || str(row.contentType) || str(row.type);\n const kind = classifyKind(mimeType, str(row.extension) ? `.${str(row.extension)}` : url);\n if (!kind) continue;\n const fileInfoId = str(row.id) || str(row._id);\n const explicitKey = str(row.key);\n // Read out of the URL too, so an index row and its bucket copy merge.\n const objectKey = objectKeyOf(row, url);\n const createdAt = str(row.createdAt) || str(row.uploadedAt) || str(row.lastModified);\n files.push({\n id: fileInfoId || explicitKey || url,\n ...(fileInfoId ? { fileInfoId } : {}),\n name: str(row.name) || str(row.filename) || str(row.fileName) || nameFromUrl(url),\n url,\n kind,\n ...(objectKey ? { objectKey } : {}),\n ...(createdAt ? { createdAt } : {}),\n });\n }\n return files;\n}\n\n/** What identifies a file across lanes: the object key where there is one, else the row id. */\nconst identityOf = (file: StorageFile): string => file.objectKey || file.id;\n\n/**\n * Collapse rows describing the same object into one - MERGING, not dropping.\n * The bucket lane has the fetchable signed URL and the provider; the index\n * lane has the FileInfo id that delete needs. The first row seen wins every\n * field it carries; a later one only fills what is missing. Pass bucket rows\n * first so their URL survives.\n */\nexport function mergeStorageFiles(rows: readonly StorageFile[]): StorageFile[] {\n const byIdentity = new Map<string, StorageFile>();\n for (const row of rows) {\n const identity = identityOf(row);\n const seen = byIdentity.get(identity);\n if (!seen) {\n byIdentity.set(identity, row);\n continue;\n }\n const merged: StorageFile = { ...seen };\n for (const [k, v] of Object.entries(row) as Array<[keyof StorageFile, unknown]>) {\n if (v !== undefined && merged[k] === undefined) (merged as unknown as Record<string, unknown>)[k] = v;\n }\n byIdentity.set(identity, merged);\n }\n return [...byIdentity.values()];\n}\n\n/** Newest first; ISO 8601 sorts as a string, an undated row sinks. */\nexport const byNewest = (a: StorageFile, b: StorageFile): number =>\n (b.createdAt ?? '').localeCompare(a.createdAt ?? '');\n\nfunction unwrap(\n result: Record<string, unknown>,\n failure = 'yantra-storage could not list your files',\n): Record<string, unknown> {\n if (result.successful === false) {\n throw new Error(str(result.error) || failure);\n }\n return (result.data && typeof result.data === 'object' ? result.data : result) as Record<string, unknown>;\n}\n\nasync function listObjects(run: RunMediaAction, provider: StorageProvider): Promise<StorageFile[]> {\n const result = await run(STORAGE, 'YANTRA_STORAGE_LIST_OBJECTS', {\n provider,\n scope: 'user',\n // GCS rows come back presigned by the agent; AWS rows carry the CDN publicUrl.\n ...(provider === 'gcs' ? { signUrls: true } : {}),\n sort: { key: 'lastModified', value: 'DESC' },\n limit: 40,\n });\n const outer = unwrap(result, `yantra-storage could not list your ${provider} objects`);\n const page = (outer.storageObjects ?? outer ?? {}) as Record<string, unknown>;\n const items = Array.isArray(page.items) ? (page.items as Array<Record<string, unknown>>) : [];\n return normalizeStorageFiles({\n data: items\n .filter((item) => !item.isFolder)\n .map((item) => {\n const key = str(item.key);\n return {\n url: str(item.url) || str(item.publicUrl) || str(item.signedUrl),\n key,\n name: key.slice(key.lastIndexOf('/') + 1),\n extension: key.includes('.') ? key.slice(key.lastIndexOf('.') + 1) : '',\n createdAt: str(item.lastModified),\n };\n }),\n }).map((file) => ({ ...file, provider }));\n}\n\n/** Delete by FileInfo id: the object AND its index row, owner-only on the backend. */\nexport async function deleteStorageFile(run: RunMediaAction, fileInfoId: string): Promise<void> {\n const data = unwrap(\n await run(STORAGE, 'YANTRA_STORAGE_DELETE_FILE', { id: fileInfoId }),\n 'Could not delete that file',\n );\n const nested = (data.deleteFileInfo ?? {}) as Record<string, unknown>;\n if (nested.success === false) throw new Error(str(nested.message) || 'The file could not be deleted');\n}\n\n/**\n * Delete a bucket object by key - the lane for everything the index never saw\n * (generated images, rendered clips). The connector confines the key to the\n * caller's own prefixes and takes any index row with it.\n */\nexport async function deleteStorageObject(\n run: RunMediaAction,\n objectKey: string,\n provider?: StorageProvider,\n): Promise<void> {\n const data = unwrap(\n await run(STORAGE, 'YANTRA_STORAGE_DELETE_OBJECT', { key: objectKey, ...(provider ? { provider } : {}) }),\n 'yantra-storage could not delete that object',\n );\n const nested = (data.deleteStorageObject ?? {}) as Record<string, unknown>;\n if (nested.success === false) throw new Error(str(nested.message) || 'The object could not be deleted');\n}\n\n/** True when a library row carries a handle delete can use. */\nexport const canDeleteLibraryFile = (file: StorageFile): boolean => Boolean(file.fileInfoId || file.objectKey);\n\n/** Delete one library row by whichever handle it has: FileInfo id first, else object key. */\nexport async function deleteLibraryFile(run: RunMediaAction, file: StorageFile): Promise<void> {\n if (file.fileInfoId) return deleteStorageFile(run, file.fileInfoId);\n if (file.objectKey) return deleteStorageObject(run, file.objectKey, file.provider);\n throw new Error('This file carries no storage id or object key, so it cannot be deleted from here.');\n}\n\nexport async function listStorageLibraryPage(\n run: RunMediaAction,\n opts: { limit?: number; skip?: number } = {},\n): Promise<{ files: StorageFile[]; hasMore: boolean }> {\n const limit = opts.limit ?? 40;\n const skip = opts.skip ?? 0;\n const indexRun = run(STORAGE, 'YANTRA_STORAGE_LIST_FILES', {\n limit,\n skip,\n sort: { key: 'createdAt', value: 'DESC' },\n }).then((result) => normalizeStorageFiles(unwrap(result)));\n if (skip > 0) {\n const fromIndex = await indexRun;\n return { files: fromIndex, hasMore: fromIndex.length >= limit };\n }\n // Lanes fail independently: part of someone's media beats an error page.\n const [indexLane, ...buckets] = await Promise.allSettled([\n indexRun,\n listObjects(run, 'gcs'),\n listObjects(run, 'aws'),\n ]);\n const lanes = [indexLane, ...buckets];\n if (lanes.every((lane) => lane.status === 'rejected')) {\n const reason = (indexLane as PromiseRejectedResult).reason;\n throw reason instanceof Error ? reason : new Error(String(reason));\n }\n const fromIndex = indexLane.status === 'fulfilled' ? indexLane.value : [];\n const fromBuckets = buckets.flatMap((lane) => (lane.status === 'fulfilled' ? lane.value : []));\n // Bucket rows first, so the fetchable signed URL survives; index rows fold their id in.\n const files = mergeStorageFiles([...fromBuckets, ...fromIndex]).sort(byNewest);\n return { files, hasMore: indexLane.status === 'fulfilled' && fromIndex.length >= limit };\n}\n\nexport async function listStorageLibrary(run: RunMediaAction): Promise<StorageFile[]> {\n const page = await listStorageLibraryPage(run, { limit: 40, skip: 0 });\n return page.files;\n}\n\n/**\n * A presigned GET for a stored object URL or key, at the full 7-day lifetime\n * (the lane's default is 5 minutes). An AWS URL is named `s3://bucket/key`.\n */\nexport async function createStorageDownloadUrl(run: RunMediaAction, s3KeyOrUrl: string): Promise<string> {\n const result = await run(STORAGE, 'YANTRA_STORAGE_CREATE_DOWNLOAD_LINK', downloadLinkParams(s3KeyOrUrl));\n const url = downloadUrlFromResult(unwrap(result, 'yantra-storage returned no download URL'));\n if (!url) throw new Error('yantra-storage returned no download URL');\n return url;\n}\n\n/**\n * A library row's URL as something the canvas can hold and a connector can\n * fetch: a presigned link is kept (re-signed once it has aged); only a raw\n * object URL goes to the storage lane. Never throws.\n */\nexport async function fetchableLibraryUrl(run: RunMediaAction | undefined, url: string): Promise<string> {\n if (isPresignedMediaUrl(url)) return ensureFetchableMediaUrl(run, url).catch(() => url);\n if (!run) return url;\n return createStorageDownloadUrl(run, url).catch(() => url);\n}\n"],"names":["fromIndex"],"mappings":"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"}
@@ -30,10 +30,23 @@ const STUDIO_CATALOG_QUERY = gql`
30
30
  }
31
31
  }
32
32
  `;
33
+ const PUBLISHED_STATUS = "published";
34
+ function catalogSearch(query) {
35
+ const words = (query != null ? query : "").split(NON_WORD).filter(Boolean);
36
+ return words.length ? words.join("-") : void 0;
37
+ }
38
+ const NON_WORD = (() => {
39
+ try {
40
+ return new RegExp("[^\\p{L}\\p{N}]+", "u");
41
+ } catch (e) {
42
+ return /[^A-Za-z0-9\u00C0-\u024F]+/;
43
+ }
44
+ })();
33
45
  function studioCatalogFilter(search, offset = 0, limit = STUDIO_TEMPLATE_PAGE_SIZE) {
34
- const term = search.trim();
46
+ const term = catalogSearch(search);
35
47
  return __spreadValues({
36
48
  group: STUDIO_CATALOG_GROUP,
49
+ status: PUBLISHED_STATUS,
37
50
  limit,
38
51
  offset
39
52
  }, term ? {
@@ -126,4 +139,4 @@ function studioTemplatesToCatalogNodes(rows) {
126
139
  }
127
140
  };
128
141
  });
129
- }export{STUDIO_CATALOG_GROUP,STUDIO_CATALOG_PREFIX,STUDIO_CATALOG_QUERY,STUDIO_TEMPLATE_PAGE_SIZE,catalogRowToStudioTemplate,studioCatalogFilter,studioTemplatesToCatalogNodes};//# sourceMappingURL=studioCatalog.js.map
142
+ }export{PUBLISHED_STATUS,STUDIO_CATALOG_GROUP,STUDIO_CATALOG_PREFIX,STUDIO_CATALOG_QUERY,STUDIO_TEMPLATE_PAGE_SIZE,catalogRowToStudioTemplate,catalogSearch,studioCatalogFilter,studioTemplatesToCatalogNodes};//# sourceMappingURL=studioCatalog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"studioCatalog.js","sources":["../../../src/features/canvas/studioCatalog.ts"],"sourcesContent":["/**\n * Video-studio marketplace rows — same GraphQL field as browser `/c/new`\n * (`formTemplateSubmissions`, group `video-studio`). Apollo typePolicies key by\n * group + search and merge pages by offset so leaving Canvas and coming back\n * is cache-first, not a connector round-trip.\n */\nimport { gql } from '@apollo/client';\nimport type { CanvasPromptTemplate } from './canvasChatTemplates';\nimport { STUDIO_TEMPLATE_PAGE_SIZE, playableTemplatePreviewUrl } from './canvasChatTemplates';\nimport { isInVideoTemplate } from './templateImport/invideoNative';\nimport { renderConfigLinks } from './templateImport/renderConfig';\n\nexport const STUDIO_CATALOG_GROUP = 'video-studio';\nexport const STUDIO_CATALOG_PREFIX = 'video-studio-';\nexport { STUDIO_TEMPLATE_PAGE_SIZE };\n\nexport const STUDIO_CATALOG_QUERY = gql`\n query StudioCatalogTemplates($filter: FormTemplateSubmissionFilter) {\n formTemplateSubmissions(filter: $filter) {\n nodes {\n id\n name\n description\n category\n tags\n formData\n }\n }\n }\n`;\n\nexport interface StudioCatalogRow {\n id?: string | null;\n name?: string | null;\n description?: string | null;\n category?: string | null;\n tags?: Array<string | null> | null;\n formData?: unknown;\n}\n\nexport interface StudioCatalogFilter {\n group: string;\n limit: number;\n offset: number;\n search?: string;\n}\n\nexport function studioCatalogFilter(\n search: string,\n offset = 0,\n limit = STUDIO_TEMPLATE_PAGE_SIZE,\n): StudioCatalogFilter {\n const term = search.trim();\n return {\n group: STUDIO_CATALOG_GROUP,\n limit,\n offset,\n ...(term ? { search: term } : {}),\n };\n}\n\nfunction str(value: unknown): string {\n return typeof value === 'string' ? value.trim() : '';\n}\n\nfunction record(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : {};\n}\n\nfunction parseFormData(value: unknown): Record<string, unknown> {\n if (typeof value === 'string') {\n try {\n return record(JSON.parse(value));\n } catch {\n return {};\n }\n }\n return record(value);\n}\n\nfunction clipSrcs(formData: Record<string, unknown>): string[] {\n const composition = record(formData.composition);\n const direct = Array.isArray(composition.clips) ? composition.clips : [];\n const nested = Array.isArray(composition.tracks)\n ? composition.tracks.flatMap((track) => {\n const clips = record(track).clips;\n return Array.isArray(clips) ? clips : [];\n })\n : [];\n return [...direct, ...nested].map((clip) => str(record(clip).src)).filter(Boolean);\n}\n\nexport function catalogRowToStudioTemplate(row: StudioCatalogRow): CanvasPromptTemplate | null {\n const formData = parseFormData(row.formData);\n const details = record(formData.generationDetails);\n const generation = record(formData.generation);\n const name = str(row.name);\n const id = name.startsWith(STUDIO_CATALOG_PREFIX) ? name.slice(STUDIO_CATALOG_PREFIX.length) : name || str(row.id);\n const title = str(details.title) || name || str(row.id);\n const prompt = str(generation.prompt) || str(row.description) || title;\n if (!id || !title) return null;\n\n const renderConfigRaw = formData.renderConfig;\n const renderConfig =\n typeof renderConfigRaw === 'string'\n ? (() => {\n try {\n return record(JSON.parse(renderConfigRaw));\n } catch {\n return {};\n }\n })()\n : record(renderConfigRaw);\n const usableConfig =\n Object.keys(renderConfig).length > 0 && isInVideoTemplate(renderConfig) ? renderConfig : undefined;\n const links = usableConfig ? undefined : renderConfigLinks(renderConfig);\n\n return {\n id,\n kind: 'video',\n title,\n description: str(details.summary) || str(row.description) || undefined,\n cover: str(details.previewUrl) || str(details.cover) || undefined,\n coverVideo: playableTemplatePreviewUrl(\n str(details.previewVideoUrl),\n str(formData.coverVideo),\n str(generation.coverVideo),\n str(generation.videoUrl),\n ...clipSrcs(formData),\n ),\n aspect: str(details.aspect) || str(generation.aspectRatio) || str(formData.aspect) || undefined,\n prompt,\n category: str(row.category) || undefined,\n tags: Array.isArray(row.tags) ? row.tags.filter((tag): tag is string => typeof tag === 'string') : undefined,\n ...(usableConfig ? { renderConfig: usableConfig } : {}),\n ...(links\n ? {\n configUrls: links.configUrls,\n ...(links.defaultAspect ? { defaultAspect: links.defaultAspect } : {}),\n }\n : {}),\n };\n}\n\nexport function studioTemplatesToCatalogNodes(rows: readonly CanvasPromptTemplate[]): StudioCatalogRow[] {\n return rows.map((row) => ({\n __typename: 'FormTemplateSubmission',\n id: row.id,\n name: row.id.startsWith(STUDIO_CATALOG_PREFIX) ? row.id : `${STUDIO_CATALOG_PREFIX}${row.id}`,\n description: row.description ?? null,\n category: row.category ?? null,\n tags: row.tags ?? null,\n formData: {\n generationDetails: {\n title: row.title,\n summary: row.description,\n previewUrl: row.cover,\n previewVideoUrl: row.coverVideo,\n },\n generation: { prompt: row.prompt },\n },\n }));\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAWO,MAAM,oBAAuB,GAAA;AAC7B,MAAM,qBAAwB,GAAA;AAE9B,MAAM,oBAAuB,GAAA,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4B7B,SAAS,mBAAoB,CAAA,MAAA,EAAgB,MAAS,GAAA,CAAA,EAAG,QAAQ,yBAAgD,EAAA;AACtH,EAAM,MAAA,IAAA,GAAO,OAAO,IAAK,EAAA;AACzB,EAAO,OAAA,cAAA,CAAA;AAAA,IACL,KAAO,EAAA,oBAAA;AAAA,IACP,KAAA;AAAA,IACA;AAAA,GAAA,EACI,IAAO,GAAA;AAAA,IACT,MAAQ,EAAA;AAAA,MACN,EAAC,CAAA;AAET;AACA,SAAS,IAAI,KAAwB,EAAA;AACnC,EAAA,OAAO,OAAO,KAAA,KAAU,QAAW,GAAA,KAAA,CAAM,MAAS,GAAA,EAAA;AACpD;AACA,SAAS,OAAO,KAAyC,EAAA;AACvD,EAAO,OAAA,KAAA,IAAS,OAAO,KAAA,KAAU,QAAY,IAAA,CAAC,MAAM,OAAQ,CAAA,KAAK,CAAI,GAAA,KAAA,GAAmC,EAAC;AAC3G;AACA,SAAS,cAAc,KAAyC,EAAA;AAC9D,EAAI,IAAA,OAAO,UAAU,QAAU,EAAA;AAC7B,IAAI,IAAA;AACF,MAAA,OAAO,MAAO,CAAA,IAAA,CAAK,KAAM,CAAA,KAAK,CAAC,CAAA;AAAA,KACzB,CAAA,OAAA,CAAA,EAAA;AACN,MAAA,OAAO,EAAC;AAAA;AACV;AAEF,EAAA,OAAO,OAAO,KAAK,CAAA;AACrB;AACA,SAAS,SAAS,QAA6C,EAAA;AAC7D,EAAM,MAAA,WAAA,GAAc,MAAO,CAAA,QAAA,CAAS,WAAW,CAAA;AAC/C,EAAM,MAAA,MAAA,GAAS,MAAM,OAAQ,CAAA,WAAA,CAAY,KAAK,CAAI,GAAA,WAAA,CAAY,QAAQ,EAAC;AACvE,EAAM,MAAA,MAAA,GAAS,MAAM,OAAQ,CAAA,WAAA,CAAY,MAAM,CAAI,GAAA,WAAA,CAAY,MAAO,CAAA,OAAA,CAAQ,CAAS,KAAA,KAAA;AACrF,IAAM,MAAA,KAAA,GAAQ,MAAO,CAAA,KAAK,CAAE,CAAA,KAAA;AAC5B,IAAA,OAAO,KAAM,CAAA,OAAA,CAAQ,KAAK,CAAA,GAAI,QAAQ,EAAC;AAAA,GACxC,IAAI,EAAC;AACN,EAAA,OAAO,CAAC,GAAG,MAAA,EAAQ,GAAG,MAAM,EAAE,GAAI,CAAA,CAAA,IAAA,KAAQ,GAAI,CAAA,MAAA,CAAO,IAAI,CAAE,CAAA,GAAG,CAAC,CAAA,CAAE,OAAO,OAAO,CAAA;AACjF;AACO,SAAS,2BAA2B,GAAoD,EAAA;AAC7F,EAAM,MAAA,QAAA,GAAW,aAAc,CAAA,GAAA,CAAI,QAAQ,CAAA;AAC3C,EAAM,MAAA,OAAA,GAAU,MAAO,CAAA,QAAA,CAAS,iBAAiB,CAAA;AACjD,EAAM,MAAA,UAAA,GAAa,MAAO,CAAA,QAAA,CAAS,UAAU,CAAA;AAC7C,EAAM,MAAA,IAAA,GAAO,GAAI,CAAA,GAAA,CAAI,IAAI,CAAA;AACzB,EAAA,MAAM,EAAK,GAAA,IAAA,CAAK,UAAW,CAAA,qBAAqB,CAAI,GAAA,IAAA,CAAK,KAAM,CAAA,qBAAA,CAAsB,MAAM,CAAA,GAAI,IAAQ,IAAA,GAAA,CAAI,IAAI,EAAE,CAAA;AACjH,EAAM,MAAA,KAAA,GAAQ,IAAI,OAAQ,CAAA,KAAK,KAAK,IAAQ,IAAA,GAAA,CAAI,IAAI,EAAE,CAAA;AACtD,EAAM,MAAA,MAAA,GAAS,IAAI,UAAW,CAAA,MAAM,KAAK,GAAI,CAAA,GAAA,CAAI,WAAW,CAAK,IAAA,KAAA;AACjE,EAAA,IAAI,CAAC,EAAA,IAAM,CAAC,KAAA,EAAc,OAAA,IAAA;AAC1B,EAAA,MAAM,kBAAkB,QAAS,CAAA,YAAA;AACjC,EAAA,MAAM,YAAe,GAAA,OAAO,eAAoB,KAAA,QAAA,GAAA,CAAY,MAAM;AAChE,IAAI,IAAA;AACF,MAAA,OAAO,MAAO,CAAA,IAAA,CAAK,KAAM,CAAA,eAAe,CAAC,CAAA;AAAA,KACnC,CAAA,OAAA,CAAA,EAAA;AACN,MAAA,OAAO,EAAC;AAAA;AACV,GACF,GAAO,GAAA,MAAA,CAAO,eAAe,CAAA;AAC7B,EAAM,MAAA,YAAA,GAAe,MAAO,CAAA,IAAA,CAAK,YAAY,CAAA,CAAE,SAAS,CAAK,IAAA,iBAAA,CAAkB,YAAY,CAAA,GAAI,YAAe,GAAA,MAAA;AAC9G,EAAA,MAAM,KAAQ,GAAA,YAAA,GAAe,MAAY,GAAA,iBAAA,CAAkB,YAAY,CAAA;AACvE,EAAO,OAAA,cAAA,CAAA,cAAA,CAAA;AAAA,IACL,EAAA;AAAA,IACA,IAAM,EAAA,OAAA;AAAA,IACN,KAAA;AAAA,IACA,WAAA,EAAa,IAAI,OAAQ,CAAA,OAAO,KAAK,GAAI,CAAA,GAAA,CAAI,WAAW,CAAK,IAAA,MAAA;AAAA,IAC7D,KAAA,EAAO,IAAI,OAAQ,CAAA,UAAU,KAAK,GAAI,CAAA,OAAA,CAAQ,KAAK,CAAK,IAAA,MAAA;AAAA,IACxD,UAAA,EAAY,2BAA2B,GAAI,CAAA,OAAA,CAAQ,eAAe,CAAG,EAAA,GAAA,CAAI,SAAS,UAAU,CAAA,EAAG,IAAI,UAAW,CAAA,UAAU,GAAG,GAAI,CAAA,UAAA,CAAW,QAAQ,CAAG,EAAA,GAAG,QAAS,CAAA,QAAQ,CAAC,CAAA;AAAA,IAC1K,MAAQ,EAAA,GAAA,CAAI,OAAQ,CAAA,MAAM,CAAK,IAAA,GAAA,CAAI,UAAW,CAAA,WAAW,CAAK,IAAA,GAAA,CAAI,QAAS,CAAA,MAAM,CAAK,IAAA,MAAA;AAAA,IACtF,MAAA;AAAA,IACA,QAAU,EAAA,GAAA,CAAI,GAAI,CAAA,QAAQ,CAAK,IAAA,MAAA;AAAA,IAC/B,IAAM,EAAA,KAAA,CAAM,OAAQ,CAAA,GAAA,CAAI,IAAI,CAAI,GAAA,GAAA,CAAI,IAAK,CAAA,MAAA,CAAO,CAAC,GAAA,KAAuB,OAAO,GAAA,KAAQ,QAAQ,CAAI,GAAA;AAAA,GAAA,EAC/F,YAAe,GAAA;AAAA,IACjB,YAAc,EAAA;AAAA,GAChB,GAAI,EAAC,CAAA,EACD,KAAQ,GAAA,cAAA,CAAA;AAAA,IACV,YAAY,KAAM,CAAA;AAAA,GAAA,EACd,MAAM,aAAgB,GAAA;AAAA,IACxB,eAAe,KAAM,CAAA;AAAA,GACvB,GAAI,EAAC,CAAA,GACH,EAAC,CAAA;AAET;AACO,SAAS,8BAA8B,IAA2D,EAAA;AACvG,EAAO,OAAA,IAAA,CAAK,IAAI,CAAI,GAAA,KAAA;AAxHtB,IAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAwH0B,IAAA,OAAA;AAAA,MACtB,UAAY,EAAA,wBAAA;AAAA,MACZ,IAAI,GAAI,CAAA,EAAA;AAAA,MACR,IAAM,EAAA,GAAA,CAAI,EAAG,CAAA,UAAA,CAAW,qBAAqB,CAAA,GAAI,GAAI,CAAA,EAAA,GAAK,CAAG,EAAA,qBAAqB,CAAG,EAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAAA,MAC3F,WAAA,EAAA,CAAa,EAAI,GAAA,GAAA,CAAA,WAAA,KAAJ,IAAmB,GAAA,EAAA,GAAA,IAAA;AAAA,MAChC,QAAA,EAAA,CAAU,EAAI,GAAA,GAAA,CAAA,QAAA,KAAJ,IAAgB,GAAA,EAAA,GAAA,IAAA;AAAA,MAC1B,IAAA,EAAA,CAAM,EAAI,GAAA,GAAA,CAAA,IAAA,KAAJ,IAAY,GAAA,EAAA,GAAA,IAAA;AAAA,MAClB,QAAU,EAAA;AAAA,QACR,iBAAmB,EAAA;AAAA,UACjB,OAAO,GAAI,CAAA,KAAA;AAAA,UACX,SAAS,GAAI,CAAA,WAAA;AAAA,UACb,YAAY,GAAI,CAAA,KAAA;AAAA,UAChB,iBAAiB,GAAI,CAAA;AAAA,SACvB;AAAA,QACA,UAAY,EAAA;AAAA,UACV,QAAQ,GAAI,CAAA;AAAA;AACd;AACF,KACF;AAAA,GAAE,CAAA;AACJ"}
1
+ {"version":3,"file":"studioCatalog.js","sources":["../../../src/features/canvas/studioCatalog.ts"],"sourcesContent":["/**\n * Video-studio marketplace rows — same GraphQL field as browser `/c/new`\n * (`formTemplateSubmissions`, group `video-studio`). Apollo typePolicies key by\n * group + search and merge pages by offset so leaving Canvas and coming back\n * is cache-first, not a connector round-trip.\n */\nimport { gql } from '@apollo/client';\nimport type { CanvasPromptTemplate } from './canvasChatTemplates';\nimport { STUDIO_TEMPLATE_PAGE_SIZE, playableTemplatePreviewUrl } from './canvasChatTemplates';\nimport { isInVideoTemplate } from './templateImport/invideoNative';\nimport { renderConfigLinks } from './templateImport/renderConfig';\n\nexport const STUDIO_CATALOG_GROUP = 'video-studio';\nexport const STUDIO_CATALOG_PREFIX = 'video-studio-';\nexport { STUDIO_TEMPLATE_PAGE_SIZE };\n\nexport const STUDIO_CATALOG_QUERY = gql`\n query StudioCatalogTemplates($filter: FormTemplateSubmissionFilter) {\n formTemplateSubmissions(filter: $filter) {\n nodes {\n id\n name\n description\n category\n tags\n formData\n }\n }\n }\n`;\n\nexport interface StudioCatalogRow {\n id?: string | null;\n name?: string | null;\n description?: string | null;\n category?: string | null;\n tags?: Array<string | null> | null;\n formData?: unknown;\n}\n\nexport interface StudioCatalogFilter {\n group: string;\n status: typeof PUBLISHED_STATUS;\n limit: number;\n offset: number;\n search?: string;\n}\n\n/** Only published rows reach a page: never a draft (surface-kit `catalogRead`). */\nexport const PUBLISHED_STATUS = 'published';\n\n/**\n * Search words as the backend resolver matches them (surface-kit\n * `catalogSearch`): it matches ONE regex against the slugged row name, so\n * words join with '-' (\"real estate\" found 0, \"real-estate\" 191) and only\n * letters/digits survive (\"c++\" or \"(\" broke the regex).\n */\nexport function catalogSearch(query: string | undefined): string | undefined {\n const words = (query ?? '').split(NON_WORD).filter(Boolean);\n return words.length ? words.join('-') : undefined;\n}\n\nconst NON_WORD: RegExp = (() => {\n try {\n return new RegExp('[^\\\\p{L}\\\\p{N}]+', 'u');\n } catch {\n // Engines without Unicode property escapes: ASCII plus Latin-1 letters.\n return /[^A-Za-z0-9\\u00C0-\\u024F]+/;\n }\n})();\n\nexport function studioCatalogFilter(\n search: string,\n offset = 0,\n limit = STUDIO_TEMPLATE_PAGE_SIZE,\n): StudioCatalogFilter {\n const term = catalogSearch(search);\n return {\n group: STUDIO_CATALOG_GROUP,\n status: PUBLISHED_STATUS,\n limit,\n offset,\n ...(term ? { search: term } : {}),\n };\n}\n\nfunction str(value: unknown): string {\n return typeof value === 'string' ? value.trim() : '';\n}\n\nfunction record(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : {};\n}\n\nfunction parseFormData(value: unknown): Record<string, unknown> {\n if (typeof value === 'string') {\n try {\n return record(JSON.parse(value));\n } catch {\n return {};\n }\n }\n return record(value);\n}\n\nfunction clipSrcs(formData: Record<string, unknown>): string[] {\n const composition = record(formData.composition);\n const direct = Array.isArray(composition.clips) ? composition.clips : [];\n const nested = Array.isArray(composition.tracks)\n ? composition.tracks.flatMap((track) => {\n const clips = record(track).clips;\n return Array.isArray(clips) ? clips : [];\n })\n : [];\n return [...direct, ...nested].map((clip) => str(record(clip).src)).filter(Boolean);\n}\n\nexport function catalogRowToStudioTemplate(row: StudioCatalogRow): CanvasPromptTemplate | null {\n const formData = parseFormData(row.formData);\n const details = record(formData.generationDetails);\n const generation = record(formData.generation);\n const name = str(row.name);\n const id = name.startsWith(STUDIO_CATALOG_PREFIX) ? name.slice(STUDIO_CATALOG_PREFIX.length) : name || str(row.id);\n const title = str(details.title) || name || str(row.id);\n const prompt = str(generation.prompt) || str(row.description) || title;\n if (!id || !title) return null;\n\n const renderConfigRaw = formData.renderConfig;\n const renderConfig =\n typeof renderConfigRaw === 'string'\n ? (() => {\n try {\n return record(JSON.parse(renderConfigRaw));\n } catch {\n return {};\n }\n })()\n : record(renderConfigRaw);\n const usableConfig =\n Object.keys(renderConfig).length > 0 && isInVideoTemplate(renderConfig) ? renderConfig : undefined;\n const links = usableConfig ? undefined : renderConfigLinks(renderConfig);\n\n return {\n id,\n kind: 'video',\n title,\n description: str(details.summary) || str(row.description) || undefined,\n cover: str(details.previewUrl) || str(details.cover) || undefined,\n coverVideo: playableTemplatePreviewUrl(\n str(details.previewVideoUrl),\n str(formData.coverVideo),\n str(generation.coverVideo),\n str(generation.videoUrl),\n ...clipSrcs(formData),\n ),\n aspect: str(details.aspect) || str(generation.aspectRatio) || str(formData.aspect) || undefined,\n prompt,\n category: str(row.category) || undefined,\n tags: Array.isArray(row.tags) ? row.tags.filter((tag): tag is string => typeof tag === 'string') : undefined,\n ...(usableConfig ? { renderConfig: usableConfig } : {}),\n ...(links\n ? {\n configUrls: links.configUrls,\n ...(links.defaultAspect ? { defaultAspect: links.defaultAspect } : {}),\n }\n : {}),\n };\n}\n\nexport function studioTemplatesToCatalogNodes(rows: readonly CanvasPromptTemplate[]): StudioCatalogRow[] {\n return rows.map((row) => ({\n __typename: 'FormTemplateSubmission',\n id: row.id,\n name: row.id.startsWith(STUDIO_CATALOG_PREFIX) ? row.id : `${STUDIO_CATALOG_PREFIX}${row.id}`,\n description: row.description ?? null,\n category: row.category ?? null,\n tags: row.tags ?? null,\n formData: {\n generationDetails: {\n title: row.title,\n summary: row.description,\n previewUrl: row.cover,\n previewVideoUrl: row.coverVideo,\n },\n generation: { prompt: row.prompt },\n },\n }));\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAWO,MAAM,oBAAuB,GAAA;AAC7B,MAAM,qBAAwB,GAAA;AAE9B,MAAM,oBAAuB,GAAA,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+B7B,MAAM,gBAAmB,GAAA;AAQzB,SAAS,cAAc,KAA+C,EAAA;AAC3E,EAAA,MAAM,SAAS,KAAS,IAAA,IAAA,GAAA,KAAA,GAAA,EAAA,EAAI,MAAM,QAAQ,CAAA,CAAE,OAAO,OAAO,CAAA;AAC1D,EAAA,OAAO,KAAM,CAAA,MAAA,GAAS,KAAM,CAAA,IAAA,CAAK,GAAG,CAAI,GAAA,MAAA;AAC1C;AACA,MAAM,YAAoB,MAAM;AAC9B,EAAI,IAAA;AACF,IAAO,OAAA,IAAI,MAAO,CAAA,kBAAA,EAAoB,GAAG,CAAA;AAAA,GACnC,CAAA,OAAA,CAAA,EAAA;AAEN,IAAO,OAAA,4BAAA;AAAA;AAEX,CAAG,GAAA;AACI,SAAS,mBAAoB,CAAA,MAAA,EAAgB,MAAS,GAAA,CAAA,EAAG,QAAQ,yBAAgD,EAAA;AACtH,EAAM,MAAA,IAAA,GAAO,cAAc,MAAM,CAAA;AACjC,EAAO,OAAA,cAAA,CAAA;AAAA,IACL,KAAO,EAAA,oBAAA;AAAA,IACP,MAAQ,EAAA,gBAAA;AAAA,IACR,KAAA;AAAA,IACA;AAAA,GAAA,EACI,IAAO,GAAA;AAAA,IACT,MAAQ,EAAA;AAAA,MACN,EAAC,CAAA;AAET;AACA,SAAS,IAAI,KAAwB,EAAA;AACnC,EAAA,OAAO,OAAO,KAAA,KAAU,QAAW,GAAA,KAAA,CAAM,MAAS,GAAA,EAAA;AACpD;AACA,SAAS,OAAO,KAAyC,EAAA;AACvD,EAAO,OAAA,KAAA,IAAS,OAAO,KAAA,KAAU,QAAY,IAAA,CAAC,MAAM,OAAQ,CAAA,KAAK,CAAI,GAAA,KAAA,GAAmC,EAAC;AAC3G;AACA,SAAS,cAAc,KAAyC,EAAA;AAC9D,EAAI,IAAA,OAAO,UAAU,QAAU,EAAA;AAC7B,IAAI,IAAA;AACF,MAAA,OAAO,MAAO,CAAA,IAAA,CAAK,KAAM,CAAA,KAAK,CAAC,CAAA;AAAA,KACzB,CAAA,OAAA,CAAA,EAAA;AACN,MAAA,OAAO,EAAC;AAAA;AACV;AAEF,EAAA,OAAO,OAAO,KAAK,CAAA;AACrB;AACA,SAAS,SAAS,QAA6C,EAAA;AAC7D,EAAM,MAAA,WAAA,GAAc,MAAO,CAAA,QAAA,CAAS,WAAW,CAAA;AAC/C,EAAM,MAAA,MAAA,GAAS,MAAM,OAAQ,CAAA,WAAA,CAAY,KAAK,CAAI,GAAA,WAAA,CAAY,QAAQ,EAAC;AACvE,EAAM,MAAA,MAAA,GAAS,MAAM,OAAQ,CAAA,WAAA,CAAY,MAAM,CAAI,GAAA,WAAA,CAAY,MAAO,CAAA,OAAA,CAAQ,CAAS,KAAA,KAAA;AACrF,IAAM,MAAA,KAAA,GAAQ,MAAO,CAAA,KAAK,CAAE,CAAA,KAAA;AAC5B,IAAA,OAAO,KAAM,CAAA,OAAA,CAAQ,KAAK,CAAA,GAAI,QAAQ,EAAC;AAAA,GACxC,IAAI,EAAC;AACN,EAAA,OAAO,CAAC,GAAG,MAAA,EAAQ,GAAG,MAAM,EAAE,GAAI,CAAA,CAAA,IAAA,KAAQ,GAAI,CAAA,MAAA,CAAO,IAAI,CAAE,CAAA,GAAG,CAAC,CAAA,CAAE,OAAO,OAAO,CAAA;AACjF;AACO,SAAS,2BAA2B,GAAoD,EAAA;AAC7F,EAAM,MAAA,QAAA,GAAW,aAAc,CAAA,GAAA,CAAI,QAAQ,CAAA;AAC3C,EAAM,MAAA,OAAA,GAAU,MAAO,CAAA,QAAA,CAAS,iBAAiB,CAAA;AACjD,EAAM,MAAA,UAAA,GAAa,MAAO,CAAA,QAAA,CAAS,UAAU,CAAA;AAC7C,EAAM,MAAA,IAAA,GAAO,GAAI,CAAA,GAAA,CAAI,IAAI,CAAA;AACzB,EAAA,MAAM,EAAK,GAAA,IAAA,CAAK,UAAW,CAAA,qBAAqB,CAAI,GAAA,IAAA,CAAK,KAAM,CAAA,qBAAA,CAAsB,MAAM,CAAA,GAAI,IAAQ,IAAA,GAAA,CAAI,IAAI,EAAE,CAAA;AACjH,EAAM,MAAA,KAAA,GAAQ,IAAI,OAAQ,CAAA,KAAK,KAAK,IAAQ,IAAA,GAAA,CAAI,IAAI,EAAE,CAAA;AACtD,EAAM,MAAA,MAAA,GAAS,IAAI,UAAW,CAAA,MAAM,KAAK,GAAI,CAAA,GAAA,CAAI,WAAW,CAAK,IAAA,KAAA;AACjE,EAAA,IAAI,CAAC,EAAA,IAAM,CAAC,KAAA,EAAc,OAAA,IAAA;AAC1B,EAAA,MAAM,kBAAkB,QAAS,CAAA,YAAA;AACjC,EAAA,MAAM,YAAe,GAAA,OAAO,eAAoB,KAAA,QAAA,GAAA,CAAY,MAAM;AAChE,IAAI,IAAA;AACF,MAAA,OAAO,MAAO,CAAA,IAAA,CAAK,KAAM,CAAA,eAAe,CAAC,CAAA;AAAA,KACnC,CAAA,OAAA,CAAA,EAAA;AACN,MAAA,OAAO,EAAC;AAAA;AACV,GACF,GAAO,GAAA,MAAA,CAAO,eAAe,CAAA;AAC7B,EAAM,MAAA,YAAA,GAAe,MAAO,CAAA,IAAA,CAAK,YAAY,CAAA,CAAE,SAAS,CAAK,IAAA,iBAAA,CAAkB,YAAY,CAAA,GAAI,YAAe,GAAA,MAAA;AAC9G,EAAA,MAAM,KAAQ,GAAA,YAAA,GAAe,MAAY,GAAA,iBAAA,CAAkB,YAAY,CAAA;AACvE,EAAO,OAAA,cAAA,CAAA,cAAA,CAAA;AAAA,IACL,EAAA;AAAA,IACA,IAAM,EAAA,OAAA;AAAA,IACN,KAAA;AAAA,IACA,WAAA,EAAa,IAAI,OAAQ,CAAA,OAAO,KAAK,GAAI,CAAA,GAAA,CAAI,WAAW,CAAK,IAAA,MAAA;AAAA,IAC7D,KAAA,EAAO,IAAI,OAAQ,CAAA,UAAU,KAAK,GAAI,CAAA,OAAA,CAAQ,KAAK,CAAK,IAAA,MAAA;AAAA,IACxD,UAAA,EAAY,2BAA2B,GAAI,CAAA,OAAA,CAAQ,eAAe,CAAG,EAAA,GAAA,CAAI,SAAS,UAAU,CAAA,EAAG,IAAI,UAAW,CAAA,UAAU,GAAG,GAAI,CAAA,UAAA,CAAW,QAAQ,CAAG,EAAA,GAAG,QAAS,CAAA,QAAQ,CAAC,CAAA;AAAA,IAC1K,MAAQ,EAAA,GAAA,CAAI,OAAQ,CAAA,MAAM,CAAK,IAAA,GAAA,CAAI,UAAW,CAAA,WAAW,CAAK,IAAA,GAAA,CAAI,QAAS,CAAA,MAAM,CAAK,IAAA,MAAA;AAAA,IACtF,MAAA;AAAA,IACA,QAAU,EAAA,GAAA,CAAI,GAAI,CAAA,QAAQ,CAAK,IAAA,MAAA;AAAA,IAC/B,IAAM,EAAA,KAAA,CAAM,OAAQ,CAAA,GAAA,CAAI,IAAI,CAAI,GAAA,GAAA,CAAI,IAAK,CAAA,MAAA,CAAO,CAAC,GAAA,KAAuB,OAAO,GAAA,KAAQ,QAAQ,CAAI,GAAA;AAAA,GAAA,EAC/F,YAAe,GAAA;AAAA,IACjB,YAAc,EAAA;AAAA,GAChB,GAAI,EAAC,CAAA,EACD,KAAQ,GAAA,cAAA,CAAA;AAAA,IACV,YAAY,KAAM,CAAA;AAAA,GAAA,EACd,MAAM,aAAgB,GAAA;AAAA,IACxB,eAAe,KAAM,CAAA;AAAA,GACvB,GAAI,EAAC,CAAA,GACH,EAAC,CAAA;AAET;AACO,SAAS,8BAA8B,IAA2D,EAAA;AACvG,EAAO,OAAA,IAAA,CAAK,IAAI,CAAI,GAAA,KAAA;AAhJtB,IAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAgJ0B,IAAA,OAAA;AAAA,MACtB,UAAY,EAAA,wBAAA;AAAA,MACZ,IAAI,GAAI,CAAA,EAAA;AAAA,MACR,IAAM,EAAA,GAAA,CAAI,EAAG,CAAA,UAAA,CAAW,qBAAqB,CAAA,GAAI,GAAI,CAAA,EAAA,GAAK,CAAG,EAAA,qBAAqB,CAAG,EAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAAA,MAC3F,WAAA,EAAA,CAAa,EAAI,GAAA,GAAA,CAAA,WAAA,KAAJ,IAAmB,GAAA,EAAA,GAAA,IAAA;AAAA,MAChC,QAAA,EAAA,CAAU,EAAI,GAAA,GAAA,CAAA,QAAA,KAAJ,IAAgB,GAAA,EAAA,GAAA,IAAA;AAAA,MAC1B,IAAA,EAAA,CAAM,EAAI,GAAA,GAAA,CAAA,IAAA,KAAJ,IAAY,GAAA,EAAA,GAAA,IAAA;AAAA,MAClB,QAAU,EAAA;AAAA,QACR,iBAAmB,EAAA;AAAA,UACjB,OAAO,GAAI,CAAA,KAAA;AAAA,UACX,SAAS,GAAI,CAAA,WAAA;AAAA,UACb,YAAY,GAAI,CAAA,KAAA;AAAA,UAChB,iBAAiB,GAAI,CAAA;AAAA,SACvB;AAAA,QACA,UAAY,EAAA;AAAA,UACV,QAAQ,GAAI,CAAA;AAAA;AACd;AACF,KACF;AAAA,GAAE,CAAA;AACJ"}
@@ -76,7 +76,6 @@ async function listViaBackendFetch(graphqlUrl, token, params) {
76
76
  var _a, _b, _c, _d, _e, _f;
77
77
  const limit = (_a = params.limit) != null ? _a : LOOKS_PAGE_SIZE;
78
78
  const offset = (_b = params.offset) != null ? _b : 0;
79
- const search = (_c = params.query) == null ? void 0 : _c.trim();
80
79
  const res = await fetch(graphqlUrl, {
81
80
  method: "POST",
82
81
  headers: {
@@ -86,13 +85,7 @@ async function listViaBackendFetch(graphqlUrl, token, params) {
86
85
  body: JSON.stringify({
87
86
  query: SUBMISSIONS_QUERY,
88
87
  variables: {
89
- filter: __spreadValues({
90
- group: "video-studio",
91
- limit,
92
- offset
93
- }, search ? {
94
- search
95
- } : {})
88
+ filter: studioCatalogFilter((_c = params.query) != null ? _c : "", offset, limit)
96
89
  }
97
90
  })
98
91
  });
@@ -1 +1 @@
1
- {"version":3,"file":"studioLooks.js","sources":["../../../src/features/canvas/studioLooks.ts"],"sourcesContent":["/**\n * Native twin of canvas-surface `rpc/studioLooksRpc` — browse-first video recipes.\n *\n * Prefer a direct `formTemplateSubmissions` read (same as web studio templates).\n * The agent-pod connector often 400s with \"Studio catalog read failed\"; never\n * fall through to it after a successful empty catalog page.\n */\nimport type { RunMediaAction } from './videoEditor/mediaActions';\nimport { deriveBackendGraphqlUrl } from './videoEditor/remoteMediaClient';\nimport {\n STUDIO_CATALOG_QUERY,\n catalogRowToStudioTemplate,\n studioCatalogFilter,\n type StudioCatalogRow,\n} from './studioCatalog';\nimport type { StudioCatalogClient } from './useStudioCatalogTemplates';\n\nexport const LOOKS_PAGE_SIZE = 24;\n\nexport interface StudioLook {\n id: string;\n name: string;\n description: string;\n cover: string;\n coverVideo: string;\n prompt: string;\n aspect: string;\n category: string;\n tags: string[];\n}\n\nexport interface ListStudioLooksOptions {\n client?: StudioCatalogClient | null;\n token?: string | null;\n indexUrl?: string | null;\n}\n\nconst str = (v: unknown): string => (typeof v === 'string' ? v : '');\n\nconst SUBMISSIONS_QUERY =\n 'query($filter: FormTemplateSubmissionFilter){ formTemplateSubmissions(filter:$filter){ nodes { id name description category tags formData } } }';\n\nfunction normalize(raw: unknown): { looks: StudioLook[]; hasMore: boolean } {\n const outer = (raw ?? {}) as Record<string, unknown>;\n const body = (outer.data ?? outer) as Record<string, unknown>;\n const list = Array.isArray(body.templates) ? body.templates : [];\n const looks = (list as Array<Record<string, unknown>>)\n .map((t) => ({\n id: str(t.id),\n name: str(t.name) || str(t.id),\n description: str(t.description),\n cover: str(t.cover),\n coverVideo: str(t.coverVideo),\n prompt: str(t.prompt),\n aspect: str(t.aspect),\n category: str(t.category),\n tags: Array.isArray(t.tags) ? t.tags.filter((x): x is string => typeof x === 'string') : [],\n }))\n .filter((l) => Boolean(l.id) && Boolean(l.prompt));\n return { looks, hasMore: Boolean(body.hasMore) };\n}\n\nfunction looksFromCatalogNodes(\n nodes: StudioCatalogRow[] | null | undefined,\n pageSize: number,\n): { looks: StudioLook[]; hasMore: boolean } {\n const looks = (nodes ?? [])\n .map(catalogRowToStudioTemplate)\n .filter((row): row is NonNullable<typeof row> => row !== null && Boolean(row.prompt))\n .map(\n (row): StudioLook => ({\n id: row.id,\n name: row.title,\n description: row.description || '',\n cover: row.cover || '',\n coverVideo: row.coverVideo || '',\n prompt: row.prompt,\n aspect: row.aspect || '',\n category: row.category || '',\n tags: row.tags || [],\n }),\n );\n return { looks, hasMore: (nodes?.length ?? 0) >= pageSize };\n}\n\nasync function listViaCatalog(\n client: StudioCatalogClient,\n params: { query?: string; offset?: number; limit?: number },\n): Promise<{ looks: StudioLook[]; hasMore: boolean }> {\n const limit = params.limit ?? LOOKS_PAGE_SIZE;\n const offset = params.offset ?? 0;\n const { data } = await client.query({\n query: STUDIO_CATALOG_QUERY,\n variables: { filter: studioCatalogFilter(params.query ?? '', offset, limit) },\n fetchPolicy: 'network-only',\n });\n const nodes = (data as { formTemplateSubmissions?: { nodes?: StudioCatalogRow[] | null } } | null)\n ?.formTemplateSubmissions?.nodes;\n return looksFromCatalogNodes(nodes, limit);\n}\n\n/** Web `readViaBackend` — skip the agent pod entirely. */\nasync function listViaBackendFetch(\n graphqlUrl: string,\n token: string,\n params: { query?: string; offset?: number; limit?: number },\n): Promise<{ looks: StudioLook[]; hasMore: boolean }> {\n const limit = params.limit ?? LOOKS_PAGE_SIZE;\n const offset = params.offset ?? 0;\n const search = params.query?.trim();\n const res = await fetch(graphqlUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n query: SUBMISSIONS_QUERY,\n variables: {\n filter: {\n group: 'video-studio',\n limit,\n offset,\n ...(search ? { search } : {}),\n },\n },\n }),\n });\n if (!res.ok) throw new Error(`Studio catalog read failed (${res.status})`);\n const json = (await res.json().catch(() => ({}))) as {\n data?: { formTemplateSubmissions?: { nodes?: StudioCatalogRow[] | null } };\n errors?: Array<{ message?: string }>;\n };\n if (json.errors?.length) {\n throw new Error(\n json.errors\n .map((e) => e?.message)\n .filter(Boolean)\n .join('; ') || 'Studio catalog read failed',\n );\n }\n const nodes = json.data?.formTemplateSubmissions?.nodes;\n if (!Array.isArray(nodes)) throw new Error('Backend returned no formTemplateSubmissions');\n return looksFromCatalogNodes(nodes, limit);\n}\n\nexport async function listStudioLooks(\n run: RunMediaAction | undefined,\n params: { query?: string; offset?: number; limit?: number } = {},\n options: ListStudioLooksOptions | StudioCatalogClient | null = {},\n): Promise<{ looks: StudioLook[]; hasMore: boolean }> {\n // Back-compat: third arg used to be apolloClient alone.\n const isLegacyClient =\n options != null &&\n typeof options === 'object' &&\n typeof (options as StudioCatalogClient).readQuery === 'function';\n const opts: ListStudioLooksOptions = isLegacyClient\n ? { client: options as StudioCatalogClient }\n : ((options as ListStudioLooksOptions | null) ?? {});\n\n const limit = params.limit ?? LOOKS_PAGE_SIZE;\n const offset = params.offset ?? 0;\n const query = params.query?.trim();\n const graphqlUrl = opts.indexUrl ? deriveBackendGraphqlUrl(opts.indexUrl) : null;\n\n if (opts.token && graphqlUrl) {\n try {\n return await listViaBackendFetch(graphqlUrl, opts.token, { query, offset, limit });\n } catch {\n // Apollo / connector fallbacks.\n }\n }\n\n if (opts.client) {\n try {\n // Successful empty page is final — do not escalate to the broken connector.\n return await listViaCatalog(opts.client, { query, offset, limit });\n } catch {\n // Connector fallback.\n }\n }\n\n if (!run) return { looks: [], hasMore: false };\n\n try {\n const result = await run('yantra-video-generation', 'YANTRA_VIDEO_LIST_STUDIO_TEMPLATES', {\n limit,\n offset,\n ...(query ? { query } : {}),\n });\n const page = normalize(result);\n return { looks: page.looks, hasMore: page.hasMore || page.looks.length >= limit };\n } catch {\n return { looks: [], hasMore: false };\n }\n}\n\nexport function nearestAspect(aspect: string, supported: readonly string[]): string | undefined {\n const wanted = aspect.trim();\n if (!wanted) return undefined;\n if (supported.includes(wanted)) return wanted;\n const ratio = (value: string): number | undefined => {\n const [w, h] = value.split(':').map(Number);\n return Number.isFinite(w) && Number.isFinite(h) && h > 0 ? w / h : undefined;\n };\n const target = ratio(wanted);\n if (target === undefined) return undefined;\n const portrait = target < 1;\n const sameOrientation = supported.filter((option) => {\n const r = ratio(option);\n return r !== undefined && (portrait ? r < 1 : r >= 1);\n });\n const pool = sameOrientation.length > 0 ? sameOrientation : supported;\n let best: string | undefined;\n let bestGap = Infinity;\n for (const option of pool) {\n const r = ratio(option);\n if (r === undefined) continue;\n const gap = Math.abs(r - target);\n if (gap < bestGap) {\n bestGap = gap;\n best = option;\n }\n }\n return best;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"studioLooks.js","sources":["../../../src/features/canvas/studioLooks.ts"],"sourcesContent":["/**\n * Native twin of canvas-surface `rpc/studioLooksRpc` — browse-first video recipes.\n *\n * Prefer a direct `formTemplateSubmissions` read (same as web studio templates).\n * The agent-pod connector often 400s with \"Studio catalog read failed\"; never\n * fall through to it after a successful empty catalog page.\n */\nimport type { RunMediaAction } from './videoEditor/mediaActions';\nimport { deriveBackendGraphqlUrl } from './videoEditor/remoteMediaClient';\nimport {\n STUDIO_CATALOG_QUERY,\n catalogRowToStudioTemplate,\n studioCatalogFilter,\n type StudioCatalogRow,\n} from './studioCatalog';\nimport type { StudioCatalogClient } from './useStudioCatalogTemplates';\n\nexport const LOOKS_PAGE_SIZE = 24;\n\nexport interface StudioLook {\n id: string;\n name: string;\n description: string;\n cover: string;\n coverVideo: string;\n prompt: string;\n aspect: string;\n category: string;\n tags: string[];\n}\n\nexport interface ListStudioLooksOptions {\n client?: StudioCatalogClient | null;\n token?: string | null;\n indexUrl?: string | null;\n}\n\nconst str = (v: unknown): string => (typeof v === 'string' ? v : '');\n\nconst SUBMISSIONS_QUERY =\n 'query($filter: FormTemplateSubmissionFilter){ formTemplateSubmissions(filter:$filter){ nodes { id name description category tags formData } } }';\n\nfunction normalize(raw: unknown): { looks: StudioLook[]; hasMore: boolean } {\n const outer = (raw ?? {}) as Record<string, unknown>;\n const body = (outer.data ?? outer) as Record<string, unknown>;\n const list = Array.isArray(body.templates) ? body.templates : [];\n const looks = (list as Array<Record<string, unknown>>)\n .map((t) => ({\n id: str(t.id),\n name: str(t.name) || str(t.id),\n description: str(t.description),\n cover: str(t.cover),\n coverVideo: str(t.coverVideo),\n prompt: str(t.prompt),\n aspect: str(t.aspect),\n category: str(t.category),\n tags: Array.isArray(t.tags) ? t.tags.filter((x): x is string => typeof x === 'string') : [],\n }))\n .filter((l) => Boolean(l.id) && Boolean(l.prompt));\n return { looks, hasMore: Boolean(body.hasMore) };\n}\n\nfunction looksFromCatalogNodes(\n nodes: StudioCatalogRow[] | null | undefined,\n pageSize: number,\n): { looks: StudioLook[]; hasMore: boolean } {\n const looks = (nodes ?? [])\n .map(catalogRowToStudioTemplate)\n .filter((row): row is NonNullable<typeof row> => row !== null && Boolean(row.prompt))\n .map(\n (row): StudioLook => ({\n id: row.id,\n name: row.title,\n description: row.description || '',\n cover: row.cover || '',\n coverVideo: row.coverVideo || '',\n prompt: row.prompt,\n aspect: row.aspect || '',\n category: row.category || '',\n tags: row.tags || [],\n }),\n );\n return { looks, hasMore: (nodes?.length ?? 0) >= pageSize };\n}\n\nasync function listViaCatalog(\n client: StudioCatalogClient,\n params: { query?: string; offset?: number; limit?: number },\n): Promise<{ looks: StudioLook[]; hasMore: boolean }> {\n const limit = params.limit ?? LOOKS_PAGE_SIZE;\n const offset = params.offset ?? 0;\n const { data } = await client.query({\n query: STUDIO_CATALOG_QUERY,\n variables: { filter: studioCatalogFilter(params.query ?? '', offset, limit) },\n fetchPolicy: 'network-only',\n });\n const nodes = (data as { formTemplateSubmissions?: { nodes?: StudioCatalogRow[] | null } } | null)\n ?.formTemplateSubmissions?.nodes;\n return looksFromCatalogNodes(nodes, limit);\n}\n\n/** Web `readViaBackend` — skip the agent pod entirely. */\nasync function listViaBackendFetch(\n graphqlUrl: string,\n token: string,\n params: { query?: string; offset?: number; limit?: number },\n): Promise<{ looks: StudioLook[]; hasMore: boolean }> {\n const limit = params.limit ?? LOOKS_PAGE_SIZE;\n const offset = params.offset ?? 0;\n const res = await fetch(graphqlUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n query: SUBMISSIONS_QUERY,\n variables: { filter: studioCatalogFilter(params.query ?? '', offset, limit) },\n }),\n });\n if (!res.ok) throw new Error(`Studio catalog read failed (${res.status})`);\n const json = (await res.json().catch(() => ({}))) as {\n data?: { formTemplateSubmissions?: { nodes?: StudioCatalogRow[] | null } };\n errors?: Array<{ message?: string }>;\n };\n if (json.errors?.length) {\n throw new Error(\n json.errors\n .map((e) => e?.message)\n .filter(Boolean)\n .join('; ') || 'Studio catalog read failed',\n );\n }\n const nodes = json.data?.formTemplateSubmissions?.nodes;\n if (!Array.isArray(nodes)) throw new Error('Backend returned no formTemplateSubmissions');\n return looksFromCatalogNodes(nodes, limit);\n}\n\nexport async function listStudioLooks(\n run: RunMediaAction | undefined,\n params: { query?: string; offset?: number; limit?: number } = {},\n options: ListStudioLooksOptions | StudioCatalogClient | null = {},\n): Promise<{ looks: StudioLook[]; hasMore: boolean }> {\n // Back-compat: third arg used to be apolloClient alone.\n const isLegacyClient =\n options != null &&\n typeof options === 'object' &&\n typeof (options as StudioCatalogClient).readQuery === 'function';\n const opts: ListStudioLooksOptions = isLegacyClient\n ? { client: options as StudioCatalogClient }\n : ((options as ListStudioLooksOptions | null) ?? {});\n\n const limit = params.limit ?? LOOKS_PAGE_SIZE;\n const offset = params.offset ?? 0;\n const query = params.query?.trim();\n const graphqlUrl = opts.indexUrl ? deriveBackendGraphqlUrl(opts.indexUrl) : null;\n\n if (opts.token && graphqlUrl) {\n try {\n return await listViaBackendFetch(graphqlUrl, opts.token, { query, offset, limit });\n } catch {\n // Apollo / connector fallbacks.\n }\n }\n\n if (opts.client) {\n try {\n // Successful empty page is final — do not escalate to the broken connector.\n return await listViaCatalog(opts.client, { query, offset, limit });\n } catch {\n // Connector fallback.\n }\n }\n\n if (!run) return { looks: [], hasMore: false };\n\n try {\n const result = await run('yantra-video-generation', 'YANTRA_VIDEO_LIST_STUDIO_TEMPLATES', {\n limit,\n offset,\n ...(query ? { query } : {}),\n });\n const page = normalize(result);\n return { looks: page.looks, hasMore: page.hasMore || page.looks.length >= limit };\n } catch {\n return { looks: [], hasMore: false };\n }\n}\n\nexport function nearestAspect(aspect: string, supported: readonly string[]): string | undefined {\n const wanted = aspect.trim();\n if (!wanted) return undefined;\n if (supported.includes(wanted)) return wanted;\n const ratio = (value: string): number | undefined => {\n const [w, h] = value.split(':').map(Number);\n return Number.isFinite(w) && Number.isFinite(h) && h > 0 ? w / h : undefined;\n };\n const target = ratio(wanted);\n if (target === undefined) return undefined;\n const portrait = target < 1;\n const sameOrientation = supported.filter((option) => {\n const r = ratio(option);\n return r !== undefined && (portrait ? r < 1 : r >= 1);\n });\n const pool = sameOrientation.length > 0 ? sameOrientation : supported;\n let best: string | undefined;\n let bestGap = Infinity;\n for (const option of pool) {\n const r = ratio(option);\n if (r === undefined) continue;\n const gap = Math.abs(r - target);\n if (gap < bestGap) {\n bestGap = gap;\n best = option;\n }\n }\n return best;\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import {useEffect,useRef}from'react';import {configureMediaSigning,isPresignedUrlExpiring,canonicalMediaUrl,signStoredMediaUrl}from'./mediaUrls.js';import {deriveAgentEndpoint}from'./videoEditor/remoteMediaClient.js';var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ async function renewBoardItemSrcs(items, run, nowMs = Date.now()) {
21
+ const stale = [...new Set(items.map((it) => it.src))].filter((src) => isPresignedUrlExpiring(canonicalMediaUrl(src), nowMs));
22
+ const out = /* @__PURE__ */ new Map();
23
+ await Promise.all(stale.map(async (src) => {
24
+ const fresh = await signStoredMediaUrl(run, canonicalMediaUrl(src)).catch(() => null);
25
+ if (fresh && fresh !== src) out.set(src, fresh);
26
+ }));
27
+ return out;
28
+ }
29
+ function applySrcRenewals(items, renewals) {
30
+ if (renewals.size === 0) return items;
31
+ let changed = false;
32
+ const next = items.map((item) => {
33
+ const fresh = renewals.get(item.src);
34
+ if (!fresh) return item;
35
+ changed = true;
36
+ return __spreadProps(__spreadValues({}, item), {
37
+ src: fresh
38
+ });
39
+ });
40
+ return changed ? next : items;
41
+ }
42
+ function useMediaSigning(token, indexUrl) {
43
+ useEffect(() => {
44
+ configureMediaSigning(token && indexUrl ? {
45
+ token,
46
+ agentEndpoint: deriveAgentEndpoint(indexUrl)
47
+ } : null);
48
+ }, [token, indexUrl]);
49
+ }
50
+ function useBoardMediaRefresh(boardId, items, run, apply) {
51
+ const itemsRef = useRef(items);
52
+ itemsRef.current = items;
53
+ const applyRef = useRef(apply);
54
+ applyRef.current = apply;
55
+ useEffect(() => {
56
+ const list = itemsRef.current;
57
+ if (!boardId || !(list == null ? void 0 : list.length)) return void 0;
58
+ let cancelled = false;
59
+ void renewBoardItemSrcs(list, run).then((renewals) => {
60
+ if (!cancelled && renewals.size > 0) applyRef.current(boardId, renewals);
61
+ });
62
+ return () => {
63
+ cancelled = true;
64
+ };
65
+ }, [boardId, run]);
66
+ }export{applySrcRenewals,renewBoardItemSrcs,useBoardMediaRefresh,useMediaSigning};//# sourceMappingURL=useBoardMediaRefresh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBoardMediaRefresh.js","sources":["../../../src/features/canvas/useBoardMediaRefresh.ts"],"sourcesContent":["/**\n * Board-level presigned link upkeep for the canvas screen (web\n * `state/boards.ts` pullBoard -> `refreshPresignedUrlsDeep`).\n *\n * When a board opens, every item whose presigned `src` is expired or lapsing\n * is re-signed, and the fresh URLs are written back into the board - so the\n * auto-save that follows persists them and the next open (on any device)\n * starts from live links instead of a 400 `ExpiredToken` per tile.\n */\nimport { useEffect, useRef } from 'react';\n\nimport type { CanvasItem } from './canvasCore';\nimport { canonicalMediaUrl, configureMediaSigning, isPresignedUrlExpiring, signStoredMediaUrl } from './mediaUrls';\nimport type { RunMediaAction } from './videoEditor/mediaActions';\nimport { deriveAgentEndpoint } from './videoEditor/remoteMediaClient';\n\n/** stale src -> fresh src, for the items whose link was renewed. */\nexport type SrcRenewals = ReadonlyMap<string, string>;\n\n/**\n * Re-sign every item src that is presigned and expiring. Empty map when\n * nothing needed (or could get) a fresh link. Never throws.\n */\nexport async function renewBoardItemSrcs(\n items: readonly CanvasItem[],\n run: RunMediaAction | undefined,\n nowMs = Date.now(),\n): Promise<Map<string, string>> {\n const stale = [...new Set(items.map((it) => it.src))].filter((src) =>\n isPresignedUrlExpiring(canonicalMediaUrl(src), nowMs),\n );\n const out = new Map<string, string>();\n await Promise.all(\n stale.map(async (src) => {\n const fresh = await signStoredMediaUrl(run, canonicalMediaUrl(src)).catch(() => null);\n if (fresh && fresh !== src) out.set(src, fresh);\n }),\n );\n return out;\n}\n\n/**\n * Items with renewed srcs swapped in. Only an item still holding the exact\n * stale src is touched, so an edit made while signing is never overwritten.\n * Returns the input array when nothing changed.\n */\nexport function applySrcRenewals<T extends Pick<CanvasItem, 'src'>>(items: readonly T[], renewals: SrcRenewals): T[] {\n if (renewals.size === 0) return items as T[];\n let changed = false;\n const next = items.map((item) => {\n const fresh = renewals.get(item.src);\n if (!fresh) return item;\n changed = true;\n return { ...item, src: fresh };\n });\n return changed ? next : (items as T[]);\n}\n\n/** Register the agent signer (`/v1/files/sign`) for this session's token + environment. */\nexport function useMediaSigning(token: string | null | undefined, indexUrl: string | null | undefined): void {\n useEffect(() => {\n configureMediaSigning(token && indexUrl ? { token, agentEndpoint: deriveAgentEndpoint(indexUrl) } : null);\n }, [token, indexUrl]);\n}\n\n/**\n * Renew a board's expiring links once each time it is opened. `apply` gets the\n * renewals for that board id; the host swaps them in with\n * {@link applySrcRenewals} and its usual save path persists the result.\n */\nexport function useBoardMediaRefresh(\n boardId: string | null | undefined,\n items: readonly CanvasItem[] | undefined,\n run: RunMediaAction | undefined,\n apply: (boardId: string, renewals: SrcRenewals) => void,\n): void {\n const itemsRef = useRef(items);\n itemsRef.current = items;\n const applyRef = useRef(apply);\n applyRef.current = apply;\n useEffect(() => {\n const list = itemsRef.current;\n if (!boardId || !list?.length) return undefined;\n let cancelled = false;\n void renewBoardItemSrcs(list, run).then((renewals) => {\n if (!cancelled && renewals.size > 0) applyRef.current(boardId, renewals);\n });\n return () => {\n cancelled = true;\n };\n // Once per open (and when the runner arrives): items are read through the ref.\n }, [boardId, run]);\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAsBA,eAAsB,mBAAmB,KAA8B,EAAA,GAAA,EAAiC,KAAQ,GAAA,IAAA,CAAK,KAAqC,EAAA;AACxJ,EAAM,MAAA,KAAA,GAAQ,CAAC,GAAG,IAAI,IAAI,KAAM,CAAA,GAAA,CAAI,QAAM,EAAG,CAAA,GAAG,CAAC,CAAC,CAAA,CAAE,OAAO,CAAO,GAAA,KAAA,sBAAA,CAAuB,kBAAkB,GAAG,CAAA,EAAG,KAAK,CAAC,CAAA;AACvH,EAAM,MAAA,GAAA,uBAAU,GAAoB,EAAA;AACpC,EAAA,MAAM,OAAQ,CAAA,GAAA,CAAI,KAAM,CAAA,GAAA,CAAI,OAAM,GAAO,KAAA;AACvC,IAAM,MAAA,KAAA,GAAQ,MAAM,kBAAA,CAAmB,GAAK,EAAA,iBAAA,CAAkB,GAAG,CAAC,CAAA,CAAE,KAAM,CAAA,MAAM,IAAI,CAAA;AACpF,IAAA,IAAI,SAAS,KAAU,KAAA,GAAA,EAAS,GAAA,CAAA,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,GAC/C,CAAC,CAAA;AACF,EAAO,OAAA,GAAA;AACT;AAOgB,SAAA,gBAAA,CAAoD,OAAqB,QAA4B,EAAA;AACnH,EAAI,IAAA,QAAA,CAAS,IAAS,KAAA,CAAA,EAAU,OAAA,KAAA;AAChC,EAAA,IAAI,OAAU,GAAA,KAAA;AACd,EAAM,MAAA,IAAA,GAAO,KAAM,CAAA,GAAA,CAAI,CAAQ,IAAA,KAAA;AAC7B,IAAA,MAAM,KAAQ,GAAA,QAAA,CAAS,GAAI,CAAA,IAAA,CAAK,GAAG,CAAA;AACnC,IAAI,IAAA,CAAC,OAAc,OAAA,IAAA;AACnB,IAAU,OAAA,GAAA,IAAA;AACV,IAAA,OAAO,iCACF,IADE,CAAA,EAAA;AAAA,MAEL,GAAK,EAAA;AAAA,KACP,CAAA;AAAA,GACD,CAAA;AACD,EAAA,OAAO,UAAU,IAAO,GAAA,KAAA;AAC1B;AAGgB,SAAA,eAAA,CAAgB,OAAkC,QAA2C,EAAA;AAC3G,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,qBAAA,CAAsB,SAAS,QAAW,GAAA;AAAA,MACxC,KAAA;AAAA,MACA,aAAA,EAAe,oBAAoB,QAAQ;AAAA,QACzC,IAAI,CAAA;AAAA,GACP,EAAA,CAAC,KAAO,EAAA,QAAQ,CAAC,CAAA;AACtB;AAOO,SAAS,oBAAqB,CAAA,OAAA,EAAoC,KAA0C,EAAA,GAAA,EAAiC,KAA+D,EAAA;AACjN,EAAM,MAAA,QAAA,GAAW,OAAO,KAAK,CAAA;AAC7B,EAAA,QAAA,CAAS,OAAU,GAAA,KAAA;AACnB,EAAM,MAAA,QAAA,GAAW,OAAO,KAAK,CAAA;AAC7B,EAAA,QAAA,CAAS,OAAU,GAAA,KAAA;AACnB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,OAAO,QAAS,CAAA,OAAA;AACtB,IAAA,IAAI,CAAC,OAAA,IAAW,EAAC,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAM,SAAe,OAAA,MAAA;AACtC,IAAA,IAAI,SAAY,GAAA,KAAA;AAChB,IAAA,KAAK,kBAAmB,CAAA,IAAA,EAAM,GAAG,CAAA,CAAE,KAAK,CAAY,QAAA,KAAA;AAClD,MAAI,IAAA,CAAC,aAAa,QAAS,CAAA,IAAA,GAAO,GAAY,QAAA,CAAA,OAAA,CAAQ,SAAS,QAAQ,CAAA;AAAA,KACxE,CAAA;AACD,IAAA,OAAO,MAAM;AACX,MAAY,SAAA,GAAA,IAAA;AAAA,KACd;AAAA,GAEC,EAAA,CAAC,OAAS,EAAA,GAAG,CAAC,CAAA;AACnB"}