@lingxia/types 0.15.0 → 0.17.0

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.
Files changed (47) hide show
  1. package/dist/automation/index.d.ts +15 -1
  2. package/dist/automation/index.d.ts.map +1 -1
  3. package/dist/error.d.ts +4 -3
  4. package/dist/error.d.ts.map +1 -1
  5. package/dist/error.js +2 -2
  6. package/dist/error.js.map +1 -1
  7. package/dist/esm/automation/index.js +12 -0
  8. package/dist/esm/automation/index.js.map +1 -0
  9. package/dist/esm/error.js +148 -0
  10. package/dist/esm/error.js.map +1 -0
  11. package/dist/esm/generated/error.js +44 -0
  12. package/dist/esm/generated/error.js.map +1 -0
  13. package/dist/esm/generated/i18n.js +167 -0
  14. package/dist/esm/generated/i18n.js.map +1 -0
  15. package/dist/esm/generated/logic.js +4 -0
  16. package/dist/esm/generated/logic.js.map +1 -0
  17. package/dist/esm/index.js +11 -0
  18. package/dist/esm/index.js.map +1 -0
  19. package/dist/esm/package.json +4 -0
  20. package/dist/esm/process.js +9 -0
  21. package/dist/esm/process.js.map +1 -0
  22. package/dist/{testing/public-api.mjs → esm/testing/public-api.js} +79 -20
  23. package/dist/esm/testing/public-api.js.map +1 -0
  24. package/dist/generated/error.d.ts +1 -1
  25. package/dist/generated/error.d.ts.map +1 -1
  26. package/dist/generated/logic-web.d.ts +124 -0
  27. package/dist/generated/logic.d.ts +320 -142
  28. package/dist/generated/logic.d.ts.map +1 -1
  29. package/dist/index.d.ts +20 -10
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +5 -6
  32. package/dist/index.js.map +1 -1
  33. package/dist/process.d.ts +2 -2
  34. package/dist/process.js +2 -2
  35. package/dist/testing/public-api.d.ts +66 -15
  36. package/dist/testing/public-api.d.ts.map +1 -1
  37. package/dist/testing/public-api.js +78 -20
  38. package/dist/testing/public-api.js.map +1 -1
  39. package/package.json +9 -93
  40. package/src/automation/index.ts +17 -1
  41. package/src/error.ts +4 -3
  42. package/src/generated/error.ts +1 -1
  43. package/src/generated/logic-web.d.ts +124 -0
  44. package/src/generated/logic.ts +348 -150
  45. package/src/index.ts +32 -11
  46. package/src/process.ts +2 -2
  47. package/src/testing/public-api.ts +90 -20
@@ -14,9 +14,61 @@ export interface PageConfig<TData extends Record<string, unknown> = Record<strin
14
14
  onHide?: () => void | Promise<void>;
15
15
  onUnload?: () => void | Promise<void>;
16
16
  onPullDownRefresh?: () => void | Promise<void>;
17
- [key: string]: unknown;
18
17
  }
19
18
 
19
+ /** Lifecycle hook names a `Page({...})` config may declare. */
20
+ export type PageLifecycleName = Exclude<keyof PageConfig, 'data'>;
21
+
22
+ /** Lifecycle hook names an `App({...})` config may declare. */
23
+ export type AppLifecycleName = Exclude<keyof AppConfig, 'globalData'>;
24
+
25
+ /**
26
+ * What a key that differs from a lifecycle hook only in case resolves to, so
27
+ * the compiler names the mistake instead of silently accepting a new method.
28
+ */
29
+ export type MisspelledLifecycle<K extends string> = {
30
+ 'LingXia type error': `'${K}' differs only in case from a lifecycle hook`;
31
+ };
32
+
33
+ /**
34
+ * Applied to the custom half of a `Page`/`App` config. `onload` and `onShow`
35
+ * are one keystroke apart from real hooks and the runtime would simply never
36
+ * call the misspelling, so the closest case-insensitive match is rejected.
37
+ * Genuinely different names stay ordinary methods.
38
+ */
39
+ export type NoLifecycleTypos<TCustom, TNames extends string> = {
40
+ [K in keyof TCustom]: K extends TNames
41
+ ? TCustom[K]
42
+ : Lowercase<K & string> extends Lowercase<TNames>
43
+ ? MisspelledLifecycle<K & string>
44
+ : TCustom[K];
45
+ };
46
+
47
+ /**
48
+ * A `setData` key that addresses inside `data` — `'a.b'` or `'rows[0].name'`.
49
+ * Values behind a path stay `unknown`: the runtime resolves the path, so the
50
+ * type cannot.
51
+ */
52
+ export type PageDataPath = `${string}.${string}` | `${string}[${number}]${string}`;
53
+
54
+ /**
55
+ * A field initialized to `null` or `[]` states nothing about what will fill it
56
+ * later, so it stays open. Annotate it (`null as Profile | null`) to have the
57
+ * fill checked.
58
+ */
59
+ export type LazyInitField<T> = [T] extends [null | undefined]
60
+ ? unknown
61
+ : [T] extends [never[]]
62
+ ? unknown[]
63
+ : T;
64
+
65
+ /**
66
+ * Top-level keys are checked against `data`; only path-shaped keys stay open.
67
+ * A misspelled or wrongly typed top-level key is a compile error.
68
+ */
69
+ export type SetDataPatch<TData> = { [K in keyof TData]?: LazyInitField<TData[K]> } &
70
+ Partial<Record<PageDataPath, unknown>>;
71
+
20
72
  export interface PageInstance<TData extends Record<string, unknown> = Record<string, unknown>> {
21
73
  data: TData;
22
74
  route: string;
@@ -29,7 +81,7 @@ export interface PageInstance<TData extends Record<string, unknown> = Record<str
29
81
  * Available when this page was opened by `lx.navigateTo(...)`.
30
82
  */
31
83
  opener?: PageMessagePort;
32
- setData(data: Partial<TData> | Record<string, unknown>, callback?: () => void): void;
84
+ setData(data: SetDataPatch<TData>, callback?: () => void): void;
33
85
  }
34
86
 
