@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.
- package/lib/features/apps/appArt.js +1 -1
- package/lib/features/apps/appArt.js.map +1 -1
- package/lib/features/apps/mobileAppCatalog.js +15 -11
- package/lib/features/apps/mobileAppCatalog.js.map +1 -1
- package/lib/features/canvas/CanvasAgentChatPane.js +82 -20
- package/lib/features/canvas/CanvasAgentChatPane.js.map +1 -1
- package/lib/features/canvas/CanvasBoardsGrid.js +291 -100
- package/lib/features/canvas/CanvasBoardsGrid.js.map +1 -1
- package/lib/features/canvas/CanvasEditToolsPanel.js +105 -12
- package/lib/features/canvas/CanvasEditToolsPanel.js.map +1 -1
- package/lib/features/canvas/CanvasExperience.js +266 -68
- package/lib/features/canvas/CanvasExperience.js.map +1 -1
- package/lib/features/canvas/CanvasGeneratePanel.js +204 -66
- package/lib/features/canvas/CanvasGeneratePanel.js.map +1 -1
- package/lib/features/canvas/CanvasLibrarySheet.js +31 -13
- package/lib/features/canvas/CanvasLibrarySheet.js.map +1 -1
- package/lib/features/canvas/CanvasModelPicker.js +176 -0
- package/lib/features/canvas/CanvasModelPicker.js.map +1 -0
- package/lib/features/canvas/CanvasTasksPanel.js +325 -29
- package/lib/features/canvas/CanvasTasksPanel.js.map +1 -1
- package/lib/features/canvas/CanvasTemplatesPanel.js +5 -4
- package/lib/features/canvas/CanvasTemplatesPanel.js.map +1 -1
- package/lib/features/canvas/CanvasToolDock.js +137 -61
- package/lib/features/canvas/CanvasToolDock.js.map +1 -1
- package/lib/features/canvas/FrameExtractorExperience.js +33 -2
- package/lib/features/canvas/FrameExtractorExperience.js.map +1 -1
- package/lib/features/canvas/GeneratorReferenceSlots.js +197 -0
- package/lib/features/canvas/GeneratorReferenceSlots.js.map +1 -0
- package/lib/features/canvas/NativeCanvasViewer.js +89 -11
- package/lib/features/canvas/NativeCanvasViewer.js.map +1 -1
- package/lib/features/canvas/PromoContextFields.js +55 -2
- package/lib/features/canvas/PromoContextFields.js.map +1 -1
- package/lib/features/canvas/SetStudioExperience.js +323 -13
- package/lib/features/canvas/SetStudioExperience.js.map +1 -1
- package/lib/features/canvas/VideoEditExperience.js +1 -53
- package/lib/features/canvas/VideoEditExperience.js.map +1 -1
- package/lib/features/canvas/VideoEditorExperience.js +697 -506
- package/lib/features/canvas/VideoEditorExperience.js.map +1 -1
- package/lib/features/canvas/VideoGeneratorExperience.js +22 -5
- package/lib/features/canvas/VideoGeneratorExperience.js.map +1 -1
- package/lib/features/canvas/canvasAgentChat.js +125 -11
- package/lib/features/canvas/canvasAgentChat.js.map +1 -1
- package/lib/features/canvas/canvasCore.js +117 -12
- package/lib/features/canvas/canvasCore.js.map +1 -1
- package/lib/features/canvas/canvasEditOps.js +148 -111
- package/lib/features/canvas/canvasEditOps.js.map +1 -1
- package/lib/features/canvas/canvasTaskSync.js +235 -0
- package/lib/features/canvas/canvasTaskSync.js.map +1 -0
- package/lib/features/canvas/canvasTasks.js +98 -11
- package/lib/features/canvas/canvasTasks.js.map +1 -1
- package/lib/features/canvas/createTiles.js +247 -0
- package/lib/features/canvas/createTiles.js.map +1 -0
- package/lib/features/canvas/deepLinks.js +83 -0
- package/lib/features/canvas/deepLinks.js.map +1 -0
- package/lib/features/canvas/frameExtract.js +13 -1
- package/lib/features/canvas/frameExtract.js.map +1 -1
- package/lib/features/canvas/generationModels.js +36 -8
- package/lib/features/canvas/generationModels.js.map +1 -1
- package/lib/features/canvas/generatorCommands.js +106 -0
- package/lib/features/canvas/generatorCommands.js.map +1 -0
- package/lib/features/canvas/generatorReferences.js +82 -0
- package/lib/features/canvas/generatorReferences.js.map +1 -0
- package/lib/features/canvas/homeWork.js +74 -0
- package/lib/features/canvas/homeWork.js.map +1 -0
- package/lib/features/canvas/linksRpc.js +130 -0
- package/lib/features/canvas/linksRpc.js.map +1 -0
- package/lib/features/canvas/mediaRecheck.js +176 -0
- package/lib/features/canvas/mediaRecheck.js.map +1 -0
- package/lib/features/canvas/mediaUrls.js +258 -0
- package/lib/features/canvas/mediaUrls.js.map +1 -0
- package/lib/features/canvas/nativeViewerRegistry.js.map +1 -1
- package/lib/features/canvas/promoProjectImport.js +80 -13
- package/lib/features/canvas/promoProjectImport.js.map +1 -1
- package/lib/features/canvas/promoVideo.js +106 -15
- package/lib/features/canvas/promoVideo.js.map +1 -1
- package/lib/features/canvas/reframe.js +228 -0
- package/lib/features/canvas/reframe.js.map +1 -0
- package/lib/features/canvas/serverTasks.js +697 -0
- package/lib/features/canvas/serverTasks.js.map +1 -0
- package/lib/features/canvas/set/SetViewportWebView.js +207 -28
- package/lib/features/canvas/set/SetViewportWebView.js.map +1 -1
- package/lib/features/canvas/set/agent/prompt.js +66 -0
- package/lib/features/canvas/set/agent/prompt.js.map +1 -0
- package/lib/features/canvas/set/agent/setOps.js +203 -0
- package/lib/features/canvas/set/agent/setOps.js.map +1 -0
- package/lib/features/canvas/set/agent/setTurn.js +128 -0
- package/lib/features/canvas/set/agent/setTurn.js.map +1 -0
- package/lib/features/canvas/set/agent/snapshot.js +43 -0
- package/lib/features/canvas/set/agent/snapshot.js.map +1 -0
- package/lib/features/canvas/set/agent/tools.js +580 -0
- package/lib/features/canvas/set/agent/tools.js.map +1 -0
- package/lib/features/canvas/set/setProject.js +43 -4
- package/lib/features/canvas/set/setProject.js.map +1 -1
- package/lib/features/canvas/set/supplyLibrary.js +397 -0
- package/lib/features/canvas/set/supplyLibrary.js.map +1 -0
- package/lib/features/canvas/storageLibrary.js +113 -52
- package/lib/features/canvas/storageLibrary.js.map +1 -1
- package/lib/features/canvas/studioCatalog.js +15 -2
- package/lib/features/canvas/studioCatalog.js.map +1 -1
- package/lib/features/canvas/studioLooks.js +1 -8
- package/lib/features/canvas/studioLooks.js.map +1 -1
- package/lib/features/canvas/useBoardMediaRefresh.js +66 -0
- package/lib/features/canvas/useBoardMediaRefresh.js.map +1 -0
- package/lib/features/canvas/useMediaSource.js +84 -0
- package/lib/features/canvas/useMediaSource.js.map +1 -0
- package/lib/features/canvas/video3d.js +11 -10
- package/lib/features/canvas/video3d.js.map +1 -1
- package/lib/features/canvas/videoEditor/BlurBoxOverlay.js +46 -0
- package/lib/features/canvas/videoEditor/BlurBoxOverlay.js.map +1 -0
- package/lib/features/canvas/videoEditor/ExportTaskCard.js +134 -0
- package/lib/features/canvas/videoEditor/ExportTaskCard.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/AgentCutPane.js +45 -7
- package/lib/features/canvas/videoEditor/agent/AgentCutPane.js.map +1 -1
- package/lib/features/canvas/videoEditor/agent/agentLoop.js +4 -2
- package/lib/features/canvas/videoEditor/agent/agentLoop.js.map +1 -1
- package/lib/features/canvas/videoEditor/agent/attachments.js +304 -0
- package/lib/features/canvas/videoEditor/agent/attachments.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/brainClient.js +3 -2
- package/lib/features/canvas/videoEditor/agent/brainClient.js.map +1 -1
- package/lib/features/canvas/videoEditor/agent/cutTools.js +207 -7
- package/lib/features/canvas/videoEditor/agent/cutTools.js.map +1 -1
- package/lib/features/canvas/videoEditor/blurBox.js +34 -0
- package/lib/features/canvas/videoEditor/blurBox.js.map +1 -0
- package/lib/features/canvas/videoEditor/compileTimeline.js +668 -0
- package/lib/features/canvas/videoEditor/compileTimeline.js.map +1 -0
- package/lib/features/canvas/videoEditor/editorModel.js +56 -22
- package/lib/features/canvas/videoEditor/editorModel.js.map +1 -1
- package/lib/features/canvas/videoEditor/exportPipeline.js +77 -0
- package/lib/features/canvas/videoEditor/exportPipeline.js.map +1 -0
- package/lib/features/canvas/videoEditor/exportRenderer.js +19 -12
- package/lib/features/canvas/videoEditor/exportRenderer.js.map +1 -1
- package/lib/features/canvas/videoEditor/exportTask.js +216 -0
- package/lib/features/canvas/videoEditor/exportTask.js.map +1 -0
- package/lib/features/canvas/videoEditor/formWidgets.js +142 -0
- package/lib/features/canvas/videoEditor/formWidgets.js.map +1 -0
- package/lib/features/canvas/videoEditor/produce/ProduceVideoSheet.js +195 -0
- package/lib/features/canvas/videoEditor/produce/ProduceVideoSheet.js.map +1 -0
- package/lib/features/canvas/videoEditor/produce/produceScenes.js +158 -0
- package/lib/features/canvas/videoEditor/produce/produceScenes.js.map +1 -0
- package/lib/features/canvas/videoEditor/remoteMediaClient.js +17 -5
- package/lib/features/canvas/videoEditor/remoteMediaClient.js.map +1 -1
- package/lib/features/canvas/videoEditor/renderTimeline.js +207 -0
- package/lib/features/canvas/videoEditor/renderTimeline.js.map +1 -0
- package/lib/features/canvas/videoEditor/renewLinks.js +64 -0
- package/lib/features/canvas/videoEditor/renewLinks.js.map +1 -0
- package/lib/features/canvas/videoEditor/sceneLayers.js +101 -0
- package/lib/features/canvas/videoEditor/sceneLayers.js.map +1 -0
- package/lib/features/canvas/videoEditor/tools/ToolsDrawer.js +283 -0
- package/lib/features/canvas/videoEditor/tools/ToolsDrawer.js.map +1 -0
- package/lib/features/canvas/videoEditor/tools/catalog.js +576 -0
- package/lib/features/canvas/videoEditor/tools/catalog.js.map +1 -0
- package/lib/features/canvas/videoEditor/videoProjectsStore.js +27 -3
- package/lib/features/canvas/videoEditor/videoProjectsStore.js.map +1 -1
- package/lib/features/webbuilder/WebBuilderExperience.js +29 -1
- package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -1
- package/lib/features/webbuilder/buildFragments.js +8 -4
- package/lib/features/webbuilder/buildFragments.js.map +1 -1
- package/lib/features/webbuilder/codezenHandoff.js +108 -0
- package/lib/features/webbuilder/codezenHandoff.js.map +1 -0
- package/lib/features/webbuilder/workflow.js.map +1 -1
- package/lib/hooks/useChatApi.js +1 -2
- package/lib/hooks/useChatApi.js.map +1 -1
- package/lib/screens/CanvasBoard/index.js +12 -1
- package/lib/screens/CanvasBoard/index.js.map +1 -1
- package/lib/screens/Home/HomeScreen.js.map +1 -1
- package/lib/screens/Home/components/HomeSuggestions.js +3 -3
- package/lib/screens/Home/components/HomeSuggestions.js.map +1 -1
- package/lib/screens/WebBuilder/index.js +4 -2
- package/lib/screens/WebBuilder/index.js.map +1 -1
- package/lib/screens/WebBuilderNative/index.js +29 -2
- package/lib/screens/WebBuilderNative/index.js.map +1 -1
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js +30 -6
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -1
- package/package.json +3 -3
- /package/lib/assets/apps/{paper2poster.webp → poster.webp} +0 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import {useSyncExternalStore}from'react';import {AppState}from'react-native';var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
const CHECK_SCHEDULE = [{
|
|
18
|
+
untilMs: 2 * 6e4,
|
|
19
|
+
everyMs: 5e3
|
|
20
|
+
}, {
|
|
21
|
+
untilMs: 10 * 6e4,
|
|
22
|
+
everyMs: 3e4
|
|
23
|
+
}];
|
|
24
|
+
const GIVE_UP_AFTER_MS = CHECK_SCHEDULE[CHECK_SCHEDULE.length - 1].untilMs;
|
|
25
|
+
const PROBE_TIMEOUT_MS = 2e4;
|
|
26
|
+
const PENDING_STATE = {
|
|
27
|
+
status: "pending"
|
|
28
|
+
};
|
|
29
|
+
const GAVE_UP_STATE = {
|
|
30
|
+
status: "gave_up"
|
|
31
|
+
};
|
|
32
|
+
const pending = /* @__PURE__ */ new Map();
|
|
33
|
+
const settled = /* @__PURE__ */ new Map();
|
|
34
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
35
|
+
let timer;
|
|
36
|
+
let wakeAttached = false;
|
|
37
|
+
let probe = probeMedia;
|
|
38
|
+
function markMediaFailed(url, kind) {
|
|
39
|
+
if (!url || pending.has(url) || settled.get(url) === GAVE_UP_STATE) return;
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
settled.delete(url);
|
|
42
|
+
pending.set(url, {
|
|
43
|
+
kind,
|
|
44
|
+
markedAt: now,
|
|
45
|
+
nextCheckAt: now + CHECK_SCHEDULE[0].everyMs,
|
|
46
|
+
probing: false
|
|
47
|
+
});
|
|
48
|
+
attachWakeListener();
|
|
49
|
+
notify(url);
|
|
50
|
+
scheduleNextTick();
|
|
51
|
+
}
|
|
52
|
+
function getMediaRecheckState(url) {
|
|
53
|
+
if (pending.has(url)) return PENDING_STATE;
|
|
54
|
+
return settled.get(url);
|
|
55
|
+
}
|
|
56
|
+
function useMediaRecheck(url) {
|
|
57
|
+
return useSyncExternalStore((onChange) => url ? watchMediaRecheck(url, onChange) : () => void 0, () => url ? getMediaRecheckState(url) : void 0, () => void 0);
|
|
58
|
+
}
|
|
59
|
+
function appActive() {
|
|
60
|
+
var _a;
|
|
61
|
+
const state = (_a = AppState) == null ? void 0 : _a.currentState;
|
|
62
|
+
return !state || state === "active" || state === "unknown";
|
|
63
|
+
}
|
|
64
|
+
function scheduleNextTick() {
|
|
65
|
+
if (timer) clearTimeout(timer);
|
|
66
|
+
timer = void 0;
|
|
67
|
+
if (pending.size === 0) return;
|
|
68
|
+
let earliest = Infinity;
|
|
69
|
+
for (const entry of pending.values()) {
|
|
70
|
+
if (!entry.probing) earliest = Math.min(earliest, entry.nextCheckAt);
|
|
71
|
+
}
|
|
72
|
+
if (earliest === Infinity) return;
|
|
73
|
+
timer = setTimeout(tick, Math.max(0, earliest - Date.now()));
|
|
74
|
+
}
|
|
75
|
+
function tick() {
|
|
76
|
+
var _a;
|
|
77
|
+
timer = void 0;
|
|
78
|
+
if (!appActive()) return;
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
for (const [url, entry] of pending) {
|
|
81
|
+
if (entry.probing || entry.nextCheckAt > now) continue;
|
|
82
|
+
if (!((_a = listeners.get(url)) == null ? void 0 : _a.size)) {
|
|
83
|
+
pending.delete(url);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (now - entry.markedAt >= GIVE_UP_AFTER_MS) {
|
|
87
|
+
pending.delete(url);
|
|
88
|
+
settled.set(url, GAVE_UP_STATE);
|
|
89
|
+
notify(url);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
runProbe(url, entry);
|
|
93
|
+
}
|
|
94
|
+
scheduleNextTick();
|
|
95
|
+
}
|
|
96
|
+
function runProbe(url, entry) {
|
|
97
|
+
entry.probing = true;
|
|
98
|
+
const src = withCacheBust(url);
|
|
99
|
+
void probe(src, entry.kind).then((loaded) => {
|
|
100
|
+
if (pending.get(url) !== entry) return;
|
|
101
|
+
if (loaded) {
|
|
102
|
+
pending.delete(url);
|
|
103
|
+
settled.set(url, {
|
|
104
|
+
status: "ready",
|
|
105
|
+
src,
|
|
106
|
+
recoveredAt: Date.now()
|
|
107
|
+
});
|
|
108
|
+
notify(url);
|
|
109
|
+
} else {
|
|
110
|
+
entry.probing = false;
|
|
111
|
+
entry.nextCheckAt = Date.now() + checkInterval(Date.now() - entry.markedAt);
|
|
112
|
+
}
|
|
113
|
+
scheduleNextTick();
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function checkInterval(ageMs) {
|
|
117
|
+
const slot = CHECK_SCHEDULE.find((w) => ageMs < w.untilMs);
|
|
118
|
+
return (slot != null ? slot : CHECK_SCHEDULE[CHECK_SCHEDULE.length - 1]).everyMs;
|
|
119
|
+
}
|
|
120
|
+
function attachWakeListener() {
|
|
121
|
+
var _a;
|
|
122
|
+
if (wakeAttached || !((_a = AppState) == null ? void 0 : _a.addEventListener)) return;
|
|
123
|
+
wakeAttached = true;
|
|
124
|
+
AppState.addEventListener("change", (state) => {
|
|
125
|
+
if (state !== "active" || pending.size === 0) return;
|
|
126
|
+
const now = Date.now();
|
|
127
|
+
for (const entry of pending.values()) entry.nextCheckAt = Math.min(entry.nextCheckAt, now);
|
|
128
|
+
scheduleNextTick();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function watchMediaRecheck(url, onChange) {
|
|
132
|
+
let set = listeners.get(url);
|
|
133
|
+
if (!set) {
|
|
134
|
+
set = /* @__PURE__ */ new Set();
|
|
135
|
+
listeners.set(url, set);
|
|
136
|
+
}
|
|
137
|
+
set.add(onChange);
|
|
138
|
+
return () => {
|
|
139
|
+
set.delete(onChange);
|
|
140
|
+
if (set.size === 0 && listeners.get(url) === set) listeners.delete(url);
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function notify(url) {
|
|
144
|
+
var _a;
|
|
145
|
+
(_a = listeners.get(url)) == null ? void 0 : _a.forEach((cb) => cb());
|
|
146
|
+
}
|
|
147
|
+
function withCacheBust(url, now = Date.now()) {
|
|
148
|
+
if (!/^https?:\/\//i.test(url)) return url;
|
|
149
|
+
const hashAt = url.indexOf("#");
|
|
150
|
+
const base = hashAt >= 0 ? url.slice(0, hashAt) : url;
|
|
151
|
+
const hash = hashAt >= 0 ? url.slice(hashAt) : "";
|
|
152
|
+
const query = base.includes("?") ? base.slice(base.indexOf("?") + 1) : "";
|
|
153
|
+
if (/(^|&)X-(Goog|Amz)-Signature=/.test(query)) return url;
|
|
154
|
+
const kept = query.split("&").filter((p) => p && !p.startsWith("_r=")).join("&");
|
|
155
|
+
const path = base.includes("?") ? base.slice(0, base.indexOf("?")) : base;
|
|
156
|
+
return `${path}?${kept ? `${kept}&` : ""}_r=${now}${hash}`;
|
|
157
|
+
}
|
|
158
|
+
async function probeMedia(src) {
|
|
159
|
+
const controller = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
160
|
+
const deadline = setTimeout(() => controller == null ? void 0 : controller.abort(), PROBE_TIMEOUT_MS);
|
|
161
|
+
try {
|
|
162
|
+
const resp = await fetch(src, __spreadValues({
|
|
163
|
+
method: "GET",
|
|
164
|
+
headers: {
|
|
165
|
+
Range: "bytes=0-0"
|
|
166
|
+
}
|
|
167
|
+
}, controller ? {
|
|
168
|
+
signal: controller.signal
|
|
169
|
+
} : {}));
|
|
170
|
+
return resp.ok || resp.status === 206;
|
|
171
|
+
} catch (e) {
|
|
172
|
+
return false;
|
|
173
|
+
} finally {
|
|
174
|
+
clearTimeout(deadline);
|
|
175
|
+
}
|
|
176
|
+
}export{GIVE_UP_AFTER_MS,PROBE_TIMEOUT_MS,checkInterval,getMediaRecheckState,markMediaFailed,useMediaRecheck,watchMediaRecheck,withCacheBust};//# sourceMappingURL=mediaRecheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mediaRecheck.js","sources":["../../../src/features/canvas/mediaRecheck.ts"],"sourcesContent":["/**\n * Native twin of canvas-surface `components/media/mediaRecheck.ts` - one\n * shared re-check for media that failed to load but may still come good.\n *\n * A tile whose image failed used to re-sign once and give up, so one\n * transient failure (dropped connection, bucket 5xx) left a broken tile on a\n * file that was fine a second later. A tile marks such a URL here instead; one\n * checker probes every marked URL on a backoff until it loads, and the tiles\n * showing it swap the media back in.\n *\n * Schedule: every 5s for two minutes, then every 30s up to ten minutes, then\n * give up. Paused while the app is backgrounded, checked at once when it comes\n * back to the foreground. A URL no tile shows any more is dropped at its next\n * check.\n *\n * Probe: a ranged GET (`bytes=0-0`). Unlike the browser, the phone has no CORS\n * to dodge, and a presigned signature covers the method and host - not the\n * Range header - so a GET probe answers exactly what the tile will see.\n * A probe adds `_r=<now>` to bust caches EXCEPT on a presigned URL, whose\n * signature covers every query param; that one is probed as is, and the tile\n * reloads it by remounting its element (`recoveredAt` keys it).\n *\n * The original is ported and trimmed from ArtCraft's\n * `pending-video-thumbnails.ts` (MIT; see the web file for the full notice).\n */\nimport { useSyncExternalStore } from 'react';\nimport { AppState } from 'react-native';\n\nexport type MediaKind = 'image' | 'video' | 'audio';\n\nexport type MediaRecheckState =\n | { status: 'ready'; src: string; recoveredAt: number }\n | { status: 'pending' }\n | { status: 'gave_up' };\n\nconst CHECK_SCHEDULE: ReadonlyArray<{ untilMs: number; everyMs: number }> = [\n { untilMs: 2 * 60_000, everyMs: 5_000 },\n { untilMs: 10 * 60_000, everyMs: 30_000 },\n];\n\nexport const GIVE_UP_AFTER_MS = CHECK_SCHEDULE[CHECK_SCHEDULE.length - 1].untilMs;\nexport const PROBE_TIMEOUT_MS = 20_000;\n\n/** True when the probed URL loaded. Never rejects. */\nexport type MediaProbe = (src: string, kind: MediaKind) => Promise<boolean>;\n\ninterface PendingEntry {\n kind: MediaKind;\n markedAt: number;\n nextCheckAt: number;\n probing: boolean;\n}\n\nconst PENDING_STATE: MediaRecheckState = { status: 'pending' };\nconst GAVE_UP_STATE: MediaRecheckState = { status: 'gave_up' };\n\nconst pending = new Map<string, PendingEntry>();\nconst settled = new Map<string, MediaRecheckState>();\nconst listeners = new Map<string, Set<() => void>>();\n\nlet timer: ReturnType<typeof setTimeout> | undefined;\nlet wakeAttached = false;\nlet probe: MediaProbe = probeMedia;\n\n/**\n * Mark a URL that failed to load. Already-checked is free; one that recovered\n * and failed again starts over; one given up on stays given up this session.\n */\nexport function markMediaFailed(url: string, kind: MediaKind): void {\n if (!url || pending.has(url) || settled.get(url) === GAVE_UP_STATE) return;\n const now = Date.now();\n settled.delete(url);\n pending.set(url, { kind, markedAt: now, nextCheckAt: now + CHECK_SCHEDULE[0].everyMs, probing: false });\n attachWakeListener();\n notify(url);\n scheduleNextTick();\n}\n\nexport function getMediaRecheckState(url: string): MediaRecheckState | undefined {\n if (pending.has(url)) return PENDING_STATE;\n return settled.get(url);\n}\n\n/** The re-check state of a URL; untracked URLs (the normal case) are `undefined`. Null opts out. */\nexport function useMediaRecheck(url: string | null): MediaRecheckState | undefined {\n return useSyncExternalStore(\n (onChange) => (url ? watchMediaRecheck(url, onChange) : () => undefined),\n () => (url ? getMediaRecheckState(url) : undefined),\n () => undefined,\n );\n}\n\nexport function resetMediaRecheckForTests(): void {\n pending.clear();\n settled.clear();\n listeners.clear();\n if (timer) clearTimeout(timer);\n timer = undefined;\n probe = probeMedia;\n}\n\nexport function setMediaProbeForTests(next: MediaProbe): void {\n probe = next;\n}\n\nfunction appActive(): boolean {\n const state = AppState?.currentState;\n return !state || state === 'active' || state === 'unknown';\n}\n\nfunction scheduleNextTick(): void {\n if (timer) clearTimeout(timer);\n timer = undefined;\n if (pending.size === 0) return;\n let earliest = Infinity;\n for (const entry of pending.values()) {\n if (!entry.probing) earliest = Math.min(earliest, entry.nextCheckAt);\n }\n if (earliest === Infinity) return;\n timer = setTimeout(tick, Math.max(0, earliest - Date.now()));\n}\n\nfunction tick(): void {\n timer = undefined;\n // Paused in the background; the AppState listener resumes it.\n if (!appActive()) return;\n const now = Date.now();\n for (const [url, entry] of pending) {\n if (entry.probing || entry.nextCheckAt > now) continue;\n if (!listeners.get(url)?.size) {\n pending.delete(url);\n continue;\n }\n if (now - entry.markedAt >= GIVE_UP_AFTER_MS) {\n pending.delete(url);\n settled.set(url, GAVE_UP_STATE);\n notify(url);\n continue;\n }\n runProbe(url, entry);\n }\n scheduleNextTick();\n}\n\nfunction runProbe(url: string, entry: PendingEntry): void {\n entry.probing = true;\n const src = withCacheBust(url);\n void probe(src, entry.kind).then((loaded) => {\n if (pending.get(url) !== entry) return;\n if (loaded) {\n pending.delete(url);\n settled.set(url, { status: 'ready', src, recoveredAt: Date.now() });\n notify(url);\n } else {\n entry.probing = false;\n entry.nextCheckAt = Date.now() + checkInterval(Date.now() - entry.markedAt);\n }\n scheduleNextTick();\n });\n}\n\nexport function checkInterval(ageMs: number): number {\n const slot = CHECK_SCHEDULE.find((w) => ageMs < w.untilMs);\n return (slot ?? CHECK_SCHEDULE[CHECK_SCHEDULE.length - 1]).everyMs;\n}\n\nfunction attachWakeListener(): void {\n if (wakeAttached || !AppState?.addEventListener) return;\n wakeAttached = true;\n AppState.addEventListener('change', (state) => {\n if (state !== 'active' || pending.size === 0) return;\n const now = Date.now();\n for (const entry of pending.values()) entry.nextCheckAt = Math.min(entry.nextCheckAt, now);\n scheduleNextTick();\n });\n}\n\nexport function watchMediaRecheck(url: string, onChange: () => void): () => void {\n let set = listeners.get(url);\n if (!set) {\n set = new Set();\n listeners.set(url, set);\n }\n set.add(onChange);\n return () => {\n set.delete(onChange);\n if (set.size === 0 && listeners.get(url) === set) listeners.delete(url);\n };\n}\n\nfunction notify(url: string): void {\n listeners.get(url)?.forEach((cb) => cb());\n}\n\n/** The URL to probe: a cache-busted copy, unless busting would void a signature. */\nexport function withCacheBust(url: string, now = Date.now()): string {\n if (!/^https?:\\/\\//i.test(url)) return url;\n const hashAt = url.indexOf('#');\n const base = hashAt >= 0 ? url.slice(0, hashAt) : url;\n const hash = hashAt >= 0 ? url.slice(hashAt) : '';\n const query = base.includes('?') ? base.slice(base.indexOf('?') + 1) : '';\n if (/(^|&)X-(Goog|Amz)-Signature=/.test(query)) return url;\n const kept = query\n .split('&')\n .filter((p) => p && !p.startsWith('_r='))\n .join('&');\n const path = base.includes('?') ? base.slice(0, base.indexOf('?')) : base;\n return `${path}?${kept ? `${kept}&` : ''}_r=${now}${hash}`;\n}\n\n/** The real probe: a one-byte ranged GET, aborted at {@link PROBE_TIMEOUT_MS}. */\nasync function probeMedia(src: string): Promise<boolean> {\n const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;\n const deadline = setTimeout(() => controller?.abort(), PROBE_TIMEOUT_MS);\n try {\n const resp = await fetch(src, {\n method: 'GET',\n headers: { Range: 'bytes=0-0' },\n ...(controller ? { signal: controller.signal } : {}),\n });\n return resp.ok || resp.status === 206;\n } catch {\n return false;\n } finally {\n clearTimeout(deadline);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
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
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
|
|
21
|
+
const SIGNATURE_SCHEMES = [{
|
|
22
|
+
date: "X-Goog-Date",
|
|
23
|
+
expires: "X-Goog-Expires",
|
|
24
|
+
signature: "X-Goog-Signature"
|
|
25
|
+
}, {
|
|
26
|
+
date: "X-Amz-Date",
|
|
27
|
+
expires: "X-Amz-Expires",
|
|
28
|
+
signature: "X-Amz-Signature"
|
|
29
|
+
}];
|
|
30
|
+
const PRESIGN_EXPIRY_SKEW_MS = 10 * 6e4;
|
|
31
|
+
const STORED_MEDIA_URL_TTL_SECONDS = 7 * 24 * 60 * 60;
|
|
32
|
+
const AGENT_PROXY_PATH = "/v1/files/proxy";
|
|
33
|
+
function parseUrl(url) {
|
|
34
|
+
var _a;
|
|
35
|
+
const m = /^([a-z][a-z0-9+.-]*:)\/\/([^/?#]*)([^?#]*)(?:\?([^#]*))?/i.exec(url.trim());
|
|
36
|
+
if (!m) return null;
|
|
37
|
+
return {
|
|
38
|
+
protocol: m[1].toLowerCase(),
|
|
39
|
+
host: m[2].toLowerCase(),
|
|
40
|
+
pathname: m[3] || "/",
|
|
41
|
+
query: (_a = m[4]) != null ? _a : ""
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function queryParam(query, name) {
|
|
45
|
+
for (const pair of query.split("&")) {
|
|
46
|
+
const eq = pair.indexOf("=");
|
|
47
|
+
const key = eq >= 0 ? pair.slice(0, eq) : pair;
|
|
48
|
+
if (key !== name) continue;
|
|
49
|
+
const raw = eq >= 0 ? pair.slice(eq + 1) : "";
|
|
50
|
+
try {
|
|
51
|
+
return decodeURIComponent(raw.replace(/\+/g, " "));
|
|
52
|
+
} catch (e) {
|
|
53
|
+
return raw;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
function unwrapProxyUrl(src) {
|
|
59
|
+
if (!src.includes(AGENT_PROXY_PATH)) return src;
|
|
60
|
+
const q = src.indexOf("?");
|
|
61
|
+
const path = (q >= 0 ? src.slice(0, q) : src).split("#")[0];
|
|
62
|
+
if (!path.endsWith(AGENT_PROXY_PATH)) return src;
|
|
63
|
+
return (q >= 0 ? queryParam(src.slice(q + 1).split("#")[0], "url") : null) || src;
|
|
64
|
+
}
|
|
65
|
+
function carriesSignature(url) {
|
|
66
|
+
return url.includes("X-Goog-Signature=") || url.includes("X-Amz-Signature=");
|
|
67
|
+
}
|
|
68
|
+
function canonicalMediaUrl(url) {
|
|
69
|
+
const inner = unwrapProxyUrl(url);
|
|
70
|
+
return inner !== url && carriesSignature(inner) ? inner : url;
|
|
71
|
+
}
|
|
72
|
+
function isPresignedMediaUrl(url) {
|
|
73
|
+
return carriesSignature(unwrapProxyUrl(url));
|
|
74
|
+
}
|
|
75
|
+
function parseSignatureDate(value) {
|
|
76
|
+
const m = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/.exec(value);
|
|
77
|
+
if (!m) return null;
|
|
78
|
+
return Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3]), Number(m[4]), Number(m[5]), Number(m[6]));
|
|
79
|
+
}
|
|
80
|
+
function presignedUrlExpiresAtMs(url) {
|
|
81
|
+
var _a;
|
|
82
|
+
const parsed = parseUrl(unwrapProxyUrl(url));
|
|
83
|
+
if (!parsed) return null;
|
|
84
|
+
for (const scheme of SIGNATURE_SCHEMES) {
|
|
85
|
+
if (!queryParam(parsed.query, scheme.signature)) continue;
|
|
86
|
+
const signedAt = parseSignatureDate((_a = queryParam(parsed.query, scheme.date)) != null ? _a : "");
|
|
87
|
+
const lifetimeSec = Number(queryParam(parsed.query, scheme.expires));
|
|
88
|
+
if (signedAt === null || !Number.isFinite(lifetimeSec) || lifetimeSec <= 0) return null;
|
|
89
|
+
return signedAt + lifetimeSec * 1e3;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const ENCODED_PERCENT = /%25[0-9a-f]{2}/i;
|
|
94
|
+
function isMisencodedPresignedUrl(url) {
|
|
95
|
+
const inner = unwrapProxyUrl(url);
|
|
96
|
+
if (!carriesSignature(inner)) return false;
|
|
97
|
+
const parsed = parseUrl(inner);
|
|
98
|
+
return Boolean(parsed && ENCODED_PERCENT.test(parsed.pathname));
|
|
99
|
+
}
|
|
100
|
+
function isPresignedUrlExpiring(url, nowMs = Date.now(), skewMs = PRESIGN_EXPIRY_SKEW_MS) {
|
|
101
|
+
if (!isPresignedMediaUrl(url)) return false;
|
|
102
|
+
if (isMisencodedPresignedUrl(url)) return true;
|
|
103
|
+
const expiresAt = presignedUrlExpiresAtMs(url);
|
|
104
|
+
if (expiresAt === null) return true;
|
|
105
|
+
return expiresAt - nowMs <= skewMs;
|
|
106
|
+
}
|
|
107
|
+
function decodeFully(path) {
|
|
108
|
+
let current = path;
|
|
109
|
+
for (let i = 0; i < 8; i += 1) {
|
|
110
|
+
let next;
|
|
111
|
+
try {
|
|
112
|
+
next = decodeURIComponent(current);
|
|
113
|
+
} catch (e) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
if (next === current) break;
|
|
117
|
+
current = next;
|
|
118
|
+
}
|
|
119
|
+
return current;
|
|
120
|
+
}
|
|
121
|
+
const AWS_VIRTUAL_HOST = /^([^.]+)\.s3(?:[.-][a-z0-9-]+)?\.amazonaws\.com$/i;
|
|
122
|
+
const AWS_PATH_HOST = /^s3(?:[.-][a-z0-9-]+)?\.amazonaws\.com$/i;
|
|
123
|
+
function storageObjectRef(url) {
|
|
124
|
+
const parsed = parseUrl(unwrapProxyUrl(url));
|
|
125
|
+
if (!parsed || parsed.protocol !== "https:") return null;
|
|
126
|
+
const path = parsed.pathname.replace(/^\/+/, "");
|
|
127
|
+
let bucket;
|
|
128
|
+
let rawKey;
|
|
129
|
+
const virtual = AWS_VIRTUAL_HOST.exec(parsed.host);
|
|
130
|
+
if (virtual) {
|
|
131
|
+
bucket = virtual[1];
|
|
132
|
+
rawKey = path;
|
|
133
|
+
} else if (AWS_PATH_HOST.test(parsed.host)) {
|
|
134
|
+
const slash = path.indexOf("/");
|
|
135
|
+
if (slash <= 0) return null;
|
|
136
|
+
bucket = path.slice(0, slash);
|
|
137
|
+
rawKey = path.slice(slash + 1);
|
|
138
|
+
} else {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
if (!rawKey) return null;
|
|
142
|
+
let key;
|
|
143
|
+
if (ENCODED_PERCENT.test(rawKey)) key = decodeFully(rawKey);
|
|
144
|
+
else {
|
|
145
|
+
try {
|
|
146
|
+
key = decodeURIComponent(rawKey);
|
|
147
|
+
} catch (e) {
|
|
148
|
+
key = rawKey;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return `s3://${bucket}/${key}`;
|
|
152
|
+
}
|
|
153
|
+
let signingConfig = null;
|
|
154
|
+
const freshSignedUrlCache = /* @__PURE__ */ new Map();
|
|
155
|
+
let filesSignUnavailable = false;
|
|
156
|
+
function configureMediaSigning(config) {
|
|
157
|
+
const next = (config == null ? void 0 : config.token) && config.agentEndpoint ? config : null;
|
|
158
|
+
const changed = (next == null ? void 0 : next.agentEndpoint) !== (signingConfig == null ? void 0 : signingConfig.agentEndpoint) || (next == null ? void 0 : next.token) !== (signingConfig == null ? void 0 : signingConfig.token);
|
|
159
|
+
signingConfig = next ? __spreadProps(__spreadValues({}, next), {
|
|
160
|
+
agentEndpoint: next.agentEndpoint.replace(/\/+$/, "")
|
|
161
|
+
}) : null;
|
|
162
|
+
if (changed) filesSignUnavailable = false;
|
|
163
|
+
}
|
|
164
|
+
async function signViaAgent(url) {
|
|
165
|
+
const config = signingConfig;
|
|
166
|
+
if (!config || filesSignUnavailable) return null;
|
|
167
|
+
try {
|
|
168
|
+
const resp = await fetch(`${config.agentEndpoint}/v1/files/sign`, {
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: {
|
|
171
|
+
"content-type": "application/json",
|
|
172
|
+
authorization: `Bearer ${config.token}`
|
|
173
|
+
},
|
|
174
|
+
body: JSON.stringify({
|
|
175
|
+
url
|
|
176
|
+
})
|
|
177
|
+
});
|
|
178
|
+
if (resp.status === 404 || resp.status === 405) {
|
|
179
|
+
filesSignUnavailable = true;
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
if (!resp.ok) return null;
|
|
183
|
+
const data = await resp.json();
|
|
184
|
+
return data.url || null;
|
|
185
|
+
} catch (e) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const STORAGE_RESIGN_CONCURRENCY = 4;
|
|
190
|
+
let resignInFlight = 0;
|
|
191
|
+
const resignWaiters = [];
|
|
192
|
+
async function withResignSlot(run) {
|
|
193
|
+
if (resignInFlight >= STORAGE_RESIGN_CONCURRENCY) {
|
|
194
|
+
await new Promise((resolve) => resignWaiters.push(resolve));
|
|
195
|
+
} else {
|
|
196
|
+
resignInFlight += 1;
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
return await run();
|
|
200
|
+
} finally {
|
|
201
|
+
const next = resignWaiters.shift();
|
|
202
|
+
if (next) next();
|
|
203
|
+
else resignInFlight -= 1;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function downloadUrlFromResult(result) {
|
|
207
|
+
var _a;
|
|
208
|
+
const data = result.data && typeof result.data === "object" ? result.data : result;
|
|
209
|
+
const nested = (_a = data.createDownloadLink) != null ? _a : {};
|
|
210
|
+
const fresh = [data.downloadUrl, nested.downloadUrl, data.url].find((v) => typeof v === "string" && v.length > 0);
|
|
211
|
+
return fresh != null ? fresh : null;
|
|
212
|
+
}
|
|
213
|
+
function downloadLinkParams(s3KeyOrUrl) {
|
|
214
|
+
var _a;
|
|
215
|
+
return {
|
|
216
|
+
s3KeyOrUrl: (_a = storageObjectRef(s3KeyOrUrl)) != null ? _a : s3KeyOrUrl,
|
|
217
|
+
expiresIn: STORED_MEDIA_URL_TTL_SECONDS
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async function signViaStorageConnector(run, url) {
|
|
221
|
+
try {
|
|
222
|
+
const result = await withResignSlot(() => run("yantra-storage", "YANTRA_STORAGE_CREATE_DOWNLOAD_LINK", downloadLinkParams(url)));
|
|
223
|
+
if (result.successful === false) return null;
|
|
224
|
+
return downloadUrlFromResult(result);
|
|
225
|
+
} catch (e) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function signStoredMediaUrl(run, url) {
|
|
230
|
+
var _a;
|
|
231
|
+
const cached = freshSignedUrlCache.get(url);
|
|
232
|
+
if (cached) return cached;
|
|
233
|
+
const stored = unwrapProxyUrl(url);
|
|
234
|
+
const fresh = (_a = await signViaAgent(stored)) != null ? _a : run ? await signViaStorageConnector(run, stored) : null;
|
|
235
|
+
if (fresh) freshSignedUrlCache.set(url, fresh);
|
|
236
|
+
return fresh;
|
|
237
|
+
}
|
|
238
|
+
const STALE_MEDIA_URL_MESSAGE = "The attached media link has expired and could not be renewed - re-attach the file and try again.";
|
|
239
|
+
class StaleMediaUrlError extends Error {
|
|
240
|
+
constructor(url) {
|
|
241
|
+
super(STALE_MEDIA_URL_MESSAGE);
|
|
242
|
+
__publicField(this, "url");
|
|
243
|
+
this.name = "StaleMediaUrlError";
|
|
244
|
+
this.url = url;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async function ensureFetchableMediaUrl(run, url) {
|
|
248
|
+
const stored = canonicalMediaUrl(url);
|
|
249
|
+
if (!isPresignedUrlExpiring(stored)) return stored;
|
|
250
|
+
const fresh = await signStoredMediaUrl(run, stored);
|
|
251
|
+
if (fresh) return fresh;
|
|
252
|
+
const expiresAt = presignedUrlExpiresAtMs(stored);
|
|
253
|
+
if (expiresAt !== null && expiresAt <= Date.now()) throw new StaleMediaUrlError(url);
|
|
254
|
+
return stored;
|
|
255
|
+
}
|
|
256
|
+
function ensureFetchableMediaUrls(run, urls) {
|
|
257
|
+
return Promise.all(urls.map((u) => ensureFetchableMediaUrl(run, u)));
|
|
258
|
+
}export{PRESIGN_EXPIRY_SKEW_MS,STALE_MEDIA_URL_MESSAGE,STORED_MEDIA_URL_TTL_SECONDS,StaleMediaUrlError,canonicalMediaUrl,configureMediaSigning,downloadLinkParams,downloadUrlFromResult,ensureFetchableMediaUrl,ensureFetchableMediaUrls,isMisencodedPresignedUrl,isPresignedMediaUrl,isPresignedUrlExpiring,presignedUrlExpiresAtMs,signStoredMediaUrl,storageObjectRef,unwrapProxyUrl};//# sourceMappingURL=mediaUrls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mediaUrls.js","sources":["../../../src/features/canvas/mediaUrls.ts"],"sourcesContent":["/**\n * Native twin of surface-kit `presignedMediaUrl.ts` + the stored-media refresh\n * lane of `agentExec.ts` - presigned link forensics and re-signing.\n *\n * Connector output lands in a bucket and comes back as a V4-presigned GET URL.\n * A board persists that URL as the asset's identity, so it dies when the\n * signature lapses: the object is still there, but the bucket answers HTTP 400\n * `ExpiredToken` and retrying never fixes it. The signature's lifetime is in\n * the URL (`X-Goog-Date` + `X-Goog-Expires`, or the `X-Amz-*` pair), so expiry\n * is decided offline, and a stale link is traded for a fresh signature on the\n * same object before it reaches a connector or an <Image>.\n *\n * Two signers, in order of cost (web parity):\n * 1. the agent's `POST /v1/files/sign {url} -> {url}` (objects in its own\n * bucket) - needs the agent endpoint + bearer, set once by the host screen\n * via {@link configureMediaSigning};\n * 2. `yantra-storage` YANTRA_STORAGE_CREATE_DOWNLOAD_LINK through the\n * connector runner the caller passes (uploads and library files).\n *\n * URL parsing is hand-rolled on purpose: React Native's `URL` only grew\n * `searchParams` through a polyfill, and these helpers run on every tile.\n *\n * FOR OTHER CALLERS: run {@link ensureFetchableMediaUrl}(run, url) on every\n * media URL right before handing it to a connector (generate/edit/export).\n * It never uploads `file://` media - use the host `uploadMedia` seam for that.\n */\nimport type { RunMediaAction } from './videoEditor/mediaActions';\n\n/** Signed-at + lifetime query params for GCS V4 and AWS SigV4 presigned URLs. */\nconst SIGNATURE_SCHEMES = [\n { date: 'X-Goog-Date', expires: 'X-Goog-Expires', signature: 'X-Goog-Signature' },\n { date: 'X-Amz-Date', expires: 'X-Amz-Expires', signature: 'X-Amz-Signature' },\n] as const;\n\n/**\n * Refresh anything expiring within this window: a URL alive now must still\n * outlive the work it is handed to (an export runs many steps back to back).\n */\nexport const PRESIGN_EXPIRY_SKEW_MS = 10 * 60_000;\n\n/** Seven days - the longest a V4 presigned GET carries; the storage lane's default is 5 minutes. */\nexport const STORED_MEDIA_URL_TTL_SECONDS = 7 * 24 * 60 * 60;\n\nconst AGENT_PROXY_PATH = '/v1/files/proxy';\n\n// ============= Parsing =============\n\ninterface ParsedUrl {\n protocol: string;\n host: string;\n pathname: string;\n query: string;\n}\n\nfunction parseUrl(url: string): ParsedUrl | null {\n const m = /^([a-z][a-z0-9+.-]*:)\\/\\/([^/?#]*)([^?#]*)(?:\\?([^#]*))?/i.exec(url.trim());\n if (!m) return null;\n return { protocol: m[1].toLowerCase(), host: m[2].toLowerCase(), pathname: m[3] || '/', query: m[4] ?? '' };\n}\n\n/** One query param, decoded once (`+` is a space, as `URLSearchParams` reads it). */\nfunction queryParam(query: string, name: string): string | null {\n for (const pair of query.split('&')) {\n const eq = pair.indexOf('=');\n const key = eq >= 0 ? pair.slice(0, eq) : pair;\n if (key !== name) continue;\n const raw = eq >= 0 ? pair.slice(eq + 1) : '';\n try {\n return decodeURIComponent(raw.replace(/\\+/g, ' '));\n } catch {\n return raw;\n }\n }\n return null;\n}\n\n/**\n * The URL an agent proxy link wraps (`<agent>/v1/files/proxy?url=<encoded>`),\n * or the input unchanged. Decoded exactly once, as the agent decodes it.\n */\nexport function unwrapProxyUrl(src: string): string {\n if (!src.includes(AGENT_PROXY_PATH)) return src;\n const q = src.indexOf('?');\n const path = (q >= 0 ? src.slice(0, q) : src).split('#')[0];\n if (!path.endsWith(AGENT_PROXY_PATH)) return src;\n return (q >= 0 ? queryParam(src.slice(q + 1).split('#')[0], 'url') : null) || src;\n}\n\nfunction carriesSignature(url: string): boolean {\n return url.includes('X-Goog-Signature=') || url.includes('X-Amz-Signature=');\n}\n\n/**\n * What a stored media reference should be: a proxy link around a presigned\n * storage object is unwrapped (the proxy only adds an agent hop); a proxy link\n * around a provider-held file (no signature) is the only way to load it, so it stays.\n */\nexport function canonicalMediaUrl(url: string): string {\n const inner = unwrapProxyUrl(url);\n return inner !== url && carriesSignature(inner) ? inner : url;\n}\n\n/** True when the URL carries a V4 presigned GET signature, itself or inside an agent proxy link. */\nexport function isPresignedMediaUrl(url: string): boolean {\n return carriesSignature(unwrapProxyUrl(url));\n}\n\n/** `20260727T124517Z` (SigV4 datetime) -> epoch ms, or null when malformed. */\nfunction parseSignatureDate(value: string): number | null {\n const m = /^(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})Z$/.exec(value);\n if (!m) return null;\n return Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3]), Number(m[4]), Number(m[5]), Number(m[6]));\n}\n\n/** When the URL's signature stops being accepted (epoch ms); null when not presigned or unparseable. */\nexport function presignedUrlExpiresAtMs(url: string): number | null {\n const parsed = parseUrl(unwrapProxyUrl(url));\n if (!parsed) return null;\n for (const scheme of SIGNATURE_SCHEMES) {\n if (!queryParam(parsed.query, scheme.signature)) continue;\n const signedAt = parseSignatureDate(queryParam(parsed.query, scheme.date) ?? '');\n const lifetimeSec = Number(queryParam(parsed.query, scheme.expires));\n if (signedAt === null || !Number.isFinite(lifetimeSec) || lifetimeSec <= 0) return null;\n return signedAt + lifetimeSec * 1000;\n }\n return null;\n}\n\n/** A percent-encoded `%` in a signed path: the key was signed in its URL spelling. */\nconst ENCODED_PERCENT = /%25[0-9a-f]{2}/i;\n\n/** A presigned link signed for a twice-encoded key (`%2528`): dead however long it has left. */\nexport function isMisencodedPresignedUrl(url: string): boolean {\n const inner = unwrapProxyUrl(url);\n if (!carriesSignature(inner)) return false;\n const parsed = parseUrl(inner);\n return Boolean(parsed && ENCODED_PERCENT.test(parsed.pathname));\n}\n\n/**\n * True when the URL is presigned and expired, lapses within `skewMs`, has\n * unreadable signing params, or is misencoded. Re-signing a live URL is\n * harmless; trusting an unreadable one risks a dead link.\n */\nexport function isPresignedUrlExpiring(url: string, nowMs = Date.now(), skewMs = PRESIGN_EXPIRY_SKEW_MS): boolean {\n if (!isPresignedMediaUrl(url)) return false;\n if (isMisencodedPresignedUrl(url)) return true;\n const expiresAt = presignedUrlExpiresAtMs(url);\n if (expiresAt === null) return true;\n return expiresAt - nowMs <= skewMs;\n}\n\nfunction decodeFully(path: string): string {\n let current = path;\n for (let i = 0; i < 8; i += 1) {\n let next: string;\n try {\n next = decodeURIComponent(current);\n } catch {\n break;\n }\n if (next === current) break;\n current = next;\n }\n return current;\n}\n\nconst AWS_VIRTUAL_HOST = /^([^.]+)\\.s3(?:[.-][a-z0-9-]+)?\\.amazonaws\\.com$/i;\nconst AWS_PATH_HOST = /^s3(?:[.-][a-z0-9-]+)?\\.amazonaws\\.com$/i;\n\n/**\n * The object an AWS bucket URL names, as `s3://bucket/key` with the key in its\n * own spelling - what a signer must be handed (signers that read an https path\n * don't decode it). Null for anything that is not an AWS bucket URL.\n */\nexport function storageObjectRef(url: string): string | null {\n const parsed = parseUrl(unwrapProxyUrl(url));\n if (!parsed || parsed.protocol !== 'https:') return null;\n const path = parsed.pathname.replace(/^\\/+/, '');\n let bucket: string;\n let rawKey: string;\n const virtual = AWS_VIRTUAL_HOST.exec(parsed.host);\n if (virtual) {\n bucket = virtual[1];\n rawKey = path;\n } else if (AWS_PATH_HOST.test(parsed.host)) {\n const slash = path.indexOf('/');\n if (slash <= 0) return null;\n bucket = path.slice(0, slash);\n rawKey = path.slice(slash + 1);\n } else {\n return null;\n }\n if (!rawKey) return null;\n let key: string;\n if (ENCODED_PERCENT.test(rawKey)) key = decodeFully(rawKey);\n else {\n try {\n key = decodeURIComponent(rawKey);\n } catch {\n key = rawKey;\n }\n }\n return `s3://${bucket}/${key}`;\n}\n\n// ============= Signing =============\n\nexport interface MediaSigningConfig {\n /** cdecli agent base, e.g. `deriveAgentEndpoint(indexUrl)`. */\n agentEndpoint: string;\n token: string;\n}\n\nlet signingConfig: MediaSigningConfig | null = null;\n/** Session cache: stale URL -> fresh one. A 7-day signature outlives any session. */\nconst freshSignedUrlCache = new Map<string, string>();\n/** Latched once the deployed agent proves it has no `/v1/files/sign`. */\nlet filesSignUnavailable = false;\n\n/** The host screen registers the agent signer (token + endpoint); null clears it. */\nexport function configureMediaSigning(config: MediaSigningConfig | null): void {\n const next = config?.token && config.agentEndpoint ? config : null;\n const changed = next?.agentEndpoint !== signingConfig?.agentEndpoint || next?.token !== signingConfig?.token;\n signingConfig = next ? { ...next, agentEndpoint: next.agentEndpoint.replace(/\\/+$/, '') } : null;\n if (changed) filesSignUnavailable = false;\n}\n\n/** Test hook: forget the cache, the endpoint latch and the signer. */\nexport function resetMediaSigningForTests(): void {\n signingConfig = null;\n filesSignUnavailable = false;\n freshSignedUrlCache.clear();\n resignInFlight = 0;\n resignWaiters.length = 0;\n}\n\nasync function signViaAgent(url: string): Promise<string | null> {\n const config = signingConfig;\n if (!config || filesSignUnavailable) return null;\n try {\n const resp = await fetch(`${config.agentEndpoint}/v1/files/sign`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${config.token}` },\n body: JSON.stringify({ url }),\n });\n if (resp.status === 404 || resp.status === 405) {\n filesSignUnavailable = true;\n return null;\n }\n if (!resp.ok) return null;\n const data = (await resp.json()) as { url?: string };\n return data.url || null;\n } catch {\n return null;\n }\n}\n\n/** At most this many storage-connector re-signs in flight (each is an agent process). */\nconst STORAGE_RESIGN_CONCURRENCY = 4;\nlet resignInFlight = 0;\nconst resignWaiters: Array<() => void> = [];\n\nasync function withResignSlot<T>(run: () => Promise<T>): Promise<T> {\n if (resignInFlight >= STORAGE_RESIGN_CONCURRENCY) {\n // A finishing call hands its slot straight to the first waiter.\n await new Promise<void>((resolve) => resignWaiters.push(resolve));\n } else {\n resignInFlight += 1;\n }\n try {\n return await run();\n } finally {\n const next = resignWaiters.shift();\n if (next) next();\n else resignInFlight -= 1;\n }\n}\n\n/** The download URL out of a CREATE_DOWNLOAD_LINK result: bare or enveloped, flat or nested. */\nexport function downloadUrlFromResult(result: Record<string, unknown>): string | null {\n const data = (result.data && typeof result.data === 'object' ? result.data : result) as Record<string, unknown>;\n const nested = (data.createDownloadLink ?? {}) as Record<string, unknown>;\n const fresh = [data.downloadUrl, nested.downloadUrl, data.url].find(\n (v): v is string => typeof v === 'string' && v.length > 0,\n );\n return fresh ?? null;\n}\n\n/** CREATE_DOWNLOAD_LINK params for a URL or key: `s3://bucket/key` when it is an AWS link, 7-day lifetime. */\nexport function downloadLinkParams(s3KeyOrUrl: string): { s3KeyOrUrl: string; expiresIn: number } {\n return { s3KeyOrUrl: storageObjectRef(s3KeyOrUrl) ?? s3KeyOrUrl, expiresIn: STORED_MEDIA_URL_TTL_SECONDS };\n}\n\nasync function signViaStorageConnector(run: RunMediaAction, url: string): Promise<string | null> {\n try {\n const result = await withResignSlot(() =>\n run('yantra-storage', 'YANTRA_STORAGE_CREATE_DOWNLOAD_LINK', downloadLinkParams(url)),\n );\n if (result.successful === false) return null;\n return downloadUrlFromResult(result);\n } catch {\n return null;\n }\n}\n\n/**\n * Trade a persisted (possibly long-expired) presigned URL for a fresh\n * signature on the same object. Null - never throws - when nobody can sign it.\n */\nexport async function signStoredMediaUrl(run: RunMediaAction | undefined, url: string): Promise<string | null> {\n const cached = freshSignedUrlCache.get(url);\n if (cached) return cached;\n const stored = unwrapProxyUrl(url);\n const fresh = (await signViaAgent(stored)) ?? (run ? await signViaStorageConnector(run, stored) : null);\n if (fresh) freshSignedUrlCache.set(url, fresh);\n return fresh;\n}\n\nexport const STALE_MEDIA_URL_MESSAGE =\n 'The attached media link has expired and could not be renewed - re-attach the file and try again.';\n\nexport class StaleMediaUrlError extends Error {\n readonly url: string;\n constructor(url: string) {\n super(STALE_MEDIA_URL_MESSAGE);\n this.name = 'StaleMediaUrlError';\n this.url = url;\n }\n}\n\nexport function isStaleMediaUrlError(err: unknown): err is StaleMediaUrlError {\n return err instanceof Error && err.name === 'StaleMediaUrlError';\n}\n\n/**\n * Resolve a media reference to something a connector can fetch: a stored\n * presigned URL whose signature is expired (or about to be) is re-signed;\n * anything else passes through (canonicalised). A link that has ALREADY lapsed\n * and cannot be renewed throws {@link StaleMediaUrlError} - the connector's\n * fetch is certain to fail, and learning that after a full generation is worse.\n */\nexport async function ensureFetchableMediaUrl(run: RunMediaAction | undefined, url: string): Promise<string> {\n const stored = canonicalMediaUrl(url);\n if (!isPresignedUrlExpiring(stored)) return stored;\n const fresh = await signStoredMediaUrl(run, stored);\n if (fresh) return fresh;\n const expiresAt = presignedUrlExpiresAtMs(stored);\n if (expiresAt !== null && expiresAt <= Date.now()) throw new StaleMediaUrlError(url);\n return stored;\n}\n\n/** {@link ensureFetchableMediaUrl} over a list, concurrently, order preserved. */\nexport function ensureFetchableMediaUrls(run: RunMediaAction | undefined, urls: readonly string[]): Promise<string[]> {\n return Promise.all(urls.map((u) => ensureFetchableMediaUrl(run, u)));\n}\n\n/**\n * Refresh every stale presigned URL in a plain structure (a board's items).\n * Strings are resolved by copy; arrays and plain objects are walked. Returns\n * the input itself when nothing changed, so callers can skip a state write.\n */\nexport async function refreshPresignedUrlsDeep<T>(run: RunMediaAction | undefined, value: T): Promise<T> {\n if (typeof value === 'string') {\n const stored = canonicalMediaUrl(value);\n const next = isPresignedUrlExpiring(stored) ? ((await signStoredMediaUrl(run, stored)) ?? stored) : stored;\n return (next === value ? value : next) as T;\n }\n if (Array.isArray(value)) {\n const next = await Promise.all(value.map((v) => refreshPresignedUrlsDeep(run, v)));\n return (next.every((v, i) => v === value[i]) ? value : next) as T;\n }\n if (value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype) {\n const entries = Object.entries(value as Record<string, unknown>);\n const next = await Promise.all(\n entries.map(async ([k, v]) => [k, await refreshPresignedUrlsDeep(run, v)] as const),\n );\n return (next.every(([, v], i) => v === entries[i][1]) ? value : Object.fromEntries(next)) as T;\n }\n return value;\n}\n\n/** True when any string in a board's items is a presigned link worth renewing now. */\nexport function hasExpiringPresignedUrl(value: unknown, nowMs = Date.now()): boolean {\n if (typeof value === 'string') return isPresignedUrlExpiring(value, nowMs);\n if (Array.isArray(value)) return value.some((v) => hasExpiringPresignedUrl(v, nowMs));\n if (value && typeof value === 'object') {\n return Object.values(value as Record<string, unknown>).some((v) => hasExpiringPresignedUrl(v, nowMs));\n }\n return false;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA6BA,MAAM,oBAAoB,CAAC;AAAA,EACzB,IAAM,EAAA,aAAA;AAAA,EACN,OAAS,EAAA,gBAAA;AAAA,EACT,SAAW,EAAA;AACb,CAAG,EAAA;AAAA,EACD,IAAM,EAAA,YAAA;AAAA,EACN,OAAS,EAAA,eAAA;AAAA,EACT,SAAW,EAAA;AACb,CAAC,CAAA;AAMM,MAAM,yBAAyB,EAAK,GAAA;AAG9B,MAAA,4BAAA,GAA+B,CAAI,GAAA,EAAA,GAAK,EAAK,GAAA;AAC1D,MAAM,gBAAmB,GAAA,iBAAA;AAUzB,SAAS,SAAS,GAA+B,EAAA;AAzDjD,EAAA,IAAA,EAAA;AA0DE,EAAA,MAAM,CAAI,GAAA,2DAAA,CAA4D,IAAK,CAAA,GAAA,CAAI,MAAM,CAAA;AACrF,EAAI,IAAA,CAAC,GAAU,OAAA,IAAA;AACf,EAAO,OAAA;AAAA,IACL,QAAU,EAAA,CAAA,CAAE,CAAC,CAAA,CAAE,WAAY,EAAA;AAAA,IAC3B,IAAM,EAAA,CAAA,CAAE,CAAC,CAAA,CAAE,WAAY,EAAA;AAAA,IACvB,QAAA,EAAU,CAAE,CAAA,CAAC,CAAK,IAAA,GAAA;AAAA,IAClB,KAAO,EAAA,CAAA,EAAA,GAAA,CAAA,CAAE,CAAC,CAAA,KAAH,IAAQ,GAAA,EAAA,GAAA;AAAA,GACjB;AACF;AAGA,SAAS,UAAA,CAAW,OAAe,IAA6B,EAAA;AAC9D,EAAA,KAAA,MAAW,IAAQ,IAAA,KAAA,CAAM,KAAM,CAAA,GAAG,CAAG,EAAA;AACnC,IAAM,MAAA,EAAA,GAAK,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA;AAC3B,IAAA,MAAM,MAAM,EAAM,IAAA,CAAA,GAAI,KAAK,KAAM,CAAA,CAAA,EAAG,EAAE,CAAI,GAAA,IAAA;AAC1C,IAAA,IAAI,QAAQ,IAAM,EAAA;AAClB,IAAA,MAAM,MAAM,EAAM,IAAA,CAAA,GAAI,KAAK,KAAM,CAAA,EAAA,GAAK,CAAC,CAAI,GAAA,EAAA;AAC3C,IAAI,IAAA;AACF,MAAA,OAAO,kBAAmB,CAAA,GAAA,CAAI,OAAQ,CAAA,KAAA,EAAO,GAAG,CAAC,CAAA;AAAA,KAC3C,CAAA,OAAA,CAAA,EAAA;AACN,MAAO,OAAA,GAAA;AAAA;AACT;AAEF,EAAO,OAAA,IAAA;AACT;AAMO,SAAS,eAAe,GAAqB,EAAA;AAClD,EAAA,IAAI,CAAC,GAAA,CAAI,QAAS,CAAA,gBAAgB,GAAU,OAAA,GAAA;AAC5C,EAAM,MAAA,CAAA,GAAI,GAAI,CAAA,OAAA,CAAQ,GAAG,CAAA;AACzB,EAAA,MAAM,IAAQ,GAAA,CAAA,CAAA,IAAK,CAAI,GAAA,GAAA,CAAI,KAAM,CAAA,CAAA,EAAG,CAAC,CAAA,GAAI,GAAK,EAAA,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA;AAC1D,EAAA,IAAI,CAAC,IAAA,CAAK,QAAS,CAAA,gBAAgB,GAAU,OAAA,GAAA;AAC7C,EAAA,OAAA,CAAQ,CAAK,IAAA,CAAA,GAAI,UAAW,CAAA,GAAA,CAAI,MAAM,CAAI,GAAA,CAAC,CAAE,CAAA,KAAA,CAAM,GAAG,CAAE,CAAA,CAAC,CAAG,EAAA,KAAK,IAAI,IAAS,KAAA,GAAA;AAChF;AACA,SAAS,iBAAiB,GAAsB,EAAA;AAC9C,EAAA,OAAO,IAAI,QAAS,CAAA,mBAAmB,CAAK,IAAA,GAAA,CAAI,SAAS,kBAAkB,CAAA;AAC7E;AAOO,SAAS,kBAAkB,GAAqB,EAAA;AACrD,EAAM,MAAA,KAAA,GAAQ,eAAe,GAAG,CAAA;AAChC,EAAA,OAAO,KAAU,KAAA,GAAA,IAAO,gBAAiB,CAAA,KAAK,IAAI,KAAQ,GAAA,GAAA;AAC5D;AAGO,SAAS,oBAAoB,GAAsB,EAAA;AACxD,EAAO,OAAA,gBAAA,CAAiB,cAAe,CAAA,GAAG,CAAC,CAAA;AAC7C;AAGA,SAAS,mBAAmB,KAA8B,EAAA;AACxD,EAAM,MAAA,CAAA,GAAI,gDAAiD,CAAA,IAAA,CAAK,KAAK,CAAA;AACrE,EAAI,IAAA,CAAC,GAAU,OAAA,IAAA;AACf,EAAA,OAAO,IAAK,CAAA,GAAA,CAAI,MAAO,CAAA,CAAA,CAAE,CAAC,CAAC,CAAA,EAAG,MAAO,CAAA,CAAA,CAAE,CAAC,CAAC,CAAI,GAAA,CAAA,EAAG,OAAO,CAAE,CAAA,CAAC,CAAC,CAAA,EAAG,MAAO,CAAA,CAAA,CAAE,CAAC,CAAC,GAAG,MAAO,CAAA,CAAA,CAAE,CAAC,CAAC,CAAG,EAAA,MAAA,CAAO,CAAE,CAAA,CAAC,CAAC,CAAC,CAAA;AACxG;AAGO,SAAS,wBAAwB,GAA4B,EAAA;AA1HpE,EAAA,IAAA,EAAA;AA2HE,EAAA,MAAM,MAAS,GAAA,QAAA,CAAS,cAAe,CAAA,GAAG,CAAC,CAAA;AAC3C,EAAI,IAAA,CAAC,QAAe,OAAA,IAAA;AACpB,EAAA,KAAA,MAAW,UAAU,iBAAmB,EAAA;AACtC,IAAA,IAAI,CAAC,UAAW,CAAA,MAAA,CAAO,KAAO,EAAA,MAAA,CAAO,SAAS,CAAG,EAAA;AACjD,IAAM,MAAA,QAAA,GAAW,oBAAmB,EAAW,GAAA,UAAA,CAAA,MAAA,CAAO,OAAO,MAAO,CAAA,IAAI,CAApC,KAAA,IAAA,GAAA,EAAA,GAAyC,EAAE,CAAA;AAC/E,IAAA,MAAM,cAAc,MAAO,CAAA,UAAA,CAAW,OAAO,KAAO,EAAA,MAAA,CAAO,OAAO,CAAC,CAAA;AACnE,IAAI,IAAA,QAAA,KAAa,QAAQ,CAAC,MAAA,CAAO,SAAS,WAAW,CAAA,IAAK,WAAe,IAAA,CAAA,EAAU,OAAA,IAAA;AACnF,IAAA,OAAO,WAAW,WAAc,GAAA,GAAA;AAAA;AAElC,EAAO,OAAA,IAAA;AACT;AAGA,MAAM,eAAkB,GAAA,iBAAA;AAGjB,SAAS,yBAAyB,GAAsB,EAAA;AAC7D,EAAM,MAAA,KAAA,GAAQ,eAAe,GAAG,CAAA;AAChC,EAAA,IAAI,CAAC,gBAAA,CAAiB,KAAK,CAAA,EAAU,OAAA,KAAA;AACrC,EAAM,MAAA,MAAA,GAAS,SAAS,KAAK,CAAA;AAC7B,EAAA,OAAO,QAAQ,MAAU,IAAA,eAAA,CAAgB,IAAK,CAAA,MAAA,CAAO,QAAQ,CAAC,CAAA;AAChE;AAOO,SAAS,uBAAuB,GAAa,EAAA,KAAA,GAAQ,KAAK,GAAI,EAAA,EAAG,SAAS,sBAAiC,EAAA;AAChH,EAAA,IAAI,CAAC,mBAAA,CAAoB,GAAG,CAAA,EAAU,OAAA,KAAA;AACtC,EAAI,IAAA,wBAAA,CAAyB,GAAG,CAAA,EAAU,OAAA,IAAA;AAC1C,EAAM,MAAA,SAAA,GAAY,wBAAwB,GAAG,CAAA;AAC7C,EAAI,IAAA,SAAA,KAAc,MAAa,OAAA,IAAA;AAC/B,EAAA,OAAO,YAAY,KAAS,IAAA,MAAA;AAC9B;AACA,SAAS,YAAY,IAAsB,EAAA;AACzC,EAAA,IAAI,OAAU,GAAA,IAAA;AACd,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,CAAA,EAAG,KAAK,CAAG,EAAA;AAC7B,IAAI,IAAA,IAAA;AACJ,IAAI,IAAA;AACF,MAAA,IAAA,GAAO,mBAAmB,OAAO,CAAA;AAAA,KAC3B,CAAA,OAAA,CAAA,EAAA;AACN,MAAA;AAAA;AAEF,IAAA,IAAI,SAAS,OAAS,EAAA;AACtB,IAAU,OAAA,GAAA,IAAA;AAAA;AAEZ,EAAO,OAAA,OAAA;AACT;AACA,MAAM,gBAAmB,GAAA,mDAAA;AACzB,MAAM,aAAgB,GAAA,0CAAA;AAOf,SAAS,iBAAiB,GAA4B,EAAA;AAC3D,EAAA,MAAM,MAAS,GAAA,QAAA,CAAS,cAAe,CAAA,GAAG,CAAC,CAAA;AAC3C,EAAA,IAAI,CAAC,MAAA,IAAU,MAAO,CAAA,QAAA,KAAa,UAAiB,OAAA,IAAA;AACpD,EAAA,MAAM,IAAO,GAAA,MAAA,CAAO,QAAS,CAAA,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAC/C,EAAI,IAAA,MAAA;AACJ,EAAI,IAAA,MAAA;AACJ,EAAA,MAAM,OAAU,GAAA,gBAAA,CAAiB,IAAK,CAAA,MAAA,CAAO,IAAI,CAAA;AACjD,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,MAAA,GAAS,QAAQ,CAAC,CAAA;AAClB,IAAS,MAAA,GAAA,IAAA;AAAA,GACA,MAAA,IAAA,aAAA,CAAc,IAAK,CAAA,MAAA,CAAO,IAAI,CAAG,EAAA;AAC1C,IAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA;AAC9B,IAAI,IAAA,KAAA,IAAS,GAAU,OAAA,IAAA;AACvB,IAAS,MAAA,GAAA,IAAA,CAAK,KAAM,CAAA,CAAA,EAAG,KAAK,CAAA;AAC5B,IAAS,MAAA,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,GAAQ,CAAC,CAAA;AAAA,GACxB,MAAA;AACL,IAAO,OAAA,IAAA;AAAA;AAET,EAAI,IAAA,CAAC,QAAe,OAAA,IAAA;AACpB,EAAI,IAAA,GAAA;AACJ,EAAA,IAAI,gBAAgB,IAAK,CAAA,MAAM,CAAG,EAAA,GAAA,GAAM,YAAY,MAAM,CAAA;AAAA,OAAO;AAC/D,IAAI,IAAA;AACF,MAAA,GAAA,GAAM,mBAAmB,MAAM,CAAA;AAAA,KACzB,CAAA,OAAA,CAAA,EAAA;AACN,MAAM,GAAA,GAAA,MAAA;AAAA;AACR;AAEF,EAAO,OAAA,CAAA,KAAA,EAAQ,MAAM,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA;AAC9B;AASA,IAAI,aAA2C,GAAA,IAAA;AAE/C,MAAM,mBAAA,uBAA0B,GAAoB,EAAA;AAEpD,IAAI,oBAAuB,GAAA,KAAA;AAGpB,SAAS,sBAAsB,MAAyC,EAAA;AAC7E,EAAA,MAAM,IAAO,GAAA,CAAA,MAAA,IAAA,IAAA,GAAA,MAAA,GAAA,MAAA,CAAQ,KAAS,KAAA,MAAA,CAAO,gBAAgB,MAAS,GAAA,IAAA;AAC9D,EAAA,MAAM,WAAU,IAAM,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAA,aAAA,OAAkB,+CAAe,aAAiB,CAAA,IAAA,CAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAM,YAAU,aAAe,IAAA,IAAA,GAAA,MAAA,GAAA,aAAA,CAAA,KAAA,CAAA;AACvG,EAAgB,aAAA,GAAA,IAAA,GAAO,iCAClB,IADkB,CAAA,EAAA;AAAA,IAErB,aAAe,EAAA,IAAA,CAAK,aAAc,CAAA,OAAA,CAAQ,QAAQ,EAAE;AAAA,GAClD,CAAA,GAAA,IAAA;AACJ,EAAA,IAAI,SAAgC,oBAAA,GAAA,KAAA;AACtC;AAUA,eAAe,aAAa,GAAqC,EAAA;AAC/D,EAAA,MAAM,MAAS,GAAA,aAAA;AACf,EAAI,IAAA,CAAC,MAAU,IAAA,oBAAA,EAA6B,OAAA,IAAA;AAC5C,EAAI,IAAA;AACF,IAAA,MAAM,OAAO,MAAM,KAAA,CAAM,CAAG,EAAA,MAAA,CAAO,aAAa,CAAkB,cAAA,CAAA,EAAA;AAAA,MAChE,MAAQ,EAAA,MAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,cAAgB,EAAA,kBAAA;AAAA,QAChB,aAAA,EAAe,CAAU,OAAA,EAAA,MAAA,CAAO,KAAK,CAAA;AAAA,OACvC;AAAA,MACA,IAAA,EAAM,KAAK,SAAU,CAAA;AAAA,QACnB;AAAA,OACD;AAAA,KACF,CAAA;AACD,IAAA,IAAI,IAAK,CAAA,MAAA,KAAW,GAAO,IAAA,IAAA,CAAK,WAAW,GAAK,EAAA;AAC9C,MAAuB,oBAAA,GAAA,IAAA;AACvB,MAAO,OAAA,IAAA;AAAA;AAET,IAAI,IAAA,CAAC,IAAK,CAAA,EAAA,EAAW,OAAA,IAAA;AACrB,IAAM,MAAA,IAAA,GAAQ,MAAM,IAAA,CAAK,IAAK,EAAA;AAG9B,IAAA,OAAO,KAAK,GAAO,IAAA,IAAA;AAAA,GACb,CAAA,OAAA,CAAA,EAAA;AACN,IAAO,OAAA,IAAA;AAAA;AAEX;AAGA,MAAM,0BAA6B,GAAA,CAAA;AACnC,IAAI,cAAiB,GAAA,CAAA;AACrB,MAAM,gBAAmC,EAAC;AAC1C,eAAe,eAAkB,GAAmC,EAAA;AAClE,EAAA,IAAI,kBAAkB,0BAA4B,EAAA;AAEhD,IAAA,MAAM,IAAI,OAAc,CAAA,CAAA,OAAA,KAAW,aAAc,CAAA,IAAA,CAAK,OAAO,CAAC,CAAA;AAAA,GACzD,MAAA;AACL,IAAkB,cAAA,IAAA,CAAA;AAAA;AAEpB,EAAI,IAAA;AACF,IAAA,OAAO,MAAM,GAAI,EAAA;AAAA,GACjB,SAAA;AACA,IAAM,MAAA,IAAA,GAAO,cAAc,KAAM,EAAA;AACjC,IAAA,IAAI,MAAW,IAAA,EAAA;AAAA,SAAyB,cAAA,IAAA,CAAA;AAAA;AAE5C;AAGO,SAAS,sBAAsB,MAAgD,EAAA;AAlStF,EAAA,IAAA,EAAA;AAmSE,EAAM,MAAA,IAAA,GAAQ,OAAO,IAAQ,IAAA,OAAO,OAAO,IAAS,KAAA,QAAA,GAAW,OAAO,IAAO,GAAA,MAAA;AAC7E,EAAA,MAAM,MAAU,GAAA,CAAA,EAAA,GAAA,IAAA,CAAK,kBAAL,KAAA,IAAA,GAAA,EAAA,GAA2B,EAAC;AAC5C,EAAA,MAAM,QAAQ,CAAC,IAAA,CAAK,WAAa,EAAA,MAAA,CAAO,aAAa,IAAK,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,CAAC,CAAmB,KAAA,OAAO,MAAM,QAAY,IAAA,CAAA,CAAE,SAAS,CAAC,CAAA;AAC7H,EAAA,OAAO,KAAS,IAAA,IAAA,GAAA,KAAA,GAAA,IAAA;AAClB;AAGO,SAAS,mBAAmB,UAGjC,EAAA;AA7SF,EAAA,IAAA,EAAA;AA8SE,EAAO,OAAA;AAAA,IACL,UAAY,EAAA,CAAA,EAAA,GAAA,gBAAA,CAAiB,UAAU,CAAA,KAA3B,IAAgC,GAAA,EAAA,GAAA,UAAA;AAAA,IAC5C,SAAW,EAAA;AAAA,GACb;AACF;AACA,eAAe,uBAAA,CAAwB,KAAqB,GAAqC,EAAA;AAC/F,EAAI,IAAA;AACF,IAAM,MAAA,MAAA,GAAS,MAAM,cAAA,CAAe,MAAM,GAAA,CAAI,kBAAkB,qCAAuC,EAAA,kBAAA,CAAmB,GAAG,CAAC,CAAC,CAAA;AAC/H,IAAI,IAAA,MAAA,CAAO,UAAe,KAAA,KAAA,EAAc,OAAA,IAAA;AACxC,IAAA,OAAO,sBAAsB,MAAM,CAAA;AAAA,GAC7B,CAAA,OAAA,CAAA,EAAA;AACN,IAAO,OAAA,IAAA;AAAA;AAEX;AAMsB,eAAA,kBAAA,CAAmB,KAAiC,GAAqC,EAAA;AAjU/G,EAAA,IAAA,EAAA;AAkUE,EAAM,MAAA,MAAA,GAAS,mBAAoB,CAAA,GAAA,CAAI,GAAG,CAAA;AAC1C,EAAA,IAAI,QAAe,OAAA,MAAA;AACnB,EAAM,MAAA,MAAA,GAAS,eAAe,GAAG,CAAA;AACjC,EAAM,MAAA,KAAA,GAAA,CAAS,EAAM,GAAA,MAAA,YAAA,CAAa,MAAM,CAAA,KAAzB,IAAgC,GAAA,EAAA,GAAA,GAAA,GAAM,MAAM,uBAAA,CAAwB,GAAK,EAAA,MAAM,CAAI,GAAA,IAAA;AAClG,EAAA,IAAI,KAAO,EAAA,mBAAA,CAAoB,GAAI,CAAA,GAAA,EAAK,KAAK,CAAA;AAC7C,EAAO,OAAA,KAAA;AACT;AACO,MAAM,uBAA0B,GAAA;AAChC,MAAM,2BAA2B,KAAM,CAAA;AAAA,EAE5C,YAAY,GAAa,EAAA;AACvB,IAAA,KAAA,CAAM,uBAAuB,CAAA;AAF/B,IAAS,aAAA,CAAA,IAAA,EAAA,KAAA,CAAA;AAGP,IAAA,IAAA,CAAK,IAAO,GAAA,oBAAA;AACZ,IAAA,IAAA,CAAK,GAAM,GAAA,GAAA;AAAA;AAEf;AAYsB,eAAA,uBAAA,CAAwB,KAAiC,GAA8B,EAAA;AAC3G,EAAM,MAAA,MAAA,GAAS,kBAAkB,GAAG,CAAA;AACpC,EAAA,IAAI,CAAC,sBAAA,CAAuB,MAAM,CAAA,EAAU,OAAA,MAAA;AAC5C,EAAA,MAAM,KAAQ,GAAA,MAAM,kBAAmB,CAAA,GAAA,EAAK,MAAM,CAAA;AAClD,EAAA,IAAI,OAAc,OAAA,KAAA;AAClB,EAAM,MAAA,SAAA,GAAY,wBAAwB,MAAM,CAAA;AAChD,EAAI,IAAA,SAAA,KAAc,QAAQ,SAAa,IAAA,IAAA,CAAK,KAAO,EAAA,MAAM,IAAI,kBAAA,CAAmB,GAAG,CAAA;AACnF,EAAO,OAAA,MAAA;AACT;AAGgB,SAAA,wBAAA,CAAyB,KAAiC,IAA4C,EAAA;AACpH,EAAO,OAAA,OAAA,CAAQ,IAAI,IAAK,CAAA,GAAA,CAAI,OAAK,uBAAwB,CAAA,GAAA,EAAK,CAAC,CAAC,CAAC,CAAA;AACnE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nativeViewerRegistry.js","sources":["../../../src/features/canvas/nativeViewerRegistry.ts"],"sourcesContent":["/**\n * Seam between the app shell and this package for the FEDERATED canvas viewer.\n *\n * The federated loader (`import('canvas_native/Viewer')`) must live in the app\n * (portable-devices/mobile): this package also builds through rollup for lib/,\n * and rollup must never see a bare `canvas_native/...` specifier. The screen,\n * however, lives HERE, where routes register. So the app injects its loader at\n * startup and the screen reads it back - the same inversion the surfaces use\n * for host services, scaled down to one component.\n */\nimport type { ComponentType } from 'react';\nimport type { NativeCanvasViewerProps } from './NativeCanvasViewer';\n\nlet registered: ComponentType<NativeCanvasViewerProps> | null = null;\n\nexport function registerNativeCanvasViewer(component: ComponentType<NativeCanvasViewerProps>): void {\n registered = component;\n}\n\n/** Null when the host app has not injected a loader (e.g. a build without federation). */\nexport function getNativeCanvasViewer(): ComponentType<NativeCanvasViewerProps> | null {\n return registered;\n}\n\n/**\n * The federated canvas EXPERIENCE (boards + viewer), registered by the app the\n * same way the viewer is. Kept as a separate seam so a host that only wants the\n * raw renderer - a preview, a test - is unaffected.\n */\nexport type CanvasExperienceComponent = ComponentType<{\n token?: string | null;\n indexUrl: string;\n channelId?: string;\n sessionError?: string | null;\n onRetrySession?: () => void;\n}>;\n\nlet experience: CanvasExperienceComponent | null = null;\nlet experiencePreload: (() => Promise<void>) | null = null;\n\nexport function registerNativeCanvasExperience(component: CanvasExperienceComponent): void {\n experience = component;\n}\n\nexport function getNativeCanvasExperience(): CanvasExperienceComponent | null {\n return experience;\n}\n\n/**\n * Host registers the federated `import('canvas_native/Viewer')` so Home can\n * start the download before the user opens Canvas Native.\n */\nexport function registerCanvasExperiencePreload(fn: () => Promise<void>): void {\n experiencePreload = fn;\n}\n\nexport function preloadNativeCanvasExperience(): Promise<void> {\n return experiencePreload?.() ?? Promise.resolve();\n}\n"],"names":[],"mappings":"AAYA,IAAI,UAA4D,GAAA,IAAA;AACzD,SAAS,2BAA2B,SAAyD,EAAA;AAClG,EAAa,UAAA,GAAA,SAAA;AACf;AAGO,SAAS,qBAAuE,GAAA;AACrF,EAAO,OAAA,UAAA;AACT;
|
|
1
|
+
{"version":3,"file":"nativeViewerRegistry.js","sources":["../../../src/features/canvas/nativeViewerRegistry.ts"],"sourcesContent":["/**\n * Seam between the app shell and this package for the FEDERATED canvas viewer.\n *\n * The federated loader (`import('canvas_native/Viewer')`) must live in the app\n * (portable-devices/mobile): this package also builds through rollup for lib/,\n * and rollup must never see a bare `canvas_native/...` specifier. The screen,\n * however, lives HERE, where routes register. So the app injects its loader at\n * startup and the screen reads it back - the same inversion the surfaces use\n * for host services, scaled down to one component.\n */\nimport type { ComponentType } from 'react';\nimport type { NativeCanvasViewerProps } from './NativeCanvasViewer';\n\nlet registered: ComponentType<NativeCanvasViewerProps> | null = null;\n\nexport function registerNativeCanvasViewer(component: ComponentType<NativeCanvasViewerProps>): void {\n registered = component;\n}\n\n/** Null when the host app has not injected a loader (e.g. a build without federation). */\nexport function getNativeCanvasViewer(): ComponentType<NativeCanvasViewerProps> | null {\n return registered;\n}\n\n/**\n * The federated canvas EXPERIENCE (boards + viewer), registered by the app the\n * same way the viewer is. Kept as a separate seam so a host that only wants the\n * raw renderer - a preview, a test - is unaffected.\n */\nexport type CanvasExperienceComponent = ComponentType<{\n token?: string | null;\n indexUrl: string;\n channelId?: string;\n sessionError?: string | null;\n onRetrySession?: () => void;\n /** Deep links (CanvasExperienceProps): each runs once on mount. */\n createTile?: string;\n media?: { src: string; kind?: string; name?: string };\n designId?: string;\n designTemplateId?: string;\n artifactId?: string;\n}>;\n\nlet experience: CanvasExperienceComponent | null = null;\nlet experiencePreload: (() => Promise<void>) | null = null;\n\nexport function registerNativeCanvasExperience(component: CanvasExperienceComponent): void {\n experience = component;\n}\n\nexport function getNativeCanvasExperience(): CanvasExperienceComponent | null {\n return experience;\n}\n\n/**\n * Host registers the federated `import('canvas_native/Viewer')` so Home can\n * start the download before the user opens Canvas Native.\n */\nexport function registerCanvasExperiencePreload(fn: () => Promise<void>): void {\n experiencePreload = fn;\n}\n\nexport function preloadNativeCanvasExperience(): Promise<void> {\n return experiencePreload?.() ?? Promise.resolve();\n}\n"],"names":[],"mappings":"AAYA,IAAI,UAA4D,GAAA,IAAA;AACzD,SAAS,2BAA2B,SAAyD,EAAA;AAClG,EAAa,UAAA,GAAA,SAAA;AACf;AAGO,SAAS,qBAAuE,GAAA;AACrF,EAAO,OAAA,UAAA;AACT;AAwBA,IAAI,UAA+C,GAAA,IAAA;AACnD,IAAI,iBAAkD,GAAA,IAAA;AAC/C,SAAS,+BAA+B,SAA4C,EAAA;AACzF,EAAa,UAAA,GAAA,SAAA;AACf;AACO,SAAS,yBAA8D,GAAA;AAC5E,EAAO,OAAA,UAAA;AACT;AAMO,SAAS,gCAAgC,EAA+B,EAAA;AAC7E,EAAoB,iBAAA,GAAA,EAAA;AACtB;AACO,SAAS,6BAA+C,GAAA;AA5D/D,EAAA,IAAA,EAAA;AA6DE,EAAO,OAAA,CAAA,EAAA,GAAA,iBAAA,IAAA,IAAA,GAAA,MAAA,GAAA,iBAAA,EAAA,KAAA,IAAA,GAAA,EAAA,GAAyB,QAAQ,OAAQ,EAAA;AAClD"}
|