mithril-lynx 2.6.0 → 3.0.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.
- package/CHANGELOG.md +50 -0
- package/FETCH_INVESTIGATION.md +3 -2
- package/INPUT.md +115 -0
- package/LICENSE.txt +21 -0
- package/PLAN_REVIEW.md +134 -0
- package/README.md +47 -7
- package/REQUEST.md +5 -2
- package/ROUTE.md +111 -16
- package/ROUTE_CONTRACT_ANALYSIS.md +224 -0
- package/UPDATE_ANIMATION_GAP.md +133 -0
- package/informe-contrato-mithril-lynx.md +206 -0
- package/package.json +1 -9
- package/plugin.js +33 -0
- package/prompts-analisis-contrato-mithril-lynx.md +141 -0
- package/src/apply-patch.js +408 -68
- package/src/backends/virtual-backend.js +120 -22
- package/src/background.d.ts +40 -1
- package/src/background.js +116 -7
- package/src/channel.js +32 -7
- package/src/commit.js +9 -0
- package/src/dev-reload-client.js +46 -0
- package/src/dev-transport-noop.js +3 -0
- package/src/fake-dom.js +559 -61
- package/src/list-attributes.js +69 -0
- package/src/list-runtime.js +425 -0
- package/src/main-thread.js +33 -3
- package/src/mount-redraw.d.ts +10 -0
- package/src/mount-redraw.js +69 -3
- package/src/patch-protocol.js +52 -13
- package/src/reload/version.js +10 -1
- package/src/request.d.ts +2 -0
- package/src/request.js +59 -3
- package/src/route.d.ts +52 -5
- package/src/route.js +236 -59
- package/src/testing.d.ts +14 -1
- package/src/testing.js +79 -11
- package/test/event-render-coalescing.test.ts +117 -0
- package/test/gesture.test.ts +75 -0
- package/test/input.test.ts +388 -0
- package/test/list.test.ts +422 -100
- package/test/patch-protocol.test.ts +41 -0
- package/test/remove-event.test.ts +26 -0
- package/test/remove-subtree-cleanup.test.ts +75 -0
- package/test/route-hot-reload.test.ts +4 -2
- package/test/route.test.ts +206 -6
- package/test/setup.ts +10 -0
- package/test/style-clear.test.ts +97 -0
- package/.omo/plans/m-request-fetch-lynx.md +0 -306
- package/.omo/plans/m-route-en-memoria.md +0 -397
- package/.omo/plans/mithril-lynx-v2-desde-cero.md +0 -548
- package/.omo/run-continuation/ses_f48265d07ffenKG0GAz9ZRFvY6.json +0 -10
- package/src/list-cell.d.ts +0 -20
- package/src/list-cell.js +0 -73
- package/src/list-support.d.ts +0 -13
- package/src/list-support.js +0 -171
package/src/patch-protocol.js
CHANGED
|
@@ -13,6 +13,23 @@
|
|
|
13
13
|
// main-thread side by `applyPatch()` (see backends/papi-backend.js), so
|
|
14
14
|
// nodes never need to be looked up by anything other than that integer.
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* The wire protocol version, prepended to every patch by
|
|
18
|
+
* `sendPatchToMainThread()` and validated (then stripped) by the main
|
|
19
|
+
* thread before any op is interpreted. The two bundles are normally built
|
|
20
|
+
* from the same source, but a partial HMR or a cached main-thread bundle
|
|
21
|
+
* could otherwise re-interpret a reordered opcode silently — a version
|
|
22
|
+
* mismatch throws instead of corrupting the mirrored id space.
|
|
23
|
+
*
|
|
24
|
+
* The value is deliberately outside the opcode range (0x4d4c was "ML"
|
|
25
|
+
* in ASCII; bumped to 0x4d4d in 3.0.0, when the Op.CreateList /
|
|
26
|
+
* Op.SetListItems list protocol was replaced by plain `list`/`list-item`
|
|
27
|
+
* elements, and to 0x4d4e, also in 3.0.0, when Op.InvokeUIMethod /
|
|
28
|
+
* Op.SetInputValue were added) so a versioned array can never be misread as an op sequence if
|
|
29
|
+
* it is ever fed to `applyPatch()` without the strip.
|
|
30
|
+
*/
|
|
31
|
+
export const PROTOCOL_VERSION = 0x4d4e;
|
|
32
|
+
|
|
16
33
|
export const Op = Object.freeze({
|
|
17
34
|
CreateElement: 0,
|
|
18
35
|
CreateElementNS: 1,
|
|
@@ -42,20 +59,38 @@ export const Op = Object.freeze({
|
|
|
42
59
|
// background-thread side.
|
|
43
60
|
SetGestureDetector: 14, // id, gestureId, gestureType, arenaPolicy
|
|
44
61
|
RemoveGestureDetector: 15, // id, gestureId
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
// (
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
// Calls a native UI method (`focus`, `getValue`, `scrollTo`, …) through
|
|
63
|
+
// the main-thread `__InvokeUIMethod` PAPI — the path ReactLynx's
|
|
64
|
+
// main-thread `Element.invoke()` uses. Deferred until after the patch's
|
|
65
|
+
// `__FlushElementTree()`, so an element created by the same patch
|
|
66
|
+
// already exists natively. callbackId 0 = no result wanted; otherwise
|
|
67
|
+
// the result comes back as an INVOKE_RESULT_EVENT forwarded event.
|
|
68
|
+
InvokeUIMethod: 16, // id, method, params, callbackId
|
|
69
|
+
// `value` of an <input>/<textarea>: a `setValue` UI method call guarded
|
|
70
|
+
// by `seq`, the number of native `input` events the background had seen
|
|
71
|
+
// for this field when it computed the value. The main thread drops it
|
|
72
|
+
// when the user has typed since (a newer `input` event is in flight and
|
|
73
|
+
// will re-render) — see apply-patch.js.
|
|
74
|
+
SetInputValue: 17, // id, value, seq
|
|
53
75
|
});
|
|
54
76
|
|
|
77
|
+
/** The reserved forwarded-event type that carries an Op.InvokeUIMethod
|
|
78
|
+
* result (`{ callbackId, code, data }`) back to the background thread, over
|
|
79
|
+
* the same channel as native events. Never an element's own event type. */
|
|
80
|
+
export const INVOKE_RESULT_EVENT = "mithrilLynx:invokeResult";
|
|
81
|
+
|
|
82
|
+
/** Tags whose `value` is a native UI method call (Op.SetInputValue) rather
|
|
83
|
+
* than an attribute. */
|
|
84
|
+
export const FORM_FIELD_TAGS = Object.freeze(["input", "textarea"]);
|
|
85
|
+
|
|
55
86
|
/**
|
|
56
87
|
* Encodes one op onto a flat ops array. Kept as a tiny helper (not a class)
|
|
57
88
|
* so the hot path (called on every attribute/child mutation during a real
|
|
58
89
|
* Mithril diff) is just array pushes — no object allocation per op.
|
|
90
|
+
* @param {unknown[]} ops - The flat ops array to append to.
|
|
91
|
+
* @param {number} opcode - One of the `Op` codes.
|
|
92
|
+
* @param {...unknown} args - The op's arguments (see `OP_ARITY`).
|
|
93
|
+
* @returns {void}
|
|
59
94
|
*/
|
|
60
95
|
export function pushOp(ops, opcode, ...args) {
|
|
61
96
|
ops.push(opcode, ...args);
|
|
@@ -65,8 +100,7 @@ export function pushOp(ops, opcode, ...args) {
|
|
|
65
100
|
// for walking a flat ops array without re-interpreting it (apply-patch.js's
|
|
66
101
|
// own switch increments `i` inline instead of using this table, since it
|
|
67
102
|
// also needs to look at individual arg values as it goes; this exists for
|
|
68
|
-
// callers that only need to skip/scan
|
|
69
|
-
// findTopLevelChildIds(), which never applies the ops itself).
|
|
103
|
+
// callers that only need to skip/scan an ops array without applying it).
|
|
70
104
|
export const OP_ARITY = Object.freeze({
|
|
71
105
|
[Op.CreateElement]: 2, // tag, id
|
|
72
106
|
[Op.CreateElementNS]: 3, // ns, tag, id
|
|
@@ -84,13 +118,18 @@ export const OP_ARITY = Object.freeze({
|
|
|
84
118
|
[Op.RemoveEvent]: 2, // id, type
|
|
85
119
|
[Op.SetGestureDetector]: 4, // id, gestureId, gestureType, arenaPolicy
|
|
86
120
|
[Op.RemoveGestureDetector]: 2, // id, gestureId
|
|
87
|
-
[Op.
|
|
88
|
-
[Op.
|
|
121
|
+
[Op.InvokeUIMethod]: 4, // id, method, params, callbackId
|
|
122
|
+
[Op.SetInputValue]: 3, // id, value, seq
|
|
89
123
|
});
|
|
90
124
|
|
|
91
125
|
/** Walks a flat ops array, calling `visit(opcode, args)` once per op — args
|
|
92
126
|
* is the plain slice of that op's own arguments (not including the opcode
|
|
93
|
-
* itself). Throws on an unknown opcode rather than silently desyncing.
|
|
127
|
+
* itself). Throws on an unknown opcode rather than silently desyncing.
|
|
128
|
+
* @param {unknown[]} ops - A flat ops array.
|
|
129
|
+
* @param {(opcode: number, args: unknown[]) => void} visit - Called once per op with its arguments.
|
|
130
|
+
* @returns {void}
|
|
131
|
+
* @throws {Error} On an unknown opcode.
|
|
132
|
+
*/
|
|
94
133
|
export function forEachOp(ops, visit) {
|
|
95
134
|
for (let i = 0; i < ops.length; ) {
|
|
96
135
|
const opcode = ops[i++];
|
package/src/reload/version.js
CHANGED
|
@@ -13,16 +13,25 @@
|
|
|
13
13
|
|
|
14
14
|
let version = 0;
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @returns {number} The current reload version.
|
|
18
|
+
*/
|
|
16
19
|
export function getReloadVersion() {
|
|
17
20
|
return version;
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @returns {number} The new reload version, after incrementing.
|
|
25
|
+
*/
|
|
20
26
|
export function increaseReloadVersion() {
|
|
21
27
|
return ++version;
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
/** True if a patch stamped with `patchVersion` is stale and must be
|
|
25
|
-
* dropped without being applied — the ENTIRE guard, one comparison.
|
|
31
|
+
* dropped without being applied — the ENTIRE guard, one comparison.
|
|
32
|
+
* @param {*} patchVersion - The version stamped on a patch.
|
|
33
|
+
* @returns {boolean} `true` when `patchVersion` is a number older than the current version.
|
|
34
|
+
*/
|
|
26
35
|
export function isStaleVersion(patchVersion) {
|
|
27
36
|
return typeof patchVersion === "number" && patchVersion < version;
|
|
28
37
|
}
|
package/src/request.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export interface RequestOptions<T = any> {
|
|
|
10
10
|
serialize?: (data: unknown) => string;
|
|
11
11
|
deserialize?: (data: unknown) => unknown;
|
|
12
12
|
extract?: (response: unknown, options: RequestOptions<T>) => unknown;
|
|
13
|
+
/** A constructor applied to the response: per element when the response
|
|
14
|
+
* is an array (matching real `m.request`), otherwise to the whole result. */
|
|
13
15
|
type?: new (data: any) => T;
|
|
14
16
|
background?: boolean;
|
|
15
17
|
// Present on the real m.request signature but confirmed unsupported —
|
package/src/request.js
CHANGED
|
@@ -32,6 +32,12 @@ const UNSUPPORTED = [
|
|
|
32
32
|
["withCredentials", (o) => o.withCredentials === true],
|
|
33
33
|
];
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Throws if `options` uses an option Lynx's fetch cannot honor.
|
|
37
|
+
* @param {Object} options - The request options.
|
|
38
|
+
* @returns {void}
|
|
39
|
+
* @throws {Error} If an unsupported option (`config`, `async: false`, `user`, `password`, `withCredentials`) is present.
|
|
40
|
+
*/
|
|
35
41
|
function checkUnsupported(options) {
|
|
36
42
|
for (const [name, matches] of UNSUPPORTED) {
|
|
37
43
|
if (matches(options)) {
|
|
@@ -44,6 +50,12 @@ function checkUnsupported(options) {
|
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Case-insensitive own-property check for a header name.
|
|
55
|
+
* @param {Object<string, string>} headers - The headers object.
|
|
56
|
+
* @param {string} name - The lowercase header name to look for.
|
|
57
|
+
* @returns {boolean}
|
|
58
|
+
*/
|
|
47
59
|
function hasHeader(headers, name) {
|
|
48
60
|
for (const key in headers) {
|
|
49
61
|
if (Object.prototype.hasOwnProperty.call(headers, key) && key.toLowerCase() === name) return true;
|
|
@@ -51,6 +63,12 @@ function hasHeader(headers, name) {
|
|
|
51
63
|
return false;
|
|
52
64
|
}
|
|
53
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Wraps response data in `Type` instances, per item for arrays.
|
|
68
|
+
* @param {*} data - The response data.
|
|
69
|
+
* @param {Function} [Type] - A constructor; when not a function, `data` is returned unchanged.
|
|
70
|
+
* @returns {*} The wrapped data.
|
|
71
|
+
*/
|
|
54
72
|
function applyType(data, Type) {
|
|
55
73
|
if (typeof Type !== "function") return data;
|
|
56
74
|
if (Array.isArray(data)) return data.map((item) => new Type(item));
|
|
@@ -63,10 +81,18 @@ function applyType(data, Type) {
|
|
|
63
81
|
* so importing this file never requires `lynx` to already exist) —
|
|
64
82
|
* same pattern route.js uses for `renderApp`. Tests inject a fake here
|
|
65
83
|
* instead of hitting a real network.
|
|
84
|
+
* @returns {(url: string|Object, options?: Object) => Promise<*>} A `request` function shaped like `m.request`; its promise has an extra `abort()` method.
|
|
66
85
|
*/
|
|
67
86
|
export function createRequestor(fetchImpl) {
|
|
68
87
|
const doFetch = fetchImpl || ((url, init) => lynx.fetch(url, init));
|
|
69
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Performs a request and redraws when it settles (unless `options.background` is `true`).
|
|
91
|
+
* @param {string|Object} url - The URL, or an options object containing `url`.
|
|
92
|
+
* @param {Object} [options] - `m.request`-style options (`method`, `params`, `body`, `headers`, `serialize`, `deserialize`, `extract`, `type`, `responseType`, `timeout`, `signal`, `background`).
|
|
93
|
+
* @returns {Promise<*> & {abort: () => void}} Resolves with the (typed) response data; rejects with an `Error` carrying `code` and `response` for non-OK statuses.
|
|
94
|
+
* @throws {Error} Synchronously, for unsupported options or a `FormData` body.
|
|
95
|
+
*/
|
|
70
96
|
return function request(url, options) {
|
|
71
97
|
if (typeof url !== "string") {
|
|
72
98
|
options = url;
|
|
@@ -112,9 +138,17 @@ export function createRequestor(fetchImpl) {
|
|
|
112
138
|
// controller so a caller-provided signal and our timeout can both
|
|
113
139
|
// trigger the same abort.
|
|
114
140
|
const ctrl = new AbortController();
|
|
141
|
+
// Stored so the listener can be detached on settle (see detachSignal
|
|
142
|
+
// below) — a long-lived shared AbortSignal would otherwise accumulate
|
|
143
|
+
// one dead closure per request.
|
|
144
|
+
/**
|
|
145
|
+
* Aborts the internal controller when the caller's signal aborts.
|
|
146
|
+
* @returns {void}
|
|
147
|
+
*/
|
|
148
|
+
const abortHandler = () => ctrl.abort();
|
|
115
149
|
if (options.signal) {
|
|
116
150
|
if (options.signal.aborted) ctrl.abort();
|
|
117
|
-
else options.signal.addEventListener("abort",
|
|
151
|
+
else options.signal.addEventListener("abort", abortHandler);
|
|
118
152
|
}
|
|
119
153
|
let timeoutId;
|
|
120
154
|
if (options.timeout) {
|
|
@@ -123,6 +157,10 @@ export function createRequestor(fetchImpl) {
|
|
|
123
157
|
: setTimeout;
|
|
124
158
|
timeoutId = schedule(() => ctrl.abort(), options.timeout);
|
|
125
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Cancels the pending timeout, if any.
|
|
162
|
+
* @returns {void}
|
|
163
|
+
*/
|
|
126
164
|
function clearRequestTimeout() {
|
|
127
165
|
if (timeoutId == null) return;
|
|
128
166
|
const clear = typeof lynx !== "undefined" && typeof lynx.clearTimeout === "function"
|
|
@@ -138,8 +176,10 @@ export function createRequestor(fetchImpl) {
|
|
|
138
176
|
|
|
139
177
|
if (typeof options.extract === "function") {
|
|
140
178
|
// Matches real m.request: extract() bypasses the status check
|
|
141
|
-
// entirely — it decides success/failure itself.
|
|
142
|
-
|
|
179
|
+
// entirely — it decides success/failure itself. `type` is still
|
|
180
|
+
// applied afterwards, exactly as upstream does (extract does NOT
|
|
181
|
+
// skip the type constructor).
|
|
182
|
+
return applyType(options.extract(response, options), options.type);
|
|
143
183
|
}
|
|
144
184
|
|
|
145
185
|
const ok = response.ok || response.status === 304;
|
|
@@ -156,12 +196,28 @@ export function createRequestor(fetchImpl) {
|
|
|
156
196
|
});
|
|
157
197
|
});
|
|
158
198
|
|
|
199
|
+
// Detach the caller's signal listener once this request settles, so a
|
|
200
|
+
// long-lived shared AbortSignal doesn't accumulate a dead closure per
|
|
201
|
+
// request. Done inside the settled handlers (rather than a separate
|
|
202
|
+
// `.then`) so an ignored rejection still surfaces as unhandled.
|
|
203
|
+
/**
|
|
204
|
+
* Detaches the abort listener from the caller's signal.
|
|
205
|
+
* @returns {void}
|
|
206
|
+
*/
|
|
207
|
+
const detachSignal = () => {
|
|
208
|
+
if (options.signal && !options.signal.aborted) {
|
|
209
|
+
options.signal.removeEventListener("abort", abortHandler);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
159
213
|
const result = promise.then(
|
|
160
214
|
(value) => {
|
|
215
|
+
detachSignal();
|
|
161
216
|
if (options.background !== true) sharedRedraw();
|
|
162
217
|
return value;
|
|
163
218
|
},
|
|
164
219
|
(error) => {
|
|
220
|
+
detachSignal();
|
|
165
221
|
clearRequestTimeout();
|
|
166
222
|
if (options.background !== true) sharedRedraw();
|
|
167
223
|
throw error;
|
package/src/route.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Mithril-style component type. Declared locally because this
|
|
3
|
+
* package's runtime peer is `mithril-runtime`, which ships no TypeScript
|
|
4
|
+
* types of its own; the previous `import type { Component } from "mithril"`
|
|
5
|
+
* depended on an undeclared module. `view`'s return is typed `any` so
|
|
6
|
+
* `route.Link` stays assignable to a caller's own `m()` typed against
|
|
7
|
+
* `@types/mithril`.
|
|
8
|
+
*/
|
|
9
|
+
export interface Component<Attrs = unknown> {
|
|
10
|
+
view(vnode: { attrs: Attrs; children?: unknown }): any;
|
|
11
|
+
}
|
|
2
12
|
|
|
3
13
|
export interface RouteResolver {
|
|
4
14
|
onmatch?(args: Record<string, string>, requestedPath: string, route: string): unknown;
|
|
@@ -11,17 +21,51 @@ export interface RouteLinkAttrs {
|
|
|
11
21
|
params?: Record<string, unknown>;
|
|
12
22
|
options?: { replace?: boolean };
|
|
13
23
|
disabled?: boolean;
|
|
14
|
-
ontap?: (e: unknown) => unknown;
|
|
24
|
+
ontap?: ((e: unknown) => unknown) | { handleEvent(e: unknown): void };
|
|
15
25
|
[key: string]: unknown;
|
|
16
26
|
}
|
|
17
27
|
|
|
28
|
+
export interface RouteSetOptions {
|
|
29
|
+
/** Overwrite the current history entry instead of pushing a new one. */
|
|
30
|
+
replace?: boolean;
|
|
31
|
+
/** Merged into the route's params; restored by back()/forward(). */
|
|
32
|
+
state?: Record<string, unknown>;
|
|
33
|
+
/** Accepted for m.route compatibility; ignored (no title bar). */
|
|
34
|
+
title?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ListenBackButtonOptions {
|
|
38
|
+
/** Global event the host sends when back is pressed. @defaultValue "mithrilLynx:back" */
|
|
39
|
+
eventName?: string;
|
|
40
|
+
/** Called with canGoBack() right away and whenever it changes — e.g. to
|
|
41
|
+
* enable/disable the host's OnBackPressedCallback through a native module. */
|
|
42
|
+
onCanGoBackChange?: (canGoBack: boolean) => void;
|
|
43
|
+
}
|
|
44
|
+
|
|
18
45
|
export interface Route {
|
|
46
|
+
/** `defaultRoute` is required: Lynx has no URL to start from. */
|
|
19
47
|
(defaultRoute: string, routes: Record<string, unknown | RouteResolver>): void;
|
|
20
|
-
|
|
48
|
+
/** Updates the history now; the new screen resolves on the next microtask
|
|
49
|
+
* (like m.route), so get() returns the previous path until then. */
|
|
50
|
+
set(path: string, data?: unknown, options?: RouteSetOptions): void;
|
|
51
|
+
/** The current path, decoded. */
|
|
21
52
|
get(): string | undefined;
|
|
53
|
+
/** Returns the named route parameter (with `key`), or the whole params
|
|
54
|
+
* object (without). Typed `unknown` because the value can be a string
|
|
55
|
+
* (path params), a string|boolean (query params — `"true"`/`"false"` are
|
|
56
|
+
* coerced), or anything passed as `data` to `set(path, data)`; the common
|
|
57
|
+
* path-param case is always a string. */
|
|
22
58
|
param(key?: string): unknown;
|
|
23
|
-
back()
|
|
24
|
-
|
|
59
|
+
/** Walks back one entry; returns `false` (without navigating) at the top
|
|
60
|
+
* of the history stack so a back affordance can disable itself. */
|
|
61
|
+
back(): boolean;
|
|
62
|
+
/** Walks forward one entry; returns `false` (without navigating) at the
|
|
63
|
+
* end of the history stack so a forward affordance can disable itself. */
|
|
64
|
+
forward(): boolean;
|
|
65
|
+
/** Whether back() would navigate. */
|
|
66
|
+
canGoBack(): boolean;
|
|
67
|
+
/** Opt-in Android back button bridge (see ROUTE.md). Returns a function that stops listening. */
|
|
68
|
+
listenBackButton(options?: ListenBackButtonOptions): () => void;
|
|
25
69
|
prefix: string;
|
|
26
70
|
SKIP: unknown;
|
|
27
71
|
Link: Component<RouteLinkAttrs>;
|
|
@@ -29,5 +73,8 @@ export interface Route {
|
|
|
29
73
|
|
|
30
74
|
export function createRoute(): Route;
|
|
31
75
|
|
|
76
|
+
/** Default event name listened to by `route.listenBackButton()`. */
|
|
77
|
+
export declare const BACK_EVENT_NAME: string;
|
|
78
|
+
|
|
32
79
|
declare const route: Route;
|
|
33
80
|
export default route;
|