@synopackageland/cli 0.41.8 → 0.41.9

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.41.9 (2026-10-30)
4
+
5
+ - Accept self-signed DSM and redirected gateway certificates by default in the
6
+ Chromium e2e target, before its first network navigation.
7
+ - Preserve installer-managed ports when the SPK inspector reconstructs daemon
8
+ and background lifecycle hooks, so native gateway Apps with `install.ports`
9
+ build and inspect consistently.
10
+
3
11
  ## 0.41.8 (2026-10-30)
4
12
 
5
13
  - Preserve the manifest's installer ports, settings and shared-folder context
package/README.md CHANGED
@@ -225,6 +225,10 @@ not change how the App runs or its privilege tier. See `synopkgland skill show b
225
225
  suite on [`e2e`](https://www.npmjs.com/package/e2e) and `@e2e-dev/web`
226
226
  (optional peers, with `ai` and `@ai-sdk/openai`).
227
227
 
228
+ `dsmTarget()` uses Chromium and accepts self-signed DSM and gateway HTTPS
229
+ certificates by default, including redirects from an HTTP DSM URL. It configures
230
+ CDP before the first network navigation; this certificate handling is Chromium-only.
231
+
228
232
  ```ts
229
233
  // e2e.config.ts
230
234
  import {dsmTarget, magpieAgent} from '@synopackageland/cli/e2e';
@@ -0,0 +1,6 @@
1
+ import { type EngineHandle } from "e2e/engine";
2
+ import type { surfaceOf } from "@e2e-dev/web";
3
+ type Surface = NonNullable<ReturnType<typeof surfaceOf>>;
4
+ /** Chromium DSM test targets accept self-signed DSM and redirected gateway certificates. */
5
+ export declare function withDsmCertificates(base: EngineHandle, surface: () => Surface): EngineHandle;
6
+ export {};
@@ -0,0 +1,60 @@
1
+ import { defineEngine } from "e2e/engine";
2
+ /** Chromium DSM test targets accept self-signed DSM and redirected gateway certificates. */
3
+ export function withDsmCertificates(base, surface) {
4
+ const browsers = new WeakMap();
5
+ const pages = new WeakMap();
6
+ async function prepareBrowser() {
7
+ const browser = surface().context().browser();
8
+ if (!browser)
9
+ return false;
10
+ let pending = browsers.get(browser);
11
+ if (!pending) {
12
+ pending = (async () => {
13
+ const session = await browser.newBrowserCDPSession();
14
+ await session.send("Security.setIgnoreCertificateErrors", { ignore: true });
15
+ return true;
16
+ })().catch(() => false); // Some Chromium connections expose only page CDP.
17
+ browsers.set(browser, pending);
18
+ }
19
+ return pending;
20
+ }
21
+ const { capabilities: _capabilities, ...spec } = base;
22
+ return defineEngine({
23
+ ...spec,
24
+ async startAttempt(context) {
25
+ await base.startAttempt?.(context);
26
+ await prepareBrowser();
27
+ },
28
+ session: {
29
+ ...base.session,
30
+ async open(url, operation) {
31
+ if (!base.session?.open)
32
+ throw new Error("The DSM engine cannot open a page.");
33
+ if (!await prepareBrowser()) {
34
+ // The runner creates its page lazily. Open only a blank page before
35
+ // configuring page CDP, so the first network navigation is covered.
36
+ let page;
37
+ try {
38
+ page = surface().page();
39
+ }
40
+ catch {
41
+ await base.session.open("about:blank", operation);
42
+ page = surface().page();
43
+ }
44
+ let pending = pages.get(page);
45
+ if (!pending) {
46
+ const target = page;
47
+ pending = (async () => {
48
+ const session = await surface().context().newCDPSession(target);
49
+ await session.send("Security.setIgnoreCertificateErrors", { ignore: true });
50
+ })();
51
+ pages.set(page, pending);
52
+ pending.catch(() => pages.delete(target));
53
+ }
54
+ await pending;
55
+ }
56
+ await base.session.open(url, operation);
57
+ },
58
+ },
59
+ });
60
+ }
package/dist/e2e/dsm.d.ts CHANGED
@@ -82,7 +82,7 @@ export declare function loadProfile(file: string, url: string): StorageState | n
82
82
  * process, each write their own temporary file and rename it into place.
83
83
  */
84
84
  export declare function saveProfile(file: string, url: string, state: StorageState): void;
