@synopackageland/cli 0.12.0 → 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 +16 -0
- package/README.md +12 -0
- package/dist/init.js +11 -2
- package/dist/runtime/executor-digests.json +22 -0
- package/dist/runtime/webapi-profile.d.ts +2 -1
- package/dist/runtime/webapi-profile.js +4 -2
- 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/manifest.js +4 -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,21 @@
|
|
|
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
|
+
|
|
12
|
+
## 0.12.1 (2026-10-16)
|
|
13
|
+
|
|
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.
|
|
15
|
+
- Pin the SDK 0.12.1 three-architecture executor and lifecycle digests. Templates remain 0.12.0; no template change is needed for an optional consumer-declared profile.
|
|
16
|
+
|
|
17
|
+
繁中摘要:WebAPI profile 支援 raw_max_bytes 明確啟用原始回應與大小上限;驗證及核准 digest 保留此設定,需搭配 SDK 0.12.1。更新 executor digest,templates 維持 0.12.0。
|
|
18
|
+
|
|
3
19
|
## 0.12.0 (2026-10-16)
|
|
4
20
|
|
|
5
21
|
- Generated Apps use templates 0.12.0, SDK 0.12.0 and UI 0.10.1. Vue pages and sections stack at the UI section gap, and SDK dialogs size to their content.
|
package/README.md
CHANGED
|
@@ -204,3 +204,15 @@ normal executor approval digest; a profile change needs administrator approval.
|
|
|
204
204
|
Users grant the named profile separately. The permanent denylist, current-user
|
|
205
205
|
permission checks, bounded JSON and uncertain-outcome rules are in the SDK's
|
|
206
206
|
executor/README.md. Binary downloads require later SDK support.
|
|
207
|
+
|
|
208
|
+
## Raw WebAPI profiles
|
|
209
|
+
|
|
210
|
+
SDK 0.12.1 add opt-in raw responses. In `capabilities.webapi.<profile>`,
|
|
211
|
+
set `raw_max_bytes: 26214400` for a 25 MiB MIME limit and explicitly allow
|
|
212
|
+
`SYNO.MailClient.Message.get_original` v10. Omitting the limit preserves JSON-only
|
|
213
|
+
profiles. Changing it changes the approved policy and requires fresh user consent.
|
|
214
|
+
Call `webapi.call` with `response_type: "raw"`; Go Apps use
|
|
215
|
+
`JobContext.WebAPI().CallRaw`. Small bodies use base64; large bodies use the
|
|
216
|
+
package's private executor-staging folder with size/SHA-256 and immediate cleanup.
|
|
217
|
+
Do not use Attachment.download or follow X-Accel-Redirect. See the SDK raw response
|
|
218
|
+
contract for the complete transport and CGI validation rules.
|
package/dist/init.js
CHANGED
|
@@ -305,8 +305,17 @@ function assertLocalSdkReady(sdkDir, vue) {
|
|
|
305
305
|
*/
|
|
306
306
|
function useLocalSdk(targetDir, sdkDir) {
|
|
307
307
|
const goMod = join(targetDir, "backend/go.mod");
|
|
308
|
-
if (existsSync(goMod))
|
|
309
|
-
|
|
308
|
+
if (existsSync(goMod)) {
|
|
309
|
+
let text = readFileSync(goMod, "utf8");
|
|
310
|
+
const sdkPackage = join(sdkDir, "ts/package.json");
|
|
311
|
+
if (existsSync(sdkPackage)) {
|
|
312
|
+
const version = JSON.parse(readFileSync(sdkPackage, "utf8")).version;
|
|
313
|
+
if (typeof version !== "string" || !/^\d+\.\d+\.\d+$/.test(version))
|
|
314
|
+
throw new Error('[SDK_DIR_NOT_READY] Local SDK package version must be X.Y.Z.');
|
|
315
|
+
text = text.replace(/(github\.com\/synopackageland\/syno-pkg-land-sdk v)\d+\.\d+\.\d+\b/g, `$1${version}`);
|
|
316
|
+
}
|
|
317
|
+
writeFileSync(goMod, `${text}\nreplace ${SDK_MODULE} => ${sdkDir}\n`);
|
|
318
|
+
}
|
|
310
319
|
const frontend = join(targetDir, "frontend/package.json");
|
|
311
320
|
if (!existsSync(frontend))
|
|
312
321
|
return;
|
|
@@ -9,5 +9,27 @@
|
|
|
9
9
|
"armv7": "cafc97c89f5645c14a8cf31d6d9f258394ed6f2d086478a7aebd04d57c274b4e"
|
|
10
10
|
},
|
|
11
11
|
"goToolchain": "go1.26.9"
|
|
12
|
+
},
|
|
13
|
+
"0.12.1": {
|
|
14
|
+
"x86_64": "efe409287770f6b70e7f8465e8767eeb2413b9ab8775020cf4dffb1555d7bf1f",
|
|
15
|
+
"aarch64": "d68c9889ed2391e918b9c278679ea0a01cd04425528c11090700a3b6341fc543",
|
|
16
|
+
"armv7": "9149a05efb9f2d7d86a400707099b3d657382b1c0dbad6588be8c500e90445cc",
|
|
17
|
+
"lifecycle": {
|
|
18
|
+
"x86_64": "d65500c4f04713a32b45d360059281391acfa5e00ee24895fdd2de7b82735372",
|
|
19
|
+
"aarch64": "94f6cd119186ff482b8aea56541dd1f9d53c147566bc1efdca6f5a1c86198331",
|
|
20
|
+
"armv7": "cafc97c89f5645c14a8cf31d6d9f258394ed6f2d086478a7aebd04d57c274b4e"
|
|
21
|
+
},
|
|
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"
|
|
12
34
|
}
|
|
13
35
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** WebAPI profiles, independently enforced again by the pinned executor. */
|
|
2
2
|
export interface WebAPIProfile {
|
|
3
3
|
purpose: string;
|
|
4
4
|
apis: Record<string, Record<string, number[]>>;
|
|
5
|
+
raw_max_bytes?: number;
|
|
5
6
|
}
|
|
6
7
|
export type WebAPIProfiles = Record<string, WebAPIProfile>;
|
|
7
8
|
export declare function validWebAPIProfiles(value: unknown): value is WebAPIProfiles;
|
|
@@ -6,7 +6,9 @@ export function validWebAPIProfiles(value) {
|
|
|
6
6
|
return false;
|
|
7
7
|
let total = 0;
|
|
8
8
|
for (const [name, p] of Object.entries(value)) {
|
|
9
|
-
if (!/^[a-z][a-z0-9_-]{0,63}$/.test(name) || name === 'home' || !record(p) || Object.keys(p).some(k => !['purpose', 'apis'].includes(k)) || typeof p.purpose !== 'string' || !p.purpose.trim() || Buffer.byteLength(p.purpose) > 1024 || /[\x00-\x1f\x7f]/.test(p.purpose) || !record(p.apis) || !Object.keys(p.apis).length)
|
|
9
|
+
if (!/^[a-z][a-z0-9_-]{0,63}$/.test(name) || name === 'home' || !record(p) || Object.keys(p).some(k => !['purpose', 'apis', 'raw_max_bytes'].includes(k)) || typeof p.purpose !== 'string' || !p.purpose.trim() || Buffer.byteLength(p.purpose) > 1024 || /[\x00-\x1f\x7f]/.test(p.purpose) || !record(p.apis) || !Object.keys(p.apis).length)
|
|
10
|
+
return false;
|
|
11
|
+
if (p.raw_max_bytes !== undefined && (!Number.isSafeInteger(p.raw_max_bytes) || Number(p.raw_max_bytes) < 0 || Number(p.raw_max_bytes) > 67108864))
|
|
10
12
|
return false;
|
|
11
13
|
for (const [api, methods] of Object.entries(p.apis)) {
|
|
12
14
|
if (!/^SYNO\.[A-Za-z][A-Za-z0-9]*(\.[A-Za-z][A-Za-z0-9]*)*$/.test(api) || api.toLowerCase().split('.').slice(1).some(x => blocked.has(x)) || !record(methods) || !Object.keys(methods).length)
|
|
@@ -23,5 +25,5 @@ export function validWebAPIProfiles(value) {
|
|
|
23
25
|
return true;
|
|
24
26
|
}
|
|
25
27
|
export function sortedWebAPIProfiles(profiles) {
|
|
26
|
-
return Object.fromEntries(Object.entries(profiles).sort(([a], [b]) => a < b ? -1 : 1).map(([name, p]) => [name, { purpose: p.purpose, apis: Object.fromEntries(Object.entries(p.apis).sort(([a], [b]) => a < b ? -1 : 1).map(([api, methods]) => [api, Object.fromEntries(Object.entries(methods).sort(([a], [b]) => a < b ? -1 : 1).map(([m, versions]) => [m, [...versions].sort((a, b) => a - b)]))])) }]));
|
|
28
|
+
return Object.fromEntries(Object.entries(profiles).sort(([a], [b]) => a < b ? -1 : 1).map(([name, p]) => [name, { purpose: p.purpose, apis: Object.fromEntries(Object.entries(p.apis).sort(([a], [b]) => a < b ? -1 : 1).map(([api, methods]) => [api, Object.fromEntries(Object.entries(methods).sort(([a], [b]) => a < b ? -1 : 1).map(([m, versions]) => [m, [...versions].sort((a, b) => a - b)]))])), ...(p.raw_max_bytes ? { raw_max_bytes: p.raw_max_bytes } : {}) }]));
|
|
27
29
|
}
|
|
@@ -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
|
+
`;
|
|
@@ -217,6 +217,10 @@ function readManifest(raw, c) {
|
|
|
217
217
|
const sdk = sdkVersionOrUndefined(backend);
|
|
218
218
|
if (!sdk || Number(sdk.split('.')[0]) === 0 && Number(sdk.split('.')[1]) < 11)
|
|
219
219
|
c.fail("SDK_UNSUPPORTED", "capabilities.webapi requires SDK 0.11.0 or later; update backend and frontend together.");
|
|
220
|
+
const raw = Object.values(capabilities.webapi).some(profile => (profile.raw_max_bytes ?? 0) > 0);
|
|
221
|
+
const [major, minor, patch] = (sdk ?? '0.0.0').split('.').map(Number);
|
|
222
|
+
if (raw && (!sdk || major === 0 && (minor < 12 || minor === 12 && patch < 1)))
|
|
223
|
+
c.fail("SDK_UNSUPPORTED", "Raw WebAPI profiles require SDK 0.12.1 or later; update backend and frontend together.");
|
|
220
224
|
}
|
|
221
225
|
const uninstall = readUninstall(raw.uninstall, { rootOps: capabilities.rootOps === true, ops: rootOps, en: i18n?.catalogs?.en }, e => c.fail(e.code, e.message));
|
|
222
226
|
const appScripts = readAppScripts(c.root, e => c.fail(e.code, e.message));
|
|
@@ -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",
|