zen-fs-config 0.5.40 → 0.5.42
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.
|
@@ -277,9 +277,9 @@ registerBackend("GitHub", async (options) => {
|
|
|
277
277
|
registerBackend("Gitee", async (options) => {
|
|
278
278
|
const _gt = await importOptionalBackend("zen-fs-gitee");
|
|
279
279
|
const Gitee = _gt?.Gitee ?? _gt?.default;
|
|
280
|
-
if (typeof Gitee !== "function") {
|
|
280
|
+
if (!Gitee || typeof Gitee !== "function" && typeof Gitee.create !== "function") {
|
|
281
281
|
throw new Error(
|
|
282
|
-
`Backend package "zen-fs-gitee" loaded, but its Gitee export is not a
|
|
282
|
+
`Backend package "zen-fs-gitee" loaded, but its Gitee export is not a usable backend (typeof=${typeof Gitee}). Load its UMD bundle so it exposes the global "ZenFSGitee".`
|
|
283
283
|
);
|
|
284
284
|
}
|
|
285
285
|
return wrapZenFSFileSystem({
|
|
@@ -306,6 +306,39 @@ registerBackend("Gitee", async (options) => {
|
|
|
306
306
|
// identity = the Git repo location
|
|
307
307
|
identityFields: ["owner", "repo", "branch", "baseUrl"]
|
|
308
308
|
});
|
|
309
|
+
async function resolveRemoteStorageHref(href) {
|
|
310
|
+
const raw = String(href ?? "").trim();
|
|
311
|
+
if (!raw) throw new Error("RemoteStorage href is required.");
|
|
312
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) return raw.replace(/\/+$/, "");
|
|
313
|
+
const match = raw.match(/^(?:acct:)?([^@/]+)@([^@/]+)$/);
|
|
314
|
+
if (!match) {
|
|
315
|
+
throw new Error(
|
|
316
|
+
`RemoteStorage href "${raw}" is neither an absolute URL nor a user address (user@domain).`
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
const user = match[1];
|
|
320
|
+
const domain = match[2];
|
|
321
|
+
const webfingerUrl = `https://${domain}/.well-known/webfinger?resource=acct:${encodeURIComponent(user)}@${encodeURIComponent(domain)}`;
|
|
322
|
+
let response;
|
|
323
|
+
try {
|
|
324
|
+
response = await globalThis.fetch(webfingerUrl, {
|
|
325
|
+
headers: { Accept: "application/jrd+json, application/json" }
|
|
326
|
+
});
|
|
327
|
+
} catch (err) {
|
|
328
|
+
throw new Error(
|
|
329
|
+
`RemoteStorage WebFinger request failed (${webfingerUrl}): ${err instanceof Error ? err.message : String(err)}`
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
if (!response.ok) {
|
|
333
|
+
throw new Error(`RemoteStorage WebFinger lookup failed (HTTP ${response.status}): ${webfingerUrl}`);
|
|
334
|
+
}
|
|
335
|
+
const jrd = await response.json();
|
|
336
|
+
const link = (jrd?.links ?? []).find(
|
|
337
|
+
(item) => item && item.rel === "http://tools.ietf.org/id/draft-dejong-remotestorage" && item.href
|
|
338
|
+
);
|
|
339
|
+
if (!link) throw new Error(`WebFinger response has no RemoteStorage link: ${webfingerUrl}`);
|
|
340
|
+
return String(link.href).replace(/\/+$/, "");
|
|
341
|
+
}
|
|
309
342
|
registerBackend("RemoteStorage", async (options) => {
|
|
310
343
|
const _rs = await importOptionalBackend("zen-fs-remotestoragejs");
|
|
311
344
|
const RemoteStorageFileSystem = _rs?.RemoteStorageFileSystem ?? _rs?.default ?? (typeof _rs === "function" ? _rs : void 0);
|
|
@@ -315,7 +348,7 @@ registerBackend("RemoteStorage", async (options) => {
|
|
|
315
348
|
);
|
|
316
349
|
}
|
|
317
350
|
return new RemoteStorageFileSystem({
|
|
318
|
-
href: options.href,
|
|
351
|
+
href: await resolveRemoteStorageHref(options.href),
|
|
319
352
|
token: options.token,
|
|
320
353
|
basePath: options.basePath || void 0,
|
|
321
354
|
preciseMtime: true,
|
|
@@ -326,7 +359,7 @@ registerBackend("RemoteStorage", async (options) => {
|
|
|
326
359
|
label: "RemoteStorage",
|
|
327
360
|
icon: "\u{1F4E1}",
|
|
328
361
|
fields: [
|
|
329
|
-
{ key: "href", label: "User Address (href)", type: "text", placeholder: "user@5apps.com", required: true },
|
|
362
|
+
{ key: "href", label: "User Address / Storage URL (href)", type: "text", placeholder: "user@5apps.com \u6216 https://storage.5apps.com/user", required: true },
|
|
330
363
|
{ key: "token", label: "Bearer Token", type: "password", placeholder: "rs-xxxxxxxx", required: true },
|
|
331
364
|
{ key: "basePath", label: "Base Path", type: "text", placeholder: "/zen-fs-config/" }
|
|
332
365
|
],
|
package/dist/index.js
CHANGED
|
@@ -215,6 +215,39 @@ async function importOptionalBackend(pkg) {
|
|
|
215
215
|
);
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
|
+
async function resolveRemoteStorageHref(href) {
|
|
219
|
+
const raw = String(href ?? "").trim();
|
|
220
|
+
if (!raw) throw new Error("RemoteStorage href is required.");
|
|
221
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) return raw.replace(/\/+$/, "");
|
|
222
|
+
const match = raw.match(/^(?:acct:)?([^@/]+)@([^@/]+)$/);
|
|
223
|
+
if (!match) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
`RemoteStorage href "${raw}" is neither an absolute URL nor a user address (user@domain).`
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
const user = match[1];
|
|
229
|
+
const domain = match[2];
|
|
230
|
+
const webfingerUrl = `https://${domain}/.well-known/webfinger?resource=acct:${encodeURIComponent(user)}@${encodeURIComponent(domain)}`;
|
|
231
|
+
let response;
|
|
232
|
+
try {
|
|
233
|
+
response = await globalThis.fetch(webfingerUrl, {
|
|
234
|
+
headers: { Accept: "application/jrd+json, application/json" }
|
|
235
|
+
});
|
|
236
|
+
} catch (err) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
`RemoteStorage WebFinger request failed (${webfingerUrl}): ${err instanceof Error ? err.message : String(err)}`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
if (!response.ok) {
|
|
242
|
+
throw new Error(`RemoteStorage WebFinger lookup failed (HTTP ${response.status}): ${webfingerUrl}`);
|
|
243
|
+
}
|
|
244
|
+
const jrd = await response.json();
|
|
245
|
+
const link = (jrd?.links ?? []).find(
|
|
246
|
+
(item) => item && item.rel === "http://tools.ietf.org/id/draft-dejong-remotestorage" && item.href
|
|
247
|
+
);
|
|
248
|
+
if (!link) throw new Error(`WebFinger response has no RemoteStorage link: ${webfingerUrl}`);
|
|
249
|
+
return String(link.href).replace(/\/+$/, "");
|
|
250
|
+
}
|
|
218
251
|
var registry, metadataRegistry, inMemoryCounter, _memCache, OPTIONAL_BACKEND_GLOBALS;
|
|
219
252
|
var init_backend_registry = __esm({
|
|
220
253
|
"src/backend-registry.ts"() {
|
|
@@ -326,9 +359,9 @@ var init_backend_registry = __esm({
|
|
|
326
359
|
registerBackend("Gitee", async (options) => {
|
|
327
360
|
const _gt = await importOptionalBackend("zen-fs-gitee");
|
|
328
361
|
const Gitee = _gt?.Gitee ?? _gt?.default;
|
|
329
|
-
if (typeof Gitee !== "function") {
|
|
362
|
+
if (!Gitee || typeof Gitee !== "function" && typeof Gitee.create !== "function") {
|
|
330
363
|
throw new Error(
|
|
331
|
-
`Backend package "zen-fs-gitee" loaded, but its Gitee export is not a
|
|
364
|
+
`Backend package "zen-fs-gitee" loaded, but its Gitee export is not a usable backend (typeof=${typeof Gitee}). Load its UMD bundle so it exposes the global "ZenFSGitee".`
|
|
332
365
|
);
|
|
333
366
|
}
|
|
334
367
|
return wrapZenFSFileSystem({
|
|
@@ -364,7 +397,7 @@ var init_backend_registry = __esm({
|
|
|
364
397
|
);
|
|
365
398
|
}
|
|
366
399
|
return new RemoteStorageFileSystem({
|
|
367
|
-
href: options.href,
|
|
400
|
+
href: await resolveRemoteStorageHref(options.href),
|
|
368
401
|
token: options.token,
|
|
369
402
|
basePath: options.basePath || void 0,
|
|
370
403
|
preciseMtime: true,
|
|
@@ -375,7 +408,7 @@ var init_backend_registry = __esm({
|
|
|
375
408
|
label: "RemoteStorage",
|
|
376
409
|
icon: "\u{1F4E1}",
|
|
377
410
|
fields: [
|
|
378
|
-
{ key: "href", label: "User Address (href)", type: "text", placeholder: "user@5apps.com", required: true },
|
|
411
|
+
{ key: "href", label: "User Address / Storage URL (href)", type: "text", placeholder: "user@5apps.com \u6216 https://storage.5apps.com/user", required: true },
|
|
379
412
|
{ key: "token", label: "Bearer Token", type: "password", placeholder: "rs-xxxxxxxx", required: true },
|
|
380
413
|
{ key: "basePath", label: "Base Path", type: "text", placeholder: "/zen-fs-config/" }
|
|
381
414
|
],
|
|
@@ -1394,6 +1427,8 @@ var APP_DATA_GROUPS_DIR = `${META_DIR}/app-data-groups`;
|
|
|
1394
1427
|
var CONFLICTS_DIR = `${META_DIR}/.conflicts`;
|
|
1395
1428
|
var DELETIONS_DIR = `${META_DIR}/.deleted`;
|
|
1396
1429
|
var NODES_DIR = "/nodes";
|
|
1430
|
+
var SHARED_DIR = "/shared";
|
|
1431
|
+
var CONFIG_ONLY_PREFIXES = [META_DIR, NODES_DIR, SHARED_DIR];
|
|
1397
1432
|
var LOCAL_IDB_BACKEND_ID = "local-idb";
|
|
1398
1433
|
function tombstoneFileName(filePath) {
|
|
1399
1434
|
return filePath.replace(/^\//, "").replace(/\//g, "__").replace(/\./g, "++") + ".json";
|
|
@@ -1418,6 +1453,12 @@ function identityOptions(type, options) {
|
|
|
1418
1453
|
for (const f of fields) {
|
|
1419
1454
|
if (options && options[f] !== void 0) subset[f] = options[f];
|
|
1420
1455
|
}
|
|
1456
|
+
if (type === "Gitee" || type === "GitHub") {
|
|
1457
|
+
const defaultEndpoint = type === "Gitee" ? "https://gitee.com/api/v5" : "https://api.github.com";
|
|
1458
|
+
const raw = options && options.baseUrl;
|
|
1459
|
+
const value = typeof raw === "string" && raw.trim() !== "" ? raw : defaultEndpoint;
|
|
1460
|
+
subset["baseUrl"] = value.replace(/\/+$/, "");
|
|
1461
|
+
}
|
|
1421
1462
|
return subset;
|
|
1422
1463
|
}
|
|
1423
1464
|
function backendDedupKey(desc) {
|
|
@@ -2808,10 +2849,15 @@ var ConfigRepo = class {
|
|
|
2808
2849
|
}
|
|
2809
2850
|
const descPath = this.appDataGroupFilePath(id);
|
|
2810
2851
|
try {
|
|
2811
|
-
await this.
|
|
2812
|
-
} catch {
|
|
2852
|
+
await this.deleteFile(descPath);
|
|
2853
|
+
} catch (err) {
|
|
2854
|
+
log2.log(`[ConfigRepo] removeAppDataGroup: deleteFile failed for "${id}":`, err);
|
|
2855
|
+
try {
|
|
2856
|
+
await this.cachedFS.unlink(descPath);
|
|
2857
|
+
} catch {
|
|
2858
|
+
}
|
|
2859
|
+
await this.unlinkVersionSidecar(this.cachedFS, descPath);
|
|
2813
2860
|
}
|
|
2814
|
-
await this.unlinkVersionSidecar(this.cachedFS, descPath);
|
|
2815
2861
|
log2.log(`[ConfigRepo] removeAppDataGroup: "${id}" removed`);
|
|
2816
2862
|
}
|
|
2817
2863
|
async listAccountBackends() {
|
|
@@ -2901,7 +2947,8 @@ var AppDataGroupImpl = class {
|
|
|
2901
2947
|
{
|
|
2902
2948
|
direction: import_zen_fs_sync.SyncDirection.BiDirectional,
|
|
2903
2949
|
conflictStrategy: "source-wins",
|
|
2904
|
-
pollIntervalMs: this._pollIntervalMs
|
|
2950
|
+
pollIntervalMs: this._pollIntervalMs,
|
|
2951
|
+
filter: { excludePrefixes: CONFIG_ONLY_PREFIXES }
|
|
2905
2952
|
},
|
|
2906
2953
|
"/"
|
|
2907
2954
|
);
|
|
@@ -2947,7 +2994,8 @@ var AppDataGroupImpl = class {
|
|
|
2947
2994
|
{
|
|
2948
2995
|
direction: import_zen_fs_sync.SyncDirection.BiDirectional,
|
|
2949
2996
|
conflictStrategy: "source-wins",
|
|
2950
|
-
pollIntervalMs: this._pollIntervalMs
|
|
2997
|
+
pollIntervalMs: this._pollIntervalMs,
|
|
2998
|
+
filter: { excludePrefixes: CONFIG_ONLY_PREFIXES }
|
|
2951
2999
|
},
|
|
2952
3000
|
"/"
|
|
2953
3001
|
);
|
|
@@ -3194,12 +3242,25 @@ async function connect(appId, options = {}) {
|
|
|
3194
3242
|
onConflict: options.onConflict,
|
|
3195
3243
|
syncPollIntervalMs: options.syncPollIntervalMs
|
|
3196
3244
|
});
|
|
3197
|
-
const
|
|
3245
|
+
const appDataGroups2 = [];
|
|
3246
|
+
const descriptors2 = await repo2.listAppDataGroups();
|
|
3247
|
+
for (const d of descriptors2) {
|
|
3248
|
+
try {
|
|
3249
|
+
appDataGroups2.push(await repo2.getAppDataGroup(d.id));
|
|
3250
|
+
} catch (err) {
|
|
3251
|
+
log3(`connect: failed to load app data group "${d.id}":`, err);
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
let dataGroup2 = appDataGroups2[0];
|
|
3255
|
+
if (!dataGroup2) {
|
|
3256
|
+
dataGroup2 = await repo2.createAppDataGroup("default", []);
|
|
3257
|
+
appDataGroups2.push(dataGroup2);
|
|
3258
|
+
}
|
|
3198
3259
|
return {
|
|
3199
3260
|
groupType: options.groupType ?? "config-sync",
|
|
3200
3261
|
repo: repo2,
|
|
3201
3262
|
dataGroup: dataGroup2,
|
|
3202
|
-
appDataGroups:
|
|
3263
|
+
appDataGroups: appDataGroups2
|
|
3203
3264
|
};
|
|
3204
3265
|
}
|
|
3205
3266
|
const { type, options: backendOptions } = options.backendInfo;
|
package/dist/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
registerBackend,
|
|
10
10
|
unregisterBackend,
|
|
11
11
|
wrapZenFSFileSystem
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-S2S3XBK2.mjs";
|
|
13
13
|
|
|
14
14
|
// src/config-repo.ts
|
|
15
15
|
import {
|
|
@@ -351,7 +351,7 @@ function registerFolderBackend() {
|
|
|
351
351
|
const pathMod = await import("path");
|
|
352
352
|
const dir = options.path;
|
|
353
353
|
const store = new FolderStore({ path: dir, label: options.label, fs, pathMod });
|
|
354
|
-
return (await import("./backend-registry-
|
|
354
|
+
return (await import("./backend-registry-RBKWNJZI.mjs")).wrapZenFSFileSystem({ backend: FolderBackend, path: dir, label: options.label });
|
|
355
355
|
},
|
|
356
356
|
{
|
|
357
357
|
type: "Folder",
|
|
@@ -887,6 +887,8 @@ var APP_DATA_GROUPS_DIR = `${META_DIR}/app-data-groups`;
|
|
|
887
887
|
var CONFLICTS_DIR = `${META_DIR}/.conflicts`;
|
|
888
888
|
var DELETIONS_DIR = `${META_DIR}/.deleted`;
|
|
889
889
|
var NODES_DIR = "/nodes";
|
|
890
|
+
var SHARED_DIR = "/shared";
|
|
891
|
+
var CONFIG_ONLY_PREFIXES = [META_DIR, NODES_DIR, SHARED_DIR];
|
|
890
892
|
var LOCAL_IDB_BACKEND_ID = "local-idb";
|
|
891
893
|
function tombstoneFileName(filePath) {
|
|
892
894
|
return filePath.replace(/^\//, "").replace(/\//g, "__").replace(/\./g, "++") + ".json";
|
|
@@ -911,6 +913,12 @@ function identityOptions(type, options) {
|
|
|
911
913
|
for (const f of fields) {
|
|
912
914
|
if (options && options[f] !== void 0) subset[f] = options[f];
|
|
913
915
|
}
|
|
916
|
+
if (type === "Gitee" || type === "GitHub") {
|
|
917
|
+
const defaultEndpoint = type === "Gitee" ? "https://gitee.com/api/v5" : "https://api.github.com";
|
|
918
|
+
const raw = options && options.baseUrl;
|
|
919
|
+
const value = typeof raw === "string" && raw.trim() !== "" ? raw : defaultEndpoint;
|
|
920
|
+
subset["baseUrl"] = value.replace(/\/+$/, "");
|
|
921
|
+
}
|
|
914
922
|
return subset;
|
|
915
923
|
}
|
|
916
924
|
function backendDedupKey(desc) {
|
|
@@ -2301,10 +2309,15 @@ var ConfigRepo = class {
|
|
|
2301
2309
|
}
|
|
2302
2310
|
const descPath = this.appDataGroupFilePath(id);
|
|
2303
2311
|
try {
|
|
2304
|
-
await this.
|
|
2305
|
-
} catch {
|
|
2312
|
+
await this.deleteFile(descPath);
|
|
2313
|
+
} catch (err) {
|
|
2314
|
+
log2.log(`[ConfigRepo] removeAppDataGroup: deleteFile failed for "${id}":`, err);
|
|
2315
|
+
try {
|
|
2316
|
+
await this.cachedFS.unlink(descPath);
|
|
2317
|
+
} catch {
|
|
2318
|
+
}
|
|
2319
|
+
await this.unlinkVersionSidecar(this.cachedFS, descPath);
|
|
2306
2320
|
}
|
|
2307
|
-
await this.unlinkVersionSidecar(this.cachedFS, descPath);
|
|
2308
2321
|
log2.log(`[ConfigRepo] removeAppDataGroup: "${id}" removed`);
|
|
2309
2322
|
}
|
|
2310
2323
|
async listAccountBackends() {
|
|
@@ -2394,7 +2407,8 @@ var AppDataGroupImpl = class {
|
|
|
2394
2407
|
{
|
|
2395
2408
|
direction: SyncDirection.BiDirectional,
|
|
2396
2409
|
conflictStrategy: "source-wins",
|
|
2397
|
-
pollIntervalMs: this._pollIntervalMs
|
|
2410
|
+
pollIntervalMs: this._pollIntervalMs,
|
|
2411
|
+
filter: { excludePrefixes: CONFIG_ONLY_PREFIXES }
|
|
2398
2412
|
},
|
|
2399
2413
|
"/"
|
|
2400
2414
|
);
|
|
@@ -2440,7 +2454,8 @@ var AppDataGroupImpl = class {
|
|
|
2440
2454
|
{
|
|
2441
2455
|
direction: SyncDirection.BiDirectional,
|
|
2442
2456
|
conflictStrategy: "source-wins",
|
|
2443
|
-
pollIntervalMs: this._pollIntervalMs
|
|
2457
|
+
pollIntervalMs: this._pollIntervalMs,
|
|
2458
|
+
filter: { excludePrefixes: CONFIG_ONLY_PREFIXES }
|
|
2444
2459
|
},
|
|
2445
2460
|
"/"
|
|
2446
2461
|
);
|
|
@@ -2686,12 +2701,25 @@ async function connect(appId, options = {}) {
|
|
|
2686
2701
|
onConflict: options.onConflict,
|
|
2687
2702
|
syncPollIntervalMs: options.syncPollIntervalMs
|
|
2688
2703
|
});
|
|
2689
|
-
const
|
|
2704
|
+
const appDataGroups2 = [];
|
|
2705
|
+
const descriptors2 = await repo2.listAppDataGroups();
|
|
2706
|
+
for (const d of descriptors2) {
|
|
2707
|
+
try {
|
|
2708
|
+
appDataGroups2.push(await repo2.getAppDataGroup(d.id));
|
|
2709
|
+
} catch (err) {
|
|
2710
|
+
log3(`connect: failed to load app data group "${d.id}":`, err);
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
let dataGroup2 = appDataGroups2[0];
|
|
2714
|
+
if (!dataGroup2) {
|
|
2715
|
+
dataGroup2 = await repo2.createAppDataGroup("default", []);
|
|
2716
|
+
appDataGroups2.push(dataGroup2);
|
|
2717
|
+
}
|
|
2690
2718
|
return {
|
|
2691
2719
|
groupType: options.groupType ?? "config-sync",
|
|
2692
2720
|
repo: repo2,
|
|
2693
2721
|
dataGroup: dataGroup2,
|
|
2694
|
-
appDataGroups:
|
|
2722
|
+
appDataGroups: appDataGroups2
|
|
2695
2723
|
};
|
|
2696
2724
|
}
|
|
2697
2725
|
const { type, options: backendOptions } = options.backendInfo;
|
package/dist/zen-fs-config.js
CHANGED
|
@@ -24528,6 +24528,39 @@ var ZenFSConfig = (() => {
|
|
|
24528
24528
|
);
|
|
24529
24529
|
}
|
|
24530
24530
|
}
|
|
24531
|
+
async function resolveRemoteStorageHref(href) {
|
|
24532
|
+
const raw = String(href ?? "").trim();
|
|
24533
|
+
if (!raw) throw new Error("RemoteStorage href is required.");
|
|
24534
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) return raw.replace(/\/+$/, "");
|
|
24535
|
+
const match = raw.match(/^(?:acct:)?([^@/]+)@([^@/]+)$/);
|
|
24536
|
+
if (!match) {
|
|
24537
|
+
throw new Error(
|
|
24538
|
+
`RemoteStorage href "${raw}" is neither an absolute URL nor a user address (user@domain).`
|
|
24539
|
+
);
|
|
24540
|
+
}
|
|
24541
|
+
const user = match[1];
|
|
24542
|
+
const domain = match[2];
|
|
24543
|
+
const webfingerUrl = `https://${domain}/.well-known/webfinger?resource=acct:${encodeURIComponent(user)}@${encodeURIComponent(domain)}`;
|
|
24544
|
+
let response;
|
|
24545
|
+
try {
|
|
24546
|
+
response = await globalThis.fetch(webfingerUrl, {
|
|
24547
|
+
headers: { Accept: "application/jrd+json, application/json" }
|
|
24548
|
+
});
|
|
24549
|
+
} catch (err2) {
|
|
24550
|
+
throw new Error(
|
|
24551
|
+
`RemoteStorage WebFinger request failed (${webfingerUrl}): ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
24552
|
+
);
|
|
24553
|
+
}
|
|
24554
|
+
if (!response.ok) {
|
|
24555
|
+
throw new Error(`RemoteStorage WebFinger lookup failed (HTTP ${response.status}): ${webfingerUrl}`);
|
|
24556
|
+
}
|
|
24557
|
+
const jrd = await response.json();
|
|
24558
|
+
const link5 = (jrd?.links ?? []).find(
|
|
24559
|
+
(item) => item && item.rel === "http://tools.ietf.org/id/draft-dejong-remotestorage" && item.href
|
|
24560
|
+
);
|
|
24561
|
+
if (!link5) throw new Error(`WebFinger response has no RemoteStorage link: ${webfingerUrl}`);
|
|
24562
|
+
return String(link5.href).replace(/\/+$/, "");
|
|
24563
|
+
}
|
|
24531
24564
|
var registry, metadataRegistry, inMemoryCounter, _memCache, OPTIONAL_BACKEND_GLOBALS;
|
|
24532
24565
|
var init_backend_registry = __esm({
|
|
24533
24566
|
"src/backend-registry.ts"() {
|
|
@@ -24639,9 +24672,9 @@ var ZenFSConfig = (() => {
|
|
|
24639
24672
|
registerBackend("Gitee", async (options) => {
|
|
24640
24673
|
const _gt = await importOptionalBackend("zen-fs-gitee");
|
|
24641
24674
|
const Gitee = _gt?.Gitee ?? _gt?.default;
|
|
24642
|
-
if (typeof Gitee !== "function") {
|
|
24675
|
+
if (!Gitee || typeof Gitee !== "function" && typeof Gitee.create !== "function") {
|
|
24643
24676
|
throw new Error(
|
|
24644
|
-
`Backend package "zen-fs-gitee" loaded, but its Gitee export is not a
|
|
24677
|
+
`Backend package "zen-fs-gitee" loaded, but its Gitee export is not a usable backend (typeof=${typeof Gitee}). Load its UMD bundle so it exposes the global "ZenFSGitee".`
|
|
24645
24678
|
);
|
|
24646
24679
|
}
|
|
24647
24680
|
return wrapZenFSFileSystem({
|
|
@@ -24677,7 +24710,7 @@ var ZenFSConfig = (() => {
|
|
|
24677
24710
|
);
|
|
24678
24711
|
}
|
|
24679
24712
|
return new RemoteStorageFileSystem({
|
|
24680
|
-
href: options.href,
|
|
24713
|
+
href: await resolveRemoteStorageHref(options.href),
|
|
24681
24714
|
token: options.token,
|
|
24682
24715
|
basePath: options.basePath || void 0,
|
|
24683
24716
|
preciseMtime: true,
|
|
@@ -24688,7 +24721,7 @@ var ZenFSConfig = (() => {
|
|
|
24688
24721
|
label: "RemoteStorage",
|
|
24689
24722
|
icon: "\u{1F4E1}",
|
|
24690
24723
|
fields: [
|
|
24691
|
-
{ key: "href", label: "User Address (href)", type: "text", placeholder: "user@5apps.com", required: true },
|
|
24724
|
+
{ key: "href", label: "User Address / Storage URL (href)", type: "text", placeholder: "user@5apps.com \u6216 https://storage.5apps.com/user", required: true },
|
|
24692
24725
|
{ key: "token", label: "Bearer Token", type: "password", placeholder: "rs-xxxxxxxx", required: true },
|
|
24693
24726
|
{ key: "basePath", label: "Base Path", type: "text", placeholder: "/zen-fs-config/" }
|
|
24694
24727
|
],
|
|
@@ -27327,6 +27360,8 @@ var ZenFSConfig = (() => {
|
|
|
27327
27360
|
var CONFLICTS_DIR = `${META_DIR}/.conflicts`;
|
|
27328
27361
|
var DELETIONS_DIR = `${META_DIR}/.deleted`;
|
|
27329
27362
|
var NODES_DIR = "/nodes";
|
|
27363
|
+
var SHARED_DIR = "/shared";
|
|
27364
|
+
var CONFIG_ONLY_PREFIXES = [META_DIR, NODES_DIR, SHARED_DIR];
|
|
27330
27365
|
var LOCAL_IDB_BACKEND_ID = "local-idb";
|
|
27331
27366
|
function tombstoneFileName(filePath) {
|
|
27332
27367
|
return filePath.replace(/^\//, "").replace(/\//g, "__").replace(/\./g, "++") + ".json";
|
|
@@ -27351,6 +27386,12 @@ var ZenFSConfig = (() => {
|
|
|
27351
27386
|
for (const f of fields) {
|
|
27352
27387
|
if (options && options[f] !== void 0) subset[f] = options[f];
|
|
27353
27388
|
}
|
|
27389
|
+
if (type === "Gitee" || type === "GitHub") {
|
|
27390
|
+
const defaultEndpoint = type === "Gitee" ? "https://gitee.com/api/v5" : "https://api.github.com";
|
|
27391
|
+
const raw = options && options.baseUrl;
|
|
27392
|
+
const value = typeof raw === "string" && raw.trim() !== "" ? raw : defaultEndpoint;
|
|
27393
|
+
subset["baseUrl"] = value.replace(/\/+$/, "");
|
|
27394
|
+
}
|
|
27354
27395
|
return subset;
|
|
27355
27396
|
}
|
|
27356
27397
|
function backendDedupKey(desc) {
|
|
@@ -28741,10 +28782,15 @@ var ZenFSConfig = (() => {
|
|
|
28741
28782
|
}
|
|
28742
28783
|
const descPath = this.appDataGroupFilePath(id);
|
|
28743
28784
|
try {
|
|
28744
|
-
await this.
|
|
28745
|
-
} catch {
|
|
28785
|
+
await this.deleteFile(descPath);
|
|
28786
|
+
} catch (err2) {
|
|
28787
|
+
log6.log(`[ConfigRepo] removeAppDataGroup: deleteFile failed for "${id}":`, err2);
|
|
28788
|
+
try {
|
|
28789
|
+
await this.cachedFS.unlink(descPath);
|
|
28790
|
+
} catch {
|
|
28791
|
+
}
|
|
28792
|
+
await this.unlinkVersionSidecar(this.cachedFS, descPath);
|
|
28746
28793
|
}
|
|
28747
|
-
await this.unlinkVersionSidecar(this.cachedFS, descPath);
|
|
28748
28794
|
log6.log(`[ConfigRepo] removeAppDataGroup: "${id}" removed`);
|
|
28749
28795
|
}
|
|
28750
28796
|
async listAccountBackends() {
|
|
@@ -28834,7 +28880,8 @@ var ZenFSConfig = (() => {
|
|
|
28834
28880
|
{
|
|
28835
28881
|
direction: SyncDirection.BiDirectional,
|
|
28836
28882
|
conflictStrategy: "source-wins",
|
|
28837
|
-
pollIntervalMs: this._pollIntervalMs
|
|
28883
|
+
pollIntervalMs: this._pollIntervalMs,
|
|
28884
|
+
filter: { excludePrefixes: CONFIG_ONLY_PREFIXES }
|
|
28838
28885
|
},
|
|
28839
28886
|
"/"
|
|
28840
28887
|
);
|
|
@@ -28880,7 +28927,8 @@ var ZenFSConfig = (() => {
|
|
|
28880
28927
|
{
|
|
28881
28928
|
direction: SyncDirection.BiDirectional,
|
|
28882
28929
|
conflictStrategy: "source-wins",
|
|
28883
|
-
pollIntervalMs: this._pollIntervalMs
|
|
28930
|
+
pollIntervalMs: this._pollIntervalMs,
|
|
28931
|
+
filter: { excludePrefixes: CONFIG_ONLY_PREFIXES }
|
|
28884
28932
|
},
|
|
28885
28933
|
"/"
|
|
28886
28934
|
);
|
|
@@ -29127,12 +29175,25 @@ var ZenFSConfig = (() => {
|
|
|
29127
29175
|
onConflict: options.onConflict,
|
|
29128
29176
|
syncPollIntervalMs: options.syncPollIntervalMs
|
|
29129
29177
|
});
|
|
29130
|
-
const
|
|
29178
|
+
const appDataGroups2 = [];
|
|
29179
|
+
const descriptors2 = await repo2.listAppDataGroups();
|
|
29180
|
+
for (const d of descriptors2) {
|
|
29181
|
+
try {
|
|
29182
|
+
appDataGroups2.push(await repo2.getAppDataGroup(d.id));
|
|
29183
|
+
} catch (err2) {
|
|
29184
|
+
log7(`connect: failed to load app data group "${d.id}":`, err2);
|
|
29185
|
+
}
|
|
29186
|
+
}
|
|
29187
|
+
let dataGroup2 = appDataGroups2[0];
|
|
29188
|
+
if (!dataGroup2) {
|
|
29189
|
+
dataGroup2 = await repo2.createAppDataGroup("default", []);
|
|
29190
|
+
appDataGroups2.push(dataGroup2);
|
|
29191
|
+
}
|
|
29131
29192
|
return {
|
|
29132
29193
|
groupType: options.groupType ?? "config-sync",
|
|
29133
29194
|
repo: repo2,
|
|
29134
29195
|
dataGroup: dataGroup2,
|
|
29135
|
-
appDataGroups:
|
|
29196
|
+
appDataGroups: appDataGroups2
|
|
29136
29197
|
};
|
|
29137
29198
|
}
|
|
29138
29199
|
const { type, options: backendOptions } = options.backendInfo;
|