85
- /** The `targets` entry of e2e.config.ts. */
85
+ /** The Chromium `targets` entry of e2e.config.ts; accepts self-signed test certificates. */
86
86
  export declare function dsmTarget(name?: string): {
87
87
  name: string;
88
88
  engine: import("e2e/engine").EngineHandle;
package/dist/e2e/dsm.js CHANGED
@@ -23,6 +23,7 @@ import { createOpenAI } from "@ai-sdk/openai";
23
23
  import { readSmokeEntry } from "./app-open.js";
24
24
  export { deriveSmokeEntry } from "./app-open.js";
25
25
  import { surfaceOf, test, web } from "@e2e-dev/web";
26
+ import { withDsmCertificates } from "./certificates.js";
26
27
  const safeName = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/;
27
28
  const desktopSelector = "#sds-desktop";
28
29
  const signedInSelector = "#sds-taskbar-tray-item-user";
@@ -288,15 +289,16 @@ export function saveProfile(file, url, state) {
288
289
  renameSync(temporary, file);
289
290
  }
290
291
  // ---- Browser --------------------------------------------------------------
291
- const engine = web({
292
+ const webEngine = web({
292
293
  viewport: { width: Number(process.env.DSM_E2E_VIEWPORT_WIDTH || 1280), height: Number(process.env.DSM_E2E_VIEWPORT_HEIGHT || 800) },
293
294
  });
294
- /** The `targets` entry of e2e.config.ts. */
295
+ const engine = withDsmCertificates(webEngine, surface);
296
+ /** The Chromium `targets` entry of e2e.config.ts; accepts self-signed test certificates. */
295
297
  export function dsmTarget(name = "dsm") {
296
298
  return { name, engine, app: { url: dsmUrl() } };
297
299
  }
298
300
  function surface() {
299
- const live = surfaceOf(engine);
301
+ const live = surfaceOf(webEngine);
300
302
  if (!live)
301
303
  throw new Error("The DSM web engine is unavailable.");
302
304
  return live;
@@ -248,10 +248,10 @@ export async function inspectSpk(spkPath, expectedKind) {
248
248
  if (standalone && portal)
249
249
  findings.push(...inspectPortalInfo(info, hasExecutor));
250
250
  const daemon = standalone
251
- ? await checkDaemon(dir, info, paths, payload, findings, hasExecutor, background, combined, nativeGateway, uninstallHook?.uninstall, { ingress: daemonIngress, node: daemonNode, restart: daemonRestart })
251
+ ? await checkDaemon(dir, info, paths, payload, findings, hasExecutor, background, combined, nativeGateway, uninstallHook?.uninstall, { ingress: daemonIngress, node: daemonNode, restart: daemonRestart, installPorts: Boolean(metadata.installPorts) })
252
252
  : undefined;
253
253
  if (background)
254
- checkBackground(dir, info, payload, findings, hasExecutor, daemon, kind !== "native-go", metadata.lifecycleTimeouts, nativeGateway);
254
+ checkBackground(dir, info, payload, findings, hasExecutor, daemon, kind !== "native-go", metadata.lifecycleTimeouts, nativeGateway, Boolean(metadata.installPorts));
255
255
  let executor;
256
256
  if ((metadata.capabilities ?? []).some((name) => name === "rootOps" || name === "delegate" || name === "webapi") ||
257
257
  paths.has("executor/executor")) {
@@ -1026,6 +1026,7 @@ async function checkDaemon(dir, info, paths, payload, findings, executor, backgr
1026
1026
  throw new Error("missing executable");
1027
1027
  const manifest = {
1028
1028
  package: info.package,
1029
+ ...(extras.installPorts ? { installPorts: true } : {}),
1029
1030
  backend: { kind: 'go', dir: dir, main: './cmd/app', timeoutSeconds: config.operation_seconds ?? 60 },
1030
1031
  root: dir,
1031
1032
  ...(combined ? { lifecycleTimeouts: daemon.timeouts } : {}),
@@ -1057,7 +1058,7 @@ async function checkDaemon(dir, info, paths, payload, findings, executor, backgr
1057
1058
  if (readFileSync(join(unpacked, "daemon/config.json"), "utf8") !== JSON.stringify(expectedConfig) + '\n')
1058
1059
  throw new Error("non-canonical daemon config");
1059
1060
  for (const hook of ["start-stop-status", "preupgrade", "preuninst"]) {
1060
- if (!matchesStandaloneScript(hook, nativeGateway ? { ...manifest, os_min_ver: info.os_min_ver, identityGateway: nativeGateway } : manifest, readFileSync(join(dir, "scripts", hook), "utf8")))
1061
+ if (!matchesStandaloneScript(hook, nativeGateway ? { ...manifest, os_min_ver: info.os_min_ver, identityGateway: nativeGateway } : manifest, readFileSync(join(dir, "scripts", hook), "utf8"), Boolean(extras.installPorts)))
1061
1062
  findings.push(`daemon scripts/${hook} does not match the fixed lifecycle`);
1062
1063
  }
1063
1064
  return daemon;
@@ -1379,7 +1380,7 @@ function checkConf(dir, findings, kind, background, sharedFolder, pkg, portal, c
1379
1380
  }
1380
1381
  }
1381
1382
  /** The opt-in package user unit must be exactly what the generator writes. */
1382
- function checkBackground(dir, info, payload, findings, executor, daemon, bridge = false, lifecycleTimeouts, nativeGateway) {
1383
+ function checkBackground(dir, info, payload, findings, executor, daemon, bridge = false, lifecycleTimeouts, nativeGateway, installPorts = false) {
1383
1384
  const pkg = info.package;
1384
1385
  if (!pkg)
1385
1386
  return;
@@ -1402,6 +1403,7 @@ function checkBackground(dir, info, payload, findings, executor, daemon, bridge
1402
1403
  }
1403
1404
  if (!matchesStandaloneScript("start-stop-status", {
1404
1405
  package: pkg,
1406
+ ...(installPorts ? { installPorts: true } : {}),
1405
1407
  os_min_ver: info.os_min_ver,
1406
1408
  ...(nativeGateway ? { identityGateway: nativeGateway } : {}),
1407
1409
  lifecycleTimeouts,
@@ -1410,7 +1412,7 @@ function checkBackground(dir, info, payload, findings, executor, daemon, bridge
1410
1412
  jobs: { worker: "sha256-v1" },
1411
1413
  ...(executor ? { rootOps: true } : {}),
1412
1414
  },
1413
- }, read("scripts/start-stop-status")))
1415
+ }, read("scripts/start-stop-status"), installPorts))
1414
1416
  findings.push("background scripts/start-stop-status does not match the fixed synosystemctl lifecycle");
1415
1417
  }
1416
1418
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synopackageland/cli",
3
- "version": "0.41.8",
3
+ "version": "0.41.9",
4
4
  "description": "Syno Package Land Developer Kit CLI",
5
5
  "type": "module",
6
6
  "bin": {