@blotch/angular-lynx 22.2.5 → 22.2.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotch/angular-lynx",
3
- "version": "22.2.5",
3
+ "version": "22.2.7",
4
4
  "description": "Angular renderer for the Lynx cross-platform native UI framework",
5
5
  "homepage": "https://github.com/Blotch-Smart-Frames/AngularLynx#readme",
6
6
  "bugs": {
@@ -5,6 +5,7 @@ const dependency_1 = require("@schematics/angular/utility/dependency");
5
5
  const json_file_1 = require("@schematics/angular/utility/json-file");
6
6
  const workspace_1 = require("@schematics/angular/utility/workspace");
7
7
  const dev_logs_gitignore_1 = require("../utility/dev-logs-gitignore");
8
+ const pnpm_builds_1 = require("../utility/pnpm-builds");
8
9
  const tailwind_1 = require("../utility/tailwind");
9
10
  const extract_i18n_target_1 = require("../utility/extract-i18n-target");
10
11
  const versions_1 = require("./versions");
@@ -14,9 +15,11 @@ const versions_1 = require("./versions");
14
15
  * app.component.ts) with Lynx equivalents, points `ng build`, `ng serve`,
15
16
  * `ng test` and `ng extract-i18n` at the AngularLynx builders and
16
17
  * `ng generate` at its schematics, git-ignores the `.dev-logs` file that
17
- * `ng serve` writes `LynxLogger`'s output to, and optionally sets up Tailwind
18
- * CSS (4, or 3 with the Lynx preset). Everything else stays as `ng new` left
19
- * it: the app needs no build config besides angular.json.
18
+ * `ng serve` writes `LynxLogger`'s output to, denies the install scripts of
19
+ * Angular's build tools in a pnpm app (which current pnpm fails installs
20
+ * over), and optionally sets up Tailwind CSS (4, or 3 with the Lynx preset).
21
+ * Everything else stays as `ng new` left it: the app needs no build config
22
+ * besides angular.json.
20
23
  * This is a one-shot destructive transform — the old browser-Angular files
21
24
  * are deleted because they reference DOM APIs and HTML elements that don't
22
25
  * exist on the Lynx runtime.
@@ -54,6 +57,7 @@ exports.default = (options) => async (tree) => {
54
57
  useLynxSchematics(),
55
58
  updatePackageScripts(),
56
59
  (0, dev_logs_gitignore_1.ignoreDevLogs)(),
60
+ (0, pnpm_builds_1.denyAngularBuildScripts)(),
57
61
  addCoreDependencies(),
58
62
  ];
59
63
  // `"false"` is how `ng add ... --tailwind=false` arrives (see schema.ts).
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.denyAngularBuildScripts = exports.withAngularBuildsDenied = void 0;
4
+ const workspace_1 = require("@schematics/angular/utility/workspace");
5
+ const node_child_process_1 = require("node:child_process");
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
8
+ /**
9
+ * The dependencies of a new Angular app that have install scripts: Angular's
10
+ * build tools. `esbuild` and `@parcel/watcher` are `@angular/build`'s,
11
+ * `lmdb` is an optional one of it, and `msgpackr-extract` comes with `lmdb`.
12
+ *
13
+ * None of the scripts has anything to do. Each package gets its native binary
14
+ * from a prebuilt package for the platform, one of its optional dependencies.
15
+ * esbuild's script only checks that binary; @parcel/watcher's builds one from
16
+ * source only when asked to, and lmdb's and msgpackr-extract's only when no
17
+ * prebuilt one fits. Angular's own pnpm workspace denies all four.
18
+ */
19
+ const ANGULAR_BUILD_SCRIPTS = [
20
+ '@parcel/watcher',
21
+ 'esbuild',
22
+ 'lmdb',
23
+ 'msgpackr-extract',
24
+ ];
25
+ const WORKSPACE_FILE = '/pnpm-workspace.yaml';
26
+ /**
27
+ * The value pnpm writes for a dependency whose build it's waiting for someone
28
+ * to allow or deny. It denies the build, but still fails the install.
29
+ */
30
+ const UNDECIDED = /^(['"]?)set this to true or false\1$/;
31
+ /**
32
+ * `@parcel/watcher` needs quotes in YAML, since `@` can't start a plain key.
33
+ */
34
+ const yamlKey = (name) => (name.startsWith('@') ? `'${name}'` : name);
35
+ /**
36
+ * The `allowBuilds` entries this sets, indented by `indent`.
37
+ */
38
+ const entries = (names, indent) => names.map((name) => `${indent}${yamlKey(name)}: false`);
39
+ /**
40
+ * What a pnpm-workspace.yaml without `allowBuilds` gets, with a comment that
41
+ * says why it's there.
42
+ */
43
+ const ALLOW_BUILDS_BLOCK = [
44
+ "# Angular's build tools come with their binaries prebuilt, so their install",
45
+ '# scripts have nothing to do. pnpm fails installs until each script is',
46
+ '# allowed (true) or denied (false).',
47
+ 'allowBuilds:',
48
+ ...entries(ANGULAR_BUILD_SCRIPTS, ' '),
49
+ ];
50
+ /** An `allowBuilds` key at the top level, in any style. */
51
+ const ALLOW_BUILDS_KEY = /^allowBuilds[ \t]*:/;
52
+ /** An `allowBuilds` key whose entries follow on their own lines. */
53
+ const ALLOW_BUILDS_BLOCK_KEY = /^allowBuilds[ \t]*:[ \t]*(#.*)?$/;
54
+ /** One entry of a block mapping: its indent, quote, key and value. */
55
+ const ENTRY = /^([ \t]+)(['"]?)([^'"\s#][^'":#]*?)\2[ \t]*:[ \t]*(.*?)[ \t]*$/;
56
+ /**
57
+ * pnpm-workspace.yaml's text with Angular's build scripts denied in
58
+ * `allowBuilds`. Entries the app already decided on stay; ones pnpm left
59
+ * undecided become `false`. Undefined when `allowBuilds` is written in a
60
+ * style this doesn't edit, such as `allowBuilds: { esbuild: true }`.
61
+ */
62
+ const withAngularBuildsDenied = (text) => {
63
+ const eol = text.includes('\r\n') ? '\r\n' : '\n';
64
+ const lines = text.split(/\r?\n/);
65
+ const start = lines.findIndex((line) => ALLOW_BUILDS_KEY.test(line));
66
+ if (start === -1) {
67
+ // Keep a blank line between the app's settings and the new block.
68
+ const body = text.trimEnd();
69
+ return [...(body ? [body, ''] : []), ...ALLOW_BUILDS_BLOCK, ''].join(eol);
70
+ }
71
+ if (!ALLOW_BUILDS_BLOCK_KEY.test(lines[start])) {
72
+ return undefined;
73
+ }
74
+ // The block runs over the indented lines after the key; new entries go
75
+ // after its last one, with its indent.
76
+ let end = start + 1;
77
+ let indent = ' ';
78
+ const decided = new Set();
79
+ for (let index = start + 1; index < lines.length; index++) {
80
+ const line = lines[index];
81
+ if (line.trim() === '' || /^[ \t]+#/.test(line)) {
82
+ continue;
83
+ }
84
+ if (!/^[ \t]/.test(line)) {
85
+ break;
86
+ }
87
+ end = index + 1;
88
+ const match = ENTRY.exec(line);
89
+ if (!match) {
90
+ continue;
91
+ }
92
+ const [, entryIndent, quote, name, value] = match;
93
+ indent = entryIndent;
94
+ if (UNDECIDED.test(value)) {
95
+ lines[index] = `${entryIndent}${quote}${name}${quote}: false`;
96
+ }
97
+ decided.add(name);
98
+ }
99
+ const missing = ANGULAR_BUILD_SCRIPTS.filter((name) => !decided.has(name));
100
+ lines.splice(end, 0, ...entries(missing, indent));
101
+ return lines.join(eol);
102
+ };
103
+ exports.withAngularBuildsDenied = withAngularBuildsDenied;
104
+ /**
105
+ * The pnpm version in package.json's `packageManager` field (`pnpm@12.15.0`,
106
+ * maybe with a `+sha512...` hash), which `ng new --package-manager pnpm`
107
+ * writes. Undefined when the app uses pnpm at an unknown version; null when
108
+ * it uses another package manager.
109
+ */
110
+ const pnpmVersionOf = async (tree) => {
111
+ const { packageManager } = tree.exists('/package.json')
112
+ ? tree.readJson('/package.json')
113
+ : {};
114
+ if (typeof packageManager === 'string') {
115
+ const [name, version] = packageManager.split('@');
116
+ return name === 'pnpm' ? version : null;
117
+ }
118
+ // Without the field, the same signs Angular CLI goes by: angular.json's
119
+ // `cli.packageManager`, else the lockfile.
120
+ const workspace = await (0, workspace_1.getWorkspace)(tree);
121
+ const cli = workspace.extensions['cli'];
122
+ if (typeof cli?.packageManager === 'string') {
123
+ return cli.packageManager === 'pnpm' ? undefined : null;
124
+ }
125
+ return tree.exists('/pnpm-lock.yaml') || tree.exists(WORKSPACE_FILE)
126
+ ? undefined
127
+ : null;
128
+ };
129
+ /**
130
+ * The version `pnpm --version` prints here, the way Angular's own workspace
131
+ * schematic reads it for `packageManager`. Undefined when pnpm doesn't run.
132
+ */
133
+ const installedPnpmVersion = () => {
134
+ try {
135
+ return (0, node_child_process_1.execSync)('pnpm --version', {
136
+ encoding: 'utf8',
137
+ stdio: ['ignore', 'pipe', 'ignore'],
138
+ }).trim();
139
+ }
140
+ catch {
141
+ return undefined;
142
+ }
143
+ };
144
+ /**
145
+ * Whether this pnpm reads `allowBuilds`, which it does from 10.26. Older
146
+ * pnpm doesn't fail an install over build scripts, and pnpm 9 and early
147
+ * pnpm 10 fail on a pnpm-workspace.yaml without `packages`, so they're better
148
+ * left without one.
149
+ */
150
+ const readsAllowBuilds = (version) => {
151
+ const [major = 0, minor = 0] = version.split('.').map(Number);
152
+ return major > 10 || (major === 10 && minor >= 26);
153
+ };
154
+ /**
155
+ * The pnpm-workspace.yaml of a pnpm workspace above this one, as when the
156
+ * app was made inside a monorepo. pnpm takes its settings from there, and a
157
+ * file of the app's own would split the app off into a workspace of its own.
158
+ */
159
+ const enclosingWorkspaceFile = () => {
160
+ for (let dir = process.cwd();; dir = (0, node_path_1.dirname)(dir)) {
161
+ const file = (0, node_path_1.join)(dir, 'pnpm-workspace.yaml');
162
+ if ((0, node_fs_1.existsSync)(file)) {
163
+ return file;
164
+ }
165
+ if ((0, node_path_1.dirname)(dir) === dir) {
166
+ return undefined;
167
+ }
168
+ }
169
+ };
170
+ /**
171
+ * Denies the install scripts of Angular's build tools in a pnpm app's
172
+ * pnpm-workspace.yaml, in `allowBuilds`.
173
+ *
174
+ * pnpm 11 and later fail `pnpm install` and `pnpm add` while any
175
+ * dependency's build script is neither allowed nor denied there
176
+ * (`strictDepBuilds`). `ng new` and `ng add` install with `--ignore-scripts`,
177
+ * so they pass, and the app's first `pnpm add` fails. pnpm 11 reads its
178
+ * settings only from pnpm-workspace.yaml, not package.json.
179
+ *
180
+ * Apps on npm, Yarn or bun, and on pnpm older than 10.26, are left alone.
181
+ */
182
+ const denyAngularBuildScripts = () => async (tree, context) => {
183
+ const pinned = await pnpmVersionOf(tree);
184
+ if (pinned === null) {
185
+ return;
186
+ }
187
+ const version = pinned ?? installedPnpmVersion();
188
+ if (version === undefined || !readsAllowBuilds(version)) {
189
+ return;
190
+ }
191
+ if (!tree.exists(WORKSPACE_FILE)) {
192
+ const enclosing = enclosingWorkspaceFile();
193
+ if (enclosing) {
194
+ context.logger.warn(`This app is in the pnpm workspace of ${enclosing}. Add this to it, or pnpm will fail installs over Angular's build scripts:\n${ALLOW_BUILDS_BLOCK.join('\n')}`);
195
+ return;
196
+ }
197
+ }
198
+ const text = tree.exists(WORKSPACE_FILE) ? tree.readText(WORKSPACE_FILE) : '';
199
+ const updated = (0, exports.withAngularBuildsDenied)(text);
200
+ if (updated === undefined) {
201
+ context.logger.warn(`pnpm-workspace.yaml's allowBuilds isn't a block mapping, so it was left as it is. Set these in it, or pnpm will fail installs over Angular's build scripts: ${ANGULAR_BUILD_SCRIPTS.map((name) => `${name}: false`).join(', ')}.`);
202
+ }
203
+ else if (!tree.exists(WORKSPACE_FILE)) {
204
+ tree.create(WORKSPACE_FILE, updated);
205
+ }
206
+ else if (updated !== text) {
207
+ tree.overwrite(WORKSPACE_FILE, updated);
208
+ }
209
+ };
210
+ exports.denyAngularBuildScripts = denyAngularBuildScripts;
@@ -850,7 +850,8 @@ export declare class LynxLocale {
850
850
  export declare const provideLocale: () => EnvironmentProviders;
851
851
  /**
852
852
  * Controls gesture state from within a callback.
853
- * Wraps __SetGestureState and __ConsumeGesture PAPI calls.
853
+ * Wraps the __SetGestureState and __ConsumeGesture PAPI calls (see
854
+ * gesture-papi.ts for Lynx for Web, which has neither).
854
855
  * Passed as the second argument to gesture callbacks so handlers can
855
856
  * programmatically drive the gesture state machine (e.g. activate a gesture
856
857
  * only when a condition is met, or fail it early to let a competing gesture win).
@@ -1096,7 +1097,8 @@ type AnyGesture = BaseGesture<any, any>;
1096
1097
  type GestureInput = AnyGesture | AnyGesture[] | ComposedGesture;
1097
1098
  /**
1098
1099
  * Directive that bridges Angular's gesture binding to Lynx's native gesture
1099
- * system (__SetGestureDetector / __RemoveGestureDetector). Accepts a single
1100
+ * system (__SetGestureDetector / __RemoveGestureDetector, or on Lynx for Web,
1101
+ * which has none, the runtime's port of it: see gesture-papi.ts). Accepts a single
1100
1102
  * gesture, an array of gestures, or a ComposedGesture (simultaneous/exclusive).
1101
1103
  * Each gesture is registered with the native engine via its unique numeric ID.
1102
1104
  *
@@ -4321,6 +4323,100 @@ export declare class LynxSessionStorage {
4321
4323
  static ɵfac: i0.ɵɵFactoryDeclaration<LynxSessionStorage, never>;
4322
4324
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
4323
4325
  }
4326
+ /**
4327
+ * What {@link LynxLocalStorage} and {@link LynxSecureStorage} share: a
4328
+ * key-value store of JSON values with an async API, kept by a native module
4329
+ * of the apps `ng build --platform` makes, by `localStorage` on the web, and
4330
+ * in memory elsewhere.
4331
+ */
4332
+ declare abstract class PersistentStorage {
4333
+ #private;
4334
+ /**
4335
+ * @param module - The native module's name in `NativeModules`.
4336
+ * @param webPrefix - What this store's keys start with in `localStorage`.
4337
+ */
4338
+ constructor(module: string, webPrefix: string);
4339
+ /**
4340
+ * Resolves with the value stored under `key`, or `null` if there's none.
4341
+ */
4342
+ getItem<T = unknown>(key: string): Promise<T | null>;
4343
+ /**
4344
+ * Stores `value` under `key`, as JSON: an object, an array, a string, a
4345
+ * number, a boolean or `null`. Resolves once it's stored.
4346
+ */
4347
+ setItem<T = unknown>(key: string, value: T): Promise<void>;
4348
+ /**
4349
+ * Removes the value stored under `key`, if there is one.
4350
+ */
4351
+ removeItem(key: string): Promise<void>;
4352
+ /**
4353
+ * Removes every value in this store.
4354
+ */
4355
+ clear(): Promise<void>;
4356
+ }
4357
+ /**
4358
+ * A key-value store that keeps its values after the app closes, like the
4359
+ * browser's `localStorage`. Values are JSON (objects, arrays, strings,
4360
+ * numbers, booleans) and every method returns a promise.
4361
+ *
4362
+ * - **iOS:** `UserDefaults`, in a suite of its own.
4363
+ * - **Android:** `SharedPreferences`, in a file of its own.
4364
+ * - **Web:** the page's `localStorage`, with each key starting with
4365
+ * `angular-lynx:`.
4366
+ *
4367
+ * For tokens and other secrets, use {@link LynxSecureStorage}.
4368
+ *
4369
+ * Only the apps `ng build --platform` makes have the native module behind
4370
+ * it, `AngularLynxLocalStorage`. Elsewhere, such as in Lynx Explorer and
4371
+ * tests, it keeps values in memory, so they last until the app closes.
4372
+ *
4373
+ * @usageNotes
4374
+ * ```typescript
4375
+ * const storage = inject(LynxLocalStorage);
4376
+ *
4377
+ * await storage.setItem('settings', { units: 'metric' });
4378
+ * const settings = await storage.getItem<Settings>('settings');
4379
+ * await storage.removeItem('settings');
4380
+ * ```
4381
+ */
4382
+ export declare class LynxLocalStorage extends PersistentStorage {
4383
+ constructor();
4384
+ static ɵfac: i0.ɵɵFactoryDeclaration<LynxLocalStorage, never>;
4385
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
4386
+ }
4387
+ /**
4388
+ * A key-value store for secrets such as tokens, which keeps its values after
4389
+ * the app closes, encrypted by the platform. It has the same methods as
4390
+ * {@link LynxLocalStorage}.
4391
+ *
4392
+ * - **iOS:** the Keychain, readable once the phone has been unlocked after it
4393
+ * starts, and never copied to another device. The Keychain keeps its items
4394
+ * when the app is deleted, so a reinstalled app finds them again.
4395
+ * - **Android:** `SharedPreferences`, each value encrypted with AES-GCM by a
4396
+ * key the Android Keystore holds. The file is left out of backups, which
4397
+ * can't take the key with them.
4398
+ * - **Web:** the page's `localStorage`, with each key starting with
4399
+ * `angular-lynx-secure:`. Browsers have no store for secrets, and web
4400
+ * sign-in libraries keep their tokens there too.
4401
+ *
4402
+ * Only the apps `ng build --platform` makes have the native module behind
4403
+ * it, `AngularLynxSecureStorage`. Elsewhere, such as in Lynx Explorer and
4404
+ * tests, it keeps values in memory, so they last until the app closes.
4405
+ *
4406
+ * @usageNotes
4407
+ * ```typescript
4408
+ * const storage = inject(LynxSecureStorage);
4409
+ *
4410
+ * await storage.setItem('session', session);
4411
+ * const session = await storage.getItem<Session>('session');
4412
+ * await storage.removeItem('session');
4413
+ * ```
4414
+ */
4415
+ export declare class LynxSecureStorage extends PersistentStorage {
4416
+ constructor();
4417
+ static ɵfac: i0.ɵɵFactoryDeclaration<LynxSecureStorage, never>;
4418
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
4419
+ }
4324
4420
  /**
4325
4421
  * Wraps the global `SystemInfo` object as an Angular injectable,
4326
4422
  * providing device and platform information from the Lynx runtime.
@@ -4629,6 +4725,75 @@ export declare class LynxTransitionGroup<T> {
4629
4725
  "afterLeave": "afterLeave";
4630
4726
  }, ["itemTemplate"], never, true, never>;
4631
4727
  }
4728
+ /**
4729
+ * Why a web authentication session gave no callback URL:
4730
+ * - `canceled`: the person closed the sheet, or declined to open it.
4731
+ * - `unavailable`: the host can't open one. Only the apps that
4732
+ * `ng build --platform` makes can; Lynx Explorer, the web preview and
4733
+ * tests can't.
4734
+ * - `failed`: the platform couldn't open the page, or a session was already
4735
+ * open.
4736
+ */
4737
+ type WebAuthSessionErrorCode = 'canceled' | 'unavailable' | 'failed';
4738
+ /** The error a {@link LynxWebAuthSession} rejects with. */
4739
+ export declare class WebAuthSessionError extends Error {
4740
+ readonly code: WebAuthSessionErrorCode;
4741
+ constructor(code: WebAuthSessionErrorCode, message: string);
4742
+ }
4743
+ /** What {@link LynxWebAuthSession.start} opens, and where it returns. */
4744
+ type WebAuthSessionOptions = {
4745
+ /** The page that starts the sign-in, such as a provider's authorize URL. */
4746
+ readonly url: string;
4747
+ /**
4748
+ * The URL scheme the page returns to, such as `myapp` for
4749
+ * `myapp://auth?code=…`. On Android it must also be one of the app's
4750
+ * `deepLinkSchemes`, so the redirect opens the app.
4751
+ */
4752
+ readonly callbackScheme: string;
4753
+ /**
4754
+ * Opens the page without the browser's cookies and keeps none it sets, so
4755
+ * the person signs in afresh and nothing stays signed in afterwards. iOS
4756
+ * only: Android's Custom Tabs share the browser's cookies.
4757
+ */
4758
+ readonly ephemeral?: boolean;
4759
+ };
4760
+ /**
4761
+ * Signs in through a web page, as OAuth and OpenID Connect providers need: it
4762
+ * opens the page in the platform's sign-in browser sheet, over the app, and
4763
+ * resolves with the URL the page redirects to on the app's own scheme. Read
4764
+ * the code or token from that URL.
4765
+ *
4766
+ * Lynx has no popups or redirects, so a web sign-in flow can't run inside
4767
+ * the app. The sheet is the platform's own: ASWebAuthenticationSession on
4768
+ * iOS, which asks before opening a site and shares Safari's sign-ins, and a
4769
+ * Custom Tab on Android, from which the redirect opens the app again.
4770
+ *
4771
+ * Only the apps `ng build --platform` makes have the native module behind
4772
+ * it. Elsewhere, such as Lynx Explorer, the web preview and tests, `start()`
4773
+ * rejects with `unavailable`.
4774
+ *
4775
+ * @usageNotes
4776
+ * ```typescript
4777
+ * const webAuth = inject(LynxWebAuthSession);
4778
+ *
4779
+ * const callback = await webAuth.start({
4780
+ * url: 'https://example.com/oauth/authorize?client_id=…&redirect_uri=myapp://auth',
4781
+ * callbackScheme: 'myapp',
4782
+ * });
4783
+ * const code = new URL(callback).searchParams.get('code');
4784
+ * ```
4785
+ */
4786
+ export declare class LynxWebAuthSession {
4787
+ #private;
4788
+ /**
4789
+ * Opens `url` in the sign-in sheet and resolves with the whole URL the page
4790
+ * redirects to on `callbackScheme`, query and fragment included. Rejects
4791
+ * with a {@link WebAuthSessionError}.
4792
+ */
4793
+ start({ url, callbackScheme, ephemeral }: WebAuthSessionOptions): Promise<string>;
4794
+ static ɵfac: i0.ɵɵFactoryDeclaration<LynxWebAuthSession, never>;
4795
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
4796
+ }
4632
4797
  /**
4633
4798
  * Central DI configuration for the Lynx renderer. Must be included in every
4634
4799
  * Lynx Angular app's providers (typically via app.config.ts). Sets up:
@@ -4639,6 +4804,44 @@ export declare class LynxTransitionGroup<T> {
4639
4804
  * 5. Error handler (routes to _ReportError + __lynxLastError)
4640
4805
  */
4641
4806
  export declare const provideRenderer: () => EnvironmentProviders;
4807
+ /**
4808
+ * The Lynx elements a component's host can be, besides the `<view>` every
4809
+ * host is by default.
4810
+ */
4811
+ type HostElementTag = 'view' | 'text' | 'image' | 'scroll-view' | 'svg' | 'blur-view';
4812
+ /**
4813
+ * Makes a component's host element a Lynx element other than `<view>`, such
4814
+ * as a `<text>`. Call it once, next to the component:
4815
+ *
4816
+ * ```ts
4817
+ * @Component({
4818
+ * selector: 'app-title',
4819
+ * host: { class: 'text-2xl font-semibold' },
4820
+ * template: '<ng-content />',
4821
+ * })
4822
+ * export class AppTitle {}
4823
+ *
4824
+ * registerHostElement(AppTitle, 'text');
4825
+ * ```
4826
+ *
4827
+ * Every host is a `<view>` otherwise, a real element between the parent and
4828
+ * the component's template. A component that shows text then needs a
4829
+ * `<text>` inside its host, and a class the app writes on the component
4830
+ * (`<app-title class="mb-2">`) lands on the host, which Angular gives every
4831
+ * static attribute, as well as on whatever element the component passes it
4832
+ * to: a margin there applies twice. With a `<text>` host, the component is
4833
+ * one element, the way a component's `<span>` or `<p>` would be on the web.
4834
+ *
4835
+ * The registration covers each element name in the selector, wherever a
4836
+ * template uses the component. Content projected into a `<text>` host follows
4837
+ * `<text>`'s rules: raw text, and nested `<text>` that runs inline.
4838
+ */
4839
+ export declare const registerHostElement: (component: Type<unknown>, element: HostElementTag) => void;
4840
+ /**
4841
+ * The Lynx element to create for a tag: the registered host element for a
4842
+ * component's tag, or the tag itself.
4843
+ */
4844
+ declare const hostElementOf: (tag: string) => string;
4642
4845
  /**
4643
4846
  * Keeps the app on the screen it was showing when a hot update re-bootstraps
4644
4847
  * it. Called with the old app's injector before it's destroyed, it saves the
@@ -4917,6 +5120,14 @@ declare const handlers: {
4917
5120
  * module proxies (relayedModule() below) send their calls here.
4918
5121
  */
4919
5122
  callModule: (kind: ModuleKind, name: string, method: string, args: unknown[]) => unknown;
5123
+ /**
5124
+ * Calls a native module method that answers through a callback, passed
5125
+ * after `args`, and resolves with the first value it passes back. Unlike a
5126
+ * function sent through callModule, the callback stays on this thread, so
5127
+ * the call leaves nothing registered on either thread: the storage
5128
+ * services make one of these per read and write.
5129
+ */
5130
+ callNativeModuleAsync: (name: string, method: string, args: unknown[]) => Promise<unknown>;
4920
5131
  registerJSModule: (name: string, module: unknown) => void;
4921
5132
  /**
4922
5133
  * The OS version, for LynxSystemInfo on the main thread: native Lynx builds
@@ -5068,4 +5279,4 @@ declare global {
5068
5279
  catchmouseleave: MouseEvent;
5069
5280
  }
5070
5281
  }
5071
- export type { AccessibilityTrait, AccessibilityTraitStates, BackgroundFnHandle, BaseLynxAnimation, BaseLynxElement, DataProcessorDefinition, DevToolsStats, DynamicColorRole, DynamicColorScheme, DynamicColors, ExposureEventDetail, FlingGestureEvent, GestureCallback, GestureCallbackWithState, GestureEvent, GlobalData, GlobalExposureEvent, InitData, InitDataRaw, LongPressGestureEvent, LynxAnimationOptions, LynxFontEntry, LynxFontFaceConfig, LynxFontStatus, LynxTraceOptions, MainThread, MainThreadFnHandle, NativeModuleMap, NativeModuleProxy, ObserverFrameRateOptions, PanGestureEvent, PinchGestureEvent, PortalConfig, PrefetchCacheTarget, PrefetchPriority, PrefetchRequest, PrefetchResultDetail, ResourcePrefetchData, ResourcePrefetchResult, RotationGestureEvent, SessionStorageSubscription, TapGestureEvent };
5282
+ export type { AccessibilityTrait, AccessibilityTraitStates, BackgroundFnHandle, BaseLynxAnimation, BaseLynxElement, DataProcessorDefinition, DevToolsStats, DynamicColorRole, DynamicColorScheme, DynamicColors, ExposureEventDetail, FlingGestureEvent, GestureCallback, GestureCallbackWithState, GestureEvent, GlobalData, GlobalExposureEvent, HostElementTag, InitData, InitDataRaw, LongPressGestureEvent, LynxAnimationOptions, LynxFontEntry, LynxFontFaceConfig, LynxFontStatus, LynxTraceOptions, MainThread, MainThreadFnHandle, NativeModuleMap, NativeModuleProxy, ObserverFrameRateOptions, PanGestureEvent, PinchGestureEvent, PortalConfig, PrefetchCacheTarget, PrefetchPriority, PrefetchRequest, PrefetchResultDetail, ResourcePrefetchData, ResourcePrefetchResult, RotationGestureEvent, SessionStorageSubscription, TapGestureEvent, WebAuthSessionErrorCode, WebAuthSessionOptions };