@peers-app/peers-sdk 0.19.9 → 0.19.12
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/package-installer/index.d.ts +1 -0
- package/dist/package-installer/index.js +1 -0
- package/dist/package-installer/package-installer.js +59 -8
- package/dist/package-installer/package-installer.test.js +37 -0
- package/dist/package-installer/package-seed-installer.d.ts +18 -2
- package/dist/package-installer/package-seed-installer.js +41 -18
- package/dist/package-installer/peers-core-installer.d.ts +49 -0
- package/dist/package-installer/peers-core-installer.js +126 -0
- package/package.json +1 -1
|
@@ -23,4 +23,5 @@ __exportStar(require("./package-publisher"), exports);
|
|
|
23
23
|
__exportStar(require("./package-remote-checker"), exports);
|
|
24
24
|
__exportStar(require("./package-seed-installer"), exports);
|
|
25
25
|
__exportStar(require("./package-tarball"), exports);
|
|
26
|
+
__exportStar(require("./peers-core-installer"), exports);
|
|
26
27
|
__exportStar(require("./types"), exports);
|
|
@@ -136,7 +136,11 @@ async function installAllPackageBundles(dataContext, deps) {
|
|
|
136
136
|
if (pkg.disabled)
|
|
137
137
|
continue;
|
|
138
138
|
try {
|
|
139
|
-
await
|
|
139
|
+
const localPath = await getPackageLocalPath(pkg.packageId, dataContext, deps);
|
|
140
|
+
if (!(await hasPackageJson(deps, localPath))) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
await installPackageFromBundles(dataContext, deps, pkg.packageId, { localPath });
|
|
140
144
|
}
|
|
141
145
|
catch (err) {
|
|
142
146
|
console.error(`[package-installer] Failed to install bundles for ${pkg.name} (${pkg.packageId}):`, err);
|
|
@@ -210,18 +214,65 @@ async function getPackageInfo(deps, localPath) {
|
|
|
210
214
|
}
|
|
211
215
|
return info;
|
|
212
216
|
}
|
|
213
|
-
|
|
214
|
-
* Resolve the local filesystem path for a package based on device vars.
|
|
215
|
-
* Awaits the loading promise to ensure the DB-stored value is available
|
|
216
|
-
* before reading. Falls back to `{packagesRootDir}`.
|
|
217
|
-
*/
|
|
218
|
-
async function getPackageLocalPath(packageId, dataContext, deps) {
|
|
217
|
+
async function readPackageLocalPathPvar(packageId, dataContext, deps) {
|
|
219
218
|
const pvar = (0, persistent_vars_1.groupDeviceVar)(`packageLocalPath_${packageId}`, {
|
|
220
219
|
defaultValue: deps.packagesRootDir,
|
|
221
220
|
dataContext,
|
|
222
221
|
});
|
|
223
222
|
await pvar.loadingPromise;
|
|
224
|
-
|
|
223
|
+
const value = pvar();
|
|
224
|
+
if (!value || value === deps.packagesRootDir) {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
return deps.resolvePath(value);
|
|
228
|
+
}
|
|
229
|
+
async function hasPackageJson(deps, localPath) {
|
|
230
|
+
return deps.fs.exists(deps.resolvePath(localPath, "package.json"));
|
|
231
|
+
}
|
|
232
|
+
function packageNameToFolderSlug(name) {
|
|
233
|
+
let slug = name.replace(/[^a-zA-Z0-9]/g, " ");
|
|
234
|
+
slug = slug.replace(/\s+/g, " ").trim();
|
|
235
|
+
return (0, utils_1.camelCaseToHyphens)(slug);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Resolve the local filesystem path for a package based on device vars.
|
|
239
|
+
* Awaits the loading promise to ensure the DB-stored value is available
|
|
240
|
+
* before reading. Falls back to paths from other data contexts on this device,
|
|
241
|
+
* then to `{packagesRootDir}/{name-slug}` when that directory exists.
|
|
242
|
+
*/
|
|
243
|
+
async function getPackageLocalPath(packageId, dataContext, deps) {
|
|
244
|
+
const candidates = [];
|
|
245
|
+
const currentPath = await readPackageLocalPathPvar(packageId, dataContext, deps);
|
|
246
|
+
if (currentPath) {
|
|
247
|
+
candidates.push(currentPath);
|
|
248
|
+
}
|
|
249
|
+
const userContext = dataContext.userContext;
|
|
250
|
+
if (userContext && dataContext.dataContextId !== userContext.userId) {
|
|
251
|
+
const personalPath = await readPackageLocalPathPvar(packageId, userContext.userDataContext, deps);
|
|
252
|
+
if (personalPath) {
|
|
253
|
+
candidates.push(personalPath);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (userContext) {
|
|
257
|
+
for (const dc of userContext.groupDataContexts.values()) {
|
|
258
|
+
if (dc.dataContextId === dataContext.dataContextId)
|
|
259
|
+
continue;
|
|
260
|
+
const groupPath = await readPackageLocalPathPvar(packageId, dc, deps);
|
|
261
|
+
if (groupPath) {
|
|
262
|
+
candidates.push(groupPath);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const pkg = await (0, packages_1.Packages)(dataContext).get(packageId);
|
|
267
|
+
if (pkg) {
|
|
268
|
+
candidates.push(deps.resolvePath(deps.packagesRootDir, packageNameToFolderSlug(pkg.name)));
|
|
269
|
+
}
|
|
270
|
+
for (const path of candidates) {
|
|
271
|
+
if (await hasPackageJson(deps, path)) {
|
|
272
|
+
return path;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return candidates[0] ?? deps.packagesRootDir;
|
|
225
276
|
}
|
|
226
277
|
/** Extract the first non-heading paragraph from a README as a description. */
|
|
227
278
|
function extractReadmeDescription(readme) {
|
|
@@ -658,9 +658,46 @@ describe("getPackageLocalPath (via installPackageFromBundles)", () => {
|
|
|
658
658
|
const deps = makeMockDeps({});
|
|
659
659
|
const dc = mockDataContext();
|
|
660
660
|
mockGroupDeviceVar.mockReturnValue(Object.assign(() => undefined, { loadingPromise: Promise.resolve() }));
|
|
661
|
+
mockGetPkg.mockResolvedValue(undefined);
|
|
661
662
|
// Since resolvePath just joins, and packagesRootDir = "/packages",
|
|
662
663
|
// the resolved path will be "/packages" — which won't have bundles.
|
|
663
664
|
// This should throw "Package directory does not exist"
|
|
664
665
|
await expect((0, package_installer_1.installPackageFromBundles)(dc, deps, packageId, { skipLoad: true, skipResolve: true })).rejects.toThrow("Package directory does not exist");
|
|
665
666
|
});
|
|
667
|
+
it("falls back to personal context packageLocalPath in another group context", async () => {
|
|
668
|
+
const packageId = (0, utils_1.newid)();
|
|
669
|
+
const personalPath = `/packages/my-widget`;
|
|
670
|
+
const files = {
|
|
671
|
+
[`${personalPath}/package.json`]: JSON.stringify({ name: "My Widget", version: "1.0.0" }),
|
|
672
|
+
[`${personalPath}/dist/package.bundle.js`]: "code",
|
|
673
|
+
};
|
|
674
|
+
const deps = makeMockDeps(files);
|
|
675
|
+
const personalDc = { dataContextId: "user123" };
|
|
676
|
+
const groupDc = mockDataContext({
|
|
677
|
+
dataContextId: "group456",
|
|
678
|
+
userContext: {
|
|
679
|
+
userId: "user123",
|
|
680
|
+
userDataContext: personalDc,
|
|
681
|
+
groupDataContexts: new Map([["group456", { dataContextId: "group456" }]]),
|
|
682
|
+
},
|
|
683
|
+
});
|
|
684
|
+
mockGroupDeviceVar.mockImplementation((_name, opts) => {
|
|
685
|
+
const path = opts?.dataContext?.dataContextId === "user123" ? personalPath : deps.packagesRootDir;
|
|
686
|
+
return Object.assign(() => path, { loadingPromise: Promise.resolve() });
|
|
687
|
+
});
|
|
688
|
+
mockFindOnePV.mockResolvedValue(undefined);
|
|
689
|
+
mockFindOneFile.mockResolvedValue(undefined);
|
|
690
|
+
mockGetPkg.mockResolvedValue({
|
|
691
|
+
packageId,
|
|
692
|
+
name: "My Widget",
|
|
693
|
+
description: "",
|
|
694
|
+
signature: "",
|
|
695
|
+
createdBy: "u",
|
|
696
|
+
});
|
|
697
|
+
await (0, package_installer_1.installPackageFromBundles)(groupDc, deps, packageId, {
|
|
698
|
+
skipLoad: true,
|
|
699
|
+
skipResolve: true,
|
|
700
|
+
});
|
|
701
|
+
expect(mockSignAndSavePV).toHaveBeenCalled();
|
|
702
|
+
});
|
|
666
703
|
});
|
|
@@ -5,8 +5,13 @@
|
|
|
5
5
|
* Called at group creation time (not on every startup).
|
|
6
6
|
*/
|
|
7
7
|
import type { DataContext } from "../context/data-context";
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
import { type IPackage } from "../data/packages";
|
|
9
|
+
/**
|
|
10
|
+
* Metadata needed to create (or backfill) a {@link IPackage} record, without
|
|
11
|
+
* any version/bundle data. Shared by {@link ensurePackageRecord} and
|
|
12
|
+
* {@link seedPackageInContext}.
|
|
13
|
+
*/
|
|
14
|
+
export interface IEnsurePackageRecordOpts {
|
|
10
15
|
packageId: string;
|
|
11
16
|
name: string;
|
|
12
17
|
description?: string;
|
|
@@ -16,6 +21,9 @@ export interface ISeedPackageOpts {
|
|
|
16
21
|
followVersionTags?: string;
|
|
17
22
|
updateUrl?: string;
|
|
18
23
|
remoteRepo?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Options for seeding a package into a data context. */
|
|
26
|
+
export interface ISeedPackageOpts extends IEnsurePackageRecordOpts {
|
|
19
27
|
/** Bundle data for the initial PackageVersion. */
|
|
20
28
|
version: string;
|
|
21
29
|
versionTag: string;
|
|
@@ -43,3 +51,11 @@ export interface ISeedPackageOpts {
|
|
|
43
51
|
* @returns true if seeding occurred, false if package already existed.
|
|
44
52
|
*/
|
|
45
53
|
export declare function seedPackageInContext(dataContext: DataContext, opts: ISeedPackageOpts): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Ensure a {@link IPackage} record exists in `dataContext`, creating it from
|
|
56
|
+
* `opts` when absent and backfilling any missing metadata defaults when
|
|
57
|
+
* present. Does not create or modify any PackageVersion.
|
|
58
|
+
*
|
|
59
|
+
* @returns The current (created or existing) Package record.
|
|
60
|
+
*/
|
|
61
|
+
export declare function ensurePackageRecord(dataContext: DataContext, opts: IEnsurePackageRecordOpts): Promise<IPackage>;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.seedPackageInContext = seedPackageInContext;
|
|
10
|
+
exports.ensurePackageRecord = ensurePackageRecord;
|
|
10
11
|
const package_versions_1 = require("../data/package-versions");
|
|
11
12
|
const packages_1 = require("../data/packages");
|
|
12
13
|
const utils_1 = require("../utils");
|
|
@@ -21,20 +22,35 @@ const package_installer_1 = require("./package-installer");
|
|
|
21
22
|
* @returns true if seeding occurred, false if package already existed.
|
|
22
23
|
*/
|
|
23
24
|
async function seedPackageInContext(dataContext, opts) {
|
|
24
|
-
const
|
|
25
|
-
const existingPkg = await pkgTable.get(opts.packageId);
|
|
25
|
+
const existingPkg = await (0, packages_1.Packages)(dataContext).get(opts.packageId);
|
|
26
26
|
if (existingPkg) {
|
|
27
27
|
// Package already exists — check if it has any version installed
|
|
28
|
-
const
|
|
29
|
-
const existingPvs = await pvTable.list({ packageId: opts.packageId });
|
|
28
|
+
const existingPvs = await (0, package_versions_1.PackageVersions)(dataContext).list({ packageId: opts.packageId });
|
|
30
29
|
if (existingPvs.length > 0) {
|
|
31
30
|
return false;
|
|
32
31
|
}
|
|
33
|
-
// Package record exists but no versions — install the initial PV
|
|
34
|
-
applyMissingSeedDefaults(existingPkg, opts);
|
|
35
|
-
return await installSeedVersion(dataContext, existingPkg, opts);
|
|
36
32
|
}
|
|
37
|
-
// Create Package record
|
|
33
|
+
// Create the Package record (or backfill missing defaults on an existing one),
|
|
34
|
+
// then install the initial PackageVersion from the bundle.
|
|
35
|
+
const pkg = await ensurePackageRecord(dataContext, opts);
|
|
36
|
+
return await installSeedVersion(dataContext, pkg, opts);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Ensure a {@link IPackage} record exists in `dataContext`, creating it from
|
|
40
|
+
* `opts` when absent and backfilling any missing metadata defaults when
|
|
41
|
+
* present. Does not create or modify any PackageVersion.
|
|
42
|
+
*
|
|
43
|
+
* @returns The current (created or existing) Package record.
|
|
44
|
+
*/
|
|
45
|
+
async function ensurePackageRecord(dataContext, opts) {
|
|
46
|
+
const pkgTable = (0, packages_1.Packages)(dataContext);
|
|
47
|
+
const existing = await pkgTable.get(opts.packageId);
|
|
48
|
+
if (existing) {
|
|
49
|
+
if (applyMissingRecordDefaults(existing, opts)) {
|
|
50
|
+
return await pkgTable.signAndSave(existing, { saveAsSnapshot: true });
|
|
51
|
+
}
|
|
52
|
+
return existing;
|
|
53
|
+
}
|
|
38
54
|
const pkg = {
|
|
39
55
|
packageId: opts.packageId,
|
|
40
56
|
name: opts.name,
|
|
@@ -48,17 +64,24 @@ async function seedPackageInContext(dataContext, opts) {
|
|
|
48
64
|
remoteRepo: opts.remoteRepo,
|
|
49
65
|
signature: "",
|
|
50
66
|
};
|
|
51
|
-
|
|
52
|
-
await installSeedVersion(dataContext, pkg, opts);
|
|
53
|
-
return true;
|
|
67
|
+
return pkgTable.signAndSave(pkg, { saveAsSnapshot: true });
|
|
54
68
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
69
|
+
/** Backfill missing metadata onto an existing record. Returns true if changed. */
|
|
70
|
+
function applyMissingRecordDefaults(pkg, opts) {
|
|
71
|
+
let changed = false;
|
|
72
|
+
const setIfEmpty = (key, value) => {
|
|
73
|
+
if (!pkg[key] && value) {
|
|
74
|
+
pkg[key] = value;
|
|
75
|
+
changed = true;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
setIfEmpty("description", opts.description);
|
|
79
|
+
setIfEmpty("publishPublicKey", opts.publishPublicKey);
|
|
80
|
+
setIfEmpty("versionFollowRange", opts.versionFollowRange);
|
|
81
|
+
setIfEmpty("followVersionTags", opts.followVersionTags);
|
|
82
|
+
setIfEmpty("updateUrl", opts.updateUrl);
|
|
83
|
+
setIfEmpty("remoteRepo", opts.remoteRepo);
|
|
84
|
+
return changed;
|
|
62
85
|
}
|
|
63
86
|
async function installSeedVersion(dataContext, pkg, opts) {
|
|
64
87
|
// Save bundle files (deduped by hash)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* peers-core install orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Ensures the `peers-core` package is installed into a given data context using
|
|
5
|
+
* a layered strategy:
|
|
6
|
+
*
|
|
7
|
+
* 1. No-op if peers-core already has a version in the context.
|
|
8
|
+
* 2. Copy from another context that already has it (used for new groups).
|
|
9
|
+
* 3. Install from the remote S3 `updateUrl` (used for new users; group fallback).
|
|
10
|
+
* 4. Seed the bundled copy shipped with the host app (offline fallback).
|
|
11
|
+
*
|
|
12
|
+
* Callers shape the strategy by what they pass: new users provide no
|
|
13
|
+
* `copyFromContexts` (remote-first), while new groups pass sibling contexts so
|
|
14
|
+
* they copy first and fall back to the remote `updateUrl`.
|
|
15
|
+
*/
|
|
16
|
+
import type { DataContext } from "../context/data-context";
|
|
17
|
+
import type { UserContext } from "../context/user-context";
|
|
18
|
+
import type { IHttpDeps } from "./types";
|
|
19
|
+
/** Bundled peers-core sources shipped with the host app (offline fallback). */
|
|
20
|
+
export interface IPeersCoreBundle {
|
|
21
|
+
version: string;
|
|
22
|
+
versionTag: string;
|
|
23
|
+
packageBundleCode: string;
|
|
24
|
+
routesBundleCode?: string;
|
|
25
|
+
uiBundleCode?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Options controlling {@link ensurePeersCore}'s install strategy. */
|
|
28
|
+
export interface IEnsurePeersCoreOpts {
|
|
29
|
+
/** HTTP interface for remote install. Omit to disable the remote path. */
|
|
30
|
+
http?: IHttpDeps;
|
|
31
|
+
/** S3 `updateUrl` for peers-core. Required for the remote path. */
|
|
32
|
+
updateUrl?: string;
|
|
33
|
+
/** Contexts to copy an already-installed peers-core from (e.g. personal + other groups). */
|
|
34
|
+
copyFromContexts?: DataContext[];
|
|
35
|
+
/** Bundled sources used as the offline fallback. */
|
|
36
|
+
bundle?: IPeersCoreBundle;
|
|
37
|
+
/** When true, try the bundled seed before the remote install (dev electron). */
|
|
38
|
+
preferBundle?: boolean;
|
|
39
|
+
/** Version tag to follow for the remote install. Defaults to `"stable"`. */
|
|
40
|
+
followTag?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Ensure peers-core is installed (with a usable, loaded version) in
|
|
44
|
+
* `dataContext`, applying the layered strategy described in the module docs.
|
|
45
|
+
*
|
|
46
|
+
* @returns true if an install occurred, false if it was already present or no
|
|
47
|
+
* strategy succeeded.
|
|
48
|
+
*/
|
|
49
|
+
export declare function ensurePeersCore(userContext: UserContext, dataContext: DataContext, opts: IEnsurePeersCoreOpts): Promise<boolean>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* peers-core install orchestrator.
|
|
4
|
+
*
|
|
5
|
+
* Ensures the `peers-core` package is installed into a given data context using
|
|
6
|
+
* a layered strategy:
|
|
7
|
+
*
|
|
8
|
+
* 1. No-op if peers-core already has a version in the context.
|
|
9
|
+
* 2. Copy from another context that already has it (used for new groups).
|
|
10
|
+
* 3. Install from the remote S3 `updateUrl` (used for new users; group fallback).
|
|
11
|
+
* 4. Seed the bundled copy shipped with the host app (offline fallback).
|
|
12
|
+
*
|
|
13
|
+
* Callers shape the strategy by what they pass: new users provide no
|
|
14
|
+
* `copyFromContexts` (remote-first), while new groups pass sibling contexts so
|
|
15
|
+
* they copy first and fall back to the remote `updateUrl`.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.ensurePeersCore = ensurePeersCore;
|
|
19
|
+
const package_version_resolver_1 = require("../data/package-version-resolver");
|
|
20
|
+
const package_versions_1 = require("../data/package-versions");
|
|
21
|
+
const packages_1 = require("../data/packages");
|
|
22
|
+
const packages_utils_1 = require("../data/packages.utils");
|
|
23
|
+
const system_ids_1 = require("../system-ids");
|
|
24
|
+
const package_remote_checker_1 = require("./package-remote-checker");
|
|
25
|
+
const package_seed_installer_1 = require("./package-seed-installer");
|
|
26
|
+
const PEERS_CORE_NAME = "peers-core";
|
|
27
|
+
const PEERS_CORE_DESCRIPTION = "Core system package for Peers platform";
|
|
28
|
+
/**
|
|
29
|
+
* Ensure peers-core is installed (with a usable, loaded version) in
|
|
30
|
+
* `dataContext`, applying the layered strategy described in the module docs.
|
|
31
|
+
*
|
|
32
|
+
* @returns true if an install occurred, false if it was already present or no
|
|
33
|
+
* strategy succeeded.
|
|
34
|
+
*/
|
|
35
|
+
async function ensurePeersCore(userContext, dataContext, opts) {
|
|
36
|
+
const existingPvs = await (0, package_versions_1.PackageVersions)(dataContext).list({ packageId: system_ids_1.peersCorePackageId });
|
|
37
|
+
if (existingPvs.length > 0)
|
|
38
|
+
return false;
|
|
39
|
+
if (await tryCopyFromContexts(dataContext, opts.copyFromContexts)) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
const tryRemote = () => tryRemoteInstall(userContext, dataContext, opts);
|
|
43
|
+
const tryBundle = () => tryBundleSeed(userContext, dataContext, opts);
|
|
44
|
+
const strategies = opts.preferBundle ? [tryBundle, tryRemote] : [tryRemote, tryBundle];
|
|
45
|
+
for (const strategy of strategies) {
|
|
46
|
+
if (await strategy())
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
/** Copy peers-core from the first sibling context that already has it, then load it. */
|
|
52
|
+
async function tryCopyFromContexts(dataContext, copyFromContexts) {
|
|
53
|
+
if (!copyFromContexts?.length)
|
|
54
|
+
return false;
|
|
55
|
+
for (const source of copyFromContexts) {
|
|
56
|
+
if (source.dataContextId === dataContext.dataContextId)
|
|
57
|
+
continue;
|
|
58
|
+
try {
|
|
59
|
+
const sourcePkg = await (0, packages_1.Packages)(source).get(system_ids_1.peersCorePackageId);
|
|
60
|
+
if (!sourcePkg?.activePackageVersionId)
|
|
61
|
+
continue;
|
|
62
|
+
await (0, packages_utils_1.copyPackageToAnotherDataContext)(system_ids_1.peersCorePackageId, source, dataContext);
|
|
63
|
+
const copied = await (0, packages_1.Packages)(dataContext).get(system_ids_1.peersCorePackageId);
|
|
64
|
+
if (copied) {
|
|
65
|
+
await (0, package_version_resolver_1.resolveDevicePackageVersion)(copied, dataContext, { force: true });
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
console.warn(`[peers-core-installer] copy from ${source.dataContextId} failed:`, err);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
/** Create the Package record (if needed) and install the latest remote version. */
|
|
76
|
+
async function tryRemoteInstall(userContext, dataContext, opts) {
|
|
77
|
+
if (!opts.http || !opts.updateUrl)
|
|
78
|
+
return false;
|
|
79
|
+
try {
|
|
80
|
+
const pkg = await (0, package_seed_installer_1.ensurePackageRecord)(dataContext, {
|
|
81
|
+
packageId: system_ids_1.peersCorePackageId,
|
|
82
|
+
name: PEERS_CORE_NAME,
|
|
83
|
+
description: PEERS_CORE_DESCRIPTION,
|
|
84
|
+
createdBy: userContext.userId,
|
|
85
|
+
publishPublicKey: system_ids_1.peersCorePublishPublicKey,
|
|
86
|
+
versionFollowRange: "latest",
|
|
87
|
+
followVersionTags: "stable",
|
|
88
|
+
updateUrl: opts.updateUrl,
|
|
89
|
+
remoteRepo: system_ids_1.peersCorePackageRepoUrl,
|
|
90
|
+
});
|
|
91
|
+
const result = await (0, package_remote_checker_1.checkAndInstallPackageRemoteVersion)(dataContext, pkg, opts.followTag ?? "stable", opts.http);
|
|
92
|
+
return !!result;
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
console.warn("[peers-core-installer] remote install failed:", err);
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Seed the bundled peers-core sources as an offline fallback. */
|
|
100
|
+
async function tryBundleSeed(userContext, dataContext, opts) {
|
|
101
|
+
if (!opts.bundle)
|
|
102
|
+
return false;
|
|
103
|
+
try {
|
|
104
|
+
return await (0, package_seed_installer_1.seedPackageInContext)(dataContext, {
|
|
105
|
+
packageId: system_ids_1.peersCorePackageId,
|
|
106
|
+
name: PEERS_CORE_NAME,
|
|
107
|
+
description: PEERS_CORE_DESCRIPTION,
|
|
108
|
+
createdBy: userContext.userId,
|
|
109
|
+
publishPublicKey: system_ids_1.peersCorePublishPublicKey,
|
|
110
|
+
versionFollowRange: "latest",
|
|
111
|
+
followVersionTags: "stable",
|
|
112
|
+
updateUrl: opts.updateUrl,
|
|
113
|
+
remoteRepo: system_ids_1.peersCorePackageRepoUrl,
|
|
114
|
+
version: opts.bundle.version,
|
|
115
|
+
versionTag: opts.bundle.versionTag,
|
|
116
|
+
packageBundleCode: opts.bundle.packageBundleCode,
|
|
117
|
+
routesBundleCode: opts.bundle.routesBundleCode,
|
|
118
|
+
uiBundleCode: opts.bundle.uiBundleCode,
|
|
119
|
+
loadAfterSeed: true,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
console.warn("[peers-core-installer] bundle seed failed:", err);
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|