35
87
  /**
@@ -69,8 +121,8 @@ export interface ChannelHandle<TSend = unknown, TReceive = unknown> {
69
121
  *
70
122
  * - `app`: app-owned temporary output, or durable `lx://userdata` output when
71
123
  * `filePath` is set
72
- * - `downloads`: user-visible system Downloads output, requiring
73
- * `security.privileges: ["downloads"]` in `lxapp.json`
124
+ * - `downloads`: user-visible system Downloads output, requiring a host
125
+ * privilege grant and a native Downloads grant
74
126
  *
75
127
  * Default: `app`.
76
128
  */
@@ -113,16 +165,26 @@ export interface DownloadTask<TDownloadResult extends DownloadResult = DownloadR
113
165
  }
114
166
 
115
167
  declare global {
168
+ /**
169
+ * The lxapp's configured page names, one key per page.
170
+ *
171
+ * Empty here on purpose. `lingxia dev` / `lingxia build` generates the
172
+ * project's own names into this interface; until then `ConfiguredPageName`
173
+ * stays `string` and every navigation call compiles exactly as before.
174
+ */
175
+ interface LxAppPages {}
176
+
116
177
  // HostAppApi/LxEnv members are emitted from the Rust js_api metadata; these
117
178
  // merges only add what Rong cannot express — the cfg-gated autostart member
118
- // and doc comments (js_api consts cannot carry docs). envVersion re-declares
179
+ // and doc comments (js_api consts cannot carry docs). env re-declares
119
180
  // the generated member doc-only; tsc rejects the merge if the types drift.
120
181
  interface HostAppApi {
121
182
  /**
122
- * The build environment from `app.json::envVersion`. It is fixed at boot
123
- * and defaults to `release` for older artifacts.
183
+ * The host deployment environment from `app.json::env` (`dev` | `prod`).
184
+ * It is fixed at boot and defaults to `prod` for older artifacts.
185
+ * Not the lxapp publish channel (`release` | `draft`).
124
186
  */
125
- readonly envVersion: HostAppEnvVersion;
187
+ readonly env: HostAppEnv;
126
188
 
127
189
  /**
128
190
  * Launch-at-startup control. Absent where the host cannot register a
@@ -130,6 +192,28 @@ declare global {
130
192
  * agree, so `lx.app.autostart?.…` and the query are interchangeable.
131
193
  */
132
194
  autostart?: AutostartApi;
195
+
196
+ /** The language this lxapp renders in. Every lxapp follows it. */
197
+ readonly displayLanguage: DisplayLanguageApi;
198
+
199
+ /** The light/dark scheme this lxapp renders in. */
200
+ readonly appearance: AppearanceApi;
201
+
202
+ /**
203
+ * Product-wide settings, and their single writer. Present only in the
204
+ * Control app the host sealed at build time; its presence and
205
+ * `lx.supports({ capability: 'control' })` always agree, so
206
+ * `lx.app.control?.…` and the query are interchangeable.
207
+ */
208
+ readonly control?: ControlApi;
209
+
210
+ /**
211
+ * Product-wide cache reporting and clearing for a settings screen.
212
+ * Present only in the Control app; its presence and
213
+ * `lx.supports({ capability: 'control' })` always agree, so
214
+ * `lx.app.cache?.…` and the query are interchangeable.
215
+ */
216
+ cache?: AppCacheApi;
133
217
  }
134
218
 
135
219
  /** Runtime environment constants backed by abstract `lx://` paths. */
@@ -187,6 +271,7 @@ type StorageEntry<S extends object> = {
187
271
  export type TypedStorage<S extends object> = {
188
272
  get<K extends StorageKey<S>>(key: K): Promise<S[K] | undefined>;
189
273
  set(...entry: StorageEntry<S>): Promise<void>;
274
+ has(key: StorageKey<S>): Promise<boolean>;
190
275
  delete(key: StorageKey<S>): Promise<void>;
191
276
  clear(): Promise<void>;
192
277
  list(prefix?: string): Promise<string[]>;
@@ -206,13 +291,37 @@ export type ActionSheetResult = {
206
291
  /** Every surface handle, narrowable by `kind`. */
207
292
  export type AnySurface = PageSurface | DeclaredSurface | AppSurface | TabSurface | BuiltinSurface;
208
293
 
294
+ /**
295
+ * The product-wide cache a settings screen reports and clears.
296
+ * App-scoped, not lxapp-scoped: the figure covers every lxapp the host
297
+ * has run. Injected only into the Control app, same gate as
298
+ * `lx.app.control` — guests do not have the member.
299
+ */
300
+ export type AppCacheApi = {
301
+ /** Estimated reclaimable managed bytes; excludes live session storage and WebView cache. */
302
+ size(): Promise<number>;
303
+ /**
304
+ * Clear reclaimable host caches. Control app only. Live session usercache and
305
+ * temp are preserved, including the caller's. Does not restart any lxapp.
306
+ * Userdata, KV, Downloads, cookies, valid installs and host components survive.
307
+ * Per-category failures are reported; setup/worker failures reject the call.
308
+ */
309
+ clear(): Promise<{
310
+ /** Estimated file bytes successfully removed; excludes WebView cache. */
311
+ freedBytes: number;
312
+ /** Protected usercache/session paths skipped, not a count of apps. */
313
+ skippedActivePaths: number;
314
+ webview: 'cleared' | 'unsupported' | 'failed';
315
+ failures: string[];
316
+ }>;
317
+ };
318
+
209
319
  export type AppConfig = {
210
320
  globalData?: Record<string, unknown>;
211
321
  onLaunch?: (options?: AppLaunchOptions) => void | Promise<void>;
212
322
  onShow?: (args?: AppLifecycleEventArgs) => void | Promise<void>;
213
323
  onHide?: (args?: AppLifecycleEventArgs) => void | Promise<void>;
214
324
  onUserCaptureScreen?: () => void | Promise<void>;
215
- [key: string]: unknown;
216
325
  };
217
326
 
218
327
  /** Runtime-managed app download path, usually under `lx://userdata`. */
@@ -263,16 +372,34 @@ export type AppInstance = AppConfig & {
263
372
  export type AppLaunchOptions = {
264
373
  path?: string;
265
374
  query?: Record<string, string>;
266
- scene?: number;
375
+ /** `8003` = AppLink (cold: onLaunch; warm: onShow). */
376
+ scene?: AppLaunchScene;
377
+ /**
378
+ * Inbound link exactly as the OS delivered it, fragment included. Present
379
+ * only with `scene: 8003`. Untrusted: route from an allowlist of paths.
380
+ */
381
+ url?: string;
267
382
  referrerInfo?: {
268
383
  appId?: string;
269
384
  extraData?: Record<string, unknown>;
270
385
  };
271
386
  };
272
387
 
388
+ /**
389
+ * Launch scene. `8003` is AppLink (cold: `onLaunch`; warm: `onShow`).
390
+ * Other numeric scenes stay valid; completion offers `8003`.
391
+ */
392
+ export type AppLaunchScene = 8003 | (number & {});
393
+
273
394
  export type AppLifecycleEventArgs = {
274
395
  source: 'host' | 'lxapp';
275
396
  reason: 'foreground' | 'background' | 'screenshot' | 'open' | 'close' | 'switch_back' | 'switch_away';
397
+ path?: string;
398
+ query?: Record<string, string>;
399
+ /** `8003` = AppLink. */
400
+ scene?: AppLaunchScene;
401
+ /** Inbound link, present only with `scene: 8003`. */
402
+ url?: string;
276
403
  };
277
404
 
278
405
  export type AppScreenshotOptions = {
@@ -298,8 +425,26 @@ export type AppSurface = SurfaceBase & SurfaceShowable & {
298
425
  readonly realized: 'main' | 'aside';
299
426
  };
300
427
 
301
- export type AppearanceApi = globalThis.AppearanceApi;
428
+ /** `lx.app.appearance` — the scheme this lxapp renders in. */
429
+ export type AppearanceApi = {
430
+ /**
431
+ * The scheme this lxapp is rendering in. An lxapp that pinned one in its
432
+ * `lxapp.json` reports that; every other lxapp reports the product's.
433
+ */
434
+ get(): ResolvedAppearance;
435
+ /**
436
+ * Follow it, starting with the current value. Returns an unsubscribe.
437
+ *
438
+ * The first callback runs synchronously, before `watch` returns, so the
439
+ * unsubscribe is not yet bound inside it.
440
+ */
441
+ watch(callback: (resolved: ResolvedAppearance) => void): () => void;
442
+ };
302
443
 
444
+ /**
445
+ * What the product's light/dark scheme is set to. `'auto'` follows
446
+ * the system.
447
+ */
303
448
  export type AppearancePreference = 'auto' | 'light' | 'dark';
304
449
 
305
450
  /**
@@ -318,8 +463,8 @@ export type AppearancePreference = 'auto' | 'light' | 'dark';
318
463
  * is called, so the decision stays with the user (typically a settings-page
319
464
  * toggle, default off).
320
465
  * Host-app-level capability: like `checkUpdate` and `screenshot`, the methods
321
- * are available only to the home lxapp; other lxapps receive a permission
322
- * error.
466
+ * are available only to the native-assigned Control app; other lxapps receive
467
+ * a permission error.
323
468
  */
324
469
  export type AutostartApi = {
325
470
  /**
@@ -342,12 +487,12 @@ export type BinaryFileData = ArrayBuffer | ArrayBufferView;
342
487
 
343
488
  /**
344
489
  * Built-in browser product page. Opening one requires
345
- * `capabilities.browser` and is restricted to the home lxapp.
490
+ * `capabilities.browser` and is restricted to the native-assigned Control app.
346
491
  */
347
- export type BuiltinShellPage = 'settings' | 'downloads';
492
+ export type BuiltinShellPage = 'downloads';
348
493
 
349
494
  /**
350
- * A host builtin page such as settings or downloads. The shell owns
495
+ * A host builtin page such as downloads. The shell owns
351
496
  * its lifetime and its visibility, so this handle reports identity:
352
497
  * there is no `show` / `hide`, and the inherited `close()` rejects
353
498
  * with `unsupported_placement`.
@@ -517,11 +662,73 @@ export type CompressVideoTask = PromiseLike<CompressVideoResult> & AsyncIterable
517
662
  wait(): Promise<CompressVideoResult>;
518
663
  };
519
664
 
665
+ /**
666
+ * Configured page name from `lxapp.json` / `lingxia.yaml`. JavaScript
667
+ * navigation accepts only this name; full routes such as
668
+ * `/pages/home/index` are internal runtime details. Discover names
669
+ * with `lxdev lxapp pages`.
670
+ * Narrows to the project's own names once `lingxia dev` or
671
+ * `lingxia build` has generated them; plain `string` before that, so
672
+ * a project that never ran a build still compiles.
673
+ */
674
+ export type ConfiguredPageName = keyof LxAppPages extends never ? string : keyof LxAppPages;
675
+
520
676
  export type ConnectWifiOptions = {
521
677
  SSID: string;
522
678
  password?: string;
523
679
  };
524
680
 
681
+ /**
682
+ * `lx.app.control` — product-wide settings, and their single writer.
683
+ * Present only in the Control app. Bind it once rather than repeating
684
+ * `lx.app.control!`:
685
+ * ```js
686
+ * const control = lx.app.control;
687
+ * if (!control) return; // not the Control app
688
+ * await control.appearance.setPreference('dark');
689
+ * ```
690
+ */
691
+ export type ControlApi = {
692
+ readonly displayLanguage: ControlDisplayLanguageApi;
693
+ readonly appearance: ControlAppearanceApi;
694
+ };
695
+
696
+ /** `lx.app.control.appearance` — the product's own light/dark setting. */
697
+ export type ControlAppearanceApi = {
698
+ /** What the user chose for the whole product. */
699
+ getPreference(): AppearancePreference;
700
+ /**
701
+ * Pin the product to `'light'` or `'dark'`, or follow the system with
702
+ * `'auto'`. An lxapp that pinned a scheme in its manifest keeps it.
703
+ */
704
+ setPreference(preference: AppearancePreference): Promise<void>;
705
+ /**
706
+ * Follow the choice, not what it resolves to: a system flip under `'auto'`
707
+ * moves `lx.app.appearance.watch` and leaves this quiet. Starts with the
708
+ * current value; that first callback runs synchronously, before
709
+ * `watchPreference` returns.
710
+ */
711
+ watchPreference(callback: (preference: AppearancePreference) => void): () => void;
712
+ };
713
+
714
+ /**
715
+ * `lx.app.control.displayLanguage` — the preference behind that
716
+ * language, for the one surface that edits it.
717
+ */
718
+ export type ControlDisplayLanguageApi = {
719
+ /** What the user chose: `'auto'`, or a canonical BCP-47 tag. */
720
+ getPreference(): DisplayLanguagePreference;
721
+ /** Persist the product's language. Rejects a tag that is not valid BCP-47. */
722
+ setPreference(preference: DisplayLanguagePreference): Promise<void>;
723
+ /**
724
+ * Follow the choice, not what it resolves to: a system locale change under
725
+ * `'auto'` moves the language without moving the preference. Starts with
726
+ * the current value and returns an unsubscribe; that first callback runs
727
+ * synchronously, before `watchPreference` returns.
728
+ */
729
+ watchPreference(callback: (preference: DisplayLanguagePreference) => void): () => void;
730
+ };
731
+
525
732
  /** A surface declared by the host in `lingxia.yaml`. */
526
733
  export type DeclaredSurface = SurfaceBase & SurfaceShowable & {
527
734
  readonly kind: 'declared';
@@ -534,8 +741,34 @@ export type DeviceOrientationChangeEvent = {
534
741
  value: DeviceOrientation;
535
742
  };
536
743
 
537
- /** Host display-language setting. `"auto"` follows the system locale. */
538
- export type DisplayLanguageSetting = 'auto' | 'en-US' | 'zh-CN';
744
+ /** `lx.app.displayLanguage` — the language this lxapp renders in. */
745
+ export type DisplayLanguageApi = {
746
+ /**
747
+ * The language in effect right now, as a canonical BCP-47 tag. Map it to
748
+ * the catalogs this lxapp actually ships and fall back where it has none;
749
+ * that narrowing is yours, and is not a language setting of its own.
750
+ */
751
+ get(): string;
752
+ /**
753
+ * Follow the language, starting with the current value. Returns an
754
+ * unsubscribe.
755
+ *
756
+ * Logic needs this because the strings it hands to native chrome —
757
+ * navigation bar titles, tab bar labels, modal and action-sheet text — are
758
+ * the app's own, and nothing re-renders them on its behalf.
759
+ *
760
+ * The first callback runs synchronously, before `watch` returns, so the
761
+ * unsubscribe is not yet bound inside it.
762
+ */
763
+ watch(callback: (language: string) => void): () => void;
764
+ };
765
+
766
+ /**
767
+ * What the product's language is set to: `'auto'` follows the system,
768
+ * or any canonical BCP-47 tag. `string & {}` keeps `'auto'` in
769
+ * autocomplete while still accepting a tag.
770
+ */
771
+ export type DisplayLanguagePreference = 'auto' | (string & {});
539
772
 
540
773
  export type DownloadDestination = 'app' | 'downloads';
541
774
 
@@ -573,6 +806,13 @@ export type DownloadsDownloadResult = {
573
806
  size: number;
574
807
  };
575
808
 
809
+ /**
810
+ * Configured page name belonging to *another* lxapp. This app's own
811
+ * page union cannot check it, so it stays a plain string and the
812
+ * target runtime rejects a name it does not have.
813
+ */
814
+ export type ExternalPageName = string;
815
+
576
816
  export type ExtractVideoThumbnailOptions = {
577
817
  /**
578
818
  * Source video path or `lx://` URI.
@@ -682,15 +922,17 @@ export type GetVideoInfoOptions = {
682
922
  export type HostAppApi = globalThis.HostAppApi;
683
923
 
684
924
  /**
685
- * Build-time environment version of the host app.
686
- * Surfaced via {@link HostAppApi.envVersion}. Mirrors the
687
- * `crates/lingxia-update::ReleaseType` enum and the `envVersion` field in the
688
- * generated `app.json`. Pre-envVersion app artifacts are treated as `'release'`.
689
- * Note: this is *separate* from `LxAppEnvVersion` in the navigator module,
690
- * which encodes lxapp release channels for cross-app navigation URLs —
691
- * same three names, different axis.
925
+ * Build-time deployment environment of the host app (`dev` | `prod`).
926
+ * Surfaced via {@link HostAppApi.env}. Taken from the `env` field in
927
+ * the generated `app.json`. Missing `env` is treated as `'prod'`.
928
+ * This is the host build axis: which server, package-id suffix, publish
929
+ * token, and self-update endpoint the host uses. It is **not** the
930
+ * lxapp publish channel (`LxAppEnvVersion` / `LxAppReleaseType`:
931
+ * `'release' | 'draft'`). Default channel is derived
932
+ * from env (`dev` → `draft`, `prod` → `release`) and can be
933
+ * overridden when opening an lxapp.
692
934
  */
693
- export type HostAppEnvVersion = 'developer' | 'preview' | 'release';
935
+ export type HostAppEnv = 'dev' | 'prod';
694
936
 
695
937
  export type HostAppUpdateApplyStage = 'download' | 'install';
696
938
 
@@ -752,6 +994,12 @@ export type HostAppUpdateTask = PromiseLike<HostAppUpdateResult> & AsyncIterable
752
994
  wait(): Promise<HostAppUpdateResult>;
753
995
  };
754
996
 
997
+ /**
998
+ * Canonical platform-family label shared by `lx.app.getBaseInfo().os`
999
+ * and `lx.getDeviceInfo().osName`. `"unknown"` is a non-product build.
1000
+ */
1001
+ export type HostOs = 'iOS' | 'macOS' | 'Android' | 'Windows' | 'Harmony' | 'unknown';
1002
+
755
1003
  export type InstalledTerminalFont = {
756
1004
  family: string;
757
1005
  monospace: boolean;
@@ -777,13 +1025,13 @@ export type KeyEvent = {
777
1025
 
778
1026
  export type KeyEventCallback = (event: KeyEvent) => void;
779
1027
 
780
- export type LxAppEnvVersion = 'release' | 'preview' | 'developer';
1028
+ export type LxAppEnvVersion = 'release' | 'draft';
781
1029
 
782
1030
  /** LxApp metadata APIs. */
783
- export type LxAppReleaseType = 'release' | 'preview' | 'developer';
1031
+ export type LxAppReleaseType = 'release' | 'draft';
784
1032
 
785
1033
  /** Boolean capability names accepted by `lx.supports`. */
786
- export type LxCapabilityFlag = 'terminal' | 'autostart' | 'notifications' | 'browser' | 'proxy' | 'selfUpdate' | 'process' | 'appUse' | 'computerUse' | 'browserUse' | 'mediaCapture';
1034
+ export type LxCapabilityFlag = 'control' | 'terminal' | 'autostart' | 'notifications' | 'browser' | 'proxy' | 'selfUpdate' | 'process' | 'appUse' | 'computerUse' | 'browserUse' | 'mediaCapture';
787
1035
 
788
1036
  /**
789
1037
  * One capability question per call. The catalog is closed, so
@@ -866,9 +1114,13 @@ export type NavigateToAppOptions = {
866
1114
  * open the target app's initial page. Full routes such as
867
1115
  * `/pages/home/index` are not supported.
868
1116
  */
869
- page?: string;
1117
+ page?: ExternalPageName;
870
1118
  query?: PageQuery;
871
- envVersion?: LxAppEnvVersion;
1119
+ /**
1120
+ * Lxapp publish channel. Defaults from the host env
1121
+ * (`dev` → `draft`, `prod` → `release`).
1122
+ */
1123
+ channel?: LxAppEnvVersion;
872
1124
  targetVersion?: string;
873
1125
  };
874
1126
 
@@ -953,7 +1205,7 @@ export type OpenPageShared = {
953
1205
  */
954
1206
  size?: OverlaySurfaceSize;
955
1207
  interaction?: SurfaceInteraction;
956
- query?: Record<string, unknown>;
1208
+ query?: PageQuery;
957
1209
  /** Caller-owned identity, for `lx.surface.get(key)` later. */
958
1210
  key?: string;
959
1211
  };
@@ -1011,7 +1263,7 @@ export type PageSurface = SurfaceBase & SurfaceShowable & SurfaceMessaging & {
1011
1263
  */
1012
1264
  export type PageTargetOptions = {
1013
1265
  /** Configured page name from `lingxia.yaml` / `lxapp.json`. */
1014
- page: string;
1266
+ page: ConfiguredPageName;
1015
1267
  query?: PageQuery;
1016
1268
  };
1017
1269
 
@@ -1149,7 +1401,11 @@ export type PreviewMediaSingleOptions = PreviewMediaSource & {
1149
1401
  export type PreviewMediaSource = {
1150
1402
  /**
1151
1403
  * Media source path.
1152
- * Recommended: `lx://` path (for example `lx://usercache/...`) or a sandbox-local path
1404
+ *
1405
+ * Accepts an `https://` (or `http://`) URL for a remote image or video —
1406
+ * the host loads it directly, so no prior `lx.downloadFile` is required,
1407
+ * and its domain must be permitted by the app's network policy — an
1408
+ * `lx://` path (for example `lx://usercache/...`), or a sandbox-local path
1153
1409
  * that can be resolved by runtime access rules.
1154
1410
  */
1155
1411
  path: string;
@@ -1289,8 +1545,8 @@ export type ShareTitleOptions = {
1289
1545
  };
1290
1546
 
1291
1547
  /**
1292
- * App-owned host-shell chrome. Mutations are available only to the home
1293
- * lxapp's Logic context; other lxapps receive a permission error.
1548
+ * App-owned host-shell chrome. Mutations are available only to the
1549
+ * Control app's Logic context; other lxapps receive a permission error.
1294
1550
  */
1295
1551
  export type ShellApi = {
1296
1552
  /**
@@ -1301,7 +1557,7 @@ export type ShellApi = {
1301
1557
  sidebarActions: ShellSidebarActionsApi;
1302
1558
  /** Compose another lxapp into a shell slot. */
1303
1559
  openApp(appId: string, options: ShellOpenAppOptions): Promise<AppSurface>;
1304
- /** Open a host builtin page such as settings or downloads. */
1560
+ /** Open a host builtin page such as downloads. */
1305
1561
  openBuiltin(page: BuiltinShellPage): Promise<BuiltinSurface>;
1306
1562
  /**
1307
1563
  * Open a declared surface with shell privileges — the same declaration
@@ -1322,17 +1578,20 @@ export type ShellOpenAppOptions = {
1322
1578
  * Configured page name from the target lxapp's `lxapp.json`. Omit it to
1323
1579
  * open that app's initial page. Full page routes are not supported.
1324
1580
  */
1325
- page?: string;
1581
+ page?: ExternalPageName;
1326
1582
  query?: PageQuery;
1327
- /** Defaults to 'release'. */
1328
- envVersion?: LxAppEnvVersion;
1583
+ /**
1584
+ * Lxapp publish channel. Defaults from the host env
1585
+ * (`dev` → `draft`, `prod` → `release`).
1586
+ */
1587
+ channel?: LxAppEnvVersion;
1329
1588
  targetVersion?: string;
1330
1589
  /** Stable identity for `lx.surface.get(key)`. */
1331
1590
  key?: string;
1332
1591
  };
1333
1592
 
1334
1593
  /**
1335
- * The declared-surface options only the home lxapp may use.
1594
+ * The declared-surface options only the native-assigned Control app may use.
1336
1595
  * Creating an extra instance and overriding a placement both mutate
1337
1596
  * shared shell composition, so they live here and not on
1338
1597
  * `lx.surface.openDeclared` — which consumes a declaration exactly as
@@ -1431,7 +1690,7 @@ export type ShellSidebarActionUpdate = {
1431
1690
  };
1432
1691
 
1433
1692
  /**
1434
- * Role and edge overrides the home lxapp may apply to a live declared
1693
+ * Role and edge overrides the native-assigned Control app may apply to a live declared
1435
1694
  * surface. A stable root rejects non-main roles.
1436
1695
  */
1437
1696
  export type ShellSurfacePatch = {
@@ -1479,6 +1738,12 @@ export type Storage = {
1479
1738
  */
1480
1739
  get<T = unknown>(key: string): Promise<T | undefined>;
1481
1740
  set(key: string, value: unknown): Promise<void>;
1741
+ /**
1742
+ * Resolves whether an exact key exists, without reading its value. Prefer
1743
+ * it over comparing `get` against `undefined`: presence is a key lookup,
1744
+ * while `get` also reads and deserializes the stored value.
1745
+ */
1746
+ has(key: string): Promise<boolean>;
1482
1747
  delete(key: string): Promise<void>;
1483
1748
  clear(): Promise<void>;
1484
1749
  /** Resolves every key, optionally filtered by prefix. */
@@ -1506,7 +1771,7 @@ export type StreamSourceOptions = {
1506
1771
  */
1507
1772
  export type SurfaceApi = {
1508
1773
  /** Open one of this lxapp's own pages as a float or a window. */
1509
- openPage(page: string, options?: OpenPageOptions): Promise<PageSurface>;
1774
+ openPage(page: ConfiguredPageName, options?: OpenPageOptions): Promise<PageSurface>;
1510
1775
  /** Open external content in the in-app browser. */
1511
1776
  openUrl(url: string, options?: OpenUrlOptions): Promise<TabSurface>;
1512
1777
  /**
@@ -1618,7 +1883,7 @@ export type SurfaceError = Error & {
1618
1883
  */
1619
1884
  export type SurfaceErrorCode = /** The placement cannot be realized by this host build. */
1620
1885
  'unsupported_placement'
1621
- /** A privileged operation was called by an lxapp other than the home lxapp. */
1886
+ /** A privileged operation was called by an lxapp other than the native-assigned Control app. */
1622
1887
  | 'denied'
1623
1888
  /** No such declared surface, lxapp, or builtin page. */
1624
1889
  | 'not_declared'
@@ -1861,8 +2126,7 @@ export type TerminalSettingsSnapshot = {
1861
2126
  /** Resolved configuration after all valid layers. */
1862
2127
  value: TerminalSettingsValue;
1863
2128
  effective: {
1864
- /** Host appearance before applying terminal.theme.mode. */
1865
- systemAppearance: 'light' | 'dark';
2129
+ /** The scheme the product is in, and therefore the terminal too. */
1866
2130
  appearance: 'light' | 'dark';
1867
2131
  colorScheme: string | null;
1868
2132
  font: {
@@ -1884,10 +2148,11 @@ export type TerminalSettingsWarning = {
1884
2148
  message: string;
1885
2149
  };
1886
2150
 
1887
- export type TerminalThemeMode = 'system' | 'light' | 'dark';
1888
-
2151
+ /**
2152
+ * A light scheme and a dark one. Which is in use follows the
2153
+ * product's light/dark setting; the terminal has no switch of its own.
2154
+ */
1889
2155
  export type TerminalThemeSettings = {
1890
- mode: TerminalThemeMode;
1891
2156
  light: string;
1892
2157
  dark: string;
1893
2158
  };
@@ -1921,7 +2186,7 @@ export type UpdateFailedInfo = UpdateReadyInfo & {
1921
2186
 
1922
2187
  /**
1923
2188
  * Callback-based updates for this lxapp's bundle. Available to every
1924
- * lxapp. To update the native host app, the home lxapp uses the
2189
+ * lxapp. To update the native host app, the Control app uses the
1925
2190
  * task-based `lx.app.checkUpdate()` API instead.
1926
2191
  */
1927
2192
  export type UpdateManager = {
@@ -1935,7 +2200,7 @@ export type UpdateManager = {
1935
2200
  export type UpdateReadyInfo = {
1936
2201
  version?: string;
1937
2202
  isForceUpdate?: boolean;
1938
- channel?: "release" | "preview" | "developer" | string;
2203
+ channel?: "release" | "draft" | string;
1939
2204
  };
1940
2205
 
1941
2206
  export type UploadIteratorResult = {
@@ -2168,40 +2433,28 @@ export type WindowsTerminalInlineImageStatus = {
2168
2433
  };
2169
2434
  };
2170
2435
 
2171
- /** Host app base information. */
2436
+ /**
2437
+ * Host app identity. Everything here is fixed for the life of the process;
2438
+ * the language the app renders in is not, and lives on
2439
+ * `lx.app.displayLanguage`.
2440
+ */
2172
2441
  export interface AppBaseInfo {
2173
- /**
2174
- * Raw system locale, unaffected by a saved in-app language override.
2175
- * For the language the UI should actually render in, use
2176
- * `display_language` instead.
2177
- */
2178
- locale: string;
2179
- /**
2180
- * Effective display language: a saved user override when set, else
2181
- * `locale`. This is what native chrome and `lx.*` i18n strings follow.
2182
- */
2183
- displayLanguage: string;
2184
2442
  /**
2185
2443
  * Platform family: `"iOS"` / `"macOS"` / `"Android"` / `"Windows"` /
2186
2444
  * `"Harmony"`. Matches the View-side `usePlatform().os` value.
2187
2445
  */
2188
- os: string;
2446
+ os: HostOs;
2189
2447
  productName: string;
2190
2448
  version: string;
2191
2449
  SDKVersion: string;
2192
2450
  }
2193
2451
 
2194
- export interface AppearanceState {
2195
- preference: AppearancePreference;
2196
- resolved: ResolvedAppearance;
2197
- }
2198
-
2199
2452
  /** Device info APIs. */
2200
2453
  export interface DeviceInfo {
2201
2454
  brand: string;
2202
2455
  model: string;
2203
2456
  marketName: string;
2204
- osName: string;
2457
+ osName: HostOs;
2205
2458
  osVersion: string;
2206
2459
  }
2207
2460
 
@@ -2244,7 +2497,7 @@ export interface LxAppInfo {
2244
2497
  appId: string;
2245
2498
  appName: string;
2246
2499
  version: string;
2247
- releaseType: LxAppReleaseType;
2500
+ channel: LxAppReleaseType;
2248
2501
  }
2249
2502
 
2250
2503
  export interface ScreenInfo {
@@ -2282,41 +2535,6 @@ export declare class DirEntry {
2282
2535
  readonly isSymlink: boolean;
2283
2536
  }
2284
2537
 
2285
- export declare class JSMessagePort {
2286
- constructor();
2287
- static postMessage(payload: any): void;
2288
- static onMessage(handler: (...args: any[]) => any): (...args: any[]) => any;
2289
- }
2290
-
2291
- export declare class JSSurface {
2292
- constructor();
2293
- close(): Promise<void>;
2294
- postMessage(payload: any): void;
2295
- onMessage(handler: (...args: any[]) => any): (...args: any[]) => any;
2296
- static onClose(handler: (...args: any[]) => any): (...args: any[]) => any;
2297
- }
2298
-
2299
- export declare class JSUpdateManager {
2300
- constructor();
2301
- /** Apply update by restarting the app */
2302
- applyUpdate(): void;
2303
- /** Subscribes to a ready update and returns the unsubscribe fn. */
2304
- onUpdateReady(cb: (...args: any[]) => any): (...args: any[]) => any;
2305
- /** Subscribes to a failed update and returns the unsubscribe fn. */
2306
- onUpdateFailed(cb: (...args: any[]) => any): (...args: any[]) => any;
2307
- }
2308
-
2309
- export declare class JSVideoContext {
2310
- constructor();
2311
- play(): void;
2312
- pause(): void;
2313
- stop(): void;
2314
- seek(position: number): void;
2315
- requestFullScreen(): void;
2316
- exitFullScreen(): void;
2317
- setStreamSource(options: StreamSourceOptions): void;
2318
- }
2319
-
2320
2538
  export declare class LxFile {
2321
2539
  private constructor();
2322
2540
  /** The path supplied to `lx.fs.file`. */
@@ -2342,15 +2560,6 @@ export declare class LxFile {
2342
2560
  stat(): Promise<FileStats>;
2343
2561
  }
2344
2562
 
2345
- declare global {
2346
- interface AppearanceApi {
2347
- /** Read the appearance preference and the light/dark value it resolves to. */
2348
- get(): AppearanceState;
2349
- /** Set the appearance preference to `auto`, `light`, or `dark`. */
2350
- set(preference: AppearancePreference): Promise<void>;
2351
- }
2352
- }
2353
-
2354
2563
  declare global {
2355
2564
  interface FileSystemApi {
2356
2565
  /**
@@ -2386,33 +2595,27 @@ declare global {
2386
2595
  * is what the user sees of the whole app — host-drawn navigation chrome,
2387
2596
  * native overlays, and every composited WebView, not just this lxapp's web
2388
2597
  * content. Because that view can include other lxapps' UI, the API is
2389
- * restricted to the home lxapp, like the other host-level APIs on `lx.app`.
2598
+ * restricted to the Control app, like the other host-level APIs on `lx.app`.
2390
2599
  */
2391
2600
  screenshot(options?: AppScreenshotOptions): Promise<AppScreenshotResult>;
2392
2601
  /**
2393
2602
  * Check whether the host app has an update.
2394
- * This host-level capability is restricted to the home lxapp. Calling it opts
2603
+ * This host-level capability is restricted to the Control app. Calling it opts
2395
2604
  * the process into custom update handling. Incompatible updates are hidden as
2396
2605
  * `hasUpdate: false`; platforms that cannot apply a package may still return
2397
2606
  * metadata and reject when `update.apply()` is invoked.
2398
2607
  */
2399
2608
  checkUpdate(): Promise<HostAppUpdateCheckResult>;
2400
- readonly envVersion: HostAppEnvVersion;
2609
+ readonly env: HostAppEnv;
2401
2610
  /**
2402
- * Read the host app's identity: locale, display language, OS, product name,
2403
- * product version, and SDK runtime version.
2611
+ * Read the host app's identity: OS, product name, product version, and SDK
2612
+ * runtime version.
2404
2613
  */
2405
2614
  getBaseInfo(): AppBaseInfo;
2406
- /**
2407
- * Follow the host's effective display language.
2408
- * `getBaseInfo().displayLanguage` answers what it is now; this answers when it
2409
- * changes. Logic needs both because the strings it hands to native chrome —
2410
- * navigation bar titles, tab bar labels, modal and action-sheet text — are the
2411
- * app's own, and nothing re-renders them on its behalf.
2412
- */
2413
- onDisplayLanguageChange(callback: (language: string) => void): () => void;
2414
2615
  /**
2415
2616
  * Exit the host app immediately without a confirmation dialog.
2617
+ * Control app only: quitting the product is not an lxapp's decision. Other
2618
+ * lxapps get a permission error.
2416
2619
  * If the user should confirm first, call `lx.showModal(...)` and invoke this
2417
2620
  * only after confirmation.
2418
2621
  */
@@ -2420,16 +2623,11 @@ declare global {
2420
2623
  /**
2421
2624
  * Set the app-icon badge, for example an unread count.
2422
2625
  * This targets the dock on macOS, taskbar on Windows, and home/launcher icon
2423
- * on mobile. Null or an empty string clears it. Unsupported platforms treat
2424
- * the call as a no-op.
2626
+ * on mobile — the product's own icon, not the calling lxapp's, so it is
2627
+ * Control app only and other lxapps get a permission error. Null or an empty
2628
+ * string clears it. Unsupported platforms treat the call as a no-op.
2425
2629
  */
2426
2630
  setBadge(value: string | number | null): void;
2427
- /**
2428
- * Set the host display language. `"auto"` follows the system locale;
2429
- * `"en-US"` and `"zh-CN"` pin the product. Every lxapp inherits the resolved
2430
- * tag from `getBaseInfo().displayLanguage`. Restricted to the home lxapp.
2431
- */
2432
- setDisplayLanguage(language: DisplayLanguageSetting): void;
2433
2631
  }
2434
2632
  }
2435
2633
 
@@ -2524,7 +2722,7 @@ declare global {
2524
2722
  onKeyUp(callback: KeyEventCallback): () => void;
2525
2723
  /** Get location function */
2526
2724
  getLocation(options?: GetLocationOptions): Promise<LocationInfo>;
2527
- /** Identify the running lxapp: its id, display name, version, and release type. */
2725
+ /** Identify the running lxapp: its id, display name, version, and channel. */
2528
2726
  getLxAppInfo(): LxAppInfo;
2529
2727
  /** Read an image's dimensions, type, and orientation without decoding it into a view. */
2530
2728
  getImageInfo(options: GetImageInfoOptions): Promise<ImageInfo>;
@@ -2619,7 +2817,6 @@ declare global {
2619
2817
  * an invalid selection.
2620
2818
  */
2621
2819
  showActionSheet(options: ShowActionSheetOptions): Promise<ActionSheetResult>;
2622
- readonly appearance: AppearanceApi;
2623
2820
  /**
2624
2821
  * Shows a confirmation modal.
2625
2822
  * Resolves `{ canceled: false }` when the user confirms and `{ canceled: true }`
@@ -2686,7 +2883,7 @@ declare global {
2686
2883
  readonly tray: TrayApi;
2687
2884
  /**
2688
2885
  * Return the callback-based update manager for this lxapp's bundle. This is
2689
- * available to every lxapp and is distinct from the home-only
2886
+ * available to every lxapp and is distinct from the Control-app-only
2690
2887
  * `lx.app.checkUpdate()`, which updates the native host app.
2691
2888
  */
2692
2889
  getUpdateManager(): UpdateManager;
@@ -2711,18 +2908,19 @@ declare global {
2711
2908
  interface ShellApi {
2712
2909
  /**
2713
2910
  * `lx.shell.openApp(appId, options)` — compose another lxapp into a shell
2714
- * slot. Home-lxapp only; the namespace is the privilege.
2911
+ * slot. Control-app only; the namespace is the privilege.
2715
2912
  */
2716
2913
  openApp(appId: string, options: ShellOpenAppOptions): Promise<AppSurface>;
2717
- /** `lx.shell.openBuiltin(page)` — a host builtin page. Home-lxapp only. */
2914
+ /** `lx.shell.openBuiltin(page)` — a host builtin page. Control-app only. */
2718
2915
  openBuiltin(page: BuiltinShellPage): Promise<BuiltinSurface>;
2719
2916
  /**
2720
2917
  * `lx.shell.openDeclared(id, options?)` — the declared surface, plus the
2721
- * keyed multi-instance form and placement overrides. Home-lxapp only.
2918
+ * keyed multi-instance form and placement overrides. Control-app only.
2722
2919
  */
2723
2920
  openDeclared(id: string, options?: ShellOpenDeclaredOptions): Promise<DeclaredSurface>;
2724
2921
  /** `lx.shell.reconfigure(id, patch)` — re-place a live declared surface. */
2725
2922
  reconfigure(id: string, patch: ShellSurfacePatch): Promise<void>;
2923
+ readonly sidebarActions: ShellSidebarActionsApi;
2726
2924
  }
2727
2925
  }
2728
2926
 
@@ -2730,9 +2928,9 @@ declare global {
2730
2928
  interface ShellSidebarActionsApi {
2731
2929
  /**
2732
2930
  * Atomically replaces the complete desktop sidebar action declaration. Only the
2733
- * home lxapp may call this API. Ids must be non-empty and unique across both
2931
+ * Control app may call this API. Ids must be non-empty and unique across both
2734
2932
  * placements; header accepts at most two entries. Icons must be bundled relative
2735
- * paths or runtime-managed `lx://` paths accessible to the home lxapp.
2933
+ * paths or runtime-managed `lx://` paths accessible to the Control app.
2736
2934
  * Every entry is bound to its generation-scoped callback. The shell invokes that
2737
2935
  * callback but never infers navigation or selected state. Validation or host
2738
2936
  * projection failure leaves the previous generation active. `replace([])` clears
@@ -2742,21 +2940,21 @@ declare global {
2742
2940
  replace(items: ShellSidebarAction[]): void;
2743
2941
  /**
2744
2942
  * Atomically updates the icon, label, and/or disabled state of one stable id.
2745
- * Only the home lxapp may call this API. The patch must be non-empty; unknown
2943
+ * Only the Control app may call this API. The patch must be non-empty; unknown
2746
2944
  * fields are rejected. The callback and placement stay unchanged. Throws
2747
2945
  * `E_NOT_FOUND` when `id` is not in the current declaration.
2748
2946
  */
2749
2947
  update(id: string, patch: ShellSidebarActionUpdate): void;
2750
2948
  /**
2751
2949
  * Atomically removes one stable id and its generation-scoped callback. Only the
2752
- * home lxapp may call this API. Throws `E_NOT_FOUND` when `id` is not in the
2950
+ * Control app may call this API. Throws `E_NOT_FOUND` when `id` is not in the
2753
2951
  * current declaration.
2754
2952
  */
2755
2953
  remove(id: string): void;
2756
2954
  /**
2757
- * Atomically clears every runtime sidebar action and callback. Only the home
2758
- * lxapp may call this API. Equivalent to `replace([])` and safe when already
2759
- * empty; the home lxapp must still redeclare actions after the next Logic launch.
2955
+ * Atomically clears every runtime sidebar action and callback. Only the
2956
+ * Control app may call this API. Equivalent to `replace([])` and safe when already
2957
+ * empty; the Control app must still redeclare actions after the next Logic launch.
2760
2958
  */
2761
2959
  clear(): void;
2762
2960
  }
@@ -2769,7 +2967,7 @@ declare global {
2769
2967
  * float or a window. A page can never be an aside: asides carry external
2770
2968
  * content only, which is why that member does not exist on this signature.
2771
2969
  */
2772
- openPage(page: string, options?: OpenPageOptions): Promise<PageSurface>;
2970
+ openPage(page: ConfiguredPageName, options?: OpenPageOptions): Promise<PageSurface>;
2773
2971
  /**
2774
2972
  * `lx.surface.openUrl(url, options?)` — external content in the in-app
2775
2973
  * browser, as a tab or docked as an aside.