@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.mjs
CHANGED
|
@@ -6,7 +6,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
// src/studio/ComergeStudio.tsx
|
|
9
|
-
import * as
|
|
9
|
+
import * as React43 from "react";
|
|
10
10
|
import { Platform as RNPlatform, View as View45 } from "react-native";
|
|
11
11
|
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
|
|
12
12
|
|
|
@@ -188,11 +188,11 @@ import * as React from "react";
|
|
|
188
188
|
import axios from "axios";
|
|
189
189
|
|
|
190
190
|
// src/core/services/http/baseUrl.ts
|
|
191
|
-
var BASE_URL = "https://comerge.ai";
|
|
191
|
+
var BASE_URL = "https://api.comerge.ai";
|
|
192
192
|
|
|
193
193
|
// src/core/services/http/public.ts
|
|
194
194
|
var CLIENT_KEY_HEADER = "x-comerge-api-key";
|
|
195
|
-
var
|
|
195
|
+
var clientKey = null;
|
|
196
196
|
var publicApi = axios.create({
|
|
197
197
|
baseURL: BASE_URL,
|
|
198
198
|
timeout: 3e4,
|
|
@@ -201,19 +201,19 @@ var publicApi = axios.create({
|
|
|
201
201
|
"Content-Type": "application/json"
|
|
202
202
|
}
|
|
203
203
|
});
|
|
204
|
-
function
|
|
204
|
+
function setClientKey(clientKeyInput) {
|
|
205
205
|
var _a;
|
|
206
|
-
const trimmed = ((_a =
|
|
206
|
+
const trimmed = ((_a = clientKeyInput == null ? void 0 : clientKeyInput.trim) == null ? void 0 : _a.call(clientKeyInput)) ?? "";
|
|
207
207
|
if (!trimmed) {
|
|
208
|
-
throw new Error("comerge-studio:
|
|
208
|
+
throw new Error("comerge-studio: clientKey is required");
|
|
209
209
|
}
|
|
210
|
-
|
|
210
|
+
clientKey = trimmed;
|
|
211
211
|
publicApi.defaults.headers.common[CLIENT_KEY_HEADER] = trimmed;
|
|
212
212
|
}
|
|
213
213
|
publicApi.interceptors.request.use((config) => {
|
|
214
|
-
if (!
|
|
214
|
+
if (!clientKey) return config;
|
|
215
215
|
config.headers = config.headers ?? {};
|
|
216
|
-
config.headers[CLIENT_KEY_HEADER] =
|
|
216
|
+
config.headers[CLIENT_KEY_HEADER] = clientKey;
|
|
217
217
|
return config;
|
|
218
218
|
});
|
|
219
219
|
|
|
@@ -278,42 +278,9 @@ async function ensureAnonymousSession() {
|
|
|
278
278
|
return { user: data.user, isNew: true };
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
// src/data/base-repository.ts
|
|
282
|
-
var BaseRepository = class {
|
|
283
|
-
unwrapOrThrow(res) {
|
|
284
|
-
if (res.success && res.responseObject) return res.responseObject;
|
|
285
|
-
const msg = res.message || "Request failed";
|
|
286
|
-
throw new Error(msg);
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
// src/data/base-remote.ts
|
|
291
|
-
var BaseRemote = class {
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
// src/data/public/studio-config/remote.ts
|
|
295
|
-
var StudioConfigRemoteDataSourceImpl = class extends BaseRemote {
|
|
296
|
-
async get() {
|
|
297
|
-
const { data } = await publicApi.get("/v1/public/studio-config");
|
|
298
|
-
return data;
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
var studioConfigRemoteDataSource = new StudioConfigRemoteDataSourceImpl();
|
|
302
|
-
|
|
303
|
-
// src/data/public/studio-config/repository.ts
|
|
304
|
-
var StudioConfigRepositoryImpl = class extends BaseRepository {
|
|
305
|
-
constructor(remote) {
|
|
306
|
-
super();
|
|
307
|
-
this.remote = remote;
|
|
308
|
-
}
|
|
309
|
-
async get() {
|
|
310
|
-
const res = await this.remote.get();
|
|
311
|
-
return this.unwrapOrThrow(res);
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
var studioConfigRepository = new StudioConfigRepositoryImpl(studioConfigRemoteDataSource);
|
|
315
|
-
|
|
316
281
|
// src/studio/bootstrap/useStudioBootstrap.ts
|
|
282
|
+
var SUPABASE_URL = "https://xtfxwbckjpfmqubnsusu.supabase.co";
|
|
283
|
+
var SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh0Znh3YmNranBmbXF1Ym5zdXN1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA2MDEyMzAsImV4cCI6MjA3NjE3NzIzMH0.dzWGAWrK4CvrmHVHzf8w7JlUZohdap0ZPnLZnABMV8s";
|
|
317
284
|
function useStudioBootstrap(options) {
|
|
318
285
|
const [state, setState] = React.useState({
|
|
319
286
|
ready: false,
|
|
@@ -324,11 +291,10 @@ function useStudioBootstrap(options) {
|
|
|
324
291
|
let cancelled = false;
|
|
325
292
|
(async () => {
|
|
326
293
|
try {
|
|
327
|
-
|
|
294
|
+
setClientKey(options.clientKey);
|
|
328
295
|
const requireAuth = isSupabaseClientInjected();
|
|
329
296
|
if (!requireAuth) {
|
|
330
|
-
|
|
331
|
-
setSupabaseConfig(cfg);
|
|
297
|
+
setSupabaseConfig({ url: SUPABASE_URL, anonKey: SUPABASE_ANON_KEY });
|
|
332
298
|
}
|
|
333
299
|
const { user } = requireAuth ? await ensureAuthenticatedSession() : await ensureAnonymousSession();
|
|
334
300
|
if (cancelled) return;
|
|
@@ -342,14 +308,14 @@ function useStudioBootstrap(options) {
|
|
|
342
308
|
return () => {
|
|
343
309
|
cancelled = true;
|
|
344
310
|
};
|
|
345
|
-
}, [options.
|
|
311
|
+
}, [options.clientKey]);
|
|
346
312
|
return state;
|
|
347
313
|
}
|
|
348
314
|
|
|
349
315
|
// src/studio/bootstrap/StudioBootstrap.tsx
|
|
350
316
|
import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
|
|
351
|
-
function StudioBootstrap({ children, fallback, renderError,
|
|
352
|
-
const { ready, error, userId } = useStudioBootstrap({
|
|
317
|
+
function StudioBootstrap({ children, fallback, renderError, clientKey: clientKey2 }) {
|
|
318
|
+
const { ready, error, userId } = useStudioBootstrap({ clientKey: clientKey2 });
|
|
353
319
|
if (error) {
|
|
354
320
|
return /* @__PURE__ */ jsx2(View, { style: { flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, children: renderError ? renderError(error) : /* @__PURE__ */ jsx2(Text, { variant: "bodyMuted", children: error.message }) });
|
|
355
321
|
}
|
|
@@ -497,6 +463,10 @@ var createApiClient = (baseURL) => {
|
|
|
497
463
|
};
|
|
498
464
|
var api = createApiClient(BASE_URL);
|
|
499
465
|
|
|
466
|
+
// src/data/base-remote.ts
|
|
467
|
+
var BaseRemote = class {
|
|
468
|
+
};
|
|
469
|
+
|
|
500
470
|
// src/data/apps/remote.ts
|
|
501
471
|
var AppsRemoteDataSourceImpl = class extends BaseRemote {
|
|
502
472
|
async list(projectId) {
|
|
@@ -552,6 +522,15 @@ var AppsRemoteDataSourceImpl = class extends BaseRemote {
|
|
|
552
522
|
};
|
|
553
523
|
var appsRemoteDataSource = new AppsRemoteDataSourceImpl();
|
|
554
524
|
|
|
525
|
+
// src/data/base-repository.ts
|
|
526
|
+
var BaseRepository = class {
|
|
527
|
+
unwrapOrThrow(res) {
|
|
528
|
+
if (res.success && res.responseObject) return res.responseObject;
|
|
529
|
+
const msg = res.message || "Request failed";
|
|
530
|
+
throw new Error(msg);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
|
|
555
534
|
// src/data/apps/repository.ts
|
|
556
535
|
function mapDbAppRow(row) {
|
|
557
536
|
return {
|
|
@@ -904,6 +883,8 @@ function useThreadMessages(threadId) {
|
|
|
904
883
|
// src/studio/hooks/useBundleManager.ts
|
|
905
884
|
import * as React5 from "react";
|
|
906
885
|
import * as FileSystem from "expo-file-system/legacy";
|
|
886
|
+
import { Asset } from "expo-asset";
|
|
887
|
+
import { unzip } from "react-native-zip-archive";
|
|
907
888
|
|
|
908
889
|
// src/data/apps/bundles/remote.ts
|
|
909
890
|
var BundlesRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -927,6 +908,13 @@ var BundlesRemoteDataSourceImpl = class extends BaseRemote {
|
|
|
927
908
|
);
|
|
928
909
|
return data;
|
|
929
910
|
}
|
|
911
|
+
async getSignedAssetsDownloadUrl(appId, bundleId, options) {
|
|
912
|
+
const { data } = await api.get(
|
|
913
|
+
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/assets/download`,
|
|
914
|
+
{ params: { redirect: (options == null ? void 0 : options.redirect) ?? false, kind: options == null ? void 0 : options.kind } }
|
|
915
|
+
);
|
|
916
|
+
return data;
|
|
917
|
+
}
|
|
930
918
|
};
|
|
931
919
|
var bundlesRemoteDataSource = new BundlesRemoteDataSourceImpl();
|
|
932
920
|
|
|
@@ -948,6 +936,10 @@ var BundlesRepositoryImpl = class extends BaseRepository {
|
|
|
948
936
|
const res = await this.remote.getSignedDownloadUrl(appId, bundleId, options);
|
|
949
937
|
return this.unwrapOrThrow(res);
|
|
950
938
|
}
|
|
939
|
+
async getSignedAssetsDownloadUrl(appId, bundleId, options) {
|
|
940
|
+
const res = await this.remote.getSignedAssetsDownloadUrl(appId, bundleId, options);
|
|
941
|
+
return this.unwrapOrThrow(res);
|
|
942
|
+
}
|
|
951
943
|
};
|
|
952
944
|
var bundlesRepository = new BundlesRepositoryImpl(bundlesRemoteDataSource);
|
|
953
945
|
|
|
@@ -999,20 +991,40 @@ async function ensureDir(path) {
|
|
|
999
991
|
if (info.exists) return;
|
|
1000
992
|
await FileSystem.makeDirectoryAsync(path, { intermediates: true });
|
|
1001
993
|
}
|
|
994
|
+
async function ensureBundleDir(key) {
|
|
995
|
+
await ensureDir(bundlesCacheDir());
|
|
996
|
+
await ensureDir(bundleDir(key));
|
|
997
|
+
}
|
|
1002
998
|
function baseBundleKey(appId, platform) {
|
|
1003
999
|
return `base:${appId}:${platform}`;
|
|
1004
1000
|
}
|
|
1005
1001
|
function testBundleKey(appId, commitId, platform, bundleId) {
|
|
1006
1002
|
return `test:${appId}:${commitId ?? "head"}:${platform}:${bundleId}`;
|
|
1007
1003
|
}
|
|
1008
|
-
function
|
|
1004
|
+
function legacyBundleFileUri(key) {
|
|
1009
1005
|
const dir = bundlesCacheDir();
|
|
1010
1006
|
return `${dir}${safeName(key)}.jsbundle`;
|
|
1011
1007
|
}
|
|
1012
|
-
function
|
|
1008
|
+
function legacyBundleMetaFileUri(key) {
|
|
1013
1009
|
const dir = bundlesCacheDir();
|
|
1014
1010
|
return `${dir}${safeName(key)}.meta.json`;
|
|
1015
1011
|
}
|
|
1012
|
+
function bundleDir(key) {
|
|
1013
|
+
const dir = bundlesCacheDir();
|
|
1014
|
+
return `${dir}${safeName(key)}/`;
|
|
1015
|
+
}
|
|
1016
|
+
function toBundleFileUri(key, platform) {
|
|
1017
|
+
return `${bundleDir(key)}index.${platform}.jsbundle`;
|
|
1018
|
+
}
|
|
1019
|
+
function toBundleMetaFileUri(key) {
|
|
1020
|
+
return `${bundleDir(key)}bundle.meta.json`;
|
|
1021
|
+
}
|
|
1022
|
+
function toAssetsMetaFileUri(key) {
|
|
1023
|
+
return `${bundleDir(key)}assets.meta.json`;
|
|
1024
|
+
}
|
|
1025
|
+
function toAssetsDir(key) {
|
|
1026
|
+
return `${bundleDir(key)}assets/`;
|
|
1027
|
+
}
|
|
1016
1028
|
async function readJsonFile(fileUri) {
|
|
1017
1029
|
try {
|
|
1018
1030
|
const info = await FileSystem.getInfoAsync(fileUri);
|
|
@@ -1039,6 +1051,14 @@ async function getExistingNonEmptyFileUri(fileUri) {
|
|
|
1039
1051
|
return null;
|
|
1040
1052
|
}
|
|
1041
1053
|
}
|
|
1054
|
+
async function getExistingBundleFileUri(key, platform) {
|
|
1055
|
+
const nextPath = toBundleFileUri(key, platform);
|
|
1056
|
+
const next = await getExistingNonEmptyFileUri(nextPath);
|
|
1057
|
+
if (next) return next;
|
|
1058
|
+
const legacyPath = legacyBundleFileUri(key);
|
|
1059
|
+
const legacy = await getExistingNonEmptyFileUri(legacyPath);
|
|
1060
|
+
return legacy;
|
|
1061
|
+
}
|
|
1042
1062
|
async function downloadIfMissing(url, fileUri) {
|
|
1043
1063
|
const existing = await getExistingNonEmptyFileUri(fileUri);
|
|
1044
1064
|
if (existing) return existing;
|
|
@@ -1062,8 +1082,71 @@ async function deleteFileIfExists(fileUri) {
|
|
|
1062
1082
|
} catch {
|
|
1063
1083
|
}
|
|
1064
1084
|
}
|
|
1065
|
-
async function
|
|
1066
|
-
|
|
1085
|
+
async function hydrateBaseFromEmbeddedAsset(appId, platform, embedded) {
|
|
1086
|
+
if (!(embedded == null ? void 0 : embedded.module)) return null;
|
|
1087
|
+
const key = baseBundleKey(appId, platform);
|
|
1088
|
+
const existing = await getExistingBundleFileUri(key, platform);
|
|
1089
|
+
if (existing) {
|
|
1090
|
+
return { bundlePath: existing, meta: embedded.meta ?? null };
|
|
1091
|
+
}
|
|
1092
|
+
await ensureBundleDir(key);
|
|
1093
|
+
const targetUri = toBundleFileUri(key, platform);
|
|
1094
|
+
const asset = Asset.fromModule(embedded.module);
|
|
1095
|
+
await asset.downloadAsync();
|
|
1096
|
+
const sourceUri = asset.localUri ?? asset.uri;
|
|
1097
|
+
if (!sourceUri) return null;
|
|
1098
|
+
const info = await FileSystem.getInfoAsync(sourceUri);
|
|
1099
|
+
if (!info.exists) return null;
|
|
1100
|
+
await deleteFileIfExists(targetUri);
|
|
1101
|
+
await FileSystem.copyAsync({ from: sourceUri, to: targetUri });
|
|
1102
|
+
const finalUri = await getExistingNonEmptyFileUri(targetUri);
|
|
1103
|
+
if (!finalUri) return null;
|
|
1104
|
+
return { bundlePath: finalUri, meta: embedded.meta ?? null };
|
|
1105
|
+
}
|
|
1106
|
+
async function hydrateAssetsFromEmbeddedAsset(appId, platform, key, embedded) {
|
|
1107
|
+
var _a;
|
|
1108
|
+
const moduleId = embedded == null ? void 0 : embedded.assetsModule;
|
|
1109
|
+
if (!moduleId) return false;
|
|
1110
|
+
const assetsMeta = (embedded == null ? void 0 : embedded.assetsMeta) ?? null;
|
|
1111
|
+
const assetsDir = toAssetsDir(key);
|
|
1112
|
+
const metaUri = toAssetsMetaFileUri(key);
|
|
1113
|
+
const existingMeta = await readJsonFile(metaUri);
|
|
1114
|
+
const assetsDirInfo = await FileSystem.getInfoAsync(assetsDir);
|
|
1115
|
+
const assetsDirExists = assetsDirInfo.exists && assetsDirInfo.isDirectory;
|
|
1116
|
+
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);
|
|
1117
|
+
const embeddedMetaMatches = (_a = existingMeta == null ? void 0 : existingMeta.storageKey) == null ? void 0 : _a.startsWith("embedded:");
|
|
1118
|
+
if (assetsDirExists && checksumMatches && embeddedMetaMatches) {
|
|
1119
|
+
return true;
|
|
1120
|
+
}
|
|
1121
|
+
await ensureBundleDir(key);
|
|
1122
|
+
await ensureDir(assetsDir);
|
|
1123
|
+
const asset = Asset.fromModule(moduleId);
|
|
1124
|
+
await asset.downloadAsync();
|
|
1125
|
+
const sourceUri = asset.localUri ?? asset.uri;
|
|
1126
|
+
if (!sourceUri) return false;
|
|
1127
|
+
const info = await FileSystem.getInfoAsync(sourceUri);
|
|
1128
|
+
if (!info.exists) return false;
|
|
1129
|
+
const zipUri = `${bundleDir(key)}assets.zip`;
|
|
1130
|
+
await deleteFileIfExists(zipUri);
|
|
1131
|
+
await FileSystem.copyAsync({ from: sourceUri, to: zipUri });
|
|
1132
|
+
try {
|
|
1133
|
+
await FileSystem.deleteAsync(assetsDir, { idempotent: true }).catch(() => {
|
|
1134
|
+
});
|
|
1135
|
+
} catch {
|
|
1136
|
+
}
|
|
1137
|
+
await ensureDir(assetsDir);
|
|
1138
|
+
await unzipArchive(zipUri, assetsDir);
|
|
1139
|
+
await writeJsonFile(metaUri, {
|
|
1140
|
+
checksumSha256: (assetsMeta == null ? void 0 : assetsMeta.checksumSha256) ?? null,
|
|
1141
|
+
storageKey: `embedded:${(assetsMeta == null ? void 0 : assetsMeta.checksumSha256) ?? "unknown"}`,
|
|
1142
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1143
|
+
});
|
|
1144
|
+
return true;
|
|
1145
|
+
}
|
|
1146
|
+
async function safeReplaceFileFromUrl(url, targetUri, tmpKey, platform) {
|
|
1147
|
+
const tmpKeySafe = `tmp:${tmpKey}:${Date.now()}`;
|
|
1148
|
+
const tmpUri = toBundleFileUri(tmpKeySafe, platform);
|
|
1149
|
+
await ensureDir(bundleDir(tmpKeySafe));
|
|
1067
1150
|
try {
|
|
1068
1151
|
await withRetry(
|
|
1069
1152
|
async () => {
|
|
@@ -1083,6 +1166,82 @@ async function safeReplaceFileFromUrl(url, targetUri, tmpKey) {
|
|
|
1083
1166
|
await deleteFileIfExists(tmpUri);
|
|
1084
1167
|
}
|
|
1085
1168
|
}
|
|
1169
|
+
async function safeReplaceFileFromUrlToPath(url, targetUri, tmpKey) {
|
|
1170
|
+
const tmpDir = `${bundlesCacheDir()}tmp/`;
|
|
1171
|
+
await ensureDir(tmpDir);
|
|
1172
|
+
const tmpUri = `${tmpDir}${safeName(tmpKey)}.tmp`;
|
|
1173
|
+
try {
|
|
1174
|
+
await withRetry(
|
|
1175
|
+
async () => {
|
|
1176
|
+
await deleteFileIfExists(tmpUri);
|
|
1177
|
+
await FileSystem.downloadAsync(url, tmpUri);
|
|
1178
|
+
const tmpOk = await getExistingNonEmptyFileUri(tmpUri);
|
|
1179
|
+
if (!tmpOk) throw new Error("Downloaded file is empty.");
|
|
1180
|
+
},
|
|
1181
|
+
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
1182
|
+
);
|
|
1183
|
+
await deleteFileIfExists(targetUri);
|
|
1184
|
+
await FileSystem.moveAsync({ from: tmpUri, to: targetUri });
|
|
1185
|
+
const finalOk = await getExistingNonEmptyFileUri(targetUri);
|
|
1186
|
+
if (!finalOk) throw new Error("File replacement failed.");
|
|
1187
|
+
return targetUri;
|
|
1188
|
+
} finally {
|
|
1189
|
+
await deleteFileIfExists(tmpUri);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
function getMetroAssets(bundle) {
|
|
1193
|
+
const assets = bundle.assets ?? [];
|
|
1194
|
+
return assets.find((asset) => asset.kind === "metro-assets") ?? null;
|
|
1195
|
+
}
|
|
1196
|
+
async function ensureAssetsForBundle(appId, bundle, key, platform) {
|
|
1197
|
+
var _a;
|
|
1198
|
+
const asset = getMetroAssets(bundle);
|
|
1199
|
+
if (!(asset == null ? void 0 : asset.storageKey)) return;
|
|
1200
|
+
await ensureBundleDir(key);
|
|
1201
|
+
const assetsDir = toAssetsDir(key);
|
|
1202
|
+
await ensureDir(assetsDir);
|
|
1203
|
+
const metaUri = toAssetsMetaFileUri(key);
|
|
1204
|
+
const existingMeta = await readJsonFile(metaUri);
|
|
1205
|
+
const assetsDirInfo = await FileSystem.getInfoAsync(assetsDir);
|
|
1206
|
+
const assetsDirExists = assetsDirInfo.exists && assetsDirInfo.isDirectory;
|
|
1207
|
+
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) {
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
const signed = await withRetry(
|
|
1211
|
+
async () => {
|
|
1212
|
+
return await bundlesRepository.getSignedAssetsDownloadUrl(appId, bundle.id, {
|
|
1213
|
+
redirect: false,
|
|
1214
|
+
kind: asset.kind
|
|
1215
|
+
});
|
|
1216
|
+
},
|
|
1217
|
+
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
1218
|
+
);
|
|
1219
|
+
const zipUri = `${bundleDir(key)}assets.zip`;
|
|
1220
|
+
await safeReplaceFileFromUrlToPath(signed.url, zipUri, `${appId}:${bundle.id}:${platform}:${asset.kind}`);
|
|
1221
|
+
try {
|
|
1222
|
+
await FileSystem.deleteAsync(assetsDir, { idempotent: true }).catch(() => {
|
|
1223
|
+
});
|
|
1224
|
+
} catch {
|
|
1225
|
+
}
|
|
1226
|
+
await ensureDir(assetsDir);
|
|
1227
|
+
await unzipArchive(zipUri, assetsDir);
|
|
1228
|
+
await writeJsonFile(metaUri, {
|
|
1229
|
+
checksumSha256: asset.checksumSha256 ?? null,
|
|
1230
|
+
storageKey: asset.storageKey,
|
|
1231
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
async function unzipArchive(sourceUri, destDir) {
|
|
1235
|
+
try {
|
|
1236
|
+
await unzip(sourceUri, destDir);
|
|
1237
|
+
} catch (e) {
|
|
1238
|
+
throw new Error(
|
|
1239
|
+
`Failed to extract assets archive. Ensure 'react-native-zip-archive' is installed in the host app. ${String(
|
|
1240
|
+
(e == null ? void 0 : e.message) ?? e
|
|
1241
|
+
)}`
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1086
1245
|
async function pollBundle(appId, bundleId, opts) {
|
|
1087
1246
|
const start = Date.now();
|
|
1088
1247
|
while (true) {
|
|
@@ -1118,23 +1277,39 @@ async function resolveBundlePath(src, platform, mode) {
|
|
|
1118
1277
|
if (finalBundle.status === "failed") {
|
|
1119
1278
|
throw new Error("Bundle build failed.");
|
|
1120
1279
|
}
|
|
1280
|
+
let bundleWithAssets = finalBundle;
|
|
1281
|
+
if (finalBundle.status === "succeeded" && (!finalBundle.assets || finalBundle.assets.length === 0)) {
|
|
1282
|
+
try {
|
|
1283
|
+
bundleWithAssets = await bundlesRepository.getById(appId, finalBundle.id);
|
|
1284
|
+
} catch {
|
|
1285
|
+
bundleWithAssets = finalBundle;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1121
1288
|
const signed = await withRetry(
|
|
1122
1289
|
async () => {
|
|
1123
1290
|
return await bundlesRepository.getSignedDownloadUrl(appId, finalBundle.id, { redirect: false });
|
|
1124
1291
|
},
|
|
1125
1292
|
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
1126
1293
|
);
|
|
1294
|
+
const key = mode === "base" ? baseBundleKey(appId, platform) : testBundleKey(appId, commitId, platform, finalBundle.id);
|
|
1295
|
+
await ensureBundleDir(key);
|
|
1127
1296
|
const bundlePath = mode === "base" ? await safeReplaceFileFromUrl(
|
|
1128
1297
|
signed.url,
|
|
1129
|
-
toBundleFileUri(
|
|
1130
|
-
`${appId}:${commitId ?? "head"}:${platform}:${finalBundle.id}
|
|
1131
|
-
|
|
1132
|
-
|
|
1298
|
+
toBundleFileUri(key, platform),
|
|
1299
|
+
`${appId}:${commitId ?? "head"}:${platform}:${finalBundle.id}`,
|
|
1300
|
+
platform
|
|
1301
|
+
) : await downloadIfMissing(signed.url, toBundleFileUri(key, platform));
|
|
1302
|
+
try {
|
|
1303
|
+
await ensureAssetsForBundle(appId, bundleWithAssets, key, platform);
|
|
1304
|
+
} catch {
|
|
1305
|
+
}
|
|
1306
|
+
return { bundlePath, label: "Ready", bundle: bundleWithAssets };
|
|
1133
1307
|
}
|
|
1134
1308
|
function useBundleManager({
|
|
1135
1309
|
base,
|
|
1136
1310
|
platform,
|
|
1137
|
-
canRequestLatest = true
|
|
1311
|
+
canRequestLatest = true,
|
|
1312
|
+
embeddedBaseBundles
|
|
1138
1313
|
}) {
|
|
1139
1314
|
const [bundlePath, setBundlePath] = React5.useState(null);
|
|
1140
1315
|
const [renderToken, setRenderToken] = React5.useState(0);
|
|
@@ -1145,6 +1320,8 @@ function useBundleManager({
|
|
|
1145
1320
|
const [isTesting, setIsTesting] = React5.useState(false);
|
|
1146
1321
|
const baseRef = React5.useRef(base);
|
|
1147
1322
|
baseRef.current = base;
|
|
1323
|
+
const embeddedBaseBundlesRef = React5.useRef(embeddedBaseBundles);
|
|
1324
|
+
embeddedBaseBundlesRef.current = embeddedBaseBundles;
|
|
1148
1325
|
const baseOpIdRef = React5.useRef(0);
|
|
1149
1326
|
const testOpIdRef = React5.useRef(0);
|
|
1150
1327
|
const activeLoadModeRef = React5.useRef(null);
|
|
@@ -1167,16 +1344,39 @@ function useBundleManager({
|
|
|
1167
1344
|
const hasCompletedFirstNetworkBaseLoadRef = React5.useRef(false);
|
|
1168
1345
|
const hydrateBaseFromDisk = React5.useCallback(
|
|
1169
1346
|
async (appId, reason) => {
|
|
1347
|
+
var _a, _b, _c;
|
|
1170
1348
|
try {
|
|
1171
1349
|
const dir = bundlesCacheDir();
|
|
1172
1350
|
await ensureDir(dir);
|
|
1173
1351
|
const key = baseBundleKey(appId, platform);
|
|
1174
|
-
|
|
1175
|
-
|
|
1352
|
+
let existing = await getExistingBundleFileUri(key, platform);
|
|
1353
|
+
let embeddedMeta = null;
|
|
1354
|
+
if (!existing) {
|
|
1355
|
+
const embedded = (_a = embeddedBaseBundlesRef.current) == null ? void 0 : _a[platform];
|
|
1356
|
+
const hydrated = await hydrateBaseFromEmbeddedAsset(appId, platform, embedded);
|
|
1357
|
+
if (hydrated == null ? void 0 : hydrated.bundlePath) {
|
|
1358
|
+
existing = hydrated.bundlePath;
|
|
1359
|
+
embeddedMeta = hydrated.meta ?? null;
|
|
1360
|
+
if (embeddedMeta) {
|
|
1361
|
+
await ensureBundleDir(key);
|
|
1362
|
+
await writeJsonFile(toBundleMetaFileUri(key), embeddedMeta);
|
|
1363
|
+
await writeJsonFile(legacyBundleMetaFileUri(key), embeddedMeta);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1176
1367
|
if (existing) {
|
|
1177
1368
|
lastBaseBundlePathRef.current = existing;
|
|
1178
1369
|
setBundlePath(existing);
|
|
1179
|
-
const meta = await readJsonFile(toBundleMetaFileUri(key));
|
|
1370
|
+
const meta = embeddedMeta ?? await readJsonFile(toBundleMetaFileUri(key)) ?? await readJsonFile(legacyBundleMetaFileUri(key));
|
|
1371
|
+
const embedded = (_b = embeddedBaseBundlesRef.current) == null ? void 0 : _b[platform];
|
|
1372
|
+
const embeddedFingerprint = ((_c = embedded == null ? void 0 : embedded.meta) == null ? void 0 : _c.fingerprint) ?? null;
|
|
1373
|
+
const actualFingerprint = (meta == null ? void 0 : meta.fingerprint) ?? (embeddedMeta == null ? void 0 : embeddedMeta.fingerprint) ?? null;
|
|
1374
|
+
if ((embedded == null ? void 0 : embedded.assetsModule) && embeddedFingerprint && actualFingerprint === embeddedFingerprint) {
|
|
1375
|
+
try {
|
|
1376
|
+
await hydrateAssetsFromEmbeddedAsset(appId, platform, key, embedded);
|
|
1377
|
+
} catch {
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1180
1380
|
if (meta == null ? void 0 : meta.fingerprint) {
|
|
1181
1381
|
lastBaseFingerprintRef.current = meta.fingerprint;
|
|
1182
1382
|
}
|
|
@@ -1241,7 +1441,16 @@ function useBundleManager({
|
|
|
1241
1441
|
lastBaseFingerprintRef.current = fingerprint;
|
|
1242
1442
|
hasCompletedFirstNetworkBaseLoadRef.current = true;
|
|
1243
1443
|
initialHydratedBaseFromDiskRef.current = false;
|
|
1244
|
-
|
|
1444
|
+
const metaKey = baseBundleKey(src.appId, platform);
|
|
1445
|
+
await ensureBundleDir(metaKey);
|
|
1446
|
+
void writeJsonFile(toBundleMetaFileUri(metaKey), {
|
|
1447
|
+
fingerprint,
|
|
1448
|
+
bundleId: bundle.id,
|
|
1449
|
+
checksumSha256: bundle.checksumSha256 ?? null,
|
|
1450
|
+
size: bundle.size ?? null,
|
|
1451
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1452
|
+
});
|
|
1453
|
+
void writeJsonFile(legacyBundleMetaFileUri(metaKey), {
|
|
1245
1454
|
fingerprint,
|
|
1246
1455
|
bundleId: bundle.id,
|
|
1247
1456
|
checksumSha256: bundle.checksumSha256 ?? null,
|
|
@@ -1763,11 +1972,28 @@ function hasNoOutcomeAfterLastHuman(messages) {
|
|
|
1763
1972
|
}
|
|
1764
1973
|
|
|
1765
1974
|
// src/studio/ui/RuntimeRenderer.tsx
|
|
1975
|
+
import * as React9 from "react";
|
|
1766
1976
|
import { View as View2 } from "react-native";
|
|
1767
1977
|
import { ComergeRuntimeRenderer } from "@comergehq/runtime";
|
|
1768
1978
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1769
|
-
function RuntimeRenderer({
|
|
1979
|
+
function RuntimeRenderer({
|
|
1980
|
+
appKey,
|
|
1981
|
+
bundlePath,
|
|
1982
|
+
forcePreparing,
|
|
1983
|
+
renderToken,
|
|
1984
|
+
style,
|
|
1985
|
+
allowInitialPreparing = true
|
|
1986
|
+
}) {
|
|
1987
|
+
const [hasRenderedOnce, setHasRenderedOnce] = React9.useState(false);
|
|
1988
|
+
React9.useEffect(() => {
|
|
1989
|
+
if (bundlePath) {
|
|
1990
|
+
setHasRenderedOnce(true);
|
|
1991
|
+
}
|
|
1992
|
+
}, [bundlePath]);
|
|
1770
1993
|
if (!bundlePath || forcePreparing) {
|
|
1994
|
+
if (!hasRenderedOnce && !forcePreparing && !allowInitialPreparing) {
|
|
1995
|
+
return /* @__PURE__ */ jsx3(View2, { style: [{ flex: 1 }, style] });
|
|
1996
|
+
}
|
|
1771
1997
|
return /* @__PURE__ */ jsx3(View2, { style: [{ flex: 1, justifyContent: "center", alignItems: "center", padding: 24 }, style], children: /* @__PURE__ */ jsx3(Text, { variant: "bodyMuted", children: "Preparing app\u2026" }) });
|
|
1772
1998
|
}
|
|
1773
1999
|
return /* @__PURE__ */ jsx3(View2, { style: [{ flex: 1 }, style], children: /* @__PURE__ */ jsx3(
|
|
@@ -1782,11 +2008,11 @@ function RuntimeRenderer({ appKey, bundlePath, forcePreparing, renderToken, styl
|
|
|
1782
2008
|
}
|
|
1783
2009
|
|
|
1784
2010
|
// src/studio/ui/StudioOverlay.tsx
|
|
1785
|
-
import * as
|
|
2011
|
+
import * as React42 from "react";
|
|
1786
2012
|
import { Keyboard as Keyboard5, Platform as Platform10, View as View44, useWindowDimensions as useWindowDimensions4 } from "react-native";
|
|
1787
2013
|
|
|
1788
2014
|
// src/components/studio-sheet/StudioBottomSheet.tsx
|
|
1789
|
-
import * as
|
|
2015
|
+
import * as React12 from "react";
|
|
1790
2016
|
import { AppState as AppState3, Keyboard, View as View4 } from "react-native";
|
|
1791
2017
|
import BottomSheet from "@gorhom/bottom-sheet";
|
|
1792
2018
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
@@ -1796,20 +2022,20 @@ import { Platform as Platform3, View as View3 } from "react-native";
|
|
|
1796
2022
|
import { isLiquidGlassSupported } from "@callstack/liquid-glass";
|
|
1797
2023
|
|
|
1798
2024
|
// src/components/utils/ResettableLiquidGlassView.tsx
|
|
1799
|
-
import * as
|
|
2025
|
+
import * as React11 from "react";
|
|
1800
2026
|
import { LiquidGlassView } from "@callstack/liquid-glass";
|
|
1801
2027
|
|
|
1802
2028
|
// src/components/utils/liquidGlassReset.tsx
|
|
1803
|
-
import * as
|
|
2029
|
+
import * as React10 from "react";
|
|
1804
2030
|
import { AppState as AppState2, Platform as Platform2 } from "react-native";
|
|
1805
2031
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1806
|
-
var LiquidGlassResetContext =
|
|
2032
|
+
var LiquidGlassResetContext = React10.createContext(0);
|
|
1807
2033
|
function LiquidGlassResetProvider({
|
|
1808
2034
|
children,
|
|
1809
2035
|
resetTriggers = []
|
|
1810
2036
|
}) {
|
|
1811
|
-
const [token, setToken] =
|
|
1812
|
-
|
|
2037
|
+
const [token, setToken] = React10.useState(0);
|
|
2038
|
+
React10.useEffect(() => {
|
|
1813
2039
|
if (Platform2.OS !== "ios") return;
|
|
1814
2040
|
const onChange = (state) => {
|
|
1815
2041
|
if (state === "active") setToken((t) => t + 1);
|
|
@@ -1817,21 +2043,21 @@ function LiquidGlassResetProvider({
|
|
|
1817
2043
|
const sub = AppState2.addEventListener("change", onChange);
|
|
1818
2044
|
return () => sub.remove();
|
|
1819
2045
|
}, []);
|
|
1820
|
-
|
|
2046
|
+
React10.useEffect(() => {
|
|
1821
2047
|
setToken((t) => t + 1);
|
|
1822
2048
|
}, resetTriggers);
|
|
1823
2049
|
return /* @__PURE__ */ jsx4(LiquidGlassResetContext.Provider, { value: token, children });
|
|
1824
2050
|
}
|
|
1825
2051
|
function useLiquidGlassResetToken() {
|
|
1826
|
-
return
|
|
2052
|
+
return React10.useContext(LiquidGlassResetContext);
|
|
1827
2053
|
}
|
|
1828
2054
|
|
|
1829
2055
|
// src/components/utils/ResettableLiquidGlassView.tsx
|
|
1830
2056
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1831
2057
|
function ResettableLiquidGlassView({ children, ...props }) {
|
|
1832
2058
|
const token = useLiquidGlassResetToken();
|
|
1833
|
-
const [layoutBootKey, setLayoutBootKey] =
|
|
1834
|
-
const sawNonZeroLayoutRef =
|
|
2059
|
+
const [layoutBootKey, setLayoutBootKey] = React11.useState(0);
|
|
2060
|
+
const sawNonZeroLayoutRef = React11.useRef(false);
|
|
1835
2061
|
const onLayout = (e) => {
|
|
1836
2062
|
var _a;
|
|
1837
2063
|
(_a = props.onLayout) == null ? void 0 : _a.call(props, e);
|
|
@@ -1905,11 +2131,11 @@ function StudioBottomSheet({
|
|
|
1905
2131
|
}) {
|
|
1906
2132
|
const theme = useTheme();
|
|
1907
2133
|
const insets = useSafeAreaInsets();
|
|
1908
|
-
const internalSheetRef =
|
|
2134
|
+
const internalSheetRef = React12.useRef(null);
|
|
1909
2135
|
const resolvedSheetRef = sheetRef ?? internalSheetRef;
|
|
1910
|
-
const currentIndexRef =
|
|
1911
|
-
const lastAppStateRef =
|
|
1912
|
-
|
|
2136
|
+
const currentIndexRef = React12.useRef(open ? snapPoints.length - 1 : -1);
|
|
2137
|
+
const lastAppStateRef = React12.useRef(AppState3.currentState);
|
|
2138
|
+
React12.useEffect(() => {
|
|
1913
2139
|
const sub = AppState3.addEventListener("change", (state) => {
|
|
1914
2140
|
const prev = lastAppStateRef.current;
|
|
1915
2141
|
lastAppStateRef.current = state;
|
|
@@ -1929,7 +2155,7 @@ function StudioBottomSheet({
|
|
|
1929
2155
|
});
|
|
1930
2156
|
return () => sub.remove();
|
|
1931
2157
|
}, [open, resolvedSheetRef]);
|
|
1932
|
-
|
|
2158
|
+
React12.useEffect(() => {
|
|
1933
2159
|
const sheet = resolvedSheetRef.current;
|
|
1934
2160
|
if (!sheet) return;
|
|
1935
2161
|
if (open) {
|
|
@@ -1938,7 +2164,7 @@ function StudioBottomSheet({
|
|
|
1938
2164
|
sheet.close();
|
|
1939
2165
|
}
|
|
1940
2166
|
}, [open, resolvedSheetRef, snapPoints.length]);
|
|
1941
|
-
const handleChange =
|
|
2167
|
+
const handleChange = React12.useCallback(
|
|
1942
2168
|
(index) => {
|
|
1943
2169
|
currentIndexRef.current = index;
|
|
1944
2170
|
onOpenChange == null ? void 0 : onOpenChange(index >= 0);
|
|
@@ -1967,12 +2193,12 @@ function StudioBottomSheet({
|
|
|
1967
2193
|
}
|
|
1968
2194
|
|
|
1969
2195
|
// src/components/studio-sheet/StudioSheetPager.tsx
|
|
1970
|
-
import * as
|
|
2196
|
+
import * as React13 from "react";
|
|
1971
2197
|
import { Animated } from "react-native";
|
|
1972
2198
|
import { jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1973
2199
|
function StudioSheetPager({ activePage, width, preview, chat, style }) {
|
|
1974
|
-
const anim =
|
|
1975
|
-
|
|
2200
|
+
const anim = React13.useRef(new Animated.Value(activePage === "chat" ? 1 : 0)).current;
|
|
2201
|
+
React13.useEffect(() => {
|
|
1976
2202
|
Animated.spring(anim, {
|
|
1977
2203
|
toValue: activePage === "chat" ? 1 : 0,
|
|
1978
2204
|
useNativeDriver: true,
|
|
@@ -2020,8 +2246,8 @@ function StudioSheetPager({ activePage, width, preview, chat, style }) {
|
|
|
2020
2246
|
] });
|
|
2021
2247
|
}
|
|
2022
2248
|
|
|
2023
|
-
// src/components/
|
|
2024
|
-
import { useCallback as useCallback8, useEffect as
|
|
2249
|
+
// src/components/bubble/Bubble.tsx
|
|
2250
|
+
import { useCallback as useCallback8, useEffect as useEffect11, useMemo as useMemo3, useRef as useRef7 } from "react";
|
|
2025
2251
|
import {
|
|
2026
2252
|
PanResponder,
|
|
2027
2253
|
Pressable,
|
|
@@ -2044,7 +2270,7 @@ import Animated2, {
|
|
|
2044
2270
|
} from "react-native-reanimated";
|
|
2045
2271
|
import { isLiquidGlassSupported as isLiquidGlassSupported2 } from "@callstack/liquid-glass";
|
|
2046
2272
|
|
|
2047
|
-
// src/components/
|
|
2273
|
+
// src/components/bubble/constants.ts
|
|
2048
2274
|
var DEFAULT_SIZE = 48;
|
|
2049
2275
|
var DEFAULT_EDGE_PADDING = 10;
|
|
2050
2276
|
var DEFAULT_OFFSET = {
|
|
@@ -2055,7 +2281,7 @@ var ENTER_SCALE_FROM = 0.3;
|
|
|
2055
2281
|
var ENTER_ROTATION_FROM_DEG = -180;
|
|
2056
2282
|
var PULSE_DURATION_MS = 900;
|
|
2057
2283
|
|
|
2058
|
-
// src/components/
|
|
2284
|
+
// src/components/bubble/Bubble.tsx
|
|
2059
2285
|
import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2060
2286
|
var HIDDEN_OFFSET_X = 20;
|
|
2061
2287
|
var SPRING_POSITION = { damping: 12, stiffness: 100, mass: 0.8 };
|
|
@@ -2077,7 +2303,7 @@ function getHiddenTranslateY(height) {
|
|
|
2077
2303
|
function getFinalTranslateY(height, size, bottomOffset) {
|
|
2078
2304
|
return height - size - bottomOffset;
|
|
2079
2305
|
}
|
|
2080
|
-
function
|
|
2306
|
+
function Bubble({
|
|
2081
2307
|
onPress,
|
|
2082
2308
|
size = DEFAULT_SIZE,
|
|
2083
2309
|
disabled = false,
|
|
@@ -2098,7 +2324,7 @@ function FloatingDraggableButton({
|
|
|
2098
2324
|
const { width, height } = useWindowDimensions();
|
|
2099
2325
|
const isDanger = variant === "danger";
|
|
2100
2326
|
const onPressRef = useRef7(onPress);
|
|
2101
|
-
|
|
2327
|
+
useEffect11(() => {
|
|
2102
2328
|
onPressRef.current = onPress;
|
|
2103
2329
|
}, [onPress]);
|
|
2104
2330
|
const fallbackBgColor = useMemo3(() => {
|
|
@@ -2139,7 +2365,7 @@ function FloatingDraggableButton({
|
|
|
2139
2365
|
}
|
|
2140
2366
|
});
|
|
2141
2367
|
}, [animateToHidden]);
|
|
2142
|
-
|
|
2368
|
+
useEffect11(() => {
|
|
2143
2369
|
if (isLoading) {
|
|
2144
2370
|
borderPulse.value = withRepeat(
|
|
2145
2371
|
withSequence(
|
|
@@ -2164,7 +2390,7 @@ function FloatingDraggableButton({
|
|
|
2164
2390
|
);
|
|
2165
2391
|
rotation.value = withSpring(0, SPRING_ROTATION_IN);
|
|
2166
2392
|
}, [height, offset.bottom, offset.left, rotation, scale, size, translateX, translateY]);
|
|
2167
|
-
|
|
2393
|
+
useEffect11(() => {
|
|
2168
2394
|
const timer = setTimeout(() => {
|
|
2169
2395
|
if (visible) {
|
|
2170
2396
|
animateIn();
|
|
@@ -2172,7 +2398,7 @@ function FloatingDraggableButton({
|
|
|
2172
2398
|
}, 100);
|
|
2173
2399
|
return () => clearTimeout(timer);
|
|
2174
2400
|
}, []);
|
|
2175
|
-
|
|
2401
|
+
useEffect11(() => {
|
|
2176
2402
|
if (visible && isAnimatingOut.current) {
|
|
2177
2403
|
animateIn();
|
|
2178
2404
|
} else if (!visible && !isAnimatingOut.current) {
|
|
@@ -2180,7 +2406,7 @@ function FloatingDraggableButton({
|
|
|
2180
2406
|
isAnimatingOut.current = true;
|
|
2181
2407
|
}
|
|
2182
2408
|
}, [visible, animateIn, animateToHidden]);
|
|
2183
|
-
|
|
2409
|
+
useEffect11(() => {
|
|
2184
2410
|
if (forceShowTrigger > 0 && visible) {
|
|
2185
2411
|
isAnimatingOut.current = false;
|
|
2186
2412
|
animateIn();
|
|
@@ -2302,7 +2528,7 @@ var styles = StyleSheet.create({
|
|
|
2302
2528
|
});
|
|
2303
2529
|
|
|
2304
2530
|
// src/components/overlays/EdgeGlowFrame.tsx
|
|
2305
|
-
import * as
|
|
2531
|
+
import * as React14 from "react";
|
|
2306
2532
|
import { Animated as Animated3, View as View6 } from "react-native";
|
|
2307
2533
|
import { LinearGradient } from "expo-linear-gradient";
|
|
2308
2534
|
|
|
@@ -2345,8 +2571,8 @@ function EdgeGlowFrame({
|
|
|
2345
2571
|
}) {
|
|
2346
2572
|
const theme = useTheme();
|
|
2347
2573
|
const alpha = Math.max(0, Math.min(1, intensity));
|
|
2348
|
-
const anim =
|
|
2349
|
-
|
|
2574
|
+
const anim = React14.useRef(new Animated3.Value(visible ? 1 : 0)).current;
|
|
2575
|
+
React14.useEffect(() => {
|
|
2350
2576
|
Animated3.timing(anim, {
|
|
2351
2577
|
toValue: visible ? 1 : 0,
|
|
2352
2578
|
duration: 300,
|
|
@@ -2397,12 +2623,12 @@ function EdgeGlowFrame({
|
|
|
2397
2623
|
}
|
|
2398
2624
|
|
|
2399
2625
|
// src/components/draw/DrawModeOverlay.tsx
|
|
2400
|
-
import * as
|
|
2626
|
+
import * as React17 from "react";
|
|
2401
2627
|
import { StyleSheet as StyleSheet3, View as View10 } from "react-native";
|
|
2402
2628
|
import { captureRef } from "react-native-view-shot";
|
|
2403
2629
|
|
|
2404
2630
|
// src/components/draw/DrawSurface.tsx
|
|
2405
|
-
import * as
|
|
2631
|
+
import * as React15 from "react";
|
|
2406
2632
|
import { PanResponder as PanResponder2, StyleSheet as StyleSheet2, View as View7 } from "react-native";
|
|
2407
2633
|
import Svg, { Path } from "react-native-svg";
|
|
2408
2634
|
|
|
@@ -2434,25 +2660,25 @@ function DrawSurface({
|
|
|
2434
2660
|
style,
|
|
2435
2661
|
minDistance = 1
|
|
2436
2662
|
}) {
|
|
2437
|
-
const [renderTick, setRenderTick] =
|
|
2438
|
-
const currentPointsRef =
|
|
2439
|
-
const rafRef =
|
|
2440
|
-
const triggerRender =
|
|
2663
|
+
const [renderTick, setRenderTick] = React15.useState(0);
|
|
2664
|
+
const currentPointsRef = React15.useRef([]);
|
|
2665
|
+
const rafRef = React15.useRef(null);
|
|
2666
|
+
const triggerRender = React15.useCallback(() => {
|
|
2441
2667
|
if (rafRef.current !== null) return;
|
|
2442
2668
|
rafRef.current = requestAnimationFrame(() => {
|
|
2443
2669
|
rafRef.current = null;
|
|
2444
2670
|
setRenderTick((n) => n + 1);
|
|
2445
2671
|
});
|
|
2446
2672
|
}, []);
|
|
2447
|
-
|
|
2673
|
+
React15.useEffect(() => () => {
|
|
2448
2674
|
if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
|
|
2449
2675
|
}, []);
|
|
2450
|
-
const onStart =
|
|
2676
|
+
const onStart = React15.useCallback((e) => {
|
|
2451
2677
|
const { locationX, locationY } = e.nativeEvent;
|
|
2452
2678
|
currentPointsRef.current = [{ x: locationX, y: locationY }];
|
|
2453
2679
|
triggerRender();
|
|
2454
2680
|
}, [triggerRender]);
|
|
2455
|
-
const onMove =
|
|
2681
|
+
const onMove = React15.useCallback((e, _g) => {
|
|
2456
2682
|
const { locationX, locationY } = e.nativeEvent;
|
|
2457
2683
|
const pts = currentPointsRef.current;
|
|
2458
2684
|
if (pts.length > 0) {
|
|
@@ -2465,7 +2691,7 @@ function DrawSurface({
|
|
|
2465
2691
|
currentPointsRef.current = [...pts, { x: locationX, y: locationY }];
|
|
2466
2692
|
triggerRender();
|
|
2467
2693
|
}, [minDistance, triggerRender]);
|
|
2468
|
-
const onEnd =
|
|
2694
|
+
const onEnd = React15.useCallback(() => {
|
|
2469
2695
|
const points = currentPointsRef.current;
|
|
2470
2696
|
if (points.length > 0) {
|
|
2471
2697
|
onAddStroke({ points, color, width: strokeWidth });
|
|
@@ -2473,7 +2699,7 @@ function DrawSurface({
|
|
|
2473
2699
|
currentPointsRef.current = [];
|
|
2474
2700
|
triggerRender();
|
|
2475
2701
|
}, [color, onAddStroke, strokeWidth, triggerRender]);
|
|
2476
|
-
const panResponder =
|
|
2702
|
+
const panResponder = React15.useMemo(
|
|
2477
2703
|
() => PanResponder2.create({
|
|
2478
2704
|
onStartShouldSetPanResponder: () => true,
|
|
2479
2705
|
onMoveShouldSetPanResponder: () => true,
|
|
@@ -2523,7 +2749,7 @@ var styles2 = StyleSheet2.create({
|
|
|
2523
2749
|
});
|
|
2524
2750
|
|
|
2525
2751
|
// src/components/draw/DrawToolbar.tsx
|
|
2526
|
-
import * as
|
|
2752
|
+
import * as React16 from "react";
|
|
2527
2753
|
import {
|
|
2528
2754
|
ActivityIndicator,
|
|
2529
2755
|
Animated as Animated4,
|
|
@@ -2620,11 +2846,11 @@ function DrawToolbar({
|
|
|
2620
2846
|
}) {
|
|
2621
2847
|
const insets = useSafeAreaInsets2();
|
|
2622
2848
|
const { width: screenWidth, height: screenHeight } = useWindowDimensions2();
|
|
2623
|
-
const [expanded, setExpanded] =
|
|
2624
|
-
const pos =
|
|
2625
|
-
const start =
|
|
2626
|
-
const currentPos =
|
|
2627
|
-
|
|
2849
|
+
const [expanded, setExpanded] = React16.useState(false);
|
|
2850
|
+
const pos = React16.useRef(new Animated4.ValueXY({ x: screenWidth / 2 - 110, y: -140 })).current;
|
|
2851
|
+
const start = React16.useRef({ x: 0, y: 0 });
|
|
2852
|
+
const currentPos = React16.useRef({ x: 0, y: 0 });
|
|
2853
|
+
React16.useEffect(() => {
|
|
2628
2854
|
if (hidden) return;
|
|
2629
2855
|
Animated4.spring(pos.y, {
|
|
2630
2856
|
toValue: insets.top + 60,
|
|
@@ -2634,7 +2860,7 @@ function DrawToolbar({
|
|
|
2634
2860
|
mass: 0.8
|
|
2635
2861
|
}).start();
|
|
2636
2862
|
}, [hidden, insets.top, pos.y]);
|
|
2637
|
-
|
|
2863
|
+
React16.useEffect(() => {
|
|
2638
2864
|
const id = pos.addListener((v) => {
|
|
2639
2865
|
currentPos.current = { x: v.x ?? 0, y: v.y ?? 0 };
|
|
2640
2866
|
});
|
|
@@ -2642,7 +2868,7 @@ function DrawToolbar({
|
|
|
2642
2868
|
pos.removeListener(id);
|
|
2643
2869
|
};
|
|
2644
2870
|
}, [pos]);
|
|
2645
|
-
const clamp2 =
|
|
2871
|
+
const clamp2 = React16.useCallback(
|
|
2646
2872
|
(x, y) => {
|
|
2647
2873
|
const minX = 10;
|
|
2648
2874
|
const maxX = Math.max(10, screenWidth - 230);
|
|
@@ -2652,7 +2878,7 @@ function DrawToolbar({
|
|
|
2652
2878
|
},
|
|
2653
2879
|
[insets.top, screenHeight, screenWidth]
|
|
2654
2880
|
);
|
|
2655
|
-
const panResponder =
|
|
2881
|
+
const panResponder = React16.useMemo(
|
|
2656
2882
|
() => PanResponder3.create({
|
|
2657
2883
|
onStartShouldSetPanResponder: () => false,
|
|
2658
2884
|
onMoveShouldSetPanResponder: (_e, g) => Math.abs(g.dx) > 5 || Math.abs(g.dy) > 5,
|
|
@@ -2680,7 +2906,7 @@ function DrawToolbar({
|
|
|
2680
2906
|
children
|
|
2681
2907
|
}) {
|
|
2682
2908
|
const isDisabled = Boolean(disabled) || Boolean(capturingDisabled);
|
|
2683
|
-
const [pressed, setPressed] =
|
|
2909
|
+
const [pressed, setPressed] = React16.useState(false);
|
|
2684
2910
|
return /* @__PURE__ */ jsx13(
|
|
2685
2911
|
View9,
|
|
2686
2912
|
{
|
|
@@ -2818,7 +3044,7 @@ function DrawModeOverlay({
|
|
|
2818
3044
|
renderDragHandle
|
|
2819
3045
|
}) {
|
|
2820
3046
|
const theme = useTheme();
|
|
2821
|
-
const defaultPalette =
|
|
3047
|
+
const defaultPalette = React17.useMemo(
|
|
2822
3048
|
() => [
|
|
2823
3049
|
"#EF4444",
|
|
2824
3050
|
// Red
|
|
@@ -2836,11 +3062,11 @@ function DrawModeOverlay({
|
|
|
2836
3062
|
[]
|
|
2837
3063
|
);
|
|
2838
3064
|
const colors = palette && palette.length > 0 ? palette : defaultPalette;
|
|
2839
|
-
const [selectedColor, setSelectedColor] =
|
|
2840
|
-
const [strokes, setStrokes] =
|
|
2841
|
-
const [capturing, setCapturing] =
|
|
2842
|
-
const [hideUi, setHideUi] =
|
|
2843
|
-
|
|
3065
|
+
const [selectedColor, setSelectedColor] = React17.useState(colors[0] ?? "#EF4444");
|
|
3066
|
+
const [strokes, setStrokes] = React17.useState([]);
|
|
3067
|
+
const [capturing, setCapturing] = React17.useState(false);
|
|
3068
|
+
const [hideUi, setHideUi] = React17.useState(false);
|
|
3069
|
+
React17.useEffect(() => {
|
|
2844
3070
|
if (!visible) return;
|
|
2845
3071
|
setStrokes([]);
|
|
2846
3072
|
setSelectedColor(colors[0] ?? "#EF4444");
|
|
@@ -2848,14 +3074,14 @@ function DrawModeOverlay({
|
|
|
2848
3074
|
setHideUi(false);
|
|
2849
3075
|
}, [colors, visible]);
|
|
2850
3076
|
const canUndo = strokes.length > 0;
|
|
2851
|
-
const handleUndo =
|
|
3077
|
+
const handleUndo = React17.useCallback(() => {
|
|
2852
3078
|
setStrokes((prev) => prev.slice(0, -1));
|
|
2853
3079
|
}, []);
|
|
2854
|
-
const handleCancel =
|
|
3080
|
+
const handleCancel = React17.useCallback(() => {
|
|
2855
3081
|
setStrokes([]);
|
|
2856
3082
|
onCancel();
|
|
2857
3083
|
}, [onCancel]);
|
|
2858
|
-
const handleDone =
|
|
3084
|
+
const handleDone = React17.useCallback(async () => {
|
|
2859
3085
|
if (!captureTargetRef.current || capturing) return;
|
|
2860
3086
|
try {
|
|
2861
3087
|
setCapturing(true);
|
|
@@ -2915,7 +3141,7 @@ var styles3 = StyleSheet3.create({
|
|
|
2915
3141
|
});
|
|
2916
3142
|
|
|
2917
3143
|
// src/components/comments/AppCommentsSheet.tsx
|
|
2918
|
-
import * as
|
|
3144
|
+
import * as React24 from "react";
|
|
2919
3145
|
import { ActivityIndicator as ActivityIndicator3, Keyboard as Keyboard3, Platform as Platform6, Pressable as Pressable5, View as View14 } from "react-native";
|
|
2920
3146
|
import {
|
|
2921
3147
|
BottomSheetBackdrop,
|
|
@@ -2927,7 +3153,7 @@ import { isLiquidGlassSupported as isLiquidGlassSupported4 } from "@callstack/li
|
|
|
2927
3153
|
import { Play as Play2 } from "lucide-react-native";
|
|
2928
3154
|
|
|
2929
3155
|
// src/components/chat/ChatComposer.tsx
|
|
2930
|
-
import * as
|
|
3156
|
+
import * as React19 from "react";
|
|
2931
3157
|
import {
|
|
2932
3158
|
ActivityIndicator as ActivityIndicator2,
|
|
2933
3159
|
Animated as Animated5,
|
|
@@ -2941,11 +3167,11 @@ import { isLiquidGlassSupported as isLiquidGlassSupported3 } from "@callstack/li
|
|
|
2941
3167
|
import { Plus } from "lucide-react-native";
|
|
2942
3168
|
|
|
2943
3169
|
// src/components/chat/MultilineTextInput.tsx
|
|
2944
|
-
import * as
|
|
3170
|
+
import * as React18 from "react";
|
|
2945
3171
|
import { TextInput } from "react-native";
|
|
2946
3172
|
import { BottomSheetTextInput } from "@gorhom/bottom-sheet";
|
|
2947
3173
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
2948
|
-
var MultilineTextInput =
|
|
3174
|
+
var MultilineTextInput = React18.forwardRef(function MultilineTextInput2({ useBottomSheetTextInput = false, placeholder, placeholderTextColor, style, ...props }, ref) {
|
|
2949
3175
|
const theme = useTheme();
|
|
2950
3176
|
const baseStyle = {
|
|
2951
3177
|
minHeight: 44,
|
|
@@ -3029,7 +3255,7 @@ function AspectRatioThumbnail({
|
|
|
3029
3255
|
onRemove,
|
|
3030
3256
|
renderRemoveIcon
|
|
3031
3257
|
}) {
|
|
3032
|
-
const [aspectRatio, setAspectRatio] =
|
|
3258
|
+
const [aspectRatio, setAspectRatio] = React19.useState(1);
|
|
3033
3259
|
return /* @__PURE__ */ jsxs8(View11, { style: { height: THUMBNAIL_HEIGHT, aspectRatio, position: "relative" }, children: [
|
|
3034
3260
|
/* @__PURE__ */ jsx17(View11, { style: { flex: 1, borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ jsx17(
|
|
3035
3261
|
Image,
|
|
@@ -3086,19 +3312,19 @@ function ChatComposer({
|
|
|
3086
3312
|
style
|
|
3087
3313
|
}) {
|
|
3088
3314
|
const theme = useTheme();
|
|
3089
|
-
const [internal, setInternal] =
|
|
3315
|
+
const [internal, setInternal] = React19.useState("");
|
|
3090
3316
|
const text = value ?? internal;
|
|
3091
3317
|
const setText = onChangeValue ?? setInternal;
|
|
3092
3318
|
const hasAttachments = attachments.length > 0;
|
|
3093
3319
|
const hasText = text.trim().length > 0;
|
|
3094
3320
|
const composerMinHeight = hasAttachments ? THUMBNAIL_HEIGHT + 44 + 24 : 44;
|
|
3095
3321
|
const isButtonDisabled = sending || disabled || sendDisabled;
|
|
3096
|
-
const maxInputHeight =
|
|
3097
|
-
const shakeAnim =
|
|
3098
|
-
const [sendPressed, setSendPressed] =
|
|
3099
|
-
const inputRef =
|
|
3100
|
-
const prevAutoFocusRef =
|
|
3101
|
-
|
|
3322
|
+
const maxInputHeight = React19.useMemo(() => Dimensions.get("window").height * 0.5, []);
|
|
3323
|
+
const shakeAnim = React19.useRef(new Animated5.Value(0)).current;
|
|
3324
|
+
const [sendPressed, setSendPressed] = React19.useState(false);
|
|
3325
|
+
const inputRef = React19.useRef(null);
|
|
3326
|
+
const prevAutoFocusRef = React19.useRef(false);
|
|
3327
|
+
React19.useEffect(() => {
|
|
3102
3328
|
const shouldFocus = autoFocus && !prevAutoFocusRef.current && !disabled && !sending;
|
|
3103
3329
|
prevAutoFocusRef.current = autoFocus;
|
|
3104
3330
|
if (!shouldFocus) return;
|
|
@@ -3108,7 +3334,7 @@ function ChatComposer({
|
|
|
3108
3334
|
}, 75);
|
|
3109
3335
|
return () => clearTimeout(t);
|
|
3110
3336
|
}, [autoFocus, disabled, sending]);
|
|
3111
|
-
const triggerShake =
|
|
3337
|
+
const triggerShake = React19.useCallback(() => {
|
|
3112
3338
|
shakeAnim.setValue(0);
|
|
3113
3339
|
Animated5.sequence([
|
|
3114
3340
|
Animated5.timing(shakeAnim, { toValue: 10, duration: 50, useNativeDriver: true }),
|
|
@@ -3118,7 +3344,7 @@ function ChatComposer({
|
|
|
3118
3344
|
Animated5.timing(shakeAnim, { toValue: 0, duration: 50, useNativeDriver: true })
|
|
3119
3345
|
]).start();
|
|
3120
3346
|
}, [shakeAnim]);
|
|
3121
|
-
const handleSend =
|
|
3347
|
+
const handleSend = React19.useCallback(async () => {
|
|
3122
3348
|
if (isButtonDisabled) return;
|
|
3123
3349
|
if (!hasText) {
|
|
3124
3350
|
triggerShake();
|
|
@@ -3251,7 +3477,7 @@ function ChatComposer({
|
|
|
3251
3477
|
}
|
|
3252
3478
|
|
|
3253
3479
|
// src/components/comments/CommentRow.tsx
|
|
3254
|
-
import * as
|
|
3480
|
+
import * as React20 from "react";
|
|
3255
3481
|
import { View as View13 } from "react-native";
|
|
3256
3482
|
|
|
3257
3483
|
// src/components/primitives/Avatar.tsx
|
|
@@ -3323,9 +3549,9 @@ function formatTimeAgo(iso) {
|
|
|
3323
3549
|
import { jsx as jsx19, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3324
3550
|
function CommentRow({ comment, showDivider }) {
|
|
3325
3551
|
const theme = useTheme();
|
|
3326
|
-
const [authorName, setAuthorName] =
|
|
3327
|
-
const [authorAvatar, setAuthorAvatar] =
|
|
3328
|
-
|
|
3552
|
+
const [authorName, setAuthorName] = React20.useState(null);
|
|
3553
|
+
const [authorAvatar, setAuthorAvatar] = React20.useState(null);
|
|
3554
|
+
React20.useEffect(() => {
|
|
3329
3555
|
let cancelled = false;
|
|
3330
3556
|
(async () => {
|
|
3331
3557
|
try {
|
|
@@ -3365,7 +3591,7 @@ function CommentRow({ comment, showDivider }) {
|
|
|
3365
3591
|
}
|
|
3366
3592
|
|
|
3367
3593
|
// src/components/comments/useAppComments.ts
|
|
3368
|
-
import * as
|
|
3594
|
+
import * as React21 from "react";
|
|
3369
3595
|
|
|
3370
3596
|
// src/data/comments/remote.ts
|
|
3371
3597
|
var AppCommentsRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -3437,18 +3663,18 @@ var appCommentsRepository = new AppCommentsRepositoryImpl(appCommentsRemoteDataS
|
|
|
3437
3663
|
|
|
3438
3664
|
// src/components/comments/useAppComments.ts
|
|
3439
3665
|
function useAppComments(appId) {
|
|
3440
|
-
const [comments, setComments] =
|
|
3441
|
-
const [loading, setLoading] =
|
|
3442
|
-
const [sending, setSending] =
|
|
3443
|
-
const [error, setError] =
|
|
3444
|
-
const sortByCreatedAtAsc =
|
|
3666
|
+
const [comments, setComments] = React21.useState([]);
|
|
3667
|
+
const [loading, setLoading] = React21.useState(false);
|
|
3668
|
+
const [sending, setSending] = React21.useState(false);
|
|
3669
|
+
const [error, setError] = React21.useState(null);
|
|
3670
|
+
const sortByCreatedAtAsc = React21.useCallback((items) => {
|
|
3445
3671
|
return [...items].sort((a, b) => {
|
|
3446
3672
|
const at = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
|
3447
3673
|
const bt = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
|
3448
3674
|
return at - bt;
|
|
3449
3675
|
});
|
|
3450
3676
|
}, []);
|
|
3451
|
-
const refresh =
|
|
3677
|
+
const refresh = React21.useCallback(async () => {
|
|
3452
3678
|
if (!appId) {
|
|
3453
3679
|
setComments([]);
|
|
3454
3680
|
return;
|
|
@@ -3465,10 +3691,10 @@ function useAppComments(appId) {
|
|
|
3465
3691
|
setLoading(false);
|
|
3466
3692
|
}
|
|
3467
3693
|
}, [appId, sortByCreatedAtAsc]);
|
|
3468
|
-
|
|
3694
|
+
React21.useEffect(() => {
|
|
3469
3695
|
void refresh();
|
|
3470
3696
|
}, [refresh]);
|
|
3471
|
-
const create =
|
|
3697
|
+
const create = React21.useCallback(
|
|
3472
3698
|
async (text) => {
|
|
3473
3699
|
if (!appId) return;
|
|
3474
3700
|
const trimmed = text.trim();
|
|
@@ -3491,11 +3717,11 @@ function useAppComments(appId) {
|
|
|
3491
3717
|
}
|
|
3492
3718
|
|
|
3493
3719
|
// src/components/comments/useAppDetails.ts
|
|
3494
|
-
import * as
|
|
3720
|
+
import * as React22 from "react";
|
|
3495
3721
|
function useAppDetails(appId) {
|
|
3496
|
-
const [app, setApp] =
|
|
3497
|
-
const [loading, setLoading] =
|
|
3498
|
-
|
|
3722
|
+
const [app, setApp] = React22.useState(null);
|
|
3723
|
+
const [loading, setLoading] = React22.useState(false);
|
|
3724
|
+
React22.useEffect(() => {
|
|
3499
3725
|
if (!appId) {
|
|
3500
3726
|
setApp(null);
|
|
3501
3727
|
return;
|
|
@@ -3520,11 +3746,11 @@ function useAppDetails(appId) {
|
|
|
3520
3746
|
}
|
|
3521
3747
|
|
|
3522
3748
|
// src/components/comments/useIosKeyboardSnapFix.ts
|
|
3523
|
-
import * as
|
|
3749
|
+
import * as React23 from "react";
|
|
3524
3750
|
import { Keyboard as Keyboard2, Platform as Platform5 } from "react-native";
|
|
3525
3751
|
function useIosKeyboardSnapFix(sheetRef, options) {
|
|
3526
|
-
const [keyboardVisible, setKeyboardVisible] =
|
|
3527
|
-
|
|
3752
|
+
const [keyboardVisible, setKeyboardVisible] = React23.useState(false);
|
|
3753
|
+
React23.useEffect(() => {
|
|
3528
3754
|
if (Platform5.OS !== "ios") return;
|
|
3529
3755
|
const show = Keyboard2.addListener("keyboardWillShow", () => setKeyboardVisible(true));
|
|
3530
3756
|
const hide = Keyboard2.addListener("keyboardWillHide", () => {
|
|
@@ -3552,16 +3778,16 @@ import { jsx as jsx20, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
|
3552
3778
|
function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
|
|
3553
3779
|
const theme = useTheme();
|
|
3554
3780
|
const insets = useSafeAreaInsets3();
|
|
3555
|
-
const sheetRef =
|
|
3556
|
-
const snapPoints =
|
|
3557
|
-
const currentIndexRef =
|
|
3781
|
+
const sheetRef = React24.useRef(null);
|
|
3782
|
+
const snapPoints = React24.useMemo(() => ["50%", "90%"], []);
|
|
3783
|
+
const currentIndexRef = React24.useRef(1);
|
|
3558
3784
|
const { comments, loading, sending, error, create, refresh } = useAppComments(appId);
|
|
3559
3785
|
const { app, loading: loadingApp } = useAppDetails(appId);
|
|
3560
3786
|
const { keyboardVisible } = useIosKeyboardSnapFix(sheetRef, {
|
|
3561
3787
|
getCurrentIndex: () => currentIndexRef.current,
|
|
3562
3788
|
targetIndex: 1
|
|
3563
3789
|
});
|
|
3564
|
-
|
|
3790
|
+
React24.useEffect(() => {
|
|
3565
3791
|
var _a, _b;
|
|
3566
3792
|
if (appId) {
|
|
3567
3793
|
(_a = sheetRef.current) == null ? void 0 : _a.present();
|
|
@@ -3570,22 +3796,22 @@ function AppCommentsSheet({ appId, onClose, onCountChange, onPlayApp }) {
|
|
|
3570
3796
|
(_b = sheetRef.current) == null ? void 0 : _b.dismiss();
|
|
3571
3797
|
}
|
|
3572
3798
|
}, [appId, refresh]);
|
|
3573
|
-
|
|
3799
|
+
React24.useEffect(() => {
|
|
3574
3800
|
if (!appId) return;
|
|
3575
3801
|
onCountChange == null ? void 0 : onCountChange(comments.length);
|
|
3576
3802
|
}, [appId, comments.length, onCountChange]);
|
|
3577
|
-
const renderBackdrop =
|
|
3803
|
+
const renderBackdrop = React24.useCallback(
|
|
3578
3804
|
(props) => /* @__PURE__ */ jsx20(BottomSheetBackdrop, { ...props, disappearsOnIndex: -1, appearsOnIndex: 0, opacity: 0.5 }),
|
|
3579
3805
|
[]
|
|
3580
3806
|
);
|
|
3581
|
-
const handleChange =
|
|
3807
|
+
const handleChange = React24.useCallback(
|
|
3582
3808
|
(index) => {
|
|
3583
3809
|
currentIndexRef.current = index;
|
|
3584
3810
|
if (index === -1) onClose();
|
|
3585
3811
|
},
|
|
3586
3812
|
[onClose]
|
|
3587
3813
|
);
|
|
3588
|
-
const handlePlay =
|
|
3814
|
+
const handlePlay = React24.useCallback(async () => {
|
|
3589
3815
|
var _a;
|
|
3590
3816
|
if (!appId) return;
|
|
3591
3817
|
(_a = sheetRef.current) == null ? void 0 : _a.dismiss();
|
|
@@ -3795,7 +4021,7 @@ function StudioSheetHeader({ left, center, right, style }) {
|
|
|
3795
4021
|
}
|
|
3796
4022
|
|
|
3797
4023
|
// src/components/studio-sheet/StudioSheetHeaderIconButton.tsx
|
|
3798
|
-
import * as
|
|
4024
|
+
import * as React25 from "react";
|
|
3799
4025
|
import { Pressable as Pressable6, View as View17 } from "react-native";
|
|
3800
4026
|
import { isLiquidGlassSupported as isLiquidGlassSupported5 } from "@callstack/liquid-glass";
|
|
3801
4027
|
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
@@ -3810,7 +4036,7 @@ function StudioSheetHeaderIconButton({
|
|
|
3810
4036
|
}) {
|
|
3811
4037
|
const theme = useTheme();
|
|
3812
4038
|
const size = 44;
|
|
3813
|
-
const [pressed, setPressed] =
|
|
4039
|
+
const [pressed, setPressed] = React25.useState(false);
|
|
3814
4040
|
const solidBg = intent === "danger" ? theme.colors.danger : intent === "primary" ? theme.colors.primary : theme.colors.neutral;
|
|
3815
4041
|
const glassFallbackBg = theme.scheme === "dark" ? "#18181B" : "#F6F6F6";
|
|
3816
4042
|
const glassInnerBg = intent === "danger" ? theme.colors.danger : theme.colors.primary;
|
|
@@ -4000,14 +4226,14 @@ function PreviewHeroCard({
|
|
|
4000
4226
|
}
|
|
4001
4227
|
|
|
4002
4228
|
// src/components/preview/PreviewPlaceholder.tsx
|
|
4003
|
-
import * as
|
|
4229
|
+
import * as React26 from "react";
|
|
4004
4230
|
import { Animated as Animated6 } from "react-native";
|
|
4005
4231
|
import { LinearGradient as LinearGradient2 } from "expo-linear-gradient";
|
|
4006
4232
|
import { Fragment as Fragment3, jsx as jsx28, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
4007
4233
|
function PreviewPlaceholder({ visible, style }) {
|
|
4008
4234
|
if (!visible) return null;
|
|
4009
|
-
const opacityAnim =
|
|
4010
|
-
|
|
4235
|
+
const opacityAnim = React26.useRef(new Animated6.Value(0)).current;
|
|
4236
|
+
React26.useEffect(() => {
|
|
4011
4237
|
if (!visible) return;
|
|
4012
4238
|
const animation = Animated6.loop(
|
|
4013
4239
|
Animated6.sequence([
|
|
@@ -4599,12 +4825,12 @@ function PreviewCustomizeSection({
|
|
|
4599
4825
|
}
|
|
4600
4826
|
|
|
4601
4827
|
// src/studio/ui/preview-panel/PreviewCollaborateSection.tsx
|
|
4602
|
-
import * as
|
|
4828
|
+
import * as React32 from "react";
|
|
4603
4829
|
import { ActivityIndicator as ActivityIndicator6, Alert, View as View32 } from "react-native";
|
|
4604
4830
|
import { Send as Send2 } from "lucide-react-native";
|
|
4605
4831
|
|
|
4606
4832
|
// src/components/merge-requests/MergeRequestStatusCard.tsx
|
|
4607
|
-
import * as
|
|
4833
|
+
import * as React28 from "react";
|
|
4608
4834
|
import { Animated as Animated7, Pressable as Pressable9, View as View28 } from "react-native";
|
|
4609
4835
|
import { Ban, Check as Check3, CheckCheck, ChevronDown as ChevronDown2 } from "lucide-react-native";
|
|
4610
4836
|
|
|
@@ -4686,11 +4912,11 @@ function toIsoString(input) {
|
|
|
4686
4912
|
}
|
|
4687
4913
|
|
|
4688
4914
|
// src/components/merge-requests/useControlledExpansion.ts
|
|
4689
|
-
import * as
|
|
4915
|
+
import * as React27 from "react";
|
|
4690
4916
|
function useControlledExpansion(props) {
|
|
4691
|
-
const [uncontrolled, setUncontrolled] =
|
|
4917
|
+
const [uncontrolled, setUncontrolled] = React27.useState(false);
|
|
4692
4918
|
const expanded = props.expanded ?? uncontrolled;
|
|
4693
|
-
const setExpanded =
|
|
4919
|
+
const setExpanded = React27.useCallback(
|
|
4694
4920
|
(next) => {
|
|
4695
4921
|
var _a;
|
|
4696
4922
|
(_a = props.onExpandedChange) == null ? void 0 : _a.call(props, next);
|
|
@@ -4715,8 +4941,8 @@ function MergeRequestStatusCard({
|
|
|
4715
4941
|
const isDark = theme.scheme === "dark";
|
|
4716
4942
|
const textColor = isDark ? "#FFFFFF" : "#000000";
|
|
4717
4943
|
const subTextColor = isDark ? "#A1A1AA" : "#71717A";
|
|
4718
|
-
const status =
|
|
4719
|
-
const { StatusIcon, iconColor, bgColor, statusText } =
|
|
4944
|
+
const status = React28.useMemo(() => getMergeRequestStatusDisplay(String(mergeRequest.status)), [mergeRequest.status]);
|
|
4945
|
+
const { StatusIcon, iconColor, bgColor, statusText } = React28.useMemo(() => {
|
|
4720
4946
|
switch (mergeRequest.status) {
|
|
4721
4947
|
case "approved":
|
|
4722
4948
|
case "merged":
|
|
@@ -4747,8 +4973,8 @@ function MergeRequestStatusCard({
|
|
|
4747
4973
|
const createdIso = toIsoString(mergeRequest.createdAt ?? null);
|
|
4748
4974
|
const headerTimeAgo = updatedIso ? formatTimeAgo(updatedIso) : "";
|
|
4749
4975
|
const createdTimeAgo = createdIso ? formatTimeAgo(createdIso) : "";
|
|
4750
|
-
const rotate =
|
|
4751
|
-
|
|
4976
|
+
const rotate = React28.useRef(new Animated7.Value(expanded ? 1 : 0)).current;
|
|
4977
|
+
React28.useEffect(() => {
|
|
4752
4978
|
Animated7.timing(rotate, {
|
|
4753
4979
|
toValue: expanded ? 1 : 0,
|
|
4754
4980
|
duration: 200,
|
|
@@ -4839,16 +5065,16 @@ function MergeRequestStatusCard({
|
|
|
4839
5065
|
}
|
|
4840
5066
|
|
|
4841
5067
|
// src/components/merge-requests/ReviewMergeRequestCarousel.tsx
|
|
4842
|
-
import * as
|
|
5068
|
+
import * as React31 from "react";
|
|
4843
5069
|
import { Animated as Animated9, FlatList, View as View31, useWindowDimensions as useWindowDimensions3 } from "react-native";
|
|
4844
5070
|
|
|
4845
5071
|
// src/components/merge-requests/ReviewMergeRequestCard.tsx
|
|
4846
|
-
import * as
|
|
5072
|
+
import * as React30 from "react";
|
|
4847
5073
|
import { ActivityIndicator as ActivityIndicator5, Animated as Animated8, Pressable as Pressable11, View as View30 } from "react-native";
|
|
4848
5074
|
import { Check as Check4, ChevronDown as ChevronDown3, Play as Play3, X as X3 } from "lucide-react-native";
|
|
4849
5075
|
|
|
4850
5076
|
// src/components/merge-requests/ReviewMergeRequestActionButton.tsx
|
|
4851
|
-
import * as
|
|
5077
|
+
import * as React29 from "react";
|
|
4852
5078
|
import { Pressable as Pressable10, View as View29 } from "react-native";
|
|
4853
5079
|
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
4854
5080
|
function ReviewMergeRequestActionButton({
|
|
@@ -4859,7 +5085,7 @@ function ReviewMergeRequestActionButton({
|
|
|
4859
5085
|
children,
|
|
4860
5086
|
iconOnly
|
|
4861
5087
|
}) {
|
|
4862
|
-
const [pressed, setPressed] =
|
|
5088
|
+
const [pressed, setPressed] = React29.useState(false);
|
|
4863
5089
|
const height = iconOnly ? 36 : 40;
|
|
4864
5090
|
const width = iconOnly ? 36 : void 0;
|
|
4865
5091
|
const paddingHorizontal = iconOnly ? 0 : 16;
|
|
@@ -4921,10 +5147,10 @@ function ReviewMergeRequestCard({
|
|
|
4921
5147
|
onTest
|
|
4922
5148
|
}) {
|
|
4923
5149
|
const theme = useTheme();
|
|
4924
|
-
const status =
|
|
5150
|
+
const status = React30.useMemo(() => getMergeRequestStatusDisplay(mr.status), [mr.status]);
|
|
4925
5151
|
const canAct = mr.status === "open";
|
|
4926
|
-
const rotate =
|
|
4927
|
-
|
|
5152
|
+
const rotate = React30.useRef(new Animated8.Value(isExpanded ? 1 : 0)).current;
|
|
5153
|
+
React30.useEffect(() => {
|
|
4928
5154
|
Animated8.timing(rotate, { toValue: isExpanded ? 1 : 0, duration: 200, useNativeDriver: true }).start();
|
|
4929
5155
|
}, [isExpanded, rotate]);
|
|
4930
5156
|
const position = total > 1 ? `${index + 1}/${total}` : "Merge request";
|
|
@@ -5056,11 +5282,11 @@ function ReviewMergeRequestCarousel({
|
|
|
5056
5282
|
}) {
|
|
5057
5283
|
const theme = useTheme();
|
|
5058
5284
|
const { width } = useWindowDimensions3();
|
|
5059
|
-
const [expanded, setExpanded] =
|
|
5060
|
-
const carouselScrollX =
|
|
5285
|
+
const [expanded, setExpanded] = React31.useState({});
|
|
5286
|
+
const carouselScrollX = React31.useRef(new Animated9.Value(0)).current;
|
|
5061
5287
|
const peekAmount = 24;
|
|
5062
5288
|
const gap = 16;
|
|
5063
|
-
const cardWidth =
|
|
5289
|
+
const cardWidth = React31.useMemo(() => Math.max(1, width - theme.spacing.lg * 2 - peekAmount), [peekAmount, theme.spacing.lg, width]);
|
|
5064
5290
|
const snapInterval = cardWidth + gap;
|
|
5065
5291
|
const dotColor = theme.scheme === "dark" ? "#FFFFFF" : "#000000";
|
|
5066
5292
|
if (mergeRequests.length === 0) return null;
|
|
@@ -5159,7 +5385,7 @@ function PreviewCollaborateSection({
|
|
|
5159
5385
|
onTestMr
|
|
5160
5386
|
}) {
|
|
5161
5387
|
const theme = useTheme();
|
|
5162
|
-
const [submittingMr, setSubmittingMr] =
|
|
5388
|
+
const [submittingMr, setSubmittingMr] = React32.useState(false);
|
|
5163
5389
|
const hasSection = canSubmitMergeRequest || incomingMergeRequests.length > 0 || outgoingMergeRequests.length > 0;
|
|
5164
5390
|
if (!hasSection) return null;
|
|
5165
5391
|
const showActionsSubtitle = canSubmitMergeRequest && onSubmitMergeRequest || onTestMr && incomingMergeRequests.length > 0;
|
|
@@ -5267,7 +5493,7 @@ function PreviewCollaborateSection({
|
|
|
5267
5493
|
}
|
|
5268
5494
|
|
|
5269
5495
|
// src/studio/ui/preview-panel/usePreviewPanelData.ts
|
|
5270
|
-
import * as
|
|
5496
|
+
import * as React34 from "react";
|
|
5271
5497
|
|
|
5272
5498
|
// src/data/apps/images/remote.ts
|
|
5273
5499
|
var AppImagesRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -5318,7 +5544,7 @@ var AppImagesRepositoryImpl = class extends BaseRepository {
|
|
|
5318
5544
|
var appImagesRepository = new AppImagesRepositoryImpl(appImagesRemoteDataSource);
|
|
5319
5545
|
|
|
5320
5546
|
// src/studio/hooks/useAppStats.ts
|
|
5321
|
-
import * as
|
|
5547
|
+
import * as React33 from "react";
|
|
5322
5548
|
import * as Haptics2 from "expo-haptics";
|
|
5323
5549
|
|
|
5324
5550
|
// src/data/likes/remote.ts
|
|
@@ -5387,34 +5613,34 @@ function useAppStats({
|
|
|
5387
5613
|
initialIsLiked = false,
|
|
5388
5614
|
onOpenComments
|
|
5389
5615
|
}) {
|
|
5390
|
-
const [likeCount, setLikeCount] =
|
|
5391
|
-
const [commentCount, setCommentCount] =
|
|
5392
|
-
const [forkCount, setForkCount] =
|
|
5393
|
-
const [isLiked, setIsLiked] =
|
|
5394
|
-
const didMutateRef =
|
|
5395
|
-
const lastAppIdRef =
|
|
5396
|
-
|
|
5616
|
+
const [likeCount, setLikeCount] = React33.useState(initialLikes);
|
|
5617
|
+
const [commentCount, setCommentCount] = React33.useState(initialComments);
|
|
5618
|
+
const [forkCount, setForkCount] = React33.useState(initialForks);
|
|
5619
|
+
const [isLiked, setIsLiked] = React33.useState(initialIsLiked);
|
|
5620
|
+
const didMutateRef = React33.useRef(false);
|
|
5621
|
+
const lastAppIdRef = React33.useRef("");
|
|
5622
|
+
React33.useEffect(() => {
|
|
5397
5623
|
if (lastAppIdRef.current === appId) return;
|
|
5398
5624
|
lastAppIdRef.current = appId;
|
|
5399
5625
|
didMutateRef.current = false;
|
|
5400
5626
|
}, [appId]);
|
|
5401
|
-
|
|
5627
|
+
React33.useEffect(() => {
|
|
5402
5628
|
if (didMutateRef.current) return;
|
|
5403
5629
|
setLikeCount(initialLikes);
|
|
5404
5630
|
}, [appId, initialLikes]);
|
|
5405
|
-
|
|
5631
|
+
React33.useEffect(() => {
|
|
5406
5632
|
if (didMutateRef.current) return;
|
|
5407
5633
|
setCommentCount(initialComments);
|
|
5408
5634
|
}, [appId, initialComments]);
|
|
5409
|
-
|
|
5635
|
+
React33.useEffect(() => {
|
|
5410
5636
|
if (didMutateRef.current) return;
|
|
5411
5637
|
setForkCount(initialForks);
|
|
5412
5638
|
}, [appId, initialForks]);
|
|
5413
|
-
|
|
5639
|
+
React33.useEffect(() => {
|
|
5414
5640
|
if (didMutateRef.current) return;
|
|
5415
5641
|
setIsLiked(initialIsLiked);
|
|
5416
5642
|
}, [appId, initialIsLiked]);
|
|
5417
|
-
const handleLike =
|
|
5643
|
+
const handleLike = React33.useCallback(async () => {
|
|
5418
5644
|
var _a, _b;
|
|
5419
5645
|
if (!appId) return;
|
|
5420
5646
|
didMutateRef.current = true;
|
|
@@ -5438,7 +5664,7 @@ function useAppStats({
|
|
|
5438
5664
|
setLikeCount((prev) => Math.max(0, prev + (newIsLiked ? -1 : 1)));
|
|
5439
5665
|
}
|
|
5440
5666
|
}, [appId, isLiked, likeCount]);
|
|
5441
|
-
const handleOpenComments =
|
|
5667
|
+
const handleOpenComments = React33.useCallback(() => {
|
|
5442
5668
|
if (!appId) return;
|
|
5443
5669
|
try {
|
|
5444
5670
|
void Haptics2.impactAsync(Haptics2.ImpactFeedbackStyle.Light);
|
|
@@ -5453,11 +5679,11 @@ function useAppStats({
|
|
|
5453
5679
|
var LIKE_DEBUG_PREFIX = "[COMERGE_LIKE_DEBUG]";
|
|
5454
5680
|
function usePreviewPanelData(params) {
|
|
5455
5681
|
const { app, isOwner, outgoingMergeRequests, onOpenComments, commentCountOverride } = params;
|
|
5456
|
-
const [imageUrl, setImageUrl] =
|
|
5457
|
-
const [imageLoaded, setImageLoaded] =
|
|
5458
|
-
const [insights, setInsights] =
|
|
5459
|
-
const [creator, setCreator] =
|
|
5460
|
-
|
|
5682
|
+
const [imageUrl, setImageUrl] = React34.useState(null);
|
|
5683
|
+
const [imageLoaded, setImageLoaded] = React34.useState(false);
|
|
5684
|
+
const [insights, setInsights] = React34.useState({ likes: 0, comments: 0, forks: 0, downloads: 0 });
|
|
5685
|
+
const [creator, setCreator] = React34.useState(null);
|
|
5686
|
+
React34.useEffect(() => {
|
|
5461
5687
|
if (!(app == null ? void 0 : app.id)) return;
|
|
5462
5688
|
let cancelled = false;
|
|
5463
5689
|
(async () => {
|
|
@@ -5472,7 +5698,7 @@ function usePreviewPanelData(params) {
|
|
|
5472
5698
|
cancelled = true;
|
|
5473
5699
|
};
|
|
5474
5700
|
}, [app == null ? void 0 : app.id]);
|
|
5475
|
-
|
|
5701
|
+
React34.useEffect(() => {
|
|
5476
5702
|
if (!(app == null ? void 0 : app.createdBy)) return;
|
|
5477
5703
|
let cancelled = false;
|
|
5478
5704
|
(async () => {
|
|
@@ -5488,10 +5714,10 @@ function usePreviewPanelData(params) {
|
|
|
5488
5714
|
cancelled = true;
|
|
5489
5715
|
};
|
|
5490
5716
|
}, [app == null ? void 0 : app.createdBy]);
|
|
5491
|
-
|
|
5717
|
+
React34.useEffect(() => {
|
|
5492
5718
|
setImageLoaded(false);
|
|
5493
5719
|
}, [app == null ? void 0 : app.id]);
|
|
5494
|
-
|
|
5720
|
+
React34.useEffect(() => {
|
|
5495
5721
|
if (!(app == null ? void 0 : app.id)) return;
|
|
5496
5722
|
let cancelled = false;
|
|
5497
5723
|
(async () => {
|
|
@@ -5516,7 +5742,7 @@ function usePreviewPanelData(params) {
|
|
|
5516
5742
|
cancelled = true;
|
|
5517
5743
|
};
|
|
5518
5744
|
}, [app == null ? void 0 : app.id]);
|
|
5519
|
-
|
|
5745
|
+
React34.useEffect(() => {
|
|
5520
5746
|
if (!(app == null ? void 0 : app.id)) return;
|
|
5521
5747
|
log.debug(
|
|
5522
5748
|
`${LIKE_DEBUG_PREFIX} usePreviewPanelData.appChanged appId=${app.id} app.isLiked=${String(app.isLiked)}`
|
|
@@ -5530,7 +5756,7 @@ function usePreviewPanelData(params) {
|
|
|
5530
5756
|
initialIsLiked: Boolean(app == null ? void 0 : app.isLiked),
|
|
5531
5757
|
onOpenComments
|
|
5532
5758
|
});
|
|
5533
|
-
const canSubmitMergeRequest =
|
|
5759
|
+
const canSubmitMergeRequest = React34.useMemo(() => {
|
|
5534
5760
|
if (!isOwner) return false;
|
|
5535
5761
|
if (!app) return false;
|
|
5536
5762
|
if (!app.forkedFromAppId) return false;
|
|
@@ -5643,16 +5869,16 @@ function PreviewPanel({
|
|
|
5643
5869
|
}
|
|
5644
5870
|
|
|
5645
5871
|
// src/studio/ui/ChatPanel.tsx
|
|
5646
|
-
import * as
|
|
5872
|
+
import * as React39 from "react";
|
|
5647
5873
|
import { ActivityIndicator as ActivityIndicator8, View as View41 } from "react-native";
|
|
5648
5874
|
|
|
5649
5875
|
// src/components/chat/ChatPage.tsx
|
|
5650
|
-
import * as
|
|
5876
|
+
import * as React37 from "react";
|
|
5651
5877
|
import { Keyboard as Keyboard4, Platform as Platform9, View as View37 } from "react-native";
|
|
5652
5878
|
import { useSafeAreaInsets as useSafeAreaInsets4 } from "react-native-safe-area-context";
|
|
5653
5879
|
|
|
5654
5880
|
// src/components/chat/ChatMessageList.tsx
|
|
5655
|
-
import * as
|
|
5881
|
+
import * as React36 from "react";
|
|
5656
5882
|
import { View as View36 } from "react-native";
|
|
5657
5883
|
import { BottomSheetFlatList } from "@gorhom/bottom-sheet";
|
|
5658
5884
|
|
|
@@ -5698,17 +5924,17 @@ function ChatMessageBubble({ message, renderContent, style }) {
|
|
|
5698
5924
|
}
|
|
5699
5925
|
|
|
5700
5926
|
// src/components/chat/TypingIndicator.tsx
|
|
5701
|
-
import * as
|
|
5927
|
+
import * as React35 from "react";
|
|
5702
5928
|
import { Animated as Animated10, View as View35 } from "react-native";
|
|
5703
5929
|
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
5704
5930
|
function TypingIndicator({ style }) {
|
|
5705
5931
|
const theme = useTheme();
|
|
5706
5932
|
const dotColor = theme.colors.textSubtle;
|
|
5707
|
-
const anims =
|
|
5933
|
+
const anims = React35.useMemo(
|
|
5708
5934
|
() => [new Animated10.Value(0.3), new Animated10.Value(0.3), new Animated10.Value(0.3)],
|
|
5709
5935
|
[]
|
|
5710
5936
|
);
|
|
5711
|
-
|
|
5937
|
+
React35.useEffect(() => {
|
|
5712
5938
|
const loops = [];
|
|
5713
5939
|
anims.forEach((a, idx) => {
|
|
5714
5940
|
const seq = Animated10.sequence([
|
|
@@ -5742,7 +5968,7 @@ function TypingIndicator({ style }) {
|
|
|
5742
5968
|
|
|
5743
5969
|
// src/components/chat/ChatMessageList.tsx
|
|
5744
5970
|
import { jsx as jsx48, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
5745
|
-
var ChatMessageList =
|
|
5971
|
+
var ChatMessageList = React36.forwardRef(
|
|
5746
5972
|
({
|
|
5747
5973
|
messages,
|
|
5748
5974
|
showTypingIndicator = false,
|
|
@@ -5753,20 +5979,20 @@ var ChatMessageList = React35.forwardRef(
|
|
|
5753
5979
|
nearBottomThreshold = 200
|
|
5754
5980
|
}, ref) => {
|
|
5755
5981
|
const theme = useTheme();
|
|
5756
|
-
const listRef =
|
|
5757
|
-
const nearBottomRef =
|
|
5758
|
-
const initialScrollDoneRef =
|
|
5759
|
-
const lastMessageIdRef =
|
|
5760
|
-
const data =
|
|
5982
|
+
const listRef = React36.useRef(null);
|
|
5983
|
+
const nearBottomRef = React36.useRef(true);
|
|
5984
|
+
const initialScrollDoneRef = React36.useRef(false);
|
|
5985
|
+
const lastMessageIdRef = React36.useRef(null);
|
|
5986
|
+
const data = React36.useMemo(() => {
|
|
5761
5987
|
return [...messages].reverse();
|
|
5762
5988
|
}, [messages]);
|
|
5763
|
-
const scrollToBottom =
|
|
5989
|
+
const scrollToBottom = React36.useCallback((options) => {
|
|
5764
5990
|
var _a;
|
|
5765
5991
|
const animated = (options == null ? void 0 : options.animated) ?? true;
|
|
5766
5992
|
(_a = listRef.current) == null ? void 0 : _a.scrollToOffset({ offset: 0, animated });
|
|
5767
5993
|
}, []);
|
|
5768
|
-
|
|
5769
|
-
const handleScroll =
|
|
5994
|
+
React36.useImperativeHandle(ref, () => ({ scrollToBottom }), [scrollToBottom]);
|
|
5995
|
+
const handleScroll = React36.useCallback(
|
|
5770
5996
|
(e) => {
|
|
5771
5997
|
const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent;
|
|
5772
5998
|
const distanceFromBottom = Math.max(contentOffset.y - Math.max(bottomInset, 0), 0);
|
|
@@ -5778,7 +6004,7 @@ var ChatMessageList = React35.forwardRef(
|
|
|
5778
6004
|
},
|
|
5779
6005
|
[bottomInset, nearBottomThreshold, onNearBottomChange]
|
|
5780
6006
|
);
|
|
5781
|
-
|
|
6007
|
+
React36.useEffect(() => {
|
|
5782
6008
|
if (!initialScrollDoneRef.current) return;
|
|
5783
6009
|
const lastId = messages.length > 0 ? messages[messages.length - 1].id : null;
|
|
5784
6010
|
const prevLastId = lastMessageIdRef.current;
|
|
@@ -5788,7 +6014,7 @@ var ChatMessageList = React35.forwardRef(
|
|
|
5788
6014
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
5789
6015
|
return () => cancelAnimationFrame(id);
|
|
5790
6016
|
}, [messages, scrollToBottom]);
|
|
5791
|
-
|
|
6017
|
+
React36.useEffect(() => {
|
|
5792
6018
|
if (showTypingIndicator && nearBottomRef.current) {
|
|
5793
6019
|
const id = requestAnimationFrame(() => scrollToBottom({ animated: true }));
|
|
5794
6020
|
return () => cancelAnimationFrame(id);
|
|
@@ -5850,9 +6076,9 @@ function ChatPage({
|
|
|
5850
6076
|
}) {
|
|
5851
6077
|
const theme = useTheme();
|
|
5852
6078
|
const insets = useSafeAreaInsets4();
|
|
5853
|
-
const [composerHeight, setComposerHeight] =
|
|
5854
|
-
const [keyboardVisible, setKeyboardVisible] =
|
|
5855
|
-
|
|
6079
|
+
const [composerHeight, setComposerHeight] = React37.useState(0);
|
|
6080
|
+
const [keyboardVisible, setKeyboardVisible] = React37.useState(false);
|
|
6081
|
+
React37.useEffect(() => {
|
|
5856
6082
|
if (Platform9.OS !== "ios") return;
|
|
5857
6083
|
const show = Keyboard4.addListener("keyboardWillShow", () => setKeyboardVisible(true));
|
|
5858
6084
|
const hide = Keyboard4.addListener("keyboardWillHide", () => setKeyboardVisible(false));
|
|
@@ -5864,12 +6090,12 @@ function ChatPage({
|
|
|
5864
6090
|
const footerBottomPadding = Platform9.OS === "ios" ? keyboardVisible ? 0 : insets.bottom : insets.bottom + 10;
|
|
5865
6091
|
const overlayBottom = composerHeight + footerBottomPadding + theme.spacing.lg;
|
|
5866
6092
|
const bottomInset = composerHeight + footerBottomPadding + theme.spacing.xl;
|
|
5867
|
-
const resolvedOverlay =
|
|
6093
|
+
const resolvedOverlay = React37.useMemo(() => {
|
|
5868
6094
|
var _a;
|
|
5869
6095
|
if (!overlay) return null;
|
|
5870
|
-
if (!
|
|
6096
|
+
if (!React37.isValidElement(overlay)) return overlay;
|
|
5871
6097
|
const prevStyle = (_a = overlay.props) == null ? void 0 : _a.style;
|
|
5872
|
-
return
|
|
6098
|
+
return React37.cloneElement(overlay, {
|
|
5873
6099
|
style: [prevStyle, { bottom: overlayBottom }]
|
|
5874
6100
|
});
|
|
5875
6101
|
}, [overlay, overlayBottom]);
|
|
@@ -5924,15 +6150,15 @@ function ChatPage({
|
|
|
5924
6150
|
}
|
|
5925
6151
|
|
|
5926
6152
|
// src/components/chat/ScrollToBottomButton.tsx
|
|
5927
|
-
import * as
|
|
6153
|
+
import * as React38 from "react";
|
|
5928
6154
|
import { Pressable as Pressable12, View as View38 } from "react-native";
|
|
5929
6155
|
import Animated11, { Easing as Easing2, useAnimatedStyle as useAnimatedStyle2, useSharedValue as useSharedValue2, withTiming as withTiming2 } from "react-native-reanimated";
|
|
5930
6156
|
import { jsx as jsx50 } from "react/jsx-runtime";
|
|
5931
6157
|
function ScrollToBottomButton({ visible, onPress, children, style }) {
|
|
5932
6158
|
const theme = useTheme();
|
|
5933
6159
|
const progress = useSharedValue2(visible ? 1 : 0);
|
|
5934
|
-
const [pressed, setPressed] =
|
|
5935
|
-
|
|
6160
|
+
const [pressed, setPressed] = React38.useState(false);
|
|
6161
|
+
React38.useEffect(() => {
|
|
5936
6162
|
progress.value = withTiming2(visible ? 1 : 0, { duration: 200, easing: Easing2.out(Easing2.ease) });
|
|
5937
6163
|
}, [progress, visible]);
|
|
5938
6164
|
const animStyle = useAnimatedStyle2(() => ({
|
|
@@ -6087,9 +6313,9 @@ function ChatPanel({
|
|
|
6087
6313
|
onStartDraw,
|
|
6088
6314
|
onSend
|
|
6089
6315
|
}) {
|
|
6090
|
-
const listRef =
|
|
6091
|
-
const [nearBottom, setNearBottom] =
|
|
6092
|
-
const handleSend =
|
|
6316
|
+
const listRef = React39.useRef(null);
|
|
6317
|
+
const [nearBottom, setNearBottom] = React39.useState(true);
|
|
6318
|
+
const handleSend = React39.useCallback(
|
|
6093
6319
|
async (text, composerAttachments) => {
|
|
6094
6320
|
const all = composerAttachments ?? attachments;
|
|
6095
6321
|
await onSend(text, all.length > 0 ? all : void 0);
|
|
@@ -6103,7 +6329,7 @@ function ChatPanel({
|
|
|
6103
6329
|
},
|
|
6104
6330
|
[attachments, nearBottom, onClearAttachments, onSend]
|
|
6105
6331
|
);
|
|
6106
|
-
const handleScrollToBottom =
|
|
6332
|
+
const handleScrollToBottom = React39.useCallback(() => {
|
|
6107
6333
|
var _a;
|
|
6108
6334
|
(_a = listRef.current) == null ? void 0 : _a.scrollToBottom({ animated: true });
|
|
6109
6335
|
}, []);
|
|
@@ -6177,7 +6403,7 @@ function ChatPanel({
|
|
|
6177
6403
|
}
|
|
6178
6404
|
|
|
6179
6405
|
// src/components/dialogs/ConfirmMergeRequestDialog.tsx
|
|
6180
|
-
import * as
|
|
6406
|
+
import * as React40 from "react";
|
|
6181
6407
|
import { Pressable as Pressable14, View as View43 } from "react-native";
|
|
6182
6408
|
|
|
6183
6409
|
// src/components/primitives/Modal.tsx
|
|
@@ -6229,14 +6455,14 @@ function ConfirmMergeRequestDialog({
|
|
|
6229
6455
|
onTestFirst
|
|
6230
6456
|
}) {
|
|
6231
6457
|
const theme = useTheme();
|
|
6232
|
-
const close =
|
|
6458
|
+
const close = React40.useCallback(() => onOpenChange(false), [onOpenChange]);
|
|
6233
6459
|
const canConfirm = Boolean(mergeRequest) && !approveDisabled;
|
|
6234
|
-
const handleConfirm =
|
|
6460
|
+
const handleConfirm = React40.useCallback(() => {
|
|
6235
6461
|
if (!mergeRequest) return;
|
|
6236
6462
|
onOpenChange(false);
|
|
6237
6463
|
void onConfirm();
|
|
6238
6464
|
}, [mergeRequest, onConfirm, onOpenChange]);
|
|
6239
|
-
const handleTestFirst =
|
|
6465
|
+
const handleTestFirst = React40.useCallback(() => {
|
|
6240
6466
|
if (!mergeRequest) return;
|
|
6241
6467
|
onOpenChange(false);
|
|
6242
6468
|
void onTestFirst(mergeRequest);
|
|
@@ -6385,7 +6611,7 @@ function ConfirmMergeFlow({
|
|
|
6385
6611
|
}
|
|
6386
6612
|
|
|
6387
6613
|
// src/studio/hooks/useOptimisticChatMessages.ts
|
|
6388
|
-
import * as
|
|
6614
|
+
import * as React41 from "react";
|
|
6389
6615
|
function makeOptimisticId() {
|
|
6390
6616
|
return `optimistic:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 10)}`;
|
|
6391
6617
|
}
|
|
@@ -6423,11 +6649,11 @@ function useOptimisticChatMessages({
|
|
|
6423
6649
|
chatMessages,
|
|
6424
6650
|
onSendChat
|
|
6425
6651
|
}) {
|
|
6426
|
-
const [optimisticChat, setOptimisticChat] =
|
|
6427
|
-
|
|
6652
|
+
const [optimisticChat, setOptimisticChat] = React41.useState([]);
|
|
6653
|
+
React41.useEffect(() => {
|
|
6428
6654
|
setOptimisticChat([]);
|
|
6429
6655
|
}, [threadId]);
|
|
6430
|
-
const messages =
|
|
6656
|
+
const messages = React41.useMemo(() => {
|
|
6431
6657
|
if (!optimisticChat || optimisticChat.length === 0) return chatMessages;
|
|
6432
6658
|
const unresolved = optimisticChat.filter((o) => !isOptimisticResolvedByServer(chatMessages, o));
|
|
6433
6659
|
if (unresolved.length === 0) return chatMessages;
|
|
@@ -6443,7 +6669,7 @@ function useOptimisticChatMessages({
|
|
|
6443
6669
|
merged.sort((a, b) => String(a.createdAt).localeCompare(String(b.createdAt)));
|
|
6444
6670
|
return merged;
|
|
6445
6671
|
}, [chatMessages, optimisticChat]);
|
|
6446
|
-
|
|
6672
|
+
React41.useEffect(() => {
|
|
6447
6673
|
if (optimisticChat.length === 0) return;
|
|
6448
6674
|
setOptimisticChat((prev) => {
|
|
6449
6675
|
if (prev.length === 0) return prev;
|
|
@@ -6451,7 +6677,7 @@ function useOptimisticChatMessages({
|
|
|
6451
6677
|
return next.length === prev.length ? prev : next;
|
|
6452
6678
|
});
|
|
6453
6679
|
}, [chatMessages, optimisticChat.length]);
|
|
6454
|
-
const onSend =
|
|
6680
|
+
const onSend = React41.useCallback(
|
|
6455
6681
|
async (text, attachments) => {
|
|
6456
6682
|
if (shouldForkOnEdit) {
|
|
6457
6683
|
await onSendChat(text, attachments);
|
|
@@ -6503,18 +6729,18 @@ function StudioOverlay({
|
|
|
6503
6729
|
chatShowTypingIndicator,
|
|
6504
6730
|
onSendChat,
|
|
6505
6731
|
onNavigateHome,
|
|
6506
|
-
|
|
6732
|
+
showBubble,
|
|
6507
6733
|
studioControlOptions
|
|
6508
6734
|
}) {
|
|
6509
6735
|
const theme = useTheme();
|
|
6510
6736
|
const { width } = useWindowDimensions4();
|
|
6511
|
-
const [sheetOpen, setSheetOpen] =
|
|
6512
|
-
const sheetOpenRef =
|
|
6513
|
-
const [activePage, setActivePage] =
|
|
6514
|
-
const [drawing, setDrawing] =
|
|
6515
|
-
const [chatAttachments, setChatAttachments] =
|
|
6516
|
-
const [commentsAppId, setCommentsAppId] =
|
|
6517
|
-
const [commentsCount, setCommentsCount] =
|
|
6737
|
+
const [sheetOpen, setSheetOpen] = React42.useState(false);
|
|
6738
|
+
const sheetOpenRef = React42.useRef(sheetOpen);
|
|
6739
|
+
const [activePage, setActivePage] = React42.useState("preview");
|
|
6740
|
+
const [drawing, setDrawing] = React42.useState(false);
|
|
6741
|
+
const [chatAttachments, setChatAttachments] = React42.useState([]);
|
|
6742
|
+
const [commentsAppId, setCommentsAppId] = React42.useState(null);
|
|
6743
|
+
const [commentsCount, setCommentsCount] = React42.useState(null);
|
|
6518
6744
|
const threadId = (app == null ? void 0 : app.threadId) ?? null;
|
|
6519
6745
|
const optimistic = useOptimisticChatMessages({
|
|
6520
6746
|
threadId,
|
|
@@ -6522,24 +6748,24 @@ function StudioOverlay({
|
|
|
6522
6748
|
chatMessages,
|
|
6523
6749
|
onSendChat
|
|
6524
6750
|
});
|
|
6525
|
-
const [confirmMrId, setConfirmMrId] =
|
|
6526
|
-
const confirmMr =
|
|
6751
|
+
const [confirmMrId, setConfirmMrId] = React42.useState(null);
|
|
6752
|
+
const confirmMr = React42.useMemo(
|
|
6527
6753
|
() => confirmMrId ? incomingMergeRequests.find((m) => m.id === confirmMrId) ?? null : null,
|
|
6528
6754
|
[confirmMrId, incomingMergeRequests]
|
|
6529
6755
|
);
|
|
6530
|
-
const handleSheetOpenChange =
|
|
6756
|
+
const handleSheetOpenChange = React42.useCallback((open) => {
|
|
6531
6757
|
setSheetOpen(open);
|
|
6532
6758
|
if (!open) Keyboard5.dismiss();
|
|
6533
6759
|
}, []);
|
|
6534
|
-
const closeSheet =
|
|
6760
|
+
const closeSheet = React42.useCallback(() => {
|
|
6535
6761
|
handleSheetOpenChange(false);
|
|
6536
6762
|
}, [handleSheetOpenChange]);
|
|
6537
|
-
const openSheet =
|
|
6538
|
-
const goToChat =
|
|
6763
|
+
const openSheet = React42.useCallback(() => setSheetOpen(true), []);
|
|
6764
|
+
const goToChat = React42.useCallback(() => {
|
|
6539
6765
|
setActivePage("chat");
|
|
6540
6766
|
openSheet();
|
|
6541
6767
|
}, [openSheet]);
|
|
6542
|
-
const backToPreview =
|
|
6768
|
+
const backToPreview = React42.useCallback(() => {
|
|
6543
6769
|
if (Platform10.OS !== "ios") {
|
|
6544
6770
|
Keyboard5.dismiss();
|
|
6545
6771
|
setActivePage("preview");
|
|
@@ -6557,11 +6783,11 @@ function StudioOverlay({
|
|
|
6557
6783
|
const t = setTimeout(finalize, 350);
|
|
6558
6784
|
Keyboard5.dismiss();
|
|
6559
6785
|
}, []);
|
|
6560
|
-
const startDraw =
|
|
6786
|
+
const startDraw = React42.useCallback(() => {
|
|
6561
6787
|
setDrawing(true);
|
|
6562
6788
|
closeSheet();
|
|
6563
6789
|
}, [closeSheet]);
|
|
6564
|
-
const handleDrawCapture =
|
|
6790
|
+
const handleDrawCapture = React42.useCallback(
|
|
6565
6791
|
(dataUrl) => {
|
|
6566
6792
|
setChatAttachments((prev) => [...prev, dataUrl]);
|
|
6567
6793
|
setDrawing(false);
|
|
@@ -6570,7 +6796,7 @@ function StudioOverlay({
|
|
|
6570
6796
|
},
|
|
6571
6797
|
[openSheet]
|
|
6572
6798
|
);
|
|
6573
|
-
const toggleSheet =
|
|
6799
|
+
const toggleSheet = React42.useCallback(async () => {
|
|
6574
6800
|
if (!sheetOpen) {
|
|
6575
6801
|
const shouldExitTest = Boolean(testingMrId) || isTesting;
|
|
6576
6802
|
if (shouldExitTest) {
|
|
@@ -6582,7 +6808,7 @@ function StudioOverlay({
|
|
|
6582
6808
|
closeSheet();
|
|
6583
6809
|
}
|
|
6584
6810
|
}, [closeSheet, isTesting, onRestoreBase, sheetOpen, testingMrId]);
|
|
6585
|
-
const handleTestMr =
|
|
6811
|
+
const handleTestMr = React42.useCallback(
|
|
6586
6812
|
async (mr) => {
|
|
6587
6813
|
if (!onTestMr) return;
|
|
6588
6814
|
await onTestMr(mr);
|
|
@@ -6590,10 +6816,10 @@ function StudioOverlay({
|
|
|
6590
6816
|
},
|
|
6591
6817
|
[closeSheet, onTestMr]
|
|
6592
6818
|
);
|
|
6593
|
-
|
|
6819
|
+
React42.useEffect(() => {
|
|
6594
6820
|
sheetOpenRef.current = sheetOpen;
|
|
6595
6821
|
}, [sheetOpen]);
|
|
6596
|
-
|
|
6822
|
+
React42.useEffect(() => {
|
|
6597
6823
|
const poller = startStudioControlPolling((action) => {
|
|
6598
6824
|
if (action === "show" && !sheetOpenRef.current) openSheet();
|
|
6599
6825
|
if (action === "hide" && sheetOpenRef.current) closeSheet();
|
|
@@ -6601,7 +6827,7 @@ function StudioOverlay({
|
|
|
6601
6827
|
}, studioControlOptions);
|
|
6602
6828
|
return () => poller.stop();
|
|
6603
6829
|
}, [closeSheet, openSheet, studioControlOptions, toggleSheet]);
|
|
6604
|
-
|
|
6830
|
+
React42.useEffect(() => {
|
|
6605
6831
|
void publishComergeStudioUIState(sheetOpen, studioControlOptions);
|
|
6606
6832
|
}, [sheetOpen, studioControlOptions]);
|
|
6607
6833
|
return /* @__PURE__ */ jsxs34(Fragment6, { children: [
|
|
@@ -6660,8 +6886,8 @@ function StudioOverlay({
|
|
|
6660
6886
|
)
|
|
6661
6887
|
}
|
|
6662
6888
|
) }),
|
|
6663
|
-
|
|
6664
|
-
|
|
6889
|
+
showBubble && /* @__PURE__ */ jsx57(
|
|
6890
|
+
Bubble,
|
|
6665
6891
|
{
|
|
6666
6892
|
visible: !sheetOpen && !drawing,
|
|
6667
6893
|
ariaLabel: sheetOpen ? "Hide studio" : "Show studio",
|
|
@@ -6709,24 +6935,25 @@ function StudioOverlay({
|
|
|
6709
6935
|
import { jsx as jsx58, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
6710
6936
|
function ComergeStudio({
|
|
6711
6937
|
appId,
|
|
6712
|
-
|
|
6938
|
+
clientKey: clientKey2,
|
|
6713
6939
|
appKey = "MicroMain",
|
|
6714
6940
|
onNavigateHome,
|
|
6715
6941
|
style,
|
|
6716
|
-
|
|
6717
|
-
studioControlOptions
|
|
6942
|
+
showBubble = true,
|
|
6943
|
+
studioControlOptions,
|
|
6944
|
+
embeddedBaseBundles
|
|
6718
6945
|
}) {
|
|
6719
|
-
const [activeAppId, setActiveAppId] =
|
|
6720
|
-
const [runtimeAppId, setRuntimeAppId] =
|
|
6721
|
-
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] =
|
|
6722
|
-
const platform =
|
|
6723
|
-
|
|
6946
|
+
const [activeAppId, setActiveAppId] = React43.useState(appId);
|
|
6947
|
+
const [runtimeAppId, setRuntimeAppId] = React43.useState(appId);
|
|
6948
|
+
const [pendingRuntimeTargetAppId, setPendingRuntimeTargetAppId] = React43.useState(null);
|
|
6949
|
+
const platform = React43.useMemo(() => RNPlatform.OS === "ios" ? "ios" : "android", []);
|
|
6950
|
+
React43.useEffect(() => {
|
|
6724
6951
|
setActiveAppId(appId);
|
|
6725
6952
|
setRuntimeAppId(appId);
|
|
6726
6953
|
setPendingRuntimeTargetAppId(null);
|
|
6727
6954
|
}, [appId]);
|
|
6728
|
-
const captureTargetRef =
|
|
6729
|
-
return /* @__PURE__ */ jsx58(StudioBootstrap, {
|
|
6955
|
+
const captureTargetRef = React43.useRef(null);
|
|
6956
|
+
return /* @__PURE__ */ jsx58(StudioBootstrap, { clientKey: clientKey2, fallback: /* @__PURE__ */ jsx58(View45, { style: { flex: 1 } }), children: ({ userId }) => /* @__PURE__ */ jsx58(BottomSheetModalProvider, { children: /* @__PURE__ */ jsx58(LiquidGlassResetProvider, { resetTriggers: [appId, activeAppId, runtimeAppId], children: /* @__PURE__ */ jsx58(
|
|
6730
6957
|
ComergeStudioInner,
|
|
6731
6958
|
{
|
|
6732
6959
|
userId,
|
|
@@ -6741,8 +6968,9 @@ function ComergeStudio({
|
|
|
6741
6968
|
onNavigateHome,
|
|
6742
6969
|
captureTargetRef,
|
|
6743
6970
|
style,
|
|
6744
|
-
|
|
6745
|
-
studioControlOptions
|
|
6971
|
+
showBubble,
|
|
6972
|
+
studioControlOptions,
|
|
6973
|
+
embeddedBaseBundles
|
|
6746
6974
|
}
|
|
6747
6975
|
) }) }) });
|
|
6748
6976
|
}
|
|
@@ -6759,17 +6987,18 @@ function ComergeStudioInner({
|
|
|
6759
6987
|
onNavigateHome,
|
|
6760
6988
|
captureTargetRef,
|
|
6761
6989
|
style,
|
|
6762
|
-
|
|
6763
|
-
studioControlOptions
|
|
6990
|
+
showBubble,
|
|
6991
|
+
studioControlOptions,
|
|
6992
|
+
embeddedBaseBundles
|
|
6764
6993
|
}) {
|
|
6765
6994
|
const { app, loading: appLoading } = useApp(activeAppId);
|
|
6766
6995
|
const { app: runtimeAppFromHook } = useApp(runtimeAppId, { enabled: runtimeAppId !== activeAppId });
|
|
6767
6996
|
const runtimeApp = runtimeAppId === activeAppId ? app : runtimeAppFromHook;
|
|
6768
|
-
const sawEditingOnPendingTargetRef =
|
|
6769
|
-
|
|
6997
|
+
const sawEditingOnPendingTargetRef = React43.useRef(false);
|
|
6998
|
+
React43.useEffect(() => {
|
|
6770
6999
|
sawEditingOnPendingTargetRef.current = false;
|
|
6771
7000
|
}, [pendingRuntimeTargetAppId]);
|
|
6772
|
-
|
|
7001
|
+
React43.useEffect(() => {
|
|
6773
7002
|
if (!pendingRuntimeTargetAppId) return;
|
|
6774
7003
|
if (activeAppId !== pendingRuntimeTargetAppId) return;
|
|
6775
7004
|
if ((app == null ? void 0 : app.status) === "editing") {
|
|
@@ -6784,15 +7013,16 @@ function ComergeStudioInner({
|
|
|
6784
7013
|
const bundle = useBundleManager({
|
|
6785
7014
|
base: { appId: runtimeAppId, commitId: (runtimeApp == null ? void 0 : runtimeApp.headCommitId) ?? void 0 },
|
|
6786
7015
|
platform,
|
|
6787
|
-
canRequestLatest: (runtimeApp == null ? void 0 : runtimeApp.status) === "ready"
|
|
7016
|
+
canRequestLatest: (runtimeApp == null ? void 0 : runtimeApp.status) === "ready",
|
|
7017
|
+
embeddedBaseBundles
|
|
6788
7018
|
});
|
|
6789
|
-
const sawEditingOnActiveAppRef =
|
|
6790
|
-
const [showPostEditPreparing, setShowPostEditPreparing] =
|
|
6791
|
-
|
|
7019
|
+
const sawEditingOnActiveAppRef = React43.useRef(false);
|
|
7020
|
+
const [showPostEditPreparing, setShowPostEditPreparing] = React43.useState(false);
|
|
7021
|
+
React43.useEffect(() => {
|
|
6792
7022
|
sawEditingOnActiveAppRef.current = false;
|
|
6793
7023
|
setShowPostEditPreparing(false);
|
|
6794
7024
|
}, [activeAppId]);
|
|
6795
|
-
|
|
7025
|
+
React43.useEffect(() => {
|
|
6796
7026
|
if (!(app == null ? void 0 : app.id)) return;
|
|
6797
7027
|
if (app.status === "editing") {
|
|
6798
7028
|
sawEditingOnActiveAppRef.current = true;
|
|
@@ -6804,7 +7034,7 @@ function ComergeStudioInner({
|
|
|
6804
7034
|
sawEditingOnActiveAppRef.current = false;
|
|
6805
7035
|
}
|
|
6806
7036
|
}, [app == null ? void 0 : app.id, app == null ? void 0 : app.status]);
|
|
6807
|
-
|
|
7037
|
+
React43.useEffect(() => {
|
|
6808
7038
|
if (!showPostEditPreparing) return;
|
|
6809
7039
|
const stillProcessingBaseBundle = bundle.loading && bundle.loadingMode === "base" && !bundle.isTesting;
|
|
6810
7040
|
if (!stillProcessingBaseBundle) {
|
|
@@ -6814,10 +7044,10 @@ function ComergeStudioInner({
|
|
|
6814
7044
|
const threadId = (app == null ? void 0 : app.threadId) ?? "";
|
|
6815
7045
|
const thread = useThreadMessages(threadId);
|
|
6816
7046
|
const mergeRequests = useMergeRequests({ appId: activeAppId });
|
|
6817
|
-
const hasOpenOutgoingMr =
|
|
7047
|
+
const hasOpenOutgoingMr = React43.useMemo(() => {
|
|
6818
7048
|
return mergeRequests.lists.outgoing.some((mr) => mr.status === "open");
|
|
6819
7049
|
}, [mergeRequests.lists.outgoing]);
|
|
6820
|
-
const incomingReviewMrs =
|
|
7050
|
+
const incomingReviewMrs = React43.useMemo(() => {
|
|
6821
7051
|
if (!userId) return mergeRequests.lists.incoming;
|
|
6822
7052
|
return mergeRequests.lists.incoming.filter((mr) => mr.createdBy !== userId);
|
|
6823
7053
|
}, [mergeRequests.lists.incoming, userId]);
|
|
@@ -6839,9 +7069,9 @@ function ComergeStudioInner({
|
|
|
6839
7069
|
uploadAttachments: uploader.uploadBase64Images
|
|
6840
7070
|
});
|
|
6841
7071
|
const chatSendDisabled = hasNoOutcomeAfterLastHuman(thread.raw);
|
|
6842
|
-
const [processingMrId, setProcessingMrId] =
|
|
6843
|
-
const [testingMrId, setTestingMrId] =
|
|
6844
|
-
const chatShowTypingIndicator =
|
|
7072
|
+
const [processingMrId, setProcessingMrId] = React43.useState(null);
|
|
7073
|
+
const [testingMrId, setTestingMrId] = React43.useState(null);
|
|
7074
|
+
const chatShowTypingIndicator = React43.useMemo(() => {
|
|
6845
7075
|
var _a;
|
|
6846
7076
|
if (!thread.raw || thread.raw.length === 0) return false;
|
|
6847
7077
|
const last = thread.raw[thread.raw.length - 1];
|
|
@@ -6855,7 +7085,8 @@ function ComergeStudioInner({
|
|
|
6855
7085
|
appKey,
|
|
6856
7086
|
bundlePath: bundle.bundlePath,
|
|
6857
7087
|
forcePreparing: showPostEditPreparing,
|
|
6858
|
-
renderToken: bundle.renderToken
|
|
7088
|
+
renderToken: bundle.renderToken,
|
|
7089
|
+
allowInitialPreparing: !embeddedBaseBundles
|
|
6859
7090
|
}
|
|
6860
7091
|
),
|
|
6861
7092
|
/* @__PURE__ */ jsx58(
|
|
@@ -6911,7 +7142,7 @@ function ComergeStudioInner({
|
|
|
6911
7142
|
chatShowTypingIndicator,
|
|
6912
7143
|
onSendChat: (text, attachments) => actions.sendEdit({ prompt: text, attachments }),
|
|
6913
7144
|
onNavigateHome,
|
|
6914
|
-
|
|
7145
|
+
showBubble,
|
|
6915
7146
|
studioControlOptions
|
|
6916
7147
|
}
|
|
6917
7148
|
)
|