dsh-session-manager 0.7.1 → 0.7.3
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/CHANGELOG.md +19 -0
- package/README.md +22 -20
- package/README.zh.md +20 -18
- package/lib/client.js +429 -95
- package/lib/compat/dsh-adapter.js +177 -7
- package/lib/index.js +946 -39
- package/lib/session-files.js +73 -6
- package/package.json +1 -1
|
@@ -8,18 +8,24 @@
|
|
|
8
8
|
* @module dsh-session-manager/compat/dsh-adapter
|
|
9
9
|
*/
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
|
-
import { readFileSync } from "node:fs";
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
|
|
14
14
|
const require = createRequire(import.meta.url);
|
|
15
15
|
|
|
16
16
|
/** Pull one service out of the Cordis ctx, tolerating direct property fallbacks. */
|
|
17
|
-
function getService(ctx, name) {
|
|
17
|
+
export function getService(ctx, name) {
|
|
18
18
|
try {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
if (typeof ctx?.get === "function") {
|
|
20
|
+
const value = ctx.get(name);
|
|
21
|
+
if (value !== undefined) return value;
|
|
22
|
+
}
|
|
23
|
+
} catch { /* ignore */ }
|
|
24
|
+
try {
|
|
25
|
+
return ctx && ctx[name];
|
|
26
|
+
} catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
/** Read one package's version from its package.json if resolvable from this plugin. */
|
|
@@ -268,8 +274,172 @@ export function createDshAdapter(ctx) {
|
|
|
268
274
|
}
|
|
269
275
|
},
|
|
270
276
|
pluginVersion() {
|
|
271
|
-
|
|
277
|
+
const resolved = packageVersion("dsh-session-manager");
|
|
278
|
+
if (resolved) return resolved;
|
|
279
|
+
try {
|
|
280
|
+
const pkg = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
|
|
281
|
+
if (typeof pkg.version === "string") return pkg.version;
|
|
282
|
+
} catch { /* best-effort */ }
|
|
283
|
+
return "unknown";
|
|
272
284
|
},
|
|
273
285
|
};
|
|
274
286
|
return adapter;
|
|
275
287
|
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Resolve the DSH profile directory from adapter or ctx safely without
|
|
291
|
+
* triggering un-injected property access errors on Cordis context proxies.
|
|
292
|
+
*/
|
|
293
|
+
export function resolveProfileDir(adapter, ctx) {
|
|
294
|
+
const pm = adapter?.pluginManager || getService(ctx, "pluginManager");
|
|
295
|
+
try {
|
|
296
|
+
if (typeof pm?.profile?.dir === "string") return pm.profile.dir;
|
|
297
|
+
} catch { /* ignore */ }
|
|
298
|
+
try {
|
|
299
|
+
const pCtx = getService(ctx, "profileContext");
|
|
300
|
+
if (typeof pCtx?.dir === "string") return pCtx.dir;
|
|
301
|
+
} catch { /* ignore */ }
|
|
302
|
+
try {
|
|
303
|
+
if (typeof adapter?.homePath === "string") return adapter.homePath;
|
|
304
|
+
} catch { /* ignore */ }
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Classify an installation specification string into a recognized source:
|
|
310
|
+
* "npm" | "github" | "linked" | "unknown"
|
|
311
|
+
*
|
|
312
|
+
* Implements the specification rules from DSH install-spec.ts & dependencySpec():
|
|
313
|
+
* - Local filesystem paths: file:, link:, absolute paths, or relative path segments.
|
|
314
|
+
* - Git/GitHub repositories: github:, gitlab:, bitbucket:, gist:, git+, git://, git@, or hosted repo URLs.
|
|
315
|
+
* - Registry (npm):
|
|
316
|
+
* - Bare semver version, range, or dist-tag: "^0.7.3", "~0.7.3", "0.7.3", "latest", "beta"
|
|
317
|
+
* - Package-prefixed spec from dependencySpec(): "dsh-session-manager@^0.7.3", "dsh-session-manager@0.7.3", "dsh-session-manager@latest"
|
|
318
|
+
* - npm alias: "npm:dsh-session-manager@^0.7.3" or "dsh-session-manager@npm:..."
|
|
319
|
+
* - Any unrecognized URL, arbitrary protocol, or malformed string falls back to "unknown".
|
|
320
|
+
*/
|
|
321
|
+
export function classifyInstallSource(spec, packageName = "dsh-session-manager") {
|
|
322
|
+
if (typeof spec !== "string") return "unknown";
|
|
323
|
+
const s = spec.trim();
|
|
324
|
+
if (!s) return "unknown";
|
|
325
|
+
|
|
326
|
+
// 1. Local link / filesystem path
|
|
327
|
+
if (/^(?:file|link):/i.test(s)) return "linked";
|
|
328
|
+
if (/^(?:\/|[a-zA-Z]:[\\/]|\\\\|\.{1,2}(?:[\\/]|$))/.test(s)) return "linked";
|
|
329
|
+
|
|
330
|
+
// 2. Git / GitHub
|
|
331
|
+
if (/^(?:github|gitlab|bitbucket|gist):/i.test(s)) return "github";
|
|
332
|
+
if (/^git(?:\+[a-z]+)?:\/\/|^git@[^:]+:/i.test(s)) return "github";
|
|
333
|
+
if (/^https?:\/\/(?:www\.)?(?:github\.com|gitlab\.com|bitbucket\.org)\/[^/]+\/[^/#]+(?:\.git)?(?:#.*)?$/i.test(s)) return "github";
|
|
334
|
+
if (/^git\+https?:\/\//i.test(s)) return "github";
|
|
335
|
+
|
|
336
|
+
// 3. Registry (npm)
|
|
337
|
+
// Strip package name prefix if present (e.g. "dsh-session-manager@...")
|
|
338
|
+
let target = s;
|
|
339
|
+
const prefix = packageName.toLowerCase() + "@";
|
|
340
|
+
if (target.toLowerCase().startsWith(prefix)) {
|
|
341
|
+
target = target.slice(prefix.length).trim();
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// npm alias or registry protocol (e.g. "registry:npm", "npm:dsh-session-manager@^0.7.3", "npm:...")
|
|
345
|
+
if (
|
|
346
|
+
target.toLowerCase().startsWith("registry:") ||
|
|
347
|
+
target.toLowerCase().startsWith("npm:") ||
|
|
348
|
+
/^npm:(?:@[a-z0-9][a-z0-9._~-]*\/)?[a-z0-9][a-z0-9._~-]*@/i.test(target)
|
|
349
|
+
) {
|
|
350
|
+
return "npm";
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// After stripping package prefix, check if remainder is a local path or git URL (e.g. "pkg@link:...")
|
|
354
|
+
if (/^(?:file|link):/i.test(target) || /^(?:\/|[a-zA-Z]:[\\/]|\\\\|\.{1,2}(?:[\\/]|$))/.test(target)) {
|
|
355
|
+
return "linked";
|
|
356
|
+
}
|
|
357
|
+
if (/^(?:github|gitlab|bitbucket|gist):/i.test(target) || /^git(?:\+[a-z]+)?:\/\/|^git@[^:]+:/i.test(target)) {
|
|
358
|
+
return "github";
|
|
359
|
+
}
|
|
360
|
+
if (/^https?:\/\//i.test(target)) {
|
|
361
|
+
// Arbitrary HTTP URLs are NOT standard npm registry ranges
|
|
362
|
+
return "unknown";
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Semver versions & ranges:
|
|
366
|
+
// e.g. "0.7.3", "0.7.4-test.1", "^0.7.3", "~0.7.3", ">=0.7.0", "*", "1.x", "=0.7.3"
|
|
367
|
+
if (/^[~^>=<*]/.test(target) || /^\d+\.\d+/.test(target) || /^\d+x/i.test(target)) {
|
|
368
|
+
return "npm";
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// npm dist-tags: lowercase URL-safe tag names like "latest", "beta", "next", "canary", "dev"
|
|
372
|
+
if (/^[a-zA-Z0-9_.-]+$/.test(target)) {
|
|
373
|
+
return "npm";
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return "unknown";
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Detect the installation source of dsh-session-manager ("npm" | "github" | "linked" | "installation" | "unknown").
|
|
381
|
+
* Inspects explicit test/config overrides first, then bundle records from PluginManager,
|
|
382
|
+
* then the host profile package.json dependencies. Never defaults to "npm".
|
|
383
|
+
*/
|
|
384
|
+
export function detectPluginSource(adapter, ctx, bundles) {
|
|
385
|
+
try {
|
|
386
|
+
if (typeof adapter?.pluginSourceOverride === "string") {
|
|
387
|
+
return adapter.pluginSourceOverride;
|
|
388
|
+
}
|
|
389
|
+
} catch { /* best-effort */ }
|
|
390
|
+
const override = getService(ctx, "pluginSourceOverride");
|
|
391
|
+
if (typeof override === "string") {
|
|
392
|
+
return override;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// 1. Inspect bundles from PluginManager.listBundles() if provided
|
|
396
|
+
if (Array.isArray(bundles)) {
|
|
397
|
+
const b = bundles.find(item => item?.name === "dsh-session-manager");
|
|
398
|
+
if (b) {
|
|
399
|
+
if (b.availability === "installation") {
|
|
400
|
+
return "installation";
|
|
401
|
+
}
|
|
402
|
+
if (typeof b.source === "string") {
|
|
403
|
+
const source = classifyInstallSource(b.source, "dsh-session-manager");
|
|
404
|
+
if (source !== "unknown") return source;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// 2. Inspect host profile package.json dependencies
|
|
410
|
+
const profileDir = resolveProfileDir(adapter, ctx);
|
|
411
|
+
if (profileDir) {
|
|
412
|
+
try {
|
|
413
|
+
const pkgFile = join(profileDir, "package.json");
|
|
414
|
+
if (existsSync(pkgFile)) {
|
|
415
|
+
const pkg = JSON.parse(readFileSync(pkgFile, "utf8"));
|
|
416
|
+
const spec = pkg?.dependencies?.["dsh-session-manager"]
|
|
417
|
+
|| pkg?.devDependencies?.["dsh-session-manager"];
|
|
418
|
+
if (typeof spec === "string") {
|
|
419
|
+
return classifyInstallSource(spec, "dsh-session-manager");
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
} catch { /* best-effort */ }
|
|
423
|
+
}
|
|
424
|
+
return "unknown";
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Check if the runtime is currently executing in HMR (Hot Module Replacement) development mode.
|
|
429
|
+
*/
|
|
430
|
+
export function isHmrActive(adapter, ctx) {
|
|
431
|
+
try {
|
|
432
|
+
if (typeof ctx?.get === "function" && ctx.get("hmr") !== undefined) return true;
|
|
433
|
+
} catch { /* ignore */ }
|
|
434
|
+
try {
|
|
435
|
+
const pm = adapter?.pluginManager || getService(ctx, "pluginManager");
|
|
436
|
+
if (pm?.hot === true || pm?.hmr !== undefined) return true;
|
|
437
|
+
if (pm?.ownerContext && typeof pm.ownerContext.get === "function" && pm.ownerContext.get("hmr") !== undefined) {
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
} catch { /* ignore */ }
|
|
441
|
+
try {
|
|
442
|
+
if (ctx && (ctx.hmr !== undefined || ctx.hot === true || ctx.isHmr === true)) return true;
|
|
443
|
+
} catch { /* ignore */ }
|
|
444
|
+
return false;
|
|
445
|
+
}
|