@synopackageland/cli 0.12.1 → 0.12.2
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 +9 -0
- package/dist/runtime/executor-digests.json +11 -0
- package/dist/standalone/dsm-window.d.ts +3 -0
- package/dist/standalone/dsm-window.js +30 -1
- package/dist/standalone/launch-params.d.ts +11 -0
- package/dist/standalone/launch-params.js +33 -0
- package/dist/standalone/reopen-events.d.ts +2 -2
- package/dist/standalone/reopen-events.js +3 -3
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.12.2 (2026-10-16)
|
|
4
|
+
|
|
5
|
+
- Generated Apps use templates 0.12.2, SDK 0.12.2 and UI 0.10.3. SDK 0.12.2 types `ctx.launchParams` and `ctx.onLaunch` and adds `followLaunchRoute`, `launchRoute` and `dsmLaunchURL`.
|
|
6
|
+
- Pin the SDK 0.12.2 executor and lifecycle digests, identical to 0.12.1 for all three architectures.
|
|
7
|
+
- The DSM window forwards launch parameters to the App. `ctx.launchParams` holds the App's own string values from the launch that opened the window, from a desktop URL `?launchApp=SYNO.SDS.<package>.Instance&launchParam=<url-encoded key=value&...>` or `SYNO.SDS.AppLaunch(id, {key: value})`; `ctx.onLaunch(fn)` runs fn with those of each later launch of the open window. DSM's own keys, non-string values, keys outside `[A-Za-z][A-Za-z0-9_.-]{0,63}`, values over 2048 characters or with control characters, and keys past 32 are left out.
|
|
8
|
+
- `ctx.reopen` callbacks now run when DSM launches the already open window again (main menu, desktop URL or AppLaunch); DSM calls the window's onRequest then, never onOpen again.
|
|
9
|
+
|
|
10
|
+
繁中摘要:新專案使用 templates 0.12.2、SDK 0.12.2 與 UI 0.10.3,並加入 SDK 0.12.2 的 executor digest(與 0.12.1 相同)。DSM 視窗把啟動參數轉給 App:`ctx.launchParams` 是開啟視窗那次的 App 字串參數(桌面 URL `launchParam` 或 `SYNO.SDS.AppLaunch`),`ctx.onLaunch(fn)` 在已開視窗再次被帶參數啟動時呼叫;DSM 自有欄位、非字串、不合格的 key、超過 2048 字元或含控制字元的值與第 32 個之後的 key 會被略過。已開視窗再次啟動時 `ctx.reopen` 現在會觸發(DSM 呼叫 onRequest,不會再呼叫 onOpen)。
|
|
11
|
+
|
|
3
12
|
## 0.12.1 (2026-10-16)
|
|
4
13
|
|
|
5
14
|
- Preserve optional `raw_max_bytes` in WebAPI profiles and administrator policy digests. Reject invalid limits and require raw-capable SDK 0.12.1; zero/omitted profiles stay JSON-only. Generated approval details receive the byte limit.
|
|
@@ -20,5 +20,16 @@
|
|
|
20
20
|
"armv7": "cafc97c89f5645c14a8cf31d6d9f258394ed6f2d086478a7aebd04d57c274b4e"
|
|
21
21
|
},
|
|
22
22
|
"goToolchain": "go1.26.9"
|
|
23
|
+
},
|
|
24
|
+
"0.12.2": {
|
|
25
|
+
"x86_64": "efe409287770f6b70e7f8465e8767eeb2413b9ab8775020cf4dffb1555d7bf1f",
|
|
26
|
+
"aarch64": "d68c9889ed2391e918b9c278679ea0a01cd04425528c11090700a3b6341fc543",
|
|
27
|
+
"armv7": "9149a05efb9f2d7d86a400707099b3d657382b1c0dbad6588be8c500e90445cc",
|
|
28
|
+
"lifecycle": {
|
|
29
|
+
"x86_64": "d65500c4f04713a32b45d360059281391acfa5e00ee24895fdd2de7b82735372",
|
|
30
|
+
"aarch64": "94f6cd119186ff482b8aea56541dd1f9d53c147566bc1efdca6f5a1c86198331",
|
|
31
|
+
"armv7": "cafc97c89f5645c14a8cf31d6d9f258394ed6f2d086478a7aebd04d57c274b4e"
|
|
32
|
+
},
|
|
33
|
+
"goToolchain": "go1.26.9"
|
|
23
34
|
}
|
|
24
35
|
}
|
|
@@ -42,5 +42,8 @@ export declare function renderUiConfig(manifest: StandaloneManifest, icons?: Pac
|
|
|
42
42
|
* (and add a device-width viewport), and `ctx.appIcon` is the package icon a
|
|
43
43
|
* full-page shell shows beside the name, where a DSM window has a title bar.
|
|
44
44
|
* A portal App's `ctx.portal` shows `portalText`, the SDK's panel text.
|
|
45
|
+
* `ctx.launchParams` holds the App's own values from the launch that opened
|
|
46
|
+
* the window (a `launchParam` desktop URL or `SYNO.SDS.AppLaunch(id, param)`),
|
|
47
|
+
* and `ctx.onLaunch(fn)` hands fn those of each later launch with values.
|
|
45
48
|
*/
|
|
46
49
|
export declare function renderWindowScript(manifest: StandaloneManifest, assetVersion: string, icons?: PackageIcons, portalText?: PortalCatalogs): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { REOPEN_EVENTS_RUNTIME } from "./reopen-events.js";
|
|
2
|
+
import { LAUNCH_PARAMS_RUNTIME } from "./launch-params.js";
|
|
2
3
|
import { DSM_LANGS } from "./i18n.js";
|
|
3
4
|
import { PASSWORD_CONFIRM, ROOT_PANEL, ROOT_RUNTIME, rootPanelCatalogs } from "./root-window.js";
|
|
4
5
|
import { HOST_ADAPTER_RUNTIME } from "./host-adapter.js";
|
|
@@ -128,6 +129,9 @@ export function renderUiConfig(manifest, icons = packageIcons(manifest.icon), lo
|
|
|
128
129
|
* (and add a device-width viewport), and `ctx.appIcon` is the package icon a
|
|
129
130
|
* full-page shell shows beside the name, where a DSM window has a title bar.
|
|
130
131
|
* A portal App's `ctx.portal` shows `portalText`, the SDK's panel text.
|
|
132
|
+
* `ctx.launchParams` holds the App's own values from the launch that opened
|
|
133
|
+
* the window (a `launchParam` desktop URL or `SYNO.SDS.AppLaunch(id, param)`),
|
|
134
|
+
* and `ctx.onLaunch(fn)` hands fn those of each later launch with values.
|
|
131
135
|
*/
|
|
132
136
|
export function renderWindowScript(manifest, assetVersion, icons = packageIcons(manifest.icon), portalText) {
|
|
133
137
|
const pkg = manifest.package;
|
|
@@ -270,6 +274,11 @@ ${REOPEN_EVENTS_RUNTIME}
|
|
|
270
274
|
return createReopenEvents;
|
|
271
275
|
})();
|
|
272
276
|
|
|
277
|
+
${ns}.launchParams = (function () {
|
|
278
|
+
${LAUNCH_PARAMS_RUNTIME}
|
|
279
|
+
return launchParams;
|
|
280
|
+
})();
|
|
281
|
+
|
|
273
282
|
${ns}.createHost = (function () {
|
|
274
283
|
${HOST_ADAPTER_RUNTIME}
|
|
275
284
|
return createHostAdapter;
|
|
@@ -332,7 +341,7 @@ Ext.define(${JSON.stringify(`${ns}.MainWindow`)}, {
|
|
|
332
341
|
getRestoreSizePos: function (config) {
|
|
333
342
|
return ${ns}.fitDesktop(Ext.apply({ width: config.width, height: config.height }, this.callParent(arguments)));
|
|
334
343
|
},
|
|
335
|
-
onOpen: function () {
|
|
344
|
+
onOpen: function (param) {
|
|
336
345
|
this.callParent(arguments);
|
|
337
346
|
var me = this;
|
|
338
347
|
if (me.mounted) {
|
|
@@ -341,9 +350,11 @@ Ext.define(${JSON.stringify(`${ns}.MainWindow`)}, {
|
|
|
341
350
|
}
|
|
342
351
|
if (me.mountPending) return;
|
|
343
352
|
me.mountPending = true;
|
|
353
|
+
me.launchParams = ${ns}.launchParams(param);
|
|
344
354
|
var mountToken = me.mountToken = {};
|
|
345
355
|
me.reopenEvents = ${ns}.createReopenEvents();
|
|
346
356
|
me.reopenHandlers = me.reopenEvents.handlers;
|
|
357
|
+
me.launchEvents = ${ns}.createReopenEvents();
|
|
347
358
|
var lang = "enu";
|
|
348
359
|
try { if (typeof _S === "function") lang = _S("lang"); } catch (error) {}
|
|
349
360
|
var ctx = { requestTimeout: ${requestTimeout} };
|
|
@@ -362,6 +373,8 @@ ${root ? root.mount : ""} ${ns}.loadApp(function (app) {
|
|
|
362
373
|
call: call,
|
|
363
374
|
files: {endpoint: ${JSON.stringify(cgiUrl(pkg))}, token: function () { return SYNO.SDS.Session && SYNO.SDS.Session.SynoToken; }},
|
|
364
375
|
reopen: me.reopenEvents.subscribe,
|
|
376
|
+
launchParams: me.launchParams,
|
|
377
|
+
onLaunch: me.launchEvents.subscribe,
|
|
365
378
|
user: ${ns}.sessionUser(),${manifest.portal ? `\n portal: ${renderPortalAccess(ns, manifest)},` : ""}
|
|
366
379
|
host: me.hostAccess,
|
|
367
380
|
appWindow: me,
|
|
@@ -378,17 +391,33 @@ ${root ? root.mount : ""} ${ns}.loadApp(function (app) {
|
|
|
378
391
|
me.reopenEvents.dispose();
|
|
379
392
|
me.reopenEvents = null;
|
|
380
393
|
me.reopenHandlers = [];
|
|
394
|
+
me.launchEvents.dispose();
|
|
395
|
+
me.launchEvents = null;
|
|
381
396
|
throw error;
|
|
382
397
|
}
|
|
383
398
|
}
|
|
384
399
|
});
|
|
385
400
|
},
|
|
401
|
+
// DSM opens a running App's window again through onRequest, not onOpen,
|
|
402
|
+
// with that launch's param. Before the App mounts, it mounts with the latest.
|
|
403
|
+
onRequest: function (param) {
|
|
404
|
+
this.callParent(arguments);
|
|
405
|
+
var params = ${ns}.launchParams(param);
|
|
406
|
+
if (!this.mounted) {
|
|
407
|
+
if (this.mountPending && Object.keys(params).length) this.launchParams = params;
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
this.reopenEvents.emit();
|
|
411
|
+
if (Object.keys(params).length) this.launchEvents.emit(params);
|
|
412
|
+
},
|
|
386
413
|
onDestroy: function () {
|
|
387
414
|
this.mountToken = null;
|
|
388
415
|
this.mountPending = false;
|
|
389
416
|
if (this.reopenEvents) this.reopenEvents.dispose();
|
|
390
417
|
this.reopenEvents = null;
|
|
391
418
|
this.reopenHandlers = [];
|
|
419
|
+
if (this.launchEvents) this.launchEvents.dispose();
|
|
420
|
+
this.launchEvents = null;
|
|
392
421
|
if (this.hostAccess) this.hostAccess.dispose();
|
|
393
422
|
this.hostAccess = null;
|
|
394
423
|
var mounted = this.mounted;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** At most this many App values, each at most this long, reach the App from one launch. */
|
|
2
|
+
export declare const MAX_LAUNCH_PARAMS = 32;
|
|
3
|
+
export declare const MAX_LAUNCH_VALUE = 2048;
|
|
4
|
+
/**
|
|
5
|
+
* `launchParams(param)`: the App's own values from the param DSM hands the
|
|
6
|
+
* window's onOpen and onRequest, a `launchParam` desktop URL decoded by DSM
|
|
7
|
+
* into an object or AppLaunch's second argument. Only short single-line string
|
|
8
|
+
* values under plain keys pass; the result is a frozen, prototype-free copy.
|
|
9
|
+
* The values stay untrusted text for the App.
|
|
10
|
+
*/
|
|
11
|
+
export declare const LAUNCH_PARAMS_RUNTIME: string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** At most this many App values, each at most this long, reach the App from one launch. */
|
|
2
|
+
export const MAX_LAUNCH_PARAMS = 32;
|
|
3
|
+
export const MAX_LAUNCH_VALUE = 2048;
|
|
4
|
+
/**
|
|
5
|
+
* DSM's own string keys in a launch: AppLaunch reads className and
|
|
6
|
+
* instanceName, AppWindow.onOpen sets the window title from title, and desktop
|
|
7
|
+
* restore replays openConfig with dsm_version. Its other keys (fromRestore,
|
|
8
|
+
* windowState, cms_id, ...) are not strings and are left out with the rest.
|
|
9
|
+
*/
|
|
10
|
+
const DSM_KEYS = ["className", "instanceName", "dsm_version", "title"];
|
|
11
|
+
/**
|
|
12
|
+
* `launchParams(param)`: the App's own values from the param DSM hands the
|
|
13
|
+
* window's onOpen and onRequest, a `launchParam` desktop URL decoded by DSM
|
|
14
|
+
* into an object or AppLaunch's second argument. Only short single-line string
|
|
15
|
+
* values under plain keys pass; the result is a frozen, prototype-free copy.
|
|
16
|
+
* The values stay untrusted text for the App.
|
|
17
|
+
*/
|
|
18
|
+
export const LAUNCH_PARAMS_RUNTIME = `
|
|
19
|
+
function launchParams(param) {
|
|
20
|
+
var dsmKeys = ${JSON.stringify(DSM_KEYS)};
|
|
21
|
+
var params = Object.create(null), count = 0;
|
|
22
|
+
if (param && typeof param === "object" && !Array.isArray(param)) {
|
|
23
|
+
Object.keys(param).forEach(function (key) {
|
|
24
|
+
var value = param[key];
|
|
25
|
+
if (count >= ${MAX_LAUNCH_PARAMS} || dsmKeys.indexOf(key) >= 0 || !/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(key)) return;
|
|
26
|
+
if (typeof value !== "string" || value.length > ${MAX_LAUNCH_VALUE} || /[\\u0000-\\u001f\\u007f]/.test(value)) return;
|
|
27
|
+
params[key] = value;
|
|
28
|
+
count++;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return Object.freeze(params);
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** Wrapper-owned subscriptions; no dependency on native event names or Ext. */
|
|
2
|
-
export declare const REOPEN_EVENTS_RUNTIME = "\nfunction createReopenEvents() {\n var active = true, handlers = [];\n function subscribe(fn) {\n if (!active || typeof fn !== \"function\") return function () {};\n function handler() { if (active && fn) fn(); }\n function unsubscribe() {\n if (!fn) return;\n fn = null;\n var index = handlers.indexOf(handler);\n if (index !== -1) handlers.splice(index, 1);\n }\n handler.unsubscribe = unsubscribe;\n handlers.push(handler);\n return unsubscribe;\n }\n return {\n handlers: handlers,\n subscribe: subscribe,\n emit: function () { handlers.slice().forEach(function (handler) { handler(); }); },\n dispose: function () {\n active = false;\n handlers.slice().forEach(function (handler) { handler.unsubscribe(); });\n }\n };\n}\n";
|
|
1
|
+
/** Wrapper-owned subscriptions; no dependency on native event names or Ext. emit(value) hands value to each fn. */
|
|
2
|
+
export declare const REOPEN_EVENTS_RUNTIME = "\nfunction createReopenEvents() {\n var active = true, handlers = [];\n function subscribe(fn) {\n if (!active || typeof fn !== \"function\") return function () {};\n function handler(value) { if (active && fn) fn(value); }\n function unsubscribe() {\n if (!fn) return;\n fn = null;\n var index = handlers.indexOf(handler);\n if (index !== -1) handlers.splice(index, 1);\n }\n handler.unsubscribe = unsubscribe;\n handlers.push(handler);\n return unsubscribe;\n }\n return {\n handlers: handlers,\n subscribe: subscribe,\n emit: function (value) { handlers.slice().forEach(function (handler) { handler(value); }); },\n dispose: function () {\n active = false;\n handlers.slice().forEach(function (handler) { handler.unsubscribe(); });\n }\n };\n}\n";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** Wrapper-owned subscriptions; no dependency on native event names or Ext. */
|
|
1
|
+
/** Wrapper-owned subscriptions; no dependency on native event names or Ext. emit(value) hands value to each fn. */
|
|
2
2
|
export const REOPEN_EVENTS_RUNTIME = `
|
|
3
3
|
function createReopenEvents() {
|
|
4
4
|
var active = true, handlers = [];
|
|
5
5
|
function subscribe(fn) {
|
|
6
6
|
if (!active || typeof fn !== "function") return function () {};
|
|
7
|
-
function handler() { if (active && fn) fn(); }
|
|
7
|
+
function handler(value) { if (active && fn) fn(value); }
|
|
8
8
|
function unsubscribe() {
|
|
9
9
|
if (!fn) return;
|
|
10
10
|
fn = null;
|
|
@@ -18,7 +18,7 @@ function createReopenEvents() {
|
|
|
18
18
|
return {
|
|
19
19
|
handlers: handlers,
|
|
20
20
|
subscribe: subscribe,
|
|
21
|
-
emit: function () { handlers.slice().forEach(function (handler) { handler(); }); },
|
|
21
|
+
emit: function (value) { handlers.slice().forEach(function (handler) { handler(value); }); },
|
|
22
22
|
dispose: function () {
|
|
23
23
|
active = false;
|
|
24
24
|
handlers.slice().forEach(function (handler) { handler.unsubscribe(); });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
4
4
|
"description": "Syno Package Land Developer Kit CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"prepublishOnly": "npm run build"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@synopackageland/templates": "0.12.
|
|
28
|
+
"@synopackageland/templates": "0.12.2",
|
|
29
29
|
"ajv": "^8.17.1",
|
|
30
30
|
"commander": "^13.1.0",
|
|
31
31
|
"tar": "^7.4.3",
|