@comergehq/studio 0.1.12 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +26 -3
- package/dist/index.d.ts +26 -3
- package/dist/index.js +538 -307
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +544 -313
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
- package/src/components/{floating-draggable-button/FloatingDraggableButton.tsx → bubble/Bubble.tsx} +3 -3
- package/src/components/{floating-draggable-button → bubble}/constants.ts +2 -2
- package/src/components/bubble/index.ts +4 -0
- package/src/components/{floating-draggable-button → bubble}/types.ts +3 -3
- package/src/components/index.ts +2 -2
- package/src/core/services/http/baseUrl.ts +1 -1
- package/src/core/services/http/public.ts +7 -7
- package/src/data/apps/bundles/remote.ts +17 -0
- package/src/data/apps/bundles/repository.ts +14 -0
- package/src/data/apps/bundles/types.ts +15 -0
- package/src/studio/ComergeStudio.tsx +17 -9
- package/src/studio/bootstrap/StudioBootstrap.tsx +2 -2
- package/src/studio/bootstrap/useStudioBootstrap.ts +7 -7
- package/src/studio/hooks/useBundleManager.ts +323 -19
- package/src/studio/ui/RuntimeRenderer.tsx +24 -1
- package/src/studio/ui/StudioOverlay.tsx +6 -6
- package/src/components/floating-draggable-button/index.ts +0 -4
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
|
|
38
38
|
// src/studio/ComergeStudio.tsx
|
|
39
|
-
var
|
|
39
|
+
var React43 = __toESM(require("react"));
|
|
40
40
|
var import_react_native55 = require("react-native");
|
|
41
41
|
var import_bottom_sheet6 = require("@gorhom/bottom-sheet");
|
|
42
42
|
|
|
@@ -218,11 +218,11 @@ var React = __toESM(require("react"));
|
|
|
218
218
|
var import_axios = __toESM(require("axios"));
|
|
219
219
|
|
|
220
220
|
// src/core/services/http/baseUrl.ts
|
|
221
|
-
var BASE_URL = "https://comerge.ai";
|
|
221
|
+
var BASE_URL = "https://api.comerge.ai";
|
|
222
222
|
|
|
223
223
|
// src/core/services/http/public.ts
|
|
224
224
|
var CLIENT_KEY_HEADER = "x-comerge-api-key";
|
|
225
|
-
var
|
|
225
|
+
var clientKey = null;
|
|
226
226
|
var publicApi = import_axios.default.create({
|
|
227
227
|
baseURL: BASE_URL,
|
|
228
228
|
timeout: 3e4,
|
|
@@ -231,19 +231,19 @@ var publicApi = import_axios.default.create({
|
|
|
231
231
|
"Content-Type": "application/json"
|
|
232
232
|
}
|
|
233
233
|
});
|
|
234
|
-
function
|
|
234
|
+
function setClientKey(clientKeyInput) {
|
|
235
235
|
var _a;
|
|
236
|
-
const trimmed = ((_a =
|
|
236
|
+
const trimmed = ((_a = clientKeyInput == null ? void 0 : clientKeyInput.trim) == null ? void 0 : _a.call(clientKeyInput)) ?? "";
|
|
237
237
|
if (!trimmed) {
|
|
238
|
-
throw new Error("comerge-studio:
|
|
238
|
+
throw new Error("comerge-studio: clientKey is required");
|
|
239
239
|
}
|
|
240
|
-
|
|
240
|
+
clientKey = trimmed;
|
|
241
241
|
publicApi.defaults.headers.common[CLIENT_KEY_HEADER] = trimmed;
|
|
242
242
|
}
|
|
243
243
|
publicApi.interceptors.request.use((config) => {
|
|
244
|
-
if (!
|
|
244
|
+
if (!clientKey) return config;
|
|
245
245
|
config.headers = config.headers ?? {};
|
|
246
|
-
config.headers[CLIENT_KEY_HEADER] =
|
|
246
|
+
config.headers[CLIENT_KEY_HEADER] = clientKey;
|
|
247
247
|
return config;
|
|
248
248
|
});
|
|
249
249
|
|
|
@@ -308,42 +308,9 @@ async function ensureAnonymousSession() {
|
|
|
308
308
|
return { user: data.user, isNew: true };
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
-
// src/data/base-repository.ts
|
|
312
|
-
var BaseRepository = class {
|
|
313
|
-
unwrapOrThrow(res) {
|
|
314
|
-
if (res.success && res.responseObject) return res.responseObject;
|
|
315
|
-
const msg = res.message || "Request failed";
|
|
316
|
-
throw new Error(msg);
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
// src/data/base-remote.ts
|
|
321
|
-
var BaseRemote = class {
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
// src/data/public/studio-config/remote.ts
|
|
325
|
-
var StudioConfigRemoteDataSourceImpl = class extends BaseRemote {
|
|
326
|
-
async get() {
|
|
327
|
-
const { data } = await publicApi.get("/v1/public/studio-config");
|
|
328
|
-
return data;
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
var studioConfigRemoteDataSource = new StudioConfigRemoteDataSourceImpl();
|
|
332
|
-
|
|
333
|
-
// src/data/public/studio-config/repository.ts
|
|
334
|
-
var StudioConfigRepositoryImpl = class extends BaseRepository {
|
|
335
|
-
constructor(remote) {
|
|
336
|
-
super();
|
|
337
|
-
this.remote = remote;
|
|
338
|
-
}
|
|
339
|
-
async get() {
|
|
340
|
-
const res = await this.remote.get();
|
|
341
|
-
return this.unwrapOrThrow(res);
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
var studioConfigRepository = new StudioConfigRepositoryImpl(studioConfigRemoteDataSource);
|
|
345
|
-
|
|
346
311
|
// src/studio/bootstrap/useStudioBootstrap.ts
|
|
312
|
+
var SUPABASE_URL = "https://xtfxwbckjpfmqubnsusu.supabase.co";
|
|
313
|
+
var SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh0Znh3YmNranBmbXF1Ym5zdXN1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA2MDEyMzAsImV4cCI6MjA3NjE3NzIzMH0.dzWGAWrK4CvrmHVHzf8w7JlUZohdap0ZPnLZnABMV8s";
|
|
347
314
|
function useStudioBootstrap(options) {
|
|
348
315
|
const [state, setState] = React.useState({
|
|
349
316
|
ready: false,
|
|
@@ -354,11 +321,10 @@ function useStudioBootstrap(options) {
|
|
|
354
321
|
let cancelled = false;
|
|
355
322
|
(async () => {
|
|
356
323
|
try {
|
|
357
|
-
|
|
324
|
+
setClientKey(options.clientKey);
|
|
358
325
|
const requireAuth = isSupabaseClientInjected();
|
|
359
326
|
if (!requireAuth) {
|
|
360
|
-
|
|
361
|
-
setSupabaseConfig(cfg);
|
|
327
|
+
setSupabaseConfig({ url: SUPABASE_URL, anonKey: SUPABASE_ANON_KEY });
|
|
362
328
|
}
|
|
363
329
|
const { user } = requireAuth ? await ensureAuthenticatedSession() : await ensureAnonymousSession();
|
|
364
330
|
if (cancelled) return;
|
|
@@ -372,14 +338,14 @@ function useStudioBootstrap(options) {
|
|
|
372
338
|
return () => {
|
|
373
339
|
cancelled = true;
|
|
374
340
|
};
|
|
375
|
-
}, [options.
|
|
341
|
+
}, [options.clientKey]);
|
|
376
342
|
return state;
|
|
377
343
|
}
|
|
378
344
|
|
|
379
345
|
// src/studio/bootstrap/StudioBootstrap.tsx
|
|
380
346
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
381
|
-
function StudioBootstrap({ children, fallback, renderError,
|
|
382
|
-
const { ready, error, userId } = useStudioBootstrap({
|
|
347
|
+
function StudioBootstrap({ children, fallback, renderError, clientKey: clientKey2 }) {
|
|
348
|
+
const { ready, error, userId } = useStudioBootstrap({ clientKey: clientKey2 });
|
|
383
349
|
if (error) {
|
|
384
350
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: { flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, children: renderError ? renderError(error) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { variant: "bodyMuted", children: error.message }) });
|
|
385
351
|
}
|
|
@@ -527,6 +493,10 @@ var createApiClient = (baseURL) => {
|
|
|
527
493
|
};
|
|
528
494
|
var api = createApiClient(BASE_URL);
|
|
529
495
|
|
|
496
|
+
// src/data/base-remote.ts
|
|
497
|
+
var BaseRemote = class {
|
|
498
|
+
};
|
|
499
|
+
|
|
530
500
|
// src/data/apps/remote.ts
|
|
531
501
|
var AppsRemoteDataSourceImpl = class extends BaseRemote {
|
|
532
502
|
async list(projectId) {
|
|
@@ -582,6 +552,15 @@ var AppsRemoteDataSourceImpl = class extends BaseRemote {
|
|
|
582
552
|
};
|
|
583
553
|
var appsRemoteDataSource = new AppsRemoteDataSourceImpl();
|
|
584
554
|
|
|
555
|
+
// src/data/base-repository.ts
|
|
556
|
+
var BaseRepository = class {
|
|
557
|
+
unwrapOrThrow(res) {
|
|
558
|
+
if (res.success && res.responseObject) return res.responseObject;
|
|
559
|
+
const msg = res.message || "Request failed";
|
|
560
|
+
throw new Error(msg);
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
|
|
585
564
|
// src/data/apps/repository.ts
|
|
586
565
|
function mapDbAppRow(row) {
|
|
587
566
|
return {
|
|
@@ -934,6 +913,8 @@ function useThreadMessages(threadId) {
|
|
|
934
913
|
// src/studio/hooks/useBundleManager.ts
|
|
935
914
|
var React5 = __toESM(require("react"));
|
|
936
915
|
var FileSystem = __toESM(require("expo-file-system/legacy"));
|
|
916
|
+
var import_expo_asset = require("expo-asset");
|
|
917
|
+
var import_react_native_zip_archive = require("react-native-zip-archive");
|
|
937
918
|
|
|
938
919
|
// src/data/apps/bundles/remote.ts
|
|
939
920
|
var BundlesRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -957,6 +938,13 @@ var BundlesRemoteDataSourceImpl = class extends BaseRemote {
|
|
|
957
938
|
);
|
|
958
939
|
return data;
|
|
959
940
|
}
|
|
941
|
+
async getSignedAssetsDownloadUrl(appId, bundleId, options) {
|
|
942
|
+
const { data } = await api.get(
|
|
943
|
+
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/assets/download`,
|
|
944
|
+
{ params: { redirect: (options == null ? void 0 : options.redirect) ?? false, kind: options == null ? void 0 : options.kind } }
|
|
945
|
+
);
|
|
946
|
+
return data;
|
|
947
|
+
}
|
|
960
948
|
};
|
|
961
949
|
var bundlesRemoteDataSource = new BundlesRemoteDataSourceImpl();
|
|
962
950
|
|
|
@@ -978,6 +966,10 @@ var BundlesRepositoryImpl = class extends BaseRepository {
|
|
|
978
966
|
const res = await this.remote.getSignedDownloadUrl(appId, bundleId, options);
|
|
979
967
|
return this.unwrapOrThrow(res);
|
|
980
968
|
}
|
|
969
|
+
async getSignedAssetsDownloadUrl(appId, bundleId, options) {
|
|
970
|
+
const res = await this.remote.getSignedAssetsDownloadUrl(appId, bundleId, options);
|
|
971
|
+
return this.unwrapOrThrow(res);
|
|
972
|
+
}
|
|
981
973
|
};
|
|
982
974
|
var bundlesRepository = new BundlesRepositoryImpl(bundlesRemoteDataSource);
|
|
983
975
|
|
|
@@ -1029,20 +1021,40 @@ async function ensureDir(path) {
|
|
|
1029
1021
|
if (info.exists) return;
|
|
1030
1022
|
await FileSystem.makeDirectoryAsync(path, { intermediates: true });
|
|
1031
1023
|
}
|
|
1024
|
+
async function ensureBundleDir(key) {
|
|
1025
|
+
await ensureDir(bundlesCacheDir());
|
|
1026
|
+
await ensureDir(bundleDir(key));
|
|
1027
|
+
}
|
|
1032
1028
|
function baseBundleKey(appId, platform) {
|
|
1033
1029
|
return `base:${appId}:${platform}`;
|
|
1034
1030
|
}
|
|
1035
1031
|
function testBundleKey(appId, commitId, platform, bundleId) {
|
|
1036
1032
|
return `test:${appId}:${commitId ?? "head"}:${platform}:${bundleId}`;
|
|
1037
1033
|
}
|
|
1038
|
-
function
|
|
1034
|
+
function legacyBundleFileUri(key) {
|
|
1039
1035
|
const dir = bundlesCacheDir();
|
|
1040
1036
|
return `${dir}${safeName(key)}.jsbundle`;
|
|
1041
1037
|
}
|
|
1042
|
-
function
|
|
1038
|
+
function legacyBundleMetaFileUri(key) {
|
|
1043
1039
|
const dir = bundlesCacheDir();
|
|
1044
1040
|
return `${dir}${safeName(key)}.meta.json`;
|
|
1045
1041
|
}
|
|
1042
|
+
function bundleDir(key) {
|
|
1043
|
+
const dir = bundlesCacheDir();
|
|
1044
|
+
return `${dir}${safeName(key)}/`;
|
|
1045
|
+
}
|
|
1046
|
+
function toBundleFileUri(key, platform) {
|
|
1047
|
+
return `${bundleDir(key)}index.${platform}.jsbundle`;
|
|
1048
|
+
}
|
|
1049
|
+
function toBundleMetaFileUri(key) {
|
|
1050
|
+
return `${bundleDir(key)}bundle.meta.json`;
|
|
1051
|
+
}
|
|
1052
|
+
function toAssetsMetaFileUri(key) {
|
|
1053
|
+
return `${bundleDir(key)}assets.meta.json`;
|
|
1054
|
+
}
|
|
1055
|
+
function toAssetsDir(key) {
|
|
1056
|
+
return `${bundleDir(key)}assets/`;
|
|
1057
|
+
}
|
|
1046
1058
|
async function readJsonFile(fileUri) {
|
|
1047
1059
|
try {
|
|
1048
1060
|
const info = await FileSystem.getInfoAsync(fileUri);
|
|
@@ -1069,6 +1081,14 @@ async function getExistingNonEmptyFileUri(fileUri) {
|
|
|
1069
1081
|
return null;
|
|
1070
1082
|
}
|
|
1071
1083
|
}
|
|
1084
|
+
async function getExistingBundleFileUri(key, platform) {
|
|
1085
|
+
const nextPath = toBundleFileUri(key, platform);
|
|
1086
|
+
const next = await getExistingNonEmptyFileUri(nextPath);
|
|
1087
|
+
if (next) return next;
|
|
1088
|
+
const legacyPath = legacyBundleFileUri(key);
|
|
1089
|
+
const legacy = await getExistingNonEmptyFileUri(legacyPath);
|
|
1090
|
+
return legacy;
|
|
1091
|
+
}
|
|
1072
1092
|
async function downloadIfMissing(url, fileUri) {
|
|
1073
1093
|
const existing = await getExistingNonEmptyFileUri(fileUri);
|
|
1074
1094
|
if (existing) return existing;
|
|
@@ -1092,8 +1112,71 @@ async function deleteFileIfExists(fileUri) {
|
|
|
1092
1112
|
} catch {
|
|
1093
1113
|
}
|
|
1094
1114
|
}
|
|
1095
|
-
async function
|
|
1096
|
-
|
|
1115
|
+
async function hydrateBaseFromEmbeddedAsset(appId, platform, embedded) {
|
|
1116
|
+
if (!(embedded == null ? void 0 : embedded.module)) return null;
|
|
1117
|
+
const key = baseBundleKey(appId, platform);
|
|
1118
|
+
const existing = await getExistingBundleFileUri(key, platform);
|
|
1119
|
+
if (existing) {
|
|
1120
|
+
return { bundlePath: existing, meta: embedded.meta ?? null };
|
|
1121
|
+
}
|
|
1122
|
+
await ensureBundleDir(key);
|
|
1123
|
+
const targetUri = toBundleFileUri(key, platform);
|
|
1124
|
+
const asset = import_expo_asset.Asset.fromModule(embedded.module);
|
|
1125
|
+
await asset.downloadAsync();
|
|
1126
|
+
const sourceUri = asset.localUri ?? asset.uri;
|
|
1127
|
+
if (!sourceUri) return null;
|
|
1128
|
+
const info = await FileSystem.getInfoAsync(sourceUri);
|
|
1129
|
+
if (!info.exists) return null;
|
|
1130
|
+
await deleteFileIfExists(targetUri);
|
|
1131
|
+
await FileSystem.copyAsync({ from: sourceUri, to: targetUri });
|
|
1132
|
+
const finalUri = await getExistingNonEmptyFileUri(targetUri);
|
|
1133
|
+
if (!finalUri) return null;
|
|
1134
|
+
return { bundlePath: finalUri, meta: embedded.meta ?? null };
|
|
1135
|
+
}
|
|
1136
|
+
async function hydrateAssetsFromEmbeddedAsset(appId, platform, key, embedded) {
|
|
1137
|
+
var _a;
|
|
1138
|
+
const moduleId = embedded == null ? void 0 : embedded.assetsModule;
|
|
1139
|
+
if (!moduleId) return false;
|
|
1140
|
+
const assetsMeta = (embedded == null ? void 0 : embedded.assetsMeta) ?? null;
|
|
1141
|
+
const assetsDir = toAssetsDir(key);
|
|
1142
|
+
const metaUri = toAssetsMetaFileUri(key);
|
|
1143
|
+
const existingMeta = await readJsonFile(metaUri);
|
|
1144
|
+
const assetsDirInfo = await FileSystem.getInfoAsync(assetsDir);
|
|
1145
|
+
const assetsDirExists = assetsDirInfo.exists && assetsDirInfo.isDirectory;
|
|
1146
|
+
const checksumMatches = Boolean(existingMeta == null ? void 0 : existingMeta.checksumSha256) && Boolean(assetsMeta == null ? void 0 : assetsMeta.checksumSha256) && (existingMeta == null ? void 0 : existingMeta.checksumSha256) === (assetsMeta == null ? void 0 : assetsMeta.checksumSha256);
|
|
1147
|
+
const embeddedMetaMatches = (_a = existingMeta == null ? void 0 : existingMeta.storageKey) == null ? void 0 : _a.startsWith("embedded:");
|
|
1148
|
+
if (assetsDirExists && checksumMatches && embeddedMetaMatches) {
|
|
1149
|
+
return true;
|
|
1150
|
+
}
|
|
1151
|
+
await ensureBundleDir(key);
|
|
1152
|
+
await ensureDir(assetsDir);
|
|
1153
|
+
const asset = import_expo_asset.Asset.fromModule(moduleId);
|
|
1154
|
+
await asset.downloadAsync();
|
|
1155
|
+
const sourceUri = asset.localUri ?? asset.uri;
|
|
1156
|
+
if (!sourceUri) return false;
|
|
1157
|
+
const info = await FileSystem.getInfoAsync(sourceUri);
|
|
1158
|
+
if (!info.exists) return false;
|
|
1159
|
+
const zipUri = `${bundleDir(key)}assets.zip`;
|
|
1160
|
+
await deleteFileIfExists(zipUri);
|
|
1161
|
+
await FileSystem.copyAsync({ from: sourceUri, to: zipUri });
|
|
1162
|
+
try {
|
|
1163
|
+
await FileSystem.deleteAsync(assetsDir, { idempotent: true }).catch(() => {
|
|
1164
|
+
});
|
|
1165
|
+
} catch {
|
|
1166
|
+
}
|
|
1167
|
+
await ensureDir(assetsDir);
|
|
1168
|
+
await unzipArchive(zipUri, assetsDir);
|
|
1169
|
+
await writeJsonFile(metaUri, {
|
|
1170
|
+
checksumSha256: (assetsMeta == null ? void 0 : assetsMeta.checksumSha256) ?? null,
|
|
1171
|
+
storageKey: `embedded:${(assetsMeta == null ? void 0 : assetsMeta.checksumSha256) ?? "unknown"}`,
|
|
1172
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1173
|
+
});
|
|
1174
|
+
return true;
|
|
1175
|
+
}
|
|
1176
|
+
async function safeReplaceFileFromUrl(url, targetUri, tmpKey, platform) {
|
|
1177
|
+
const tmpKeySafe = `tmp:${tmpKey}:${Date.now()}`;
|
|
1178
|
+
const tmpUri = toBundleFileUri(tmpKeySafe, platform);
|
|
1179
|
+
await ensureDir(bundleDir(tmpKeySafe));
|
|
1097
1180
|
try {
|
|
1098
1181
|
await withRetry(
|
|
1099
1182
|
async () => {
|
|
@@ -1113,6 +1196,82 @@ async function safeReplaceFileFromUrl(url, targetUri, tmpKey) {
|
|
|
1113
1196
|
await deleteFileIfExists(tmpUri);
|
|
1114
1197
|
}
|
|
1115
1198
|
}
|
|
1199
|
+
async function safeReplaceFileFromUrlToPath(url, targetUri, tmpKey) {
|
|
1200
|
+
const tmpDir = `${bundlesCacheDir()}tmp/`;
|
|
1201
|
+
await ensureDir(tmpDir);
|
|
1202
|
+
const tmpUri = `${tmpDir}${safeName(tmpKey)}.tmp`;
|
|
1203
|
+
try {
|
|
1204
|
+
await withRetry(
|
|
1205
|
+
async () => {
|
|
1206
|
+
await deleteFileIfExists(tmpUri);
|
|
1207
|
+
await FileSystem.downloadAsync(url, tmpUri);
|
|
1208
|
+
const tmpOk = await getExistingNonEmptyFileUri(tmpUri);
|
|
1209
|
+
if (!tmpOk) throw new Error("Downloaded file is empty.");
|
|
1210
|
+
},
|
|
1211
|
+
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
1212
|
+
);
|
|
1213
|
+
await deleteFileIfExists(targetUri);
|
|
1214
|
+
await FileSystem.moveAsync({ from: tmpUri, to: targetUri });
|
|
1215
|
+
const finalOk = await getExistingNonEmptyFileUri(targetUri);
|
|
1216
|
+
if (!finalOk) throw new Error("File replacement failed.");
|
|
1217
|
+
return targetUri;
|
|
1218
|
+
} finally {
|
|
1219
|
+
await deleteFileIfExists(tmpUri);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
function getMetroAssets(bundle) {
|
|
1223
|
+
const assets = bundle.assets ?? [];
|
|
1224
|
+
return assets.find((asset) => asset.kind === "metro-assets") ?? null;
|
|
1225
|
+
}
|
|
1226
|
+
async function ensureAssetsForBundle(appId, bundle, key, platform) {
|
|
1227
|
+
var _a;
|
|
1228
|
+
const asset = getMetroAssets(bundle);
|
|
1229
|
+
if (!(asset == null ? void 0 : asset.storageKey)) return;
|
|
1230
|
+
await ensureBundleDir(key);
|
|
1231
|
+
const assetsDir = toAssetsDir(key);
|
|
1232
|
+
await ensureDir(assetsDir);
|
|
1233
|
+
const metaUri = toAssetsMetaFileUri(key);
|
|
1234
|
+
const existingMeta = await readJsonFile(metaUri);
|
|
1235
|
+
const assetsDirInfo = await FileSystem.getInfoAsync(assetsDir);
|
|
1236
|
+
const assetsDirExists = assetsDirInfo.exists && assetsDirInfo.isDirectory;
|
|
1237
|
+
if ((existingMeta == null ? void 0 : existingMeta.checksumSha256) && asset.checksumSha256 && existingMeta.checksumSha256 === asset.checksumSha256 && (existingMeta.storageKey === asset.storageKey || ((_a = existingMeta.storageKey) == null ? void 0 : _a.startsWith("embedded:"))) && assetsDirExists) {
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
const signed = await withRetry(
|
|
1241
|
+
async () => {
|
|
1242
|
+
return await bundlesRepository.getSignedAssetsDownloadUrl(appId, bundle.id, {
|
|
1243
|
+
redirect: false,
|
|
1244
|
+
kind: asset.kind
|
|
1245
|
+
});
|
|
1246
|
+
},
|
|
1247
|
+
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
1248
|
+
);
|
|
1249
|
+
const zipUri = `${bundleDir(key)}assets.zip`;
|
|
1250
|
+
await safeReplaceFileFromUrlToPath(signed.url, zipUri, `${appId}:${bundle.id}:${platform}:${asset.kind}`);
|
|
1251
|
+
try {
|
|
1252
|
+
await FileSystem.deleteAsync(assetsDir, { idempotent: true }).catch(() => {
|
|
1253
|
+
});
|
|
1254
|
+
} catch {
|
|
1255
|
+
}
|
|
1256
|
+
await ensureDir(assetsDir);
|
|
1257
|
+
await unzipArchive(zipUri, assetsDir);
|
|
1258
|
+
await writeJsonFile(metaUri, {
|
|
1259
|
+
checksumSha256: asset.checksumSha256 ?? null,
|
|
1260
|
+
storageKey: asset.storageKey,
|
|
1261
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
async function unzipArchive(sourceUri, destDir) {
|
|
1265
|
+
try {
|
|
1266
|
+
await (0, import_react_native_zip_archive.unzip)(sourceUri, destDir);
|
|
1267
|
+
} catch (e) {
|
|
1268
|
+
throw new Error(
|
|
1269
|
+
`Failed to extract assets archive. Ensure 'react-native-zip-archive' is installed in the host app. ${String(
|
|
1270
|
+
(e == null ? void 0 : e.message) ?? e
|
|
1271
|
+
)}`
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1116
1275
|
async function pollBundle(appId, bundleId, opts) {
|
|
1117
1276
|
const start = Date.now();
|
|
1118
1277
|
while (true) {
|
|
@@ -1148,23 +1307,39 @@ async function resolveBundlePath(src, platform, mode) {
|
|
|
1148
1307
|
if (finalBundle.status === "failed") {
|
|
1149
1308
|
throw new Error("Bundle build failed.");
|
|
1150
1309
|
}
|
|
1310
|
+
let bundleWithAssets = finalBundle;
|
|
1311
|
+
if (finalBundle.status === "succeeded" && (!finalBundle.assets || finalBundle.assets.length === 0)) {
|
|
1312
|
+
try {
|
|
1313
|
+
bundleWithAssets = await bundlesRepository.getById(appId, finalBundle.id);
|
|
1314
|
+
} catch {
|
|
1315
|
+
bundleWithAssets = finalBundle;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1151
1318
|
const signed = await withRetry(
|
|
1152
1319
|
async () => {
|
|
1153
1320
|
return await bundlesRepository.getSignedDownloadUrl(appId, finalBundle.id, { redirect: false });
|
|
1154
1321
|
},
|
|
1155
1322
|
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
1156
1323
|
);
|
|
1324
|
+
const key = mode === "base" ? baseBundleKey(appId, platform) : testBundleKey(appId, commitId, platform, finalBundle.id);
|
|
1325
|
+
await ensureBundleDir(key);
|
|
1157
1326
|
const bundlePath = mode === "base" ? await safeReplaceFileFromUrl(
|
|
1158
1327
|
signed.url,
|
|
1159
|
-
toBundleFileUri(
|
|
1160
|
-
`${appId}:${commitId ?? "head"}:${platform}:${finalBundle.id}
|
|
1161
|
-
|
|
1162
|
-
|
|
1328
|
+
toBundleFileUri(key, platform),
|
|
1329
|
+
`${appId}:${commitId ?? "head"}:${platform}:${finalBundle.id}`,
|
|
1330
|
+
platform
|
|
1331
|
+
) : await downloadIfMissing(signed.url, toBundleFileUri(key, platform));
|
|
1332
|
+
try {
|
|
1333
|
+
await ensureAssetsForBundle(appId, bundleWithAssets, key, platform);
|
|
1334
|
+
} catch {
|
|
1335
|
+
}
|
|
1336
|
+
return { bundlePath, label: "Ready", bundle: bundleWithAssets };
|
|
1163
1337
|
}
|
|
1164
1338
|
function useBundleManager({
|
|
1165
1339
|
base,
|
|
1166
1340
|
platform,
|
|
1167
|
-
canRequestLatest = true
|
|
1341
|
+
canRequestLatest = true,
|
|
1342
|
+
embeddedBaseBundles
|
|
1168
1343
|
}) {
|
|
1169
1344
|
const [bundlePath, setBundlePath] = React5.useState(null);
|
|
1170
1345
|
const [renderToken, setRenderToken] = React5.useState(0);
|
|
@@ -1175,6 +1350,8 @@ function useBundleManager({
|
|
|
1175
1350
|
const [isTesting, setIsTesting] = React5.useState(false);
|
|
1176
1351
|
const baseRef = React5.useRef(base);
|
|
1177
1352
|
baseRef.current = base;
|
|
1353
|
+
const embeddedBaseBundlesRef = React5.useRef(embeddedBaseBundles);
|
|
1354
|
+
embeddedBaseBundlesRef.current = embeddedBaseBundles;
|
|
1178
1355
|
const baseOpIdRef = React5.useRef(0);
|
|
1179
1356
|
const testOpIdRef = React5.useRef(0);
|
|
1180
1357
|
const activeLoadModeRef = React5.useRef(null);
|
|
@@ -1197,16 +1374,39 @@ function useBundleManager({
|
|
|
1197
1374
|
const hasCompletedFirstNetworkBaseLoadRef = React5.useRef(false);
|
|
1198
1375
|
const hydrateBaseFromDisk = React5.useCallback(
|
|
1199
1376
|
async (appId, reason) => {
|
|
1377
|
+
var _a, _b, _c;
|
|
1200
1378
|
try {
|
|
1201
1379
|
const dir = bundlesCacheDir();
|
|
1202
1380
|
await ensureDir(dir);
|
|
1203
1381
|
const key = baseBundleKey(appId, platform);
|
|
1204
|
-
|
|
1205
|
-
|
|
1382
|
+
let existing = await getExistingBundleFileUri(key, platform);
|
|
1383
|
+
let embeddedMeta = null;
|
|
1384
|
+
if (!existing) {
|
|
1385
|
+
const embedded = (_a = embeddedBaseBundlesRef.current) == null ? void 0 : _a[platform];
|
|
1386
|
+
const hydrated = await hydrateBaseFromEmbeddedAsset(appId, platform, embedded);
|
|
1387
|
+
if (hydrated == null ? void 0 : hydrated.bundlePath) {
|
|
1388
|
+
existing = hydrated.bundlePath;
|
|
1389
|
+
embeddedMeta = hydrated.meta ?? null;
|
|
1390
|
+
if (embeddedMeta) {
|
|
1391
|
+
await ensureBundleDir(key);
|
|
1392
|
+
await writeJsonFile(toBundleMetaFileUri(key), embeddedMeta);
|
|
1393
|
+
await writeJsonFile(legacyBundleMetaFileUri(key), embeddedMeta);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1206
1397
|
if (existing) {
|
|
1207
1398
|
lastBaseBundlePathRef.current = existing;
|
|
1208
1399
|
setBundlePath(existing);
|
|
1209
|
-
const meta = await readJsonFile(toBundleMetaFileUri(key));
|
|
1400
|
+
const meta = embeddedMeta ?? await readJsonFile(toBundleMetaFileUri(key)) ?? await readJsonFile(legacyBundleMetaFileUri(key));
|
|
1401
|
+
const embedded = (_b = embeddedBaseBundlesRef.current) == null ? void 0 : _b[platform];
|
|
1402
|
+
const embeddedFingerprint = ((_c = embedded == null ? void 0 : embedded.meta) == null ? void 0 : _c.fingerprint) ?? null;
|
|
1403
|
+
const actualFingerprint = (meta == null ? void 0 : meta.fingerprint) ?? (embeddedMeta == null ? void 0 : embeddedMeta.fingerprint) ?? null;
|
|
1404
|
+
if ((embedded == null ? void 0 : embedded.assetsModule) && embeddedFingerprint && actualFingerprint === embeddedFingerprint) {
|
|
1405
|
+
try {
|
|
1406
|
+
await hydrateAssetsFromEmbeddedAsset(appId, platform, key, embedded);
|
|
1407
|
+
} catch {
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1210
1410
|
if (meta == null ? void 0 : meta.fingerprint) {
|
|
1211
1411
|
lastBaseFingerprintRef.current = meta.fingerprint;
|
|
1212
1412
|
}
|
|
@@ -1271,7 +1471,16 @@ function useBundleManager({
|
|
|
1271
1471
|
lastBaseFingerprintRef.current = fingerprint;
|
|
1272
1472
|
hasCompletedFirstNetworkBaseLoadRef.current = true;
|
|
1273
1473
|
initialHydratedBaseFromDiskRef.current = false;
|
|
1274
|
-
|
|
1474
|
+
const metaKey = baseBundleKey(src.appId, platform);
|
|
1475
|
+
await ensureBundleDir(metaKey);
|
|
1476
|
+
void writeJsonFile(toBundleMetaFileUri(metaKey), {
|
|
1477
|
+
fingerprint,
|
|
1478
|
+
bundleId: bundle.id,
|
|
1479
|
+
checksumSha256: bundle.checksumSha256 ?? null,
|
|
1480
|
+
size: bundle.size ?? null,
|
|
1481
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1482
|
+
});
|
|
1483
|
+
void writeJsonFile(legacyBundleMetaFileUri(metaKey), {
|
|
1275
1484
|
fingerprint,
|
|
1276
1485
|
bundleId: bundle.id,
|
|
1277
1486
|
checksumSha256: bundle.checksumSha256 ?? null,
|
|
@@ -1793,11 +2002,28 @@ function hasNoOutcomeAfterLastHuman(messages) {
|
|
|
1793
2002
|
}
|
|
1794
2003
|
|
|
1795
2004
|
// src/studio/ui/RuntimeRenderer.tsx
|
|
2005
|
+
var React9 = __toESM(require("react"));
|
|
1796
2006
|
var import_react_native6 = require("react-native");
|
|
1797
2007
|
var import_runtime = require("@comergehq/runtime");
|
|
1798
2008
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1799
|
-
function RuntimeRenderer({
|
|
2009
|
+
function RuntimeRenderer({
|
|
2010
|
+
appKey,
|
|
2011
|
+
bundlePath,
|
|
2012
|
+
forcePreparing,
|
|
2013
|
+
renderToken,
|
|
2014
|
+
style,
|
|
2015
|
+
allowInitialPreparing = true
|
|
2016
|
+
}) {
|
|
2017
|
+
const [hasRenderedOnce, setHasRenderedOnce] = React9.useState(false);
|
|
2018
|
+
React9.useEffect(() => {
|
|
2019
|
+
if (bundlePath) {
|
|
2020
|
+
setHasRenderedOnce(true);
|
|
2021
|
+
}
|
|
2022
|
+
}, [bundlePath]);
|
|
1800
2023
|
if (!bundlePath || forcePreparing) {
|
|
2024
|
+
if (!hasRenderedOnce && !forcePreparing && !allowInitialPreparing) {
|
|
2025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.View, { style: [{ flex: 1 }, style] });
|
|
2026
|
+
}
|
|
1801
2027
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.View, { style: [{ flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { variant: "bodyMuted", children: "Preparing app\u2026" }) });
|
|
1802
2028
|
}
|
|
1803
2029
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.View, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -1812,11 +2038,11 @@ function RuntimeRenderer({ appKey, bundlePath, forcePreparing, renderToken, styl
|
|
|
1812
2038
|
}
|
|
1813
2039
|
|
|
1814
2040
|
// src/studio/ui/StudioOverlay.tsx
|
|
1815
|
-
var
|
|
2041
|
+
var React42 = __toESM(require("react"));
|
|
1816
2042
|
var import_react_native54 = require("react-native");
|
|
1817
2043
|
|
|
1818
2044
|
// src/components/studio-sheet/StudioBottomSheet.tsx
|
|
1819
|
-
var
|
|
2045
|
+
var React12 = __toESM(require("react"));
|
|
1820
2046
|
var import_react_native9 = require("react-native");
|
|
1821
2047
|
var import_bottom_sheet = __toESM(require("@gorhom/bottom-sheet"));
|
|
1822
2048
|
var import_react_native_safe_area_context = require("react-native-safe-area-context");
|
|
@@ -1826,20 +2052,20 @@ var import_react_native8 = require("react-native");
|
|
|
1826
2052
|
var import_liquid_glass2 = require("@callstack/liquid-glass");
|
|
1827
2053
|
|
|
1828
2054
|
// src/components/utils/ResettableLiquidGlassView.tsx
|
|
1829
|
-
var
|
|
2055
|
+
var React11 = __toESM(require("react"));
|
|
1830
2056
|
var import_liquid_glass = require("@callstack/liquid-glass");
|
|
1831
2057
|
|
|
1832
2058
|
// src/components/utils/liquidGlassReset.tsx
|
|
1833
|
-
var
|
|
2059
|
+
var React10 = __toESM(require("react"));
|
|
1834
2060
|
var import_react_native7 = require("react-native");
|
|
1835
2061
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1836
|
-
var LiquidGlassResetContext =
|
|
2062
|
+
var LiquidGlassResetContext = React10.createContext(0);
|
|
1837
2063
|
function LiquidGlassResetProvider({
|
|
1838
2064
|
children,
|
|
1839
2065
|
resetTriggers = []
|
|
1840
2066
|
}) {
|
|
1841
|
-
const [token, setToken] =
|
|
1842
|
-
|
|
2067
|
+
const [token, setToken] = React10.useState(0);
|
|
2068
|
+
React10.useEffect(() => {
|
|
1843
2069
|
if (import_react_native7.Platform.OS !== "ios") return;
|
|
1844
2070
|
const onChange = (state) => {
|
|
1845
2071
|
if (state === "active") setToken((t) => t + 1);
|
|
@@ -1847,21 +2073,21 @@ function LiquidGlassResetProvider({
|
|
|
1847
2073
|
const sub = import_react_native7.AppState.addEventListener("change", onChange);
|
|
1848
2074
|
return () => sub.remove();
|
|
1849
2075
|
}, []);
|
|
1850
|
-
|
|
2076
|
+
React10.useEffect(() => {
|
|
1851
2077
|
setToken((t) => t + 1);
|
|
1852
2078
|
}, resetTriggers);
|
|
1853
2079
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LiquidGlassResetContext.Provider, { value: token, children });
|
|
1854
2080
|
}
|
|
1855
2081
|
function useLiquidGlassResetToken() {
|
|
1856
|
-
return
|
|
2082
|
+
return React10.useContext(LiquidGlassResetContext);
|
|
1857
2083
|
}
|
|
1858
2084
|
|
|
1859
2085
|
// src/components/utils/ResettableLiquidGlassView.tsx
|
|
1860
2086
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1861
2087
|
function ResettableLiquidGlassView({ children, ...props }) {
|
|
1862
2088
|
const token = useLiquidGlassResetToken();
|
|
1863
|
-
const [layoutBootKey, setLayoutBootKey] =
|
|
1864
|
-
const sawNonZeroLayoutRef =
|
|
2089
|
+
const [layoutBootKey, setLayoutBootKey] = React11.useState(0);
|
|
2090
|
+
const sawNonZeroLayoutRef = React11.useRef(false);
|
|
1865
2091
|
const onLayout = (e) => {
|
|
1866
2092
|
var _a;
|
|
1867
2093
|
(_a = props.onLayout) == null ? void 0 : _a.call(props, e);
|
|
@@ -1935,11 +2161,11 @@ function StudioBottomSheet({
|
|
|
1935
2161
|
}) {
|
|
1936
2162
|
const theme = useTheme();
|
|
1937
2163
|
const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
|
|
1938
|
-
const internalSheetRef =
|
|
2164
|
+
const internalSheetRef = React12.useRef(null);
|
|
1939
2165
|
const resolvedSheetRef = sheetRef ?? internalSheetRef;
|
|
1940
|
-
const currentIndexRef =
|
|
1941
|
-
const lastAppStateRef =
|
|
1942
|
-
|
|
2166
|
+
const currentIndexRef = React12.useRef(open ? snapPoints.length - 1 : -1);
|
|
2167
|
+
const lastAppStateRef = React12.useRef(import_react_native9.AppState.currentState);
|
|
2168
|
+
React12.useEffect(() => {
|
|
1943
2169
|
const sub = import_react_native9.AppState.addEventListener("change", (state) => {
|
|
1944
2170
|
const prev = lastAppStateRef.current;
|
|
1945
2171
|
lastAppStateRef.current = state;
|
|
@@ -1959,7 +2185,7 @@ function StudioBottomSheet({
|
|
|
1959
2185
|
});
|
|
1960
2186
|
return () => sub.remove();
|
|
1961
2187
|
}, [open, resolvedSheetRef]);
|
|
1962
|
-
|
|
2188
|
+
React12.useEffect(() => {
|
|
1963
2189
|
const sheet = resolvedSheetRef.current;
|
|
1964
2190
|
if (!sheet) return;
|
|
1965
2191
|
if (open) {
|
|
@@ -1968,7 +2194,7 @@ function StudioBottomSheet({
|
|
|
1968
2194
|
sheet.close();
|
|
1969
2195
|
}
|
|
1970
2196
|
}, [open, resolvedSheetRef, snapPoints.length]);
|
|
1971
|
-
const handleChange =
|
|
2197
|
+
const handleChange = React12.useCallback(
|
|
1972
2198
|
(index) => {
|
|
1973
2199
|
currentIndexRef.current = index;
|
|
1974
2200
|
onOpenChange == null ? void 0 : onOpenChange(index >= 0);
|
|
@@ -1997,12 +2223,12 @@ function StudioBottomSheet({
|
|
|
1997
2223
|
}
|
|
1998
2224
|
|
|
1999
2225
|
// src/components/studio-sheet/StudioSheetPager.tsx
|
|
2000
|
-
var
|
|
2226
|
+
var React13 = __toESM(require("react"));
|
|
2001
2227
|
var import_react_native10 = require("react-native");
|
|
2002
2228
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2003
2229
|
function StudioSheetPager({ activePage, width, preview, chat, style }) {
|
|
2004
|
-
const anim =
|
|
2005
|
-
|
|
2230
|
+
const anim = React13.useRef(new import_react_native10.Animated.Value(activePage === "chat" ? 1 : 0)).current;
|
|
2231
|
+
React13.useEffect(() => {
|
|
2006
2232
|
import_react_native10.Animated.spring(anim, {
|
|
2007
2233
|
toValue: activePage === "chat" ? 1 : 0,
|
|
2008
2234
|
useNativeDriver: true,
|
|
@@ -2050,14 +2276,14 @@ function StudioSheetPager({ activePage, width, preview, chat, style }) {
|
|
|
2050
2276
|
] });
|
|
2051
2277
|
}
|
|
2052
2278
|
|
|
2053
|
-
// src/components/
|
|
2279
|
+
// src/components/bubble/Bubble.tsx
|
|
2054
2280
|
var import_react = require("react");
|
|
2055
2281
|
var import_react_native11 = require("react-native");
|
|
2056
2282
|
var Haptics = __toESM(require("expo-haptics"));
|
|
2057
2283
|
var import_react_native_reanimated = __toESM(require("react-native-reanimated"));
|
|
2058
2284
|
var import_liquid_glass3 = require("@callstack/liquid-glass");
|
|
2059
2285
|
|
|
2060
|
-
// src/components/
|
|
2286
|
+
// src/components/bubble/constants.ts
|
|
2061
2287
|
var DEFAULT_SIZE = 48;
|
|
2062
2288
|
var DEFAULT_EDGE_PADDING = 10;
|
|
2063
2289
|
var DEFAULT_OFFSET = {
|
|
@@ -2068,7 +2294,7 @@ var ENTER_SCALE_FROM = 0.3;
|
|
|
2068
2294
|
var ENTER_ROTATION_FROM_DEG = -180;
|
|
2069
2295
|
var PULSE_DURATION_MS = 900;
|
|
2070
2296
|
|
|
2071
|
-
// src/components/
|
|
2297
|
+
// src/components/bubble/Bubble.tsx
|
|
2072
2298
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2073
2299
|
var HIDDEN_OFFSET_X = 20;
|
|
2074
2300
|
var SPRING_POSITION = { damping: 12, stiffness: 100, mass: 0.8 };
|
|
@@ -2090,7 +2316,7 @@ function getHiddenTranslateY(height) {
|
|
|
2090
2316
|
function getFinalTranslateY(height, size, bottomOffset) {
|
|
2091
2317
|
return height - size - bottomOffset;
|
|
2092
2318
|
}
|
|
2093
|
-
function
|
|
2319
|
+
function Bubble({
|
|
2094
2320
|
onPress,
|
|
2095
2321
|
size = DEFAULT_SIZE,
|
|
2096
2322
|
disabled = false,
|
|
@@ -2315,7 +2541,7 @@ var styles = import_react_native11.StyleSheet.create({
|
|
|
2315
2541
|
});
|
|
2316
2542
|
|
|
2317
2543
|
// src/components/overlays/EdgeGlowFrame.tsx
|
|
2318
|
-
var
|
|
2544
|
+
var React14 = __toESM(require("react"));
|
|
2319
2545
|
var import_react_native12 = require("react-native");
|
|
2320
2546
|
var import_expo_linear_gradient = require("expo-linear-gradient");
|
|
2321
2547
|
|
|
@@ -2358,8 +2584,8 @@ function EdgeGlowFrame({
|
|
|
2358
2584
|
}) {
|
|
2359
2585
|
const theme = useTheme();
|
|
2360
2586
|
const alpha = Math.max(0, Math.min(1, intensity));
|
|
2361
|
-
const anim =
|
|
2362
|
-
|
|
2587
|
+
const anim = React14.useRef(new import_react_native12.Animated.Value(visible ? 1 : 0)).current;
|
|
2588
|
+
React14.useEffect(() => {
|
|
2363
2589
|
import_react_native12.Animated.timing(anim, {
|
|
2364
2590
|
toValue: visible ? 1 : 0,
|
|
2365
2591
|
duration: 300,
|
|
@@ -2410,12 +2636,12 @@ function EdgeGlowFrame({
|
|
|
2410
2636
|
}
|
|
2411
2637
|
|
|
2412
2638
|
// src/components/draw/DrawModeOverlay.tsx
|
|
2413
|
-
var
|
|
2639
|
+
var React17 = __toESM(require("react"));
|
|
2414
2640
|
var import_react_native16 = require("react-native");
|
|
2415
2641
|
var import_react_native_view_shot = require("react-native-view-shot");
|
|
2416
2642
|
|
|
2417
2643
|
// src/components/draw/DrawSurface.tsx
|
|
2418
|
-
var
|
|
2644
|
+
var React15 = __toESM(require("react"));
|
|
2419
2645
|
var import_react_native13 = require("react-native");
|
|
2420
2646
|
var import_react_native_svg = __toESM(require("react-native-svg"));
|
|
2421
2647
|
|
|
@@ -2447,25 +2673,25 @@ function DrawSurface({
|
|
|
2447
2673
|
style,
|
|
2448
2674
|
minDistance = 1
|
|
2449
2675
|
}) {
|
|
2450
|
-
const [renderTick, setRenderTick] =
|
|
2451
|
-
const currentPointsRef =
|
|
2452
|
-
const rafRef =
|
|
2453
|
-
const triggerRender =
|
|
2676
|
+
const [renderTick, setRenderTick] = React15.useState(0);
|
|
2677
|
+
const currentPointsRef = React15.useRef([]);
|
|
2678
|
+
const rafRef = React15.useRef(null);
|
|
2679
|
+
const triggerRender = React15.useCallback(() => {
|
|
2454
2680
|
if (rafRef.current !== null) return;
|
|
2455
2681
|
rafRef.current = requestAnimationFrame(() => {
|
|
2456
2682
|
rafRef.current = null;
|
|
2457
2683
|
setRenderTick((n) => n + 1);
|
|
2458
2684
|
});
|
|
2459
2685
|
}, []);
|
|
2460
|
-
|
|
2686
|
+
React15.useEffect(() => () => {
|
|
2461
2687
|
if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
|
|
2462
2688
|
}, []);
|
|
2463
|
-
const onStart =
|
|
2689
|
+
const onStart = React15.useCallback((e) => {
|
|
2464
2690
|
const { locationX, locationY } = e.nativeEvent;
|
|
2465
2691
|
currentPointsRef.current = [{ x: locationX, y: locationY }];
|
|
2466
2692
|
triggerRender();
|
|
2467
2693
|
}, [triggerRender]);
|
|
2468
|
-
const onMove =
|
|
2694
|
+
const onMove = React15.useCallback((e, _g) => {
|
|
2469
2695
|
const { locationX, locationY } = e.nativeEvent;
|
|
2470
2696
|
const pts = currentPointsRef.current;
|
|
2471
2697
|
if (pts.length > 0) {
|
|
@@ -2478,7 +2704,7 @@ function DrawSurface({
|
|
|
2478
2704
|
currentPointsRef.current = [...pts, { x: locationX, y: locationY }];
|
|
2479
2705
|
triggerRender();
|
|
2480
2706
|
}, [minDistance, triggerRender]);
|
|
2481
|
-
const onEnd =
|
|
2707
|
+
const onEnd = React15.useCallback(() => {
|
|
2482
2708
|
const points = currentPointsRef.current;
|
|
2483
2709
|
if (points.length > 0) {
|
|
2484
2710
|
onAddStroke({ points, color, width: strokeWidth });
|
|
@@ -2486,7 +2712,7 @@ function DrawSurface({
|
|
|
2486
2712
|
currentPointsRef.current = [];
|
|
2487
2713
|
triggerRender();
|
|
2488
2714
|
}, [color, onAddStroke, strokeWidth, triggerRender]);
|
|
2489
|
-
const panResponder =
|
|
2715
|
+
const panResponder = React15.useMemo(
|
|
2490
2716
|
() => import_react_native13.PanResponder.create({
|
|
2491
2717
|
onStartShouldSetPanResponder: () => true,
|
|
2492
2718
|
onMoveShouldSetPanResponder: () => true,
|
|
@@ -2536,7 +2762,7 @@ var styles2 = import_react_native13.StyleSheet.create({
|
|
|
2536
2762
|
});
|
|
2537
2763
|
|
|
2538
2764
|
// src/components/draw/DrawToolbar.tsx
|
|
2539
|
-
var
|
|
2765
|
+
var React16 = __toESM(require("react"));
|
|
2540
2766
|
var import_react_native15 = require("react-native");
|
|
2541
2767
|
var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
|
|
2542
2768
|
var import_lucide_react_native = require("lucide-react-native");
|
|
@@ -2626,11 +2852,11 @@ function DrawToolbar({
|
|
|
2626
2852
|
}) {
|
|
2627
2853
|
const insets = (0, import_react_native_safe_area_context2.useSafeAreaInsets)();
|
|
2628
2854
|
const { width: screenWidth, height: screenHeight } = (0, import_react_native15.useWindowDimensions)();
|
|
2629
|
-
const [expanded, setExpanded] =
|
|
2630
|
-
const pos =
|
|
2631
|
-
const start =
|
|
2632
|
-
const currentPos =
|
|
2633
|
-
|
|
2855
|
+
const [expanded, setExpanded] = React16.useState(false);
|
|
2856
|
+
const pos = React16.useRef(new import_react_native15.Animated.ValueXY({ x: screenWidth / 2 - 110, y: -140 })).current;
|
|
2857
|
+
const start = React16.useRef({ x: 0, y: 0 });
|
|
2858
|
+
const currentPos = React16.useRef({ x: 0, y: 0 });
|
|
2859
|
+
React16.useEffect(() => {
|
|
2634
2860
|
if (hidden) return;
|
|
2635
2861
|
import_react_native15.Animated.spring(pos.y, {
|
|
2636
2862
|
toValue: insets.top + 60,
|
|
@@ -2640,7 +2866,7 @@ function DrawToolbar({
|
|
|
2640
2866
|
mass: 0.8
|
|
2641
2867
|
}).start();
|
|
2642
2868
|
}, [hidden, insets.top, pos.y]);
|
|
2643
|
-
|
|
2869
|
+
React16.useEffect(() => {
|
|
2644
2870
|
const id = pos.addListener((v) => {
|
|
2645
2871
|
currentPos.current = { x: v.x ?? 0, y: v.y ?? 0 };
|
|
2646
2872
|
});
|
|
@@ -2648,7 +2874,7 @@ function DrawToolbar({
|
|
|
2648
2874
|
pos.removeListener(id);
|
|
2649
2875
|
};
|
|
2650
2876
|
}, [pos]);
|
|
2651
|
-
const clamp2 =
|
|
2877
|
+
const clamp2 = React16.useCallback(
|
|
2652
2878
|
(x, y) => {
|
|
2653
2879
|
const minX = 10;
|
|
2654
2880
|
const maxX = Math.max(10, screenWidth - 230);
|
|
@@ -2658,7 +2884,7 @@ function DrawToolbar({
|
|
|
2658
2884
|
},
|
|
2659
2885
|
[insets.top, screenHeight, screenWidth]
|
|
2660
2886
|
);
|
|
2661
|
-
const panResponder =
|
|
2887
|
+
const panResponder = React16.useMemo(
|
|
2662
2888
|
() => import_react_native15.PanResponder.create({
|
|
2663
2889
|
onStartShouldSetPanResponder: () => false,
|
|
2664
2890
|
onMoveShouldSetPanResponder: (_e, g) => Math.abs(g.dx) > 5 || Math.abs(g.dy) > 5,
|
|
@@ -2686,7 +2912,7 @@ function DrawToolbar({
|
|
|
2686
2912
|
children
|
|
2687
2913
|
}) {
|
|
2688
2914
|
const isDisabled = Boolean(disabled) || Boolean(capturingDisabled);
|
|
2689
|
-
const [pressed, setPressed] =
|
|
2915
|
+
const [pressed, setPressed] = React16.useState(false);
|
|
2690
2916
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2691
2917
|
import_react_native15.View,
|
|
2692
2918
|
{
|
|
@@ -2824,7 +3050,7 @@ function DrawModeOverlay({
|
|
|
2824
3050
|
renderDragHandle
|
|
2825
3051
|
}) {
|
|
2826
3052
|
const theme = useTheme();
|
|
2827
|
-
const defaultPalette =
|
|
3053
|
+
const defaultPalette = React17.useMemo(
|
|
2828
3054
|
() => [
|
|
2829
3055
|
"#EF4444",
|
|
2830
3056
|
// Red
|
|
@@ -2842,11 +3068,11 @@ function DrawModeOverlay({
|
|
|
2842
3068
|
[]
|
|
2843
3069
|
);
|
|
2844
3070
|
const colors = palette && palette.length > 0 ? palette : defaultPalette;
|
|
2845
|
-
const [selectedColor, setSelectedColor] =
|
|
2846
|
-
const [strokes, setStrokes] =
|
|
2847
|
-
const [capturing, setCapturing] =
|
|
2848
|
-
const [hideUi, setHideUi] =
|
|
2849
|
-
|
|
3071
|
+
const [selectedColor, setSelectedColor] = React17.useState(colors[0] ?? "#EF4444");
|
|
3072
|
+
const [strokes, setStrokes] = React17.useState([]);
|
|
3073
|
+
const [capturing, setCapturing] = React17.useState(false);
|
|
3074
|
+
const [hideUi, setHideUi] = React17.useState(false);
|
|
3075
|
+
React17.useEffect(() => {
|
|
2850
3076
|
if (!visible) return;
|
|
2851
3077
|
setStrokes([]);
|
|
2852
3078
|
setSelectedColor(colors[0] ?? "#EF4444");
|
|
@@ -2854,14 +3080,14 @@ function DrawModeOverlay({
|
|
|
2854
3080
|
setHideUi(false);
|
|
2855
3081
|
}, [colors, visible]);
|
|
2856
3082
|
const canUndo = strokes.length > 0;
|
|
2857
|
-
const handleUndo =
|
|
3083
|
+
const handleUndo = React17.useCallback(() => {
|
|
2858
3084
|
setStrokes((prev) => prev.slice(0, -1));
|
|
2859
3085
|
}, []);
|
|
2860
|
-
const handleCancel =
|
|
3086
|
+
const handleCancel = React17.useCallback(() => {
|
|
2861
3087
|
setStrokes([]);
|
|
2862
3088
|
onCancel();
|
|
2863
3089
|
}, [onCancel]);
|
|
2864
|
-
const handleDone =
|
|
3090
|
+
const handleDone = React17.useCallback(async () => {
|
|
2865
3091
|
if (!captureTargetRef.current || capturing) return;
|
|
2866
3092
|
try {
|
|
2867
3093
|
setCapturing(true);
|
|
@@ -2921,7 +3147,7 @@ var styles3 = import_react_native16.StyleSheet.create({
|
|
|
2921
3147
|
});
|
|
2922
3148
|
|
|
2923
3149
|
// src/components/comments/AppCommentsSheet.tsx
|
|
2924
|
-
var
|
|
3150
|
+
var React24 = __toESM(require("react"));
|
|
2925
3151
|
var import_react_native22 = require("react-native");
|
|
2926
3152
|
var import_bottom_sheet3 = require("@gorhom/bottom-sheet");
|
|
2927
3153
|
var import_react_native_safe_area_context3 = require("react-native-safe-area-context");
|
|
@@ -2929,17 +3155,17 @@ var import_liquid_glass5 = require("@callstack/liquid-glass");
|
|
|
2929
3155
|
var import_lucide_react_native4 = require("lucide-react-native");
|
|
2930
3156
|
|
|
2931
3157
|
// src/components/chat/ChatComposer.tsx
|
|
2932
|
-
var
|
|
3158
|
+
var React19 = __toESM(require("react"));
|
|
2933
3159
|
var import_react_native18 = require("react-native");
|
|
2934
3160
|
var import_liquid_glass4 = require("@callstack/liquid-glass");
|
|
2935
3161
|
var import_lucide_react_native3 = require("lucide-react-native");
|
|
2936
3162
|
|
|
2937
3163
|
// src/components/chat/MultilineTextInput.tsx
|
|
2938
|
-
var
|
|
3164
|
+
var React18 = __toESM(require("react"));
|
|
2939
3165
|
var import_react_native17 = require("react-native");
|
|
2940
3166
|
var import_bottom_sheet2 = require("@gorhom/bottom-sheet");
|
|
2941
3167
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2942
|
-
var MultilineTextInput =
|
|
3168
|
+
var MultilineTextInput = React18.forwardRef(function MultilineTextInput2({ useBottomSheetTextInput = false, placeholder, placeholderTextColor, style, ...props }, ref) {
|
|
2943
3169
|
const theme = useTheme();
|
|
2944
3170
|
const baseStyle = {
|
|
2945
3171
|
minHeight: 44,
|
|
@@ -3011,7 +3237,7 @@ function AspectRatioThumbnail({
|
|
|
3011
3237
|
onRemove,
|
|
3012
3238
|
renderRemoveIcon
|
|
3013
3239
|
}) {
|
|
3014
|
-
const [aspectRatio, setAspectRatio] =
|
|
3240
|
+
const [aspectRatio, setAspectRatio] = React19.useState(1);
|
|
3015
3241
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native18.View, { style: { height: THUMBNAIL_HEIGHT, aspectRatio, position: "relative" }, children: [
|
|
3016
3242
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native18.View, { style: { flex: 1, borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3017
3243
|
import_react_native18.Image,
|
|
@@ -3068,19 +3294,19 @@ function ChatComposer({
|
|
|
3068
3294
|
style
|
|
3069
3295
|
}) {
|
|
3070
3296
|
const theme = useTheme();
|
|
3071
|
-
const [internal, setInternal] =
|
|
3297
|
+
const [internal, setInternal] = React19.useState("");
|
|
3072
3298
|
const text = value ?? internal;
|
|
3073
3299
|
const setText = onChangeValue ?? setInternal;
|
|
3074
3300
|
const hasAttachments = attachments.length > 0;
|
|
3075
3301
|
const hasText = text.trim().length > 0;
|
|
3076
3302
|
const composerMinHeight = hasAttachments ? THUMBNAIL_HEIGHT + 44 + 24 : 44;
|
|
3077
3303
|
const isButtonDisabled = sending || disabled || sendDisabled;
|
|
3078
|
-
const maxInputHeight =
|
|
3079
|
-
const shakeAnim =
|
|
3080
|
-
const [sendPressed, setSendPressed] =
|
|
3081
|
-
const inputRef =
|
|
3082
|
-
const prevAutoFocusRef =
|
|
3083
|
-
|
|
3304
|
+
const maxInputHeight = React19.useMemo(() => import_react_native18.Dimensions.get("window").height * 0.5, []);
|
|
3305
|
+
const shakeAnim = React19.useRef(new import_react_native18.Animated.Value(0)).current;
|
|
3306
|
+
const [sendPressed, setSendPressed] = React19.useState(false);
|
|
3307
|
+
const inputRef = React19.useRef(null);
|
|
3308
|
+
const prevAutoFocusRef = React19.useRef(false);
|
|
3309
|
+
React19.useEffect(() => {
|
|
3084
3310
|
const shouldFocus = autoFocus && !prevAutoFocusRef.current && !disabled && !sending;
|
|
3085
3311
|
prevAutoFocusRef.current = autoFocus;
|
|
3086
3312
|
if (!shouldFocus) return;
|
|
@@ -3090,7 +3316,7 @@ function ChatComposer({
|
|
|
3090
3316
|
}, 75);
|
|
3091
3317
|
return () => clearTimeout(t);
|
|
3092
3318
|
}, [autoFocus, disabled, sending]);
|
|
3093
|
-
const triggerShake =
|
|
3319
|
+
const triggerShake = React19.useCallback(() => {
|
|
3094
3320
|
shakeAnim.setValue(0);
|
|
3095
3321
|
import_react_native18.Animated.sequence([
|
|
3096
3322
|
import_react_native18.Animated.timing(shakeAnim, { toValue: 10, duration: 50, useNativeDriver: true }),
|
|
@@ -3100,7 +3326,7 @@ function ChatComposer({
|
|
|
3100
3326
|
import_react_native18.Animated.timing(shakeAnim, { toValue: 0, duration: 50, useNativeDriver: true })
|
|
3101
3327
|
]).start();
|
|
3102
3328
|
}, [shakeAnim]);
|
|
3103
|
-
const handleSend =
|
|
3329
|
+
const handleSend = React19.useCallback(async () => {
|
|
3104
3330
|
if (isButtonDisabled) return;
|
|
3105
3331
|
if (!hasText) {
|
|
3106
3332
|
triggerShake();
|
|
@@ -3233,7 +3459,7 @@ function ChatComposer({
|
|
|
3233
3459
|
}
|
|
3234
3460
|
|
|
3235
3461
|
// src/components/comments/CommentRow.tsx
|
|
3236
|
-
var
|
|
3462
|
+
var React20 = __toESM(require("react"));
|
|
3237
3463
|
var import_react_native20 = require("react-native");
|
|
3238
3464
|
|
|
3239
3465
|
// src/components/primitives/Avatar.tsx
|
|
@@ -3305,9 +3531,9 @@ function formatTimeAgo(iso) {
|
|
|
3305
3531
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
3306
3532
|
function CommentRow({ comment, showDivider }) {
|
|
3307
3533
|
const theme = useTheme();
|
|
3308
|
-
const [authorName, setAuthorName] =
|
|
3309
|
-
const [authorAvatar, setAuthorAvatar] =
|
|
3310
|
-
|
|
3534
|
+
const [authorName, setAuthorName] = React20.useState(null);
|
|
3535
|
+
const [authorAvatar, setAuthorAvatar] = React20.useState(null);
|
|
3536
|
+
React20.useEffect(() => {
|
|
3311
3537
|
let cancelled = false;
|
|
3312
3538
|
(async () => {
|
|
3313
3539
|
try {
|
|
@@ -3347,7 +3573,7 @@ function CommentRow({ comment, showDivider }) {
|
|
|
3347
3573
|
}
|
|
3348
3574
|
|
|
3349
3575
|
// src/components/comments/useAppComments.ts
|
|
3350
|
-
var
|
|
3576
|
+
var React21 = __toESM(require("react"));
|
|
3351
3577
|
|
|
3352
3578
|
// src/data/comments/remote.ts
|
|
3353
3579
|
var AppCommentsRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -3419,18 +3645,18 @@ var appCommentsRepository = new AppCommentsRepositoryImpl(appCommentsRemoteDataS
|
|
|
3419
3645
|
|
|
3420
3646
|
// src/components/comments/useAppComments.ts
|
|
3421
3647
|
function useAppComments(appId) {
|
|
3422
|
-
const [comments, setComments] =
|
|
3423
|
-
const [loading, setLoading] =
|
|
3424
|
-
const [sending, setSending] =
|
|
3425
|
-
const [error, setError] =
|
|
3426
|
-
const sortByCreatedAtAsc =
|
|
3648
|
+
const [comments, setComments] = React21.useState([]);
|
|
3649
|
+
const [loading, setLoading] = React21.useState(false);
|
|
3650
|
+
const [sending, setSending] = React21.useState(false);
|
|
3651
|
+
const [error, setError] = React21.useState(null);
|
|
3652
|
+
const sortByCreatedAtAsc = React21.useCallback((items) => {
|
|
3427
3653
|
return [...items].sort((a, b) => {
|
|
3428
3654
|
const at = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
|
3429
3655
|
const bt = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
|
3430
3656
|
return at - bt;
|
|
3431
3657
|
});
|
|
3432
3658
|
}, []);
|
|
3433
|
-
const refresh =
|
|
3659
|
+
const refresh = React21.useCallback(async () => {
|
|
3434
3660
|
if (!appId) {
|
|
3435
3661
|
setComments([]);
|
|
3436
3662
|
return;
|
|
@@ -3447,10 +3673,10 @@ function useAppComments(appId) {
|
|
|
3447
3673
|
setLoading(false);
|
|
3448
3674
|
}
|
|
3449
3675
|
}, [appId, sortByCreatedAtAsc]);
|
|
3450
|
-
|
|
3676
|
+
React21.useEffect(() => {
|
|
3451
3677
|
void refresh();
|
|
3452
3678
|
}, [refresh]);
|
|
3453
|
-
const create =
|
|
3679
|
+
const create = React21.useCallback(
|
|
3454
3680
|
async (text) => {
|
|
3455
3681
|
if (!appId) return;
|
|
3456
3682
|
const trimmed = text.trim();
|
|
@@ -3473,11 +3699,11 @@ function useAppComments(appId) {
|
|
|
3473
3699
|
}
|
|
3474
3700
|
|
|
3475
3701
|
// src/components/comments/useAppDetails.ts
|
|
3476
|
-
var
|
|
3702
|
+
var React22 = __toESM(require("react"));
|
|
3477
3703
|
function useAppDetails(appId) {
|
|
3478
|
-
const [app, setApp] =
|
|
3479
|
-
const [loading, setLoading] =
|
|
3480
|
-
|
|
3704
|
+
const [app, setApp] = React22.useState(null);
|
|
3705
|
+
const [loading, setLoading] = React22.useState(false);
|
|
3706
|
+
React22.useEffect(() => {
|
|
3481
3707
|
if (!appId) {
|
|
3482
3708
|
setApp(null);
|
|
3483
3709
|
return;
|
|
@@ -3502,11 +3728,11 @@ function useAppDetails(appId) {
|
|
|
3502
3728
|
}
|
|
3503
3729
|
|
|
3504
3730
|
// src/components/comments/useIosKeyboardSnapFix.ts
|
|
3505
|
-
var
|
|
3731
|
+
var React23 = __toESM(require("react"));
|
|
3506
3732
|
var import_react_native21 = require("react-native");
|
|
3507
3733
|
function useIosKeyboardSnapFix(sheetRef, options) {
|
|
3508
|
-
const [keyboardVisible, setKeyboardVisible] =
|
|
3509
|
-
|
|
3734
|
+
const [keyboardVisible, setKeyboardVisible] = React23.useState(false);
|
|
3735
|
+
React23.useEffect(() => {
|
|
3510
3736
|
if (import_react_native21.Platform.OS !== "ios") return;
|
|
3511
3737
|
const show = import_react_native21.Keyboard.addListener("keyboardWillShow", () => setKeyboardVisible(true));
|
|
3512
3738
|
const hide = import_react_native21.Keyboard.addListener("keyboardWillHide", () => {
|
|
@@ -3534,16 +3760,16 @@ var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
|
3534
3760
|
function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
|
|
3535
3761
|
const theme = useTheme();
|
|
3536
3762
|
const insets = (0, import_react_native_safe_area_context3.useSafeAreaInsets)();
|
|
3537
|
-
const sheetRef =
|
|
3538
|
-
const snapPoints =
|
|
3539
|
-
const currentIndexRef =
|
|
3763
|
+
const sheetRef = React24.useRef(null);
|
|
3764
|
+
const snapPoints = React24.useMemo(() => ["50%", "90%"], []);
|
|
3765
|
+
const currentIndexRef = React24.useRef(1);
|
|
3540
3766
|
const { comments, loading, sending, error, create, refresh } = useAppComments(appId);
|
|
3541
3767
|
const { app, loading: loadingApp } = useAppDetails(appId);
|
|
3542
3768
|
const { keyboardVisible } = useIosKeyboardSnapFix(sheetRef, {
|
|
3543
3769
|
getCurrentIndex: () => currentIndexRef.current,
|
|
3544
3770
|
targetIndex: 1
|
|
3545
3771
|
});
|
|
3546
|
-
|
|
3772
|
+
React24.useEffect(() => {
|
|
3547
3773
|
var _a, _b;
|
|
3548
3774
|
if (appId) {
|
|
3549
3775
|
(_a = sheetRef.current) == null ? void 0 : _a.present();
|
|
@@ -3552,22 +3778,22 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
|
|
|
3552
3778
|
(_b = sheetRef.current) == null ? void 0 : _b.dismiss();
|
|
3553
3779
|
}
|
|
3554
3780
|
}, [appId, refresh]);
|
|
3555
|
-
|
|
3781
|
+
React24.useEffect(() => {
|
|
3556
3782
|
if (!appId) return;
|
|
3557
3783
|
onCountChange == null ? void 0 : onCountChange(comments.length);
|
|
3558
3784
|
}, [appId, comments.length, onCountChange]);
|
|
3559
|
-
const renderBackdrop =
|
|
3785
|
+
const renderBackdrop = React24.useCallback(
|
|
3560
3786
|
(props) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_bottom_sheet3.BottomSheetBackdrop, { ...props, disappearsOnIndex: -1, appearsOnIndex: 0, opacity: 0.5 }),
|
|
3561
3787
|
[]
|
|
3562
3788
|
);
|
|
3563
|
-
const handleChange =
|
|
3789
|
+
const handleChange = React24.useCallback(
|
|
3564
3790
|
(index) => {
|
|
3565
3791
|
currentIndexRef.current = index;
|
|
3566
3792
|
if (index === -1) onClose();
|
|
3567
3793
|
},
|
|
3568
3794
|
[onClose]
|
|
3569
3795
|
);
|
|
3570
|
-
const handlePlay =
|
|
3796
|
+
const handlePlay = React24.useCallback(async () => {
|
|
3571
3797
|
var _a;
|
|
3572
3798
|
if (!appId) return;
|
|
3573
3799
|
(_a = sheetRef.current) == null ? void 0 : _a.dismiss();
|
|
@@ -3777,7 +4003,7 @@ function StudioSheetHeader({ left, center, right, style }) {
|
|
|
3777
4003
|
}
|
|
3778
4004
|
|
|
3779
4005
|
// src/components/studio-sheet/StudioSheetHeaderIconButton.tsx
|
|
3780
|
-
var
|
|
4006
|
+
var React25 = __toESM(require("react"));
|
|
3781
4007
|
var import_react_native25 = require("react-native");
|
|
3782
4008
|
var import_liquid_glass6 = require("@callstack/liquid-glass");
|
|
3783
4009
|
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
@@ -3792,7 +4018,7 @@ function StudioSheetHeaderIconButton({
|
|
|
3792
4018
|
}) {
|
|
3793
4019
|
const theme = useTheme();
|
|
3794
4020
|
const size = 44;
|
|
3795
|
-
const [pressed, setPressed] =
|
|
4021
|
+
const [pressed, setPressed] = React25.useState(false);
|
|
3796
4022
|
const solidBg = intent === "danger" ? theme.colors.danger : intent === "primary" ? theme.colors.primary : theme.colors.neutral;
|
|
3797
4023
|
const glassFallbackBg = theme.scheme === "dark" ? "#18181B" : "#F6F6F6";
|
|
3798
4024
|
const glassInnerBg = intent === "danger" ? theme.colors.danger : theme.colors.primary;
|
|
@@ -3982,14 +4208,14 @@ function PreviewHeroCard({
|
|
|
3982
4208
|
}
|
|
3983
4209
|
|
|
3984
4210
|
// src/components/preview/PreviewPlaceholder.tsx
|
|
3985
|
-
var
|
|
4211
|
+
var React26 = __toESM(require("react"));
|
|
3986
4212
|
var import_react_native29 = require("react-native");
|
|
3987
4213
|
var import_expo_linear_gradient2 = require("expo-linear-gradient");
|
|
3988
4214
|
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
3989
4215
|
function PreviewPlaceholder({ visible, style }) {
|
|
3990
4216
|
if (!visible) return null;
|
|
3991
|
-
const opacityAnim =
|
|
3992
|
-
|
|
4217
|
+
const opacityAnim = React26.useRef(new import_react_native29.Animated.Value(0)).current;
|
|
4218
|
+
React26.useEffect(() => {
|
|
3993
4219
|
if (!visible) return;
|
|
3994
4220
|
const animation = import_react_native29.Animated.loop(
|
|
3995
4221
|
import_react_native29.Animated.sequence([
|
|
@@ -4573,12 +4799,12 @@ function PreviewCustomizeSection({
|
|
|
4573
4799
|
}
|
|
4574
4800
|
|
|
4575
4801
|
// src/studio/ui/preview-panel/PreviewCollaborateSection.tsx
|
|
4576
|
-
var
|
|
4802
|
+
var React32 = __toESM(require("react"));
|
|
4577
4803
|
var import_react_native42 = require("react-native");
|
|
4578
4804
|
var import_lucide_react_native9 = require("lucide-react-native");
|
|
4579
4805
|
|
|
4580
4806
|
// src/components/merge-requests/MergeRequestStatusCard.tsx
|
|
4581
|
-
var
|
|
4807
|
+
var React28 = __toESM(require("react"));
|
|
4582
4808
|
var import_react_native38 = require("react-native");
|
|
4583
4809
|
var import_lucide_react_native7 = require("lucide-react-native");
|
|
4584
4810
|
|
|
@@ -4660,11 +4886,11 @@ function toIsoString(input) {
|
|
|
4660
4886
|
}
|
|
4661
4887
|
|
|
4662
4888
|
// src/components/merge-requests/useControlledExpansion.ts
|
|
4663
|
-
var
|
|
4889
|
+
var React27 = __toESM(require("react"));
|
|
4664
4890
|
function useControlledExpansion(props) {
|
|
4665
|
-
const [uncontrolled, setUncontrolled] =
|
|
4891
|
+
const [uncontrolled, setUncontrolled] = React27.useState(false);
|
|
4666
4892
|
const expanded = props.expanded ?? uncontrolled;
|
|
4667
|
-
const setExpanded =
|
|
4893
|
+
const setExpanded = React27.useCallback(
|
|
4668
4894
|
(next) => {
|
|
4669
4895
|
var _a;
|
|
4670
4896
|
(_a = props.onExpandedChange) == null ? void 0 : _a.call(props, next);
|
|
@@ -4689,8 +4915,8 @@ function MergeRequestStatusCard({
|
|
|
4689
4915
|
const isDark = theme.scheme === "dark";
|
|
4690
4916
|
const textColor = isDark ? "#FFFFFF" : "#000000";
|
|
4691
4917
|
const subTextColor = isDark ? "#A1A1AA" : "#71717A";
|
|
4692
|
-
const status =
|
|
4693
|
-
const { StatusIcon, iconColor, bgColor, statusText } =
|
|
4918
|
+
const status = React28.useMemo(() => getMergeRequestStatusDisplay(String(mergeRequest.status)), [mergeRequest.status]);
|
|
4919
|
+
const { StatusIcon, iconColor, bgColor, statusText } = React28.useMemo(() => {
|
|
4694
4920
|
switch (mergeRequest.status) {
|
|
4695
4921
|
case "approved":
|
|
4696
4922
|
case "merged":
|
|
@@ -4721,8 +4947,8 @@ function MergeRequestStatusCard({
|
|
|
4721
4947
|
const createdIso = toIsoString(mergeRequest.createdAt ?? null);
|
|
4722
4948
|
const headerTimeAgo = updatedIso ? formatTimeAgo(updatedIso) : "";
|
|
4723
4949
|
const createdTimeAgo = createdIso ? formatTimeAgo(createdIso) : "";
|
|
4724
|
-
const rotate =
|
|
4725
|
-
|
|
4950
|
+
const rotate = React28.useRef(new import_react_native38.Animated.Value(expanded ? 1 : 0)).current;
|
|
4951
|
+
React28.useEffect(() => {
|
|
4726
4952
|
import_react_native38.Animated.timing(rotate, {
|
|
4727
4953
|
toValue: expanded ? 1 : 0,
|
|
4728
4954
|
duration: 200,
|
|
@@ -4813,16 +5039,16 @@ function MergeRequestStatusCard({
|
|
|
4813
5039
|
}
|
|
4814
5040
|
|
|
4815
5041
|
// src/components/merge-requests/ReviewMergeRequestCarousel.tsx
|
|
4816
|
-
var
|
|
5042
|
+
var React31 = __toESM(require("react"));
|
|
4817
5043
|
var import_react_native41 = require("react-native");
|
|
4818
5044
|
|
|
4819
5045
|
// src/components/merge-requests/ReviewMergeRequestCard.tsx
|
|
4820
|
-
var
|
|
5046
|
+
var React30 = __toESM(require("react"));
|
|
4821
5047
|
var import_react_native40 = require("react-native");
|
|
4822
5048
|
var import_lucide_react_native8 = require("lucide-react-native");
|
|
4823
5049
|
|
|
4824
5050
|
// src/components/merge-requests/ReviewMergeRequestActionButton.tsx
|
|
4825
|
-
var
|
|
5051
|
+
var React29 = __toESM(require("react"));
|
|
4826
5052
|
var import_react_native39 = require("react-native");
|
|
4827
5053
|
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
4828
5054
|
function ReviewMergeRequestActionButton({
|
|
@@ -4833,7 +5059,7 @@ function ReviewMergeRequestActionButton({
|
|
|
4833
5059
|
children,
|
|
4834
5060
|
iconOnly
|
|
4835
5061
|
}) {
|
|
4836
|
-
const [pressed, setPressed] =
|
|
5062
|
+
const [pressed, setPressed] = React29.useState(false);
|
|
4837
5063
|
const height = iconOnly ? 36 : 40;
|
|
4838
5064
|
const width = iconOnly ? 36 : void 0;
|
|
4839
5065
|
const paddingHorizontal = iconOnly ? 0 : 16;
|
|
@@ -4895,10 +5121,10 @@ function ReviewMergeRequestCard({
|
|
|
4895
5121
|
onTest
|
|
4896
5122
|
}) {
|
|
4897
5123
|
const theme = useTheme();
|
|
4898
|
-
const status =
|
|
5124
|
+
const status = React30.useMemo(() => getMergeRequestStatusDisplay(mr.status), [mr.status]);
|
|
4899
5125
|
const canAct = mr.status === "open";
|
|
4900
|
-
const rotate =
|
|
4901
|
-
|
|
5126
|
+
const rotate = React30.useRef(new import_react_native40.Animated.Value(isExpanded ? 1 : 0)).current;
|
|
5127
|
+
React30.useEffect(() => {
|
|
4902
5128
|
import_react_native40.Animated.timing(rotate, { toValue: isExpanded ? 1 : 0, duration: 200, useNativeDriver: true }).start();
|
|
4903
5129
|
}, [isExpanded, rotate]);
|
|
4904
5130
|
const position = total > 1 ? `${index + 1}/${total}` : "Merge request";
|
|
@@ -5030,11 +5256,11 @@ function ReviewMergeRequestCarousel({
|
|
|
5030
5256
|
}) {
|
|
5031
5257
|
const theme = useTheme();
|
|
5032
5258
|
const { width } = (0, import_react_native41.useWindowDimensions)();
|
|
5033
|
-
const [expanded, setExpanded] =
|
|
5034
|
-
const carouselScrollX =
|
|
5259
|
+
const [expanded, setExpanded] = React31.useState({});
|
|
5260
|
+
const carouselScrollX = React31.useRef(new import_react_native41.Animated.Value(0)).current;
|
|
5035
5261
|
const peekAmount = 24;
|
|
5036
5262
|
const gap = 16;
|
|
5037
|
-
const cardWidth =
|
|
5263
|
+
const cardWidth = React31.useMemo(() => Math.max(1, width - theme.spacing.lg * 2 - peekAmount), [peekAmount, theme.spacing.lg, width]);
|
|
5038
5264
|
const snapInterval = cardWidth + gap;
|
|
5039
5265
|
const dotColor = theme.scheme === "dark" ? "#FFFFFF" : "#000000";
|
|
5040
5266
|
if (mergeRequests.length === 0) return null;
|
|
@@ -5133,7 +5359,7 @@ function PreviewCollaborateSection({
|
|
|
5133
5359
|
onTestMr
|
|
5134
5360
|
}) {
|
|
5135
5361
|
const theme = useTheme();
|
|
5136
|
-
const [submittingMr, setSubmittingMr] =
|
|
5362
|
+
const [submittingMr, setSubmittingMr] = React32.useState(false);
|
|
5137
5363
|
const hasSection = canSubmitMergeRequest || incomingMergeRequests.length > 0 || outgoingMergeRequests.length > 0;
|
|
5138
5364
|
if (!hasSection) return null;
|
|
5139
5365
|
const showActionsSubtitle = canSubmitMergeRequest && onSubmitMergeRequest || onTestMr && incomingMergeRequests.length > 0;
|
|
@@ -5241,7 +5467,7 @@ function PreviewCollaborateSection({
|
|
|
5241
5467
|
}
|
|
5242
5468
|
|
|
5243
5469
|
// src/studio/ui/preview-panel/usePreviewPanelData.ts
|
|
5244
|
-
var
|
|
5470
|
+
var React34 = __toESM(require("react"));
|
|
5245
5471
|
|
|
5246
5472
|
// src/data/apps/images/remote.ts
|
|
5247
5473
|
var AppImagesRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -5292,7 +5518,7 @@ var AppImagesRepositoryImpl = class extends BaseRepository {
|
|
|
5292
5518
|
var appImagesRepository = new AppImagesRepositoryImpl(appImagesRemoteDataSource);
|
|
5293
5519
|
|
|
5294
5520
|
// src/studio/hooks/useAppStats.ts
|
|
5295
|
-
var
|
|
5521
|
+
var React33 = __toESM(require("react"));
|
|
5296
5522
|
var Haptics2 = __toESM(require("expo-haptics"));
|
|
5297
5523
|
|
|
5298
5524
|
// src/data/likes/remote.ts
|
|
@@ -5361,34 +5587,34 @@ function useAppStats({
|
|
|
5361
5587
|
initialIsLiked = false,
|
|
5362
5588
|
onOpenComments
|
|
5363
5589
|
}) {
|
|
5364
|
-
const [likeCount, setLikeCount] =
|
|
5365
|
-
const [commentCount, setCommentCount] =
|
|
5366
|
-
const [forkCount, setForkCount] =
|
|
5367
|
-
const [isLiked, setIsLiked] =
|
|
5368
|
-
const didMutateRef =
|
|
5369
|
-
const lastAppIdRef =
|
|
5370
|
-
|
|
5590
|
+
const [likeCount, setLikeCount] = React33.useState(initialLikes);
|
|
5591
|
+
const [commentCount, setCommentCount] = React33.useState(initialComments);
|
|
5592
|
+
const [forkCount, setForkCount] = React33.useState(initialForks);
|
|
5593
|
+
const [isLiked, setIsLiked] = React33.useState(initialIsLiked);
|
|
5594
|
+
const didMutateRef = React33.useRef(false);
|
|
5595
|
+
const lastAppIdRef = React33.useRef("");
|
|
5596
|
+
React33.useEffect(() => {
|
|
5371
5597
|
if (lastAppIdRef.current === appId) return;
|
|
5372
5598
|
lastAppIdRef.current = appId;
|
|
5373
5599
|
didMutateRef.current = false;
|
|
5374
5600
|
}, [appId]);
|
|
5375
|
-
|
|
5601
|
+
React33.useEffect(() => {
|
|
5376
5602
|
if (didMutateRef.current) return;
|
|
5377
5603
|
setLikeCount(initialLikes);
|
|
5378
5604
|
}, [appId, initialLikes]);
|
|
5379
|
-
|
|
5605
|
+
React33.useEffect(() => {
|
|
5380
5606
|
if (didMutateRef.current) return;
|
|
5381
5607
|
setCommentCount(initialComments);
|
|
5382
5608
|
}, [appId, initialComments]);
|
|
5383
|
-
|
|
5609
|
+
React33.useEffect(() => {
|
|
5384
5610
|
if (didMutateRef.current) return;
|
|
5385
5611
|
setForkCount(initialForks);
|
|
5386
5612
|
}, [appId, initialForks]);
|
|
5387
|
-
|
|
5613
|
+
React33.useEffect(() => {
|
|
5388
5614
|
if (didMutateRef.current) return;
|
|
5389
5615
|
setIsLiked(initialIsLiked);
|
|
5390
5616
|
}, [appId, initialIsLiked]);
|
|
5391
|
-
const handleLike =
|
|
5617
|
+
const handleLike = React33.useCallback(async () => {
|
|
5392
5618
|
var _a, _b;
|
|
5393
5619
|
if (!appId) return;
|
|
5394
5620
|
didMutateRef.current = true;
|
|
@@ -5412,7 +5638,7 @@ function useAppStats({
|
|
|
5412
5638
|
setLikeCount((prev) => Math.max(0, prev + (newIsLiked ? -1 : 1)));
|
|
5413
5639
|
}
|
|
5414
5640
|
}, [appId, isLiked, likeCount]);
|
|
5415
|
-
const handleOpenComments =
|
|
5641
|
+
const handleOpenComments = React33.useCallback(() => {
|
|
5416
5642
|
if (!appId) return;
|
|
5417
5643
|
try {
|
|
5418
5644
|
void Haptics2.impactAsync(Haptics2.ImpactFeedbackStyle.Light);
|
|
@@ -5427,11 +5653,11 @@ function useAppStats({
|
|
|
5427
5653
|
var LIKE_DEBUG_PREFIX = "[COMERGE_LIKE_DEBUG]";
|
|
5428
5654
|
function usePreviewPanelData(params) {
|
|
5429
5655
|
const { app, isOwner, outgoingMergeRequests, onOpenComments, commentCountOverride } = params;
|
|
5430
|
-
const [imageUrl, setImageUrl] =
|
|
5431
|
-
const [imageLoaded, setImageLoaded] =
|
|
5432
|
-
const [insights, setInsights] =
|
|
5433
|
-
const [creator, setCreator] =
|
|
5434
|
-
|
|
5656
|
+
const [imageUrl, setImageUrl] = React34.useState(null);
|
|
5657
|
+
const [imageLoaded, setImageLoaded] = React34.useState(false);
|
|
5658
|
+
const [insights, setInsights] = React34.useState({ likes: 0, comments: 0, forks: 0, downloads: 0 });
|
|
5659
|
+
const [creator, setCreator] = React34.useState(null);
|
|
5660
|
+
React34.useEffect(() => {
|
|
5435
5661
|
if (!(app == null ? void 0 : app.id)) return;
|
|
5436
5662
|
let cancelled = false;
|
|
5437
5663
|
(async () => {
|
|
@@ -5446,7 +5672,7 @@ function usePreviewPanelData(params) {
|
|
|
5446
5672
|
cancelled = true;
|
|
5447
5673
|
};
|
|
5448
5674
|
}, [app == null ? void 0 : app.id]);
|
|
5449
|
-
|
|
5675
|
+
React34.useEffect(() => {
|
|
5450
5676
|
if (!(app == null ? void 0 : app.createdBy)) return;
|
|
5451
5677
|
let cancelled = false;
|
|
5452
5678
|
(async () => {
|
|
@@ -5462,10 +5688,10 @@ function usePreviewPanelData(params) {
|
|
|
5462
5688
|
cancelled = true;
|
|
5463
5689
|
};
|
|
5464
5690
|
}, [app == null ? void 0 : app.createdBy]);
|
|
5465
|
-
|
|
5691
|
+
React34.useEffect(() => {
|
|
5466
5692
|
setImageLoaded(false);
|
|
5467
5693
|
}, [app == null ? void 0 : app.id]);
|
|
5468
|
-
|
|
5694
|
+
React34.useEffect(() => {
|
|
5469
5695
|
if (!(app == null ? void 0 : app.id)) return;
|
|
5470
5696
|
let cancelled = false;
|
|
5471
5697
|
(async () => {
|
|
@@ -5490,7 +5716,7 @@ function usePreviewPanelData(params) {
|
|
|
5490
5716
|
cancelled = true;
|
|
5491
5717
|
};
|
|
5492
5718
|
}, [app == null ? void 0 : app.id]);
|
|
5493
|
-
|
|
5719
|
+
React34.useEffect(() => {
|
|
5494
5720
|
if (!(app == null ? void 0 : app.id)) return;
|
|
5495
5721
|
log.debug(
|
|
5496
5722
|
`${LIKE_DEBUG_PREFIX} usePreviewPanelData.appChanged appId=${app.id} app.isLiked=${String(app.isLiked)}`
|
|
@@ -5504,7 +5730,7 @@ function usePreviewPanelData(params) {
|
|
|
5504
5730
|
initialIsLiked: Boolean(app == null ? void 0 : app.isLiked),
|
|
5505
5731
|
onOpenComments
|
|
5506
5732
|
});
|
|
5507
|
-
const canSubmitMergeRequest =
|
|
5733
|
+
const canSubmitMergeRequest = React34.useMemo(() => {
|
|
5508
5734
|
if (!isOwner) return false;
|
|
5509
5735
|
if (!app) return false;
|
|
5510
5736
|
if (!app.forkedFromAppId) return false;
|
|
@@ -5617,16 +5843,16 @@ function PreviewPanel({
|
|
|
5617
5843
|
}
|
|
5618
5844
|
|
|
5619
5845
|
// src/studio/ui/ChatPanel.tsx
|
|
5620
|
-
var
|
|
5846
|
+
var React39 = __toESM(require("react"));
|
|
5621
5847
|
var import_react_native51 = require("react-native");
|
|
5622
5848
|
|
|
5623
5849
|
// src/components/chat/ChatPage.tsx
|
|
5624
|
-
var
|
|
5850
|
+
var React37 = __toESM(require("react"));
|
|
5625
5851
|
var import_react_native47 = require("react-native");
|
|
5626
5852
|
var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
|
|
5627
5853
|
|
|
5628
5854
|
// src/components/chat/ChatMessageList.tsx
|
|
5629
|
-
var
|
|
5855
|
+
var React36 = __toESM(require("react"));
|
|
5630
5856
|
var import_react_native46 = require("react-native");
|
|
5631
5857
|
var import_bottom_sheet5 = require("@gorhom/bottom-sheet");
|
|
5632
5858
|
|
|
@@ -5672,17 +5898,17 @@ function ChatMessageBubble({ message, renderContent, style }) {
|
|
|
5672
5898
|
}
|
|
5673
5899
|
|
|
5674
5900
|
// src/components/chat/TypingIndicator.tsx
|
|
5675
|
-
var
|
|
5901
|
+
var React35 = __toESM(require("react"));
|
|
5676
5902
|
var import_react_native45 = require("react-native");
|
|
5677
5903
|
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
5678
5904
|
function TypingIndicator({ style }) {
|
|
5679
5905
|
const theme = useTheme();
|
|
5680
5906
|
const dotColor = theme.colors.textSubtle;
|
|
5681
|
-
const anims =
|
|
5907
|
+
const anims = React35.useMemo(
|
|
5682
5908
|
() => [new import_react_native45.Animated.Value(0.3), new import_react_native45.Animated.Value(0.3), new import_react_native45.Animated.Value(0.3)],
|
|
5683
5909
|
[]
|
|
5684
5910
|
);
|
|
5685
|
-
|
|
5911
|
+
React35.useEffect(() => {
|
|
5686
5912
|
const loops = [];
|
|
5687
5913
|
anims.forEach((a, idx) => {
|
|
5688
5914
|
const seq = import_react_native45.Animated.sequence([
|
|
@@ -5716,7 +5942,7 @@ function TypingIndicator({ style }) {
|
|
|
5716
5942
|
|
|
5717
5943
|
// src/components/chat/ChatMessageList.tsx
|
|
5718
5944
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
5719
|
-
var ChatMessageList =
|
|
5945
|
+
var ChatMessageList = React36.forwardRef(
|
|
5720
5946
|
({
|
|
5721
5947
|
messages,
|
|
5722
5948
|
showTypingIndicator = false,
|
|
@@ -5727,20 +5953,20 @@ var ChatMessageList = React35.forwardRef(
|
|
|
5727
5953
|
nearBottomThreshold = 200
|
|
5728
5954
|
}, ref) => {
|
|
5729
5955
|
const theme = useTheme();
|
|
5730
|
-
const listRef =
|
|
5731
|
-
const nearBottomRef =
|
|
5732
|
-
const initialScrollDoneRef =
|
|
5733
|
-
const lastMessageIdRef =
|
|
5734
|
-
const data =
|
|
5956
|
+
const listRef = React36.useRef(null);
|
|
5957
|
+
const nearBottomRef = React36.useRef(true);
|
|
5958
|
+
const initialScrollDoneRef = React36.useRef(false);
|
|
5959
|
+
const lastMessageIdRef = React36.useRef(null);
|
|
5960
|
+
const data = React36.useMemo(() => {
|
|
5735
5961
|
return [...messages].reverse();
|
|
5736
5962
|
}, [messages]);
|
|
5737
|
-
const scrollToBottom =
|
|
5963
|
+
const scrollToBottom = React36.useCallback((options) => {
|
|
5738
5964
|
var _a;
|
|
5739
5965
|
const animated = (options == null ? void 0 : options.animated) ?? true;
|
|
5740
5966
|
(_a = listRef.current) == null ? void 0 : _a.scrollToOffset({ offset: 0, animated });
|
|
5741
5967
|
}, []);
|
|
5742
|
-
|
|
5743
|
-
const handleScroll =
|
|
5968
|
+
React36.useImperativeHandle(ref, () => ({ scrollToBottom }), [scrollToBottom]);
|
|
5969
|
+
const handleScroll = React36.useCallback(
|
|
5744
5970
|
(e) => {
|
|
5745
5971
|
const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent;
|
|
5746
5972
|
const distanceFromBottom = Math.max(contentOffset.y - Math.max(bottomInset, 0), 0);
|
|
@@ -5752,7 +5978,7 @@ var ChatMessageList = React35.forwardRef(
|
|
|
5752
5978
|
},
|
|
5753
5979
|
[bottomInset, nearBottomThreshold, onNearBottomChange]
|
|
5754
5980
|
);
|
|
5755
|
-
|
|
5981
|
+
React36.useEffect(() => {
|
|
5756
5982
|
if (!initialScrollDoneRef.current) return;
|
|
5757
5983
|
const lastId = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
5758
5984
|
const prevLastId = lastMessageIdRef.current;
|
|
@@ -5762,7 +5988,7 @@ var ChatMessageList = React35.forwardRef(
|
|
|
5762
5988
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
5763
5989
|
return () => cancelAnimationFrame(id);
|
|
5764
5990
|
}, [messages, scrollToBottom]);
|
|
5765
|
-
|
|
5991
|
+
React36.useEffect(() => {
|
|
5766
5992
|
if (showTypingIndicator && nearBottomRef.current) {
|
|
5767
5993
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
5768
5994
|
return () => cancelAnimationFrame(id);
|
|
@@ -5824,9 +6050,9 @@ function ChatPage({
|
|
|
5824
6050
|
}) {
|
|
5825
6051
|
const theme = useTheme();
|
|
5826
6052
|
const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
|
|
5827
|
-
const [composerHeight, setComposerHeight] =
|
|
5828
|
-
const [keyboardVisible, setKeyboardVisible] =
|
|
5829
|
-
|
|
6053
|
+
const [composerHeight, setComposerHeight] = React37.useState(0);
|
|
6054
|
+
const [keyboardVisible, setKeyboardVisible] = React37.useState(false);
|
|
6055
|
+
React37.useEffect(() => {
|
|
5830
6056
|
if (import_react_native47.Platform.OS !== "ios") return;
|
|
5831
6057
|
const show = import_react_native47.Keyboard.addListener("keyboardWillShow", () => setKeyboardVisible(true));
|
|
5832
6058
|
const hide = import_react_native47.Keyboard.addListener("keyboardWillHide", () => setKeyboardVisible(false));
|
|
@@ -5838,12 +6064,12 @@ function ChatPage({
|
|
|
5838
6064
|
const footerBottomPadding = import_react_native47.Platform.OS === "ios" ? keyboardVisible ? 0 : insets.bottom : insets.bottom + 10;
|
|
5839
6065
|
const overlayBottom = composerHeight + footerBottomPadding + theme.spacing.lg;
|
|
5840
6066
|
const bottomInset = composerHeight + footerBottomPadding + theme.spacing.xl;
|
|
5841
|
-
const resolvedOverlay =
|
|
6067
|
+
const resolvedOverlay = React37.useMemo(() => {
|
|
5842
6068
|
var _a;
|
|
5843
6069
|
if (!overlay) return null;
|
|
5844
|
-
if (!
|
|
6070
|
+
if (!React37.isValidElement(overlay)) return overlay;
|
|
5845
6071
|
const prevStyle = (_a = overlay.props) == null ? void 0 : _a.style;
|
|
5846
|
-
return
|
|
6072
|
+
return React37.cloneElement(overlay, {
|
|
5847
6073
|
style: [prevStyle, { bottom: overlayBottom }]
|
|
5848
6074
|
});
|
|
5849
6075
|
}, [overlay, overlayBottom]);
|
|
@@ -5898,15 +6124,15 @@ function ChatPage({
|
|
|
5898
6124
|
}
|
|
5899
6125
|
|
|
5900
6126
|
// src/components/chat/ScrollToBottomButton.tsx
|
|
5901
|
-
var
|
|
6127
|
+
var React38 = __toESM(require("react"));
|
|
5902
6128
|
var import_react_native48 = require("react-native");
|
|
5903
6129
|
var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
|
|
5904
6130
|
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
5905
6131
|
function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
5906
6132
|
const theme = useTheme();
|
|
5907
6133
|
const progress = (0, import_react_native_reanimated2.useSharedValue)(visible ? 1 : 0);
|
|
5908
|
-
const [pressed, setPressed] =
|
|
5909
|
-
|
|
6134
|
+
const [pressed, setPressed] = React38.useState(false);
|
|
6135
|
+
React38.useEffect(() => {
|
|
5910
6136
|
progress.value = (0, import_react_native_reanimated2.withTiming)(visible ? 1 : 0, { duration: 200, easing: import_react_native_reanimated2.Easing.out(import_react_native_reanimated2.Easing.ease) });
|
|
5911
6137
|
}, [progress, visible]);
|
|
5912
6138
|
const animStyle = (0, import_react_native_reanimated2.useAnimatedStyle)(() => ({
|
|
@@ -6061,9 +6287,9 @@ function ChatPanel({
|
|
|
6061
6287
|
onStartDraw,
|
|
6062
6288
|
onSend
|
|
6063
6289
|
}) {
|
|
6064
|
-
const listRef =
|
|
6065
|
-
const [nearBottom, setNearBottom] =
|
|
6066
|
-
const handleSend =
|
|
6290
|
+
const listRef = React39.useRef(null);
|
|
6291
|
+
const [nearBottom, setNearBottom] = React39.useState(true);
|
|
6292
|
+
const handleSend = React39.useCallback(
|
|
6067
6293
|
async (text, composerAttachments) => {
|
|
6068
6294
|
const all = composerAttachments ?? attachments;
|
|
6069
6295
|
await onSend(text, all.length > 0 ? all : void 0);
|
|
@@ -6077,7 +6303,7 @@ function ChatPanel({
|
|
|
6077
6303
|
},
|
|
6078
6304
|
[attachments, nearBottom, onClearAttachments, onSend]
|
|
6079
6305
|
);
|
|
6080
|
-
const handleScrollToBottom =
|
|
6306
|
+
const handleScrollToBottom = React39.useCallback(() => {
|
|
6081
6307
|
var _a;
|
|
6082
6308
|
(_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
|
|
6083
6309
|
}, []);
|
|
@@ -6151,7 +6377,7 @@ function ChatPanel({
|
|
|
6151
6377
|
}
|
|
6152
6378
|
|
|
6153
6379
|
// src/components/dialogs/ConfirmMergeRequestDialog.tsx
|
|
6154
|
-
var
|
|
6380
|
+
var React40 = __toESM(require("react"));
|
|
6155
6381
|
var import_react_native53 = require("react-native");
|
|
6156
6382
|
|
|
6157
6383
|
// src/components/primitives/Modal.tsx
|
|
@@ -6199,14 +6425,14 @@ function ConfirmMergeRequestDialog({
|
|
|
6199
6425
|
onTestFirst
|
|
6200
6426
|
}) {
|
|
6201
6427
|
const theme = useTheme();
|
|
6202
|
-
const close =
|
|
6428
|
+
const close = React40.useCallback(() => onOpenChange(false), [onOpenChange]);
|
|
6203
6429
|
const canConfirm = Boolean(mergeRequest) && !approveDisabled;
|
|
6204
|
-
const handleConfirm =
|
|
6430
|
+
const handleConfirm = React40.useCallback(() => {
|
|
6205
6431
|
if (!mergeRequest) return;
|
|
6206
6432
|
onOpenChange(false);
|
|
6207
6433
|
void onConfirm();
|
|
6208
6434
|
}, [mergeRequest, onConfirm, onOpenChange]);
|
|
6209
|
-
const handleTestFirst =
|
|
6435
|
+
const handleTestFirst = React40.useCallback(() => {
|
|
6210
6436
|
if (!mergeRequest) return;
|
|
6211
6437
|
onOpenChange(false);
|
|
6212
6438
|
void onTestFirst(mergeRequest);
|
|
@@ -6355,7 +6581,7 @@ function ConfirmMergeFlow({
|
|
|
6355
6581
|
}
|
|
6356
6582
|
|
|
6357
6583
|
// src/studio/hooks/useOptimisticChatMessages.ts
|
|
6358
|
-
var
|
|
6584
|
+
var React41 = __toESM(require("react"));
|
|
6359
6585
|
function makeOptimisticId() {
|
|
6360
6586
|
return `optimistic:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 10)}`;
|
|
6361
6587
|
}
|
|
@@ -6393,11 +6619,11 @@ function useOptimisticChatMessages({
|
|
|
6393
6619
|
chatMessages,
|
|
6394
6620
|
onSendChat
|
|
6395
6621
|
}) {
|
|
6396
|
-
const [optimisticChat, setOptimisticChat] =
|
|
6397
|
-
|
|
6622
|
+
const [optimisticChat, setOptimisticChat] = React41.useState([]);
|
|
6623
|
+
React41.useEffect(() => {
|
|
6398
6624
|
setOptimisticChat([]);
|
|
6399
6625
|
}, [threadId]);
|
|
6400
|
-
const messages =
|
|
6626
|
+
const messages = React41.useMemo(() => {
|
|
6401
6627
|
if (!optimisticChat || optimisticChat.length === 0) return chatMessages;
|
|
6402
6628
|
const unresolved = optimisticChat.filter((o) => !isOptimisticResolvedByServer(chatMessages, o));
|
|
6403
6629
|
if (unresolved.length === 0) return chatMessages;
|
|
@@ -6413,7 +6639,7 @@ function useOptimisticChatMessages({
|
|
|
6413
6639
|
merged.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
|
|
6414
6640
|
return merged;
|
|
6415
6641
|
}, [chatMessages, optimisticChat]);
|
|
6416
|
-
|
|
6642
|
+
React41.useEffect(() => {
|
|
6417
6643
|
if (optimisticChat.length === 0) return;
|
|
6418
6644
|
setOptimisticChat((prev) => {
|
|
6419
6645
|
if (prev.length === 0) return prev;
|
|
@@ -6421,7 +6647,7 @@ function useOptimisticChatMessages({
|
|
|
6421
6647
|
return next.length === prev.length ? prev : next;
|
|
6422
6648
|
});
|
|
6423
6649
|
}, [chatMessages, optimisticChat.length]);
|
|
6424
|
-
const onSend =
|
|
6650
|
+
const onSend = React41.useCallback(
|
|
6425
6651
|
async (text, attachments) => {
|
|
6426
6652
|
if (shouldForkOnEdit) {
|
|
6427
6653
|
await onSendChat(text, attachments);
|
|
@@ -6470,18 +6696,18 @@ function StudioOverlay({
|
|
|
6470
6696
|
chatShowTypingIndicator,
|
|
6471
6697
|
onSendChat,
|
|
6472
6698
|
onNavigateHome,
|
|
6473
|
-
|
|
6699
|
+
showBubble,
|
|
6474
6700
|
studioControlOptions
|
|
6475
6701
|
}) {
|
|
6476
6702
|
const theme = useTheme();
|
|
6477
6703
|
const { width } = (0, import_react_native54.useWindowDimensions)();
|
|
6478
|
-
const [sheetOpen, setSheetOpen] =
|
|
6479
|
-
const sheetOpenRef =
|
|
6480
|
-
const [activePage, setActivePage] =
|
|
6481
|
-
const [drawing, setDrawing] =
|
|
6482
|
-
const [chatAttachments, setChatAttachments] =
|
|
6483
|
-
const [commentsAppId, setCommentsAppId] =
|
|
6484
|
-
const [commentsCount, setCommentsCount] =
|
|
6704
|
+
const [sheetOpen, setSheetOpen] = React42.useState(false);
|
|
6705
|
+
const sheetOpenRef = React42.useRef(sheetOpen);
|
|
6706
|
+
const [activePage, setActivePage] = React42.useState("preview");
|
|
6707
|
+
const [drawing, setDrawing] = React42.useState(false);
|
|
6708
|
+
const [chatAttachments, setChatAttachments] = React42.useState([]);
|
|
6709
|
+
const [commentsAppId, setCommentsAppId] = React42.useState(null);
|
|
6710
|
+
const [commentsCount, setCommentsCount] = React42.useState(null);
|
|
6485
6711
|
const threadId = (app == null ? void 0 : app.threadId) ?? null;
|
|
6486
6712
|
const optimistic = useOptimisticChatMessages({
|
|
6487
6713
|
threadId,
|
|
@@ -6489,24 +6715,24 @@ function StudioOverlay({
|
|
|
6489
6715
|
chatMessages,
|
|
6490
6716
|
onSendChat
|
|
6491
6717
|
});
|
|
6492
|
-
const [confirmMrId, setConfirmMrId] =
|
|
6493
|
-
const confirmMr =
|
|
6718
|
+
const [confirmMrId, setConfirmMrId] = React42.useState(null);
|
|
6719
|
+
const confirmMr = React42.useMemo(
|
|
6494
6720
|
() => confirmMrId ? incomingMergeRequests.find((m) => m.id === confirmMrId) ?? null : null,
|
|
6495
6721
|
[confirmMrId, incomingMergeRequests]
|
|
6496
6722
|
);
|
|
6497
|
-
const handleSheetOpenChange =
|
|
6723
|
+
const handleSheetOpenChange = React42.useCallback((open) => {
|
|
6498
6724
|
setSheetOpen(open);
|
|
6499
6725
|
if (!open) import_react_native54.Keyboard.dismiss();
|
|
6500
6726
|
}, []);
|
|
6501
|
-
const closeSheet =
|
|
6727
|
+
const closeSheet = React42.useCallback(() => {
|
|
6502
6728
|
handleSheetOpenChange(false);
|
|
6503
6729
|
}, [handleSheetOpenChange]);
|
|
6504
|
-
const openSheet =
|
|
6505
|
-
const goToChat =
|
|
6730
|
+
const openSheet = React42.useCallback(() => setSheetOpen(true), []);
|
|
6731
|
+
const goToChat = React42.useCallback(() => {
|
|
6506
6732
|
setActivePage("chat");
|
|
6507
6733
|
openSheet();
|
|
6508
6734
|
}, [openSheet]);
|
|
6509
|
-
const backToPreview =
|
|
6735
|
+
const backToPreview = React42.useCallback(() => {
|
|
6510
6736
|
if (import_react_native54.Platform.OS !== "ios") {
|
|
6511
6737
|
import_react_native54.Keyboard.dismiss();
|
|
6512
6738
|
setActivePage("preview");
|
|
@@ -6524,11 +6750,11 @@ function StudioOverlay({
|
|
|
6524
6750
|
const t = setTimeout(finalize, 350);
|
|
6525
6751
|
import_react_native54.Keyboard.dismiss();
|
|
6526
6752
|
}, []);
|
|
6527
|
-
const startDraw =
|
|
6753
|
+
const startDraw = React42.useCallback(() => {
|
|
6528
6754
|
setDrawing(true);
|
|
6529
6755
|
closeSheet();
|
|
6530
6756
|
}, [closeSheet]);
|
|
6531
|
-
const handleDrawCapture =
|
|
6757
|
+
const handleDrawCapture = React42.useCallback(
|
|
6532
6758
|
(dataUrl) => {
|
|
6533
6759
|
setChatAttachments((prev) => [...prev, dataUrl]);
|
|
6534
6760
|
setDrawing(false);
|
|
@@ -6537,7 +6763,7 @@ function StudioOverlay({
|
|
|
6537
6763
|
},
|
|
6538
6764
|
[openSheet]
|
|
6539
6765
|
);
|
|
6540
|
-
const toggleSheet =
|
|
6766
|
+
const toggleSheet = React42.useCallback(async () => {
|
|
6541
6767
|
if (!sheetOpen) {
|
|
6542
6768
|
const shouldExitTest = Boolean(testingMrId) || isTesting;
|
|
6543
6769
|
if (shouldExitTest) {
|
|
@@ -6549,7 +6775,7 @@ function StudioOverlay({
|
|
|
6549
6775
|
closeSheet();
|
|
6550
6776
|
}
|
|
6551
6777
|
}, [closeSheet, isTesting, onRestoreBase, sheetOpen, testingMrId]);
|
|
6552
|
-
const handleTestMr =
|
|
6778
|
+
const handleTestMr = React42.useCallback(
|
|
6553
6779
|
async (mr) => {
|
|
6554
6780
|
if (!onTestMr) return;
|
|
6555
6781
|
await onTestMr(mr);
|
|
@@ -6557,10 +6783,10 @@ function StudioOverlay({
|
|
|
6557
6783
|
},
|
|
6558
6784
|
[closeSheet, onTestMr]
|
|
6559
6785
|
);
|
|
6560
|
-
|
|
6786
|
+
React42.useEffect(() => {
|
|
6561
6787
|
sheetOpenRef.current = sheetOpen;
|
|
6562
6788
|
}, [sheetOpen]);
|
|
6563
|
-
|
|
6789
|
+
React42.useEffect(() => {
|
|
6564
6790
|
const poller = (0, import_studio_control.startStudioControlPolling)((action) => {
|
|
6565
6791
|
if (action === "show" && !sheetOpenRef.current) openSheet();
|
|
6566
6792
|
if (action === "hide" && sheetOpenRef.current) closeSheet();
|
|
@@ -6568,7 +6794,7 @@ function StudioOverlay({
|
|
|
6568
6794
|
}, studioControlOptions);
|
|
6569
6795
|
return () => poller.stop();
|
|
6570
6796
|
}, [closeSheet, openSheet, studioControlOptions, toggleSheet]);
|
|
6571
|
-
|
|
6797
|
+
React42.useEffect(() => {
|
|
6572
6798
|
void (0, import_studio_control.publishComergeStudioUIState)(sheetOpen, studioControlOptions);
|
|
6573
6799
|
}, [sheetOpen, studioControlOptions]);
|
|
6574
6800
|
return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
|
|
@@ -6627,8 +6853,8 @@ function StudioOverlay({
|
|
|
6627
6853
|
)
|
|
6628
6854
|
}
|
|
6629
6855
|
) }),
|
|
6630
|
-
|
|
6631
|
-
|
|
6856
|
+
showBubble && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
6857
|
+
Bubble,
|
|
6632
6858
|
{
|
|
6633
6859
|
visible: !sheetOpen && !drawing,
|
|
6634
6860
|
ariaLabel: sheetOpen ? "Hide studio" : "Show studio",
|
|
@@ -6676,24 +6902,25 @@ function StudioOverlay({
|
|
|
6676
6902
|
var import_jsx_runtime58 = require("react/jsx-runtime");
|
|
6677
6903
|
function ComergeStudio({
|
|
6678
6904
|
appId,
|
|
6679
|
-
|
|
6905
|
+
clientKey: clientKey2,
|
|
6680
6906
|
appKey = "MicroMain",
|
|
6681
6907
|
onNavigateHome,
|
|
6682
6908
|
style,
|
|
6683
|
-
|
|
6684
|
-
studioControlOptions
|
|
6909
|
+
showBubble = true,
|
|
6910
|
+
studioControlOptions,
|
|
6911
|
+
embeddedBaseBundles
|
|
6685
6912
|
}) {
|
|
6686
|
-
const [activeAppId, setActiveAppId] =
|
|
6687
|
-
const [runtimeAppId, setRuntimeAppId] =
|
|
6688
|
-
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] =
|
|
6689
|
-
const platform =
|
|
6690
|
-
|
|
6913
|
+
const [activeAppId, setActiveAppId] = React43.useState(appId);
|
|
6914
|
+
const [runtimeAppId, setRuntimeAppId] = React43.useState(appId);
|
|
6915
|
+
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React43.useState(null);
|
|
6916
|
+
const platform = React43.useMemo(() => import_react_native55.Platform.OS === "ios" ? "ios" : "android", []);
|
|
6917
|
+
React43.useEffect(() => {
|
|
6691
6918
|
setActiveAppId(appId);
|
|
6692
6919
|
setRuntimeAppId(appId);
|
|
6693
6920
|
setPendingRuntimeTargetAppId(null);
|
|
6694
6921
|
}, [appId]);
|
|
6695
|
-
const captureTargetRef =
|
|
6696
|
-
return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(StudioBootstrap, {
|
|
6922
|
+
const captureTargetRef = React43.useRef(null);
|
|
6923
|
+
return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(StudioBootstrap, { clientKey: clientKey2, fallback: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(import_react_native55.View, { style: { flex: 1 } }), children: ({ userId }) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(import_bottom_sheet6.BottomSheetModalProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(LiquidGlassResetProvider, { resetTriggers: [appId, activeAppId, runtimeAppId], children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
6697
6924
|
ComergeStudioInner,
|
|
6698
6925
|
{
|
|
6699
6926
|
userId,
|
|
@@ -6708,8 +6935,9 @@ function ComergeStudio({
|
|
|
6708
6935
|
onNavigateHome,
|
|
6709
6936
|
captureTargetRef,
|
|
6710
6937
|
style,
|
|
6711
|
-
|
|
6712
|
-
studioControlOptions
|
|
6938
|
+
showBubble,
|
|
6939
|
+
studioControlOptions,
|
|
6940
|
+
embeddedBaseBundles
|
|
6713
6941
|
}
|
|
6714
6942
|
) }) }) });
|
|
6715
6943
|
}
|
|
@@ -6726,17 +6954,18 @@ function ComergeStudioInner({
|
|
|
6726
6954
|
onNavigateHome,
|
|
6727
6955
|
captureTargetRef,
|
|
6728
6956
|
style,
|
|
6729
|
-
|
|
6730
|
-
studioControlOptions
|
|
6957
|
+
showBubble,
|
|
6958
|
+
studioControlOptions,
|
|
6959
|
+
embeddedBaseBundles
|
|
6731
6960
|
}) {
|
|
6732
6961
|
const { app, loading: appLoading } = useApp(activeAppId);
|
|
6733
6962
|
const { app: runtimeAppFromHook } = useApp(runtimeAppId, { enabled: runtimeAppId !== activeAppId });
|
|
6734
6963
|
const runtimeApp = runtimeAppId === activeAppId ? app : runtimeAppFromHook;
|
|
6735
|
-
const sawEditingOnPendingTargetRef =
|
|
6736
|
-
|
|
6964
|
+
const sawEditingOnPendingTargetRef = React43.useRef(false);
|
|
6965
|
+
React43.useEffect(() => {
|
|
6737
6966
|
sawEditingOnPendingTargetRef.current = false;
|
|
6738
6967
|
}, [pendingRuntimeTargetAppId]);
|
|
6739
|
-
|
|
6968
|
+
React43.useEffect(() => {
|
|
6740
6969
|
if (!pendingRuntimeTargetAppId) return;
|
|
6741
6970
|
if (activeAppId !== pendingRuntimeTargetAppId) return;
|
|
6742
6971
|
if ((app == null ? void 0 : app.status) === "editing") {
|
|
@@ -6751,15 +6980,16 @@ function ComergeStudioInner({
|
|
|
6751
6980
|
const bundle = useBundleManager({
|
|
6752
6981
|
base: { appId: runtimeAppId, commitId: (runtimeApp == null ? void 0 : runtimeApp.headCommitId) ?? void 0 },
|
|
6753
6982
|
platform,
|
|
6754
|
-
canRequestLatest: (runtimeApp == null ? void 0 : runtimeApp.status) === "ready"
|
|
6983
|
+
canRequestLatest: (runtimeApp == null ? void 0 : runtimeApp.status) === "ready",
|
|
6984
|
+
embeddedBaseBundles
|
|
6755
6985
|
});
|
|
6756
|
-
const sawEditingOnActiveAppRef =
|
|
6757
|
-
const [showPostEditPreparing, setShowPostEditPreparing] =
|
|
6758
|
-
|
|
6986
|
+
const sawEditingOnActiveAppRef = React43.useRef(false);
|
|
6987
|
+
const [showPostEditPreparing, setShowPostEditPreparing] = React43.useState(false);
|
|
6988
|
+
React43.useEffect(() => {
|
|
6759
6989
|
sawEditingOnActiveAppRef.current = false;
|
|
6760
6990
|
setShowPostEditPreparing(false);
|
|
6761
6991
|
}, [activeAppId]);
|
|
6762
|
-
|
|
6992
|
+
React43.useEffect(() => {
|
|
6763
6993
|
if (!(app == null ? void 0 : app.id)) return;
|
|
6764
6994
|
if (app.status === "editing") {
|
|
6765
6995
|
sawEditingOnActiveAppRef.current = true;
|
|
@@ -6771,7 +7001,7 @@ function ComergeStudioInner({
|
|
|
6771
7001
|
sawEditingOnActiveAppRef.current = false;
|
|
6772
7002
|
}
|
|
6773
7003
|
}, [app == null ? void 0 : app.id, app == null ? void 0 : app.status]);
|
|
6774
|
-
|
|
7004
|
+
React43.useEffect(() => {
|
|
6775
7005
|
if (!showPostEditPreparing) return;
|
|
6776
7006
|
const stillProcessingBaseBundle = bundle.loading && bundle.loadingMode === "base" && !bundle.isTesting;
|
|
6777
7007
|
if (!stillProcessingBaseBundle) {
|
|
@@ -6781,10 +7011,10 @@ function ComergeStudioInner({
|
|
|
6781
7011
|
const threadId = (app == null ? void 0 : app.threadId) ?? "";
|
|
6782
7012
|
const thread = useThreadMessages(threadId);
|
|
6783
7013
|
const mergeRequests = useMergeRequests({ appId: activeAppId });
|
|
6784
|
-
const hasOpenOutgoingMr =
|
|
7014
|
+
const hasOpenOutgoingMr = React43.useMemo(() => {
|
|
6785
7015
|
return mergeRequests.lists.outgoing.some((mr) => mr.status === "open");
|
|
6786
7016
|
}, [mergeRequests.lists.outgoing]);
|
|
6787
|
-
const incomingReviewMrs =
|
|
7017
|
+
const incomingReviewMrs = React43.useMemo(() => {
|
|
6788
7018
|
if (!userId) return mergeRequests.lists.incoming;
|
|
6789
7019
|
return mergeRequests.lists.incoming.filter((mr) => mr.createdBy !== userId);
|
|
6790
7020
|
}, [mergeRequests.lists.incoming, userId]);
|
|
@@ -6806,9 +7036,9 @@ function ComergeStudioInner({
|
|
|
6806
7036
|
uploadAttachments: uploader.uploadBase64Images
|
|
6807
7037
|
});
|
|
6808
7038
|
const chatSendDisabled = hasNoOutcomeAfterLastHuman(thread.raw);
|
|
6809
|
-
const [processingMrId, setProcessingMrId] =
|
|
6810
|
-
const [testingMrId, setTestingMrId] =
|
|
6811
|
-
const chatShowTypingIndicator =
|
|
7039
|
+
const [processingMrId, setProcessingMrId] = React43.useState(null);
|
|
7040
|
+
const [testingMrId, setTestingMrId] = React43.useState(null);
|
|
7041
|
+
const chatShowTypingIndicator = React43.useMemo(() => {
|
|
6812
7042
|
var _a;
|
|
6813
7043
|
if (!thread.raw || thread.raw.length === 0) return false;
|
|
6814
7044
|
const last = thread.raw[thread.raw.length - 1];
|
|
@@ -6822,7 +7052,8 @@ function ComergeStudioInner({
|
|
|
6822
7052
|
appKey,
|
|
6823
7053
|
bundlePath: bundle.bundlePath,
|
|
6824
7054
|
forcePreparing: showPostEditPreparing,
|
|
6825
|
-
renderToken: bundle.renderToken
|
|
7055
|
+
renderToken: bundle.renderToken,
|
|
7056
|
+
allowInitialPreparing: !embeddedBaseBundles
|
|
6826
7057
|
}
|
|
6827
7058
|
),
|
|
6828
7059
|
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
@@ -6878,7 +7109,7 @@ function ComergeStudioInner({
|
|
|
6878
7109
|
chatShowTypingIndicator,
|
|
6879
7110
|
onSendChat: (text, attachments) => actions.sendEdit({ prompt: text, attachments }),
|
|
6880
7111
|
onNavigateHome,
|
|
6881
|
-
|
|
7112
|
+
showBubble,
|
|
6882
7113
|
studioControlOptions
|
|
6883
7114
|
}
|
|
6884
7115
|
)
|