@hoardodile/host-web 0.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/LICENSE +18 -0
- package/README.md +31 -0
- package/dist/file-backends-Dyy2BxUM.d.ts +27 -0
- package/dist/index.d.ts +293 -0
- package/dist/index.js +532 -0
- package/dist/index.js.map +1 -0
- package/dist/node.d.ts +12 -0
- package/dist/node.js +25 -0
- package/dist/node.js.map +1 -0
- package/package.json +60 -0
- package/src/consent/consent-store.test.ts +105 -0
- package/src/consent/consent-store.ts +129 -0
- package/src/host-core/request-schemas.ts +85 -0
- package/src/host-core/router.test.ts +231 -0
- package/src/host-core/router.ts +234 -0
- package/src/index.ts +47 -0
- package/src/mock/file-backends.ts +69 -0
- package/src/mock/host.test.ts +188 -0
- package/src/mock/host.ts +370 -0
- package/src/mock/stores.ts +89 -0
- package/src/mock-node/index.ts +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wooloo <ayan0312000@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# @hoardodile/host-web
|
|
2
|
+
|
|
3
|
+
The browser-side plugin host runtime: the shared host-core protocol
|
|
4
|
+
router (used by the hoardodile web app in production and by the offline
|
|
5
|
+
mock) plus the mock host for component tests and the workbench. The wire
|
|
6
|
+
protocol itself stays in `@hoardodile/sdk-web` — this package consumes
|
|
7
|
+
it, never redefines it.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @hoardodile/host-web
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## What's in it
|
|
16
|
+
|
|
17
|
+
- **`createHostRouter`** / **`defineHandler`** — the host-core protocol
|
|
18
|
+
router: message demux, method routing, per-method param validation,
|
|
19
|
+
stale-request scoping, response envelope. The real app and the mock
|
|
20
|
+
assemble on this module so routing and validation never drift
|
|
21
|
+
- **`createMockHost`** — an in-memory host for jsdom component tests and
|
|
22
|
+
the workbench; register a window and drive the iframe bridge with no
|
|
23
|
+
server
|
|
24
|
+
- **`createInMemoryFileBackend`** — file backend for the mock
|
|
25
|
+
|
|
26
|
+
## Subpaths
|
|
27
|
+
|
|
28
|
+
| Entry | Contents |
|
|
29
|
+
| ----- | -------- |
|
|
30
|
+
| `@hoardodile/host-web` | Browser-safe router + mock (no node imports) |
|
|
31
|
+
| `@hoardodile/host-web/node` | Node file backends (directory-backed mock storage) |
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReadFileRange } from '@hoardodile/sdk-types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* File backends for the offline mock host: the plugin's `listFiles` and
|
|
5
|
+
* `readFile` requests resolve against this interface, so a mock can be
|
|
6
|
+
* pointed at an in-memory map, a real directory (Node), or a read-only
|
|
7
|
+
* HTTP mount (workbench) without changing the host.
|
|
8
|
+
*/
|
|
9
|
+
type MockFileBackend = {
|
|
10
|
+
readonly listFiles: (resId: string) => Promise<readonly string[]>;
|
|
11
|
+
readonly readFile: (resId: string, path: string, range?: ReadFileRange) => Promise<ArrayBuffer>;
|
|
12
|
+
readonly statFile: (resId: string, path: string) => Promise<{
|
|
13
|
+
readonly sizeBytes: number;
|
|
14
|
+
} | undefined>;
|
|
15
|
+
/**
|
|
16
|
+
* The rows the plugin's own `listFiles` hook produced, when the
|
|
17
|
+
* backend can obtain them (the workbench reads them from a sandboxed
|
|
18
|
+
* hook snapshot). In production the host answers `listFiles` with
|
|
19
|
+
* exactly these plugin-shaped entries; returning `undefined` falls
|
|
20
|
+
* back to generic `{filename, ext, sizeBytes}` rows.
|
|
21
|
+
*/
|
|
22
|
+
readonly listFileEntries?: (resId: string) => Promise<readonly unknown[] | undefined>;
|
|
23
|
+
};
|
|
24
|
+
/** In-memory file map backend for unit tests. `resId` is ignored. */
|
|
25
|
+
declare function createInMemoryFileBackend(files?: Readonly<Record<string, string | Uint8Array>>): MockFileBackend;
|
|
26
|
+
|
|
27
|
+
export { type MockFileBackend as M, createInMemoryFileBackend as c };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { HostResponse, PluginIframeContext } from '@hoardodile/sdk-web';
|
|
3
|
+
import { M as MockFileBackend } from './file-backends-Dyy2BxUM.js';
|
|
4
|
+
export { c as createInMemoryFileBackend } from './file-backends-Dyy2BxUM.js';
|
|
5
|
+
import { Danmaku, Message, PluginDownloadRequest, PluginDownloadResult, PluginAssetDeleteResult } from '@hoardodile/sdk-types';
|
|
6
|
+
export { ReadFileRange } from '@hoardodile/sdk-types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The consent-dialog queue for plugin asset downloads — the shared
|
|
10
|
+
* implementation both host apps mount:
|
|
11
|
+
*
|
|
12
|
+
* - the **app** feeds it from SSE (`pluginDownloadRequested` /
|
|
13
|
+
* `pluginDownloadResolved`) and drives decisions through the server
|
|
14
|
+
* (`pluginAsset.decide`); the resolved broadcast closes entries here;
|
|
15
|
+
* - the **workbench** has no server: its asset engine enqueues via
|
|
16
|
+
* {@link request} and the dialog answers via {@link decide} — the same
|
|
17
|
+
* dialog component, one queue per page, FIFO, one dialog at a time.
|
|
18
|
+
*
|
|
19
|
+
* State-only by design: decisions never mutate the queue directly
|
|
20
|
+
* except through `close`/`decide`, which the two hosts wire to their
|
|
21
|
+
* own decision path.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* A queued consent question: the ticket shape. Structurally identical to
|
|
25
|
+
* the server's `pluginDownloadRequested` SSE event minus its `type`
|
|
26
|
+
* discriminator (and to `pluginAsset.listPending` rows) — declared here
|
|
27
|
+
* instead of importing `@hoardodile/schemas` so the host-core package
|
|
28
|
+
* stays dependency-lean.
|
|
29
|
+
*/
|
|
30
|
+
type DownloadConsentEntry = {
|
|
31
|
+
readonly ticketId: string;
|
|
32
|
+
readonly pluginId: string;
|
|
33
|
+
readonly pluginName: string;
|
|
34
|
+
readonly url: string;
|
|
35
|
+
readonly dest: string;
|
|
36
|
+
readonly sizeBytes?: number;
|
|
37
|
+
readonly reason?: string;
|
|
38
|
+
};
|
|
39
|
+
type State = {
|
|
40
|
+
readonly queue: readonly DownloadConsentEntry[];
|
|
41
|
+
};
|
|
42
|
+
declare function subscribeDownloadConsent(listener: () => void): () => void;
|
|
43
|
+
declare function getDownloadConsentSnapshot(): State;
|
|
44
|
+
/** A new ticket arrived (SSE) or was requested locally: append if absent. */
|
|
45
|
+
declare function enqueueDownloadConsent(entry: DownloadConsentEntry): void;
|
|
46
|
+
/** A ticket resolved (decide/timeout/dispose): drop it in every consumer. */
|
|
47
|
+
declare function closeDownloadConsent(ticketId: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Replace the queue from a pending list (app: `listPending` after an SSE
|
|
50
|
+
* reconnect; workbench: same API on restart).
|
|
51
|
+
*/
|
|
52
|
+
declare function rehydrateDownloadConsent(entries: readonly DownloadConsentEntry[]): void;
|
|
53
|
+
/**
|
|
54
|
+
* Enqueue a ticket and wait for its decision (workbench engine path).
|
|
55
|
+
* The dialog's answer arrives through {@link decideDownloadConsent}.
|
|
56
|
+
*/
|
|
57
|
+
declare function requestDownloadConsent(entry: DownloadConsentEntry): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Answer a ticket from the dialog. Closes the entry and resolves any
|
|
60
|
+
* awaiting engine call. Idempotent; unknown tickets are a no-op.
|
|
61
|
+
*/
|
|
62
|
+
declare function decideDownloadConsent(ticketId: string, approved: boolean): void;
|
|
63
|
+
/** Test-only: reset the singleton between tests. */
|
|
64
|
+
declare function resetDownloadConsent(): void;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Wire-level param schemas for every request method, shared by the real
|
|
68
|
+
* host (apps/web) and the offline mock host. Both hosts validate
|
|
69
|
+
* identical shapes, so a plugin that passes validation in the mock is
|
|
70
|
+
* guaranteed to pass in production.
|
|
71
|
+
*/
|
|
72
|
+
/**
|
|
73
|
+
* Wire shape of a message/danmaku anchor: the plugin location payload
|
|
74
|
+
* only. The resource id is host state — the host stamps its own binding
|
|
75
|
+
* into the anchor before it reaches the server.
|
|
76
|
+
*/
|
|
77
|
+
declare const anchorData: z.ZodObject<{
|
|
78
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
79
|
+
}, z.core.$strict>;
|
|
80
|
+
declare const requestSchemas: {
|
|
81
|
+
readFile: z.ZodObject<{
|
|
82
|
+
path: z.ZodString;
|
|
83
|
+
range: z.ZodOptional<z.ZodObject<{
|
|
84
|
+
start: z.ZodOptional<z.ZodNumber>;
|
|
85
|
+
end: z.ZodOptional<z.ZodNumber>;
|
|
86
|
+
}, z.core.$strip>>;
|
|
87
|
+
}, z.core.$strip>;
|
|
88
|
+
listFiles: undefined;
|
|
89
|
+
listMessages: undefined;
|
|
90
|
+
createMessage: z.ZodObject<{
|
|
91
|
+
body: z.ZodString;
|
|
92
|
+
anchor: z.ZodOptional<z.ZodObject<{
|
|
93
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
94
|
+
}, z.core.$strict>>;
|
|
95
|
+
}, z.core.$strip>;
|
|
96
|
+
listDanmaku: z.ZodObject<{
|
|
97
|
+
filter: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
98
|
+
}, z.core.$strip>;
|
|
99
|
+
createDanmaku: z.ZodObject<{
|
|
100
|
+
text: z.ZodString;
|
|
101
|
+
anchor: z.ZodObject<{
|
|
102
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
103
|
+
}, z.core.$strict>;
|
|
104
|
+
mode: z.ZodOptional<z.ZodString>;
|
|
105
|
+
}, z.core.$strip>;
|
|
106
|
+
setPref: z.ZodObject<{
|
|
107
|
+
key: z.ZodString;
|
|
108
|
+
value: z.ZodString;
|
|
109
|
+
}, z.core.$strip>;
|
|
110
|
+
setCache: z.ZodObject<{
|
|
111
|
+
key: z.ZodString;
|
|
112
|
+
value: z.ZodString;
|
|
113
|
+
}, z.core.$strip>;
|
|
114
|
+
invalidate: z.ZodObject<{
|
|
115
|
+
target: z.ZodEnum<{
|
|
116
|
+
resource: "resource";
|
|
117
|
+
resources: "resources";
|
|
118
|
+
messages: "messages";
|
|
119
|
+
danmaku: "danmaku";
|
|
120
|
+
}>;
|
|
121
|
+
}, z.core.$strip>;
|
|
122
|
+
download: z.ZodObject<{
|
|
123
|
+
url: z.ZodString;
|
|
124
|
+
dest: z.ZodString;
|
|
125
|
+
sha256: z.ZodOptional<z.ZodString>;
|
|
126
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
127
|
+
}, z.core.$strip>;
|
|
128
|
+
deleteAsset: z.ZodObject<{
|
|
129
|
+
path: z.ZodString;
|
|
130
|
+
}, z.core.$strip>;
|
|
131
|
+
logInfo: z.ZodObject<{
|
|
132
|
+
message: z.ZodString;
|
|
133
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
134
|
+
}, z.core.$strip>;
|
|
135
|
+
logWarn: z.ZodObject<{
|
|
136
|
+
message: z.ZodString;
|
|
137
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
138
|
+
}, z.core.$strip>;
|
|
139
|
+
logError: z.ZodObject<{
|
|
140
|
+
message: z.ZodString;
|
|
141
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
142
|
+
}, z.core.$strip>;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The shared host-side protocol core: message demux, method routing,
|
|
147
|
+
* per-method param validation, stale-request scoping and the response
|
|
148
|
+
* envelope. Both the real host (apps/web) and the offline mock host
|
|
149
|
+
* assemble on this module, so routing and validation never drift.
|
|
150
|
+
*/
|
|
151
|
+
/** What a registered iframe (or mock window) is bound to. */
|
|
152
|
+
type HostBinding = {
|
|
153
|
+
readonly pluginId: string;
|
|
154
|
+
readonly resId: string;
|
|
155
|
+
};
|
|
156
|
+
type HostRouterDeps = {
|
|
157
|
+
/**
|
|
158
|
+
* Authenticate an inbound message event: narrow it to a trusted source
|
|
159
|
+
* + binding, or return `undefined` to drop the message. The real host
|
|
160
|
+
* validates origin/source against its iframe registry; the mock
|
|
161
|
+
* validates against its own registered windows.
|
|
162
|
+
*/
|
|
163
|
+
readonly resolveSource: (event: MessageEvent) => {
|
|
164
|
+
readonly source: unknown;
|
|
165
|
+
readonly record: HostBinding;
|
|
166
|
+
} | undefined;
|
|
167
|
+
/** Send a response back to the source (the layer's postMessage exit). */
|
|
168
|
+
readonly respond: (source: unknown, response: HostResponse) => void;
|
|
169
|
+
/** Record a subscription key for the source. */
|
|
170
|
+
readonly subscribe: (source: unknown, key: string) => void;
|
|
171
|
+
};
|
|
172
|
+
type HostHandlerContext = {
|
|
173
|
+
readonly source: unknown;
|
|
174
|
+
/**
|
|
175
|
+
* The resource this request is scoped to: the source's current
|
|
176
|
+
* binding ("" only for never-bound sources). Requests stamped by the
|
|
177
|
+
* SDK with a different resource are dropped as stale before they
|
|
178
|
+
* reach a handler.
|
|
179
|
+
*/
|
|
180
|
+
readonly resId: string;
|
|
181
|
+
readonly pluginId: string;
|
|
182
|
+
};
|
|
183
|
+
type HostHandlerEntry = {
|
|
184
|
+
readonly method: string;
|
|
185
|
+
/** Param schema; validated in the router before the handler runs. */
|
|
186
|
+
readonly schema: z.ZodTypeAny | undefined;
|
|
187
|
+
readonly handler: (ctx: HostHandlerContext, params: unknown) => Promise<unknown>;
|
|
188
|
+
};
|
|
189
|
+
declare function defineHandler<TReturn>(method: string, handler: (ctx: HostHandlerContext) => Promise<TReturn> | TReturn): HostHandlerEntry;
|
|
190
|
+
declare function defineHandler<TSchema extends z.ZodTypeAny, TReturn>(method: string, schema: TSchema, handler: (ctx: HostHandlerContext, params: z.infer<TSchema>) => Promise<TReturn> | TReturn): HostHandlerEntry;
|
|
191
|
+
/**
|
|
192
|
+
* Create the per-window message handler: authenticates the event,
|
|
193
|
+
* routes requests by method, validates params, drops stale scopes and
|
|
194
|
+
* wraps every outcome in the response envelope.
|
|
195
|
+
*/
|
|
196
|
+
declare function createHostRouter(handlers: readonly HostHandlerEntry[], deps: HostRouterDeps): (event: MessageEvent) => void;
|
|
197
|
+
|
|
198
|
+
type MockMessageStore = {
|
|
199
|
+
readonly list: (resId: string) => readonly Message[];
|
|
200
|
+
readonly create: (resId: string, input: {
|
|
201
|
+
body: string;
|
|
202
|
+
anchor?: unknown;
|
|
203
|
+
}) => Message;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* `seed` pre-fills the store with rows the plugin should already see —
|
|
207
|
+
* the workbench passes the resource's real comments so the iframe opens
|
|
208
|
+
* with the same content the app would show.
|
|
209
|
+
*/
|
|
210
|
+
declare function createMockMessageStore(seed?: readonly Message[]): MockMessageStore;
|
|
211
|
+
type MockDanmakuStore = {
|
|
212
|
+
readonly list: (resId: string) => readonly Danmaku[];
|
|
213
|
+
readonly create: (resId: string, input: {
|
|
214
|
+
text: string;
|
|
215
|
+
anchor: unknown;
|
|
216
|
+
mode?: string;
|
|
217
|
+
}) => Danmaku;
|
|
218
|
+
};
|
|
219
|
+
/** See {@link createMockMessageStore} for `seed`. */
|
|
220
|
+
declare function createMockDanmakuStore(seed?: readonly Danmaku[]): MockDanmakuStore;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* The offline host side of the plugin postMessage bridge. Implements the
|
|
224
|
+
* same routing, validation and scoping as the production host (via
|
|
225
|
+
* host-core) with in-memory data — so plugin iframes run with no server
|
|
226
|
+
* at all. Shared by automated component tests (jsdom: register the test
|
|
227
|
+
* window) and the manual workbench page (register the real iframe
|
|
228
|
+
* window).
|
|
229
|
+
*/
|
|
230
|
+
type MockHostLogger = {
|
|
231
|
+
readonly info: (message: string, data?: unknown) => void;
|
|
232
|
+
readonly warn: (message: string, data?: unknown) => void;
|
|
233
|
+
readonly error: (message: string, data?: unknown) => void;
|
|
234
|
+
};
|
|
235
|
+
type MockHostOptions = {
|
|
236
|
+
/**
|
|
237
|
+
* Window that receives plugin postMessage traffic: the page window in
|
|
238
|
+
* a workbench, the test window in jsdom. The host listens on it and
|
|
239
|
+
* posts responses to it.
|
|
240
|
+
*/
|
|
241
|
+
readonly targetWindow: Window;
|
|
242
|
+
readonly files: MockFileBackend;
|
|
243
|
+
readonly messages?: MockMessageStore;
|
|
244
|
+
readonly danmaku?: MockDanmakuStore;
|
|
245
|
+
/** Initial plugin-scoped prefs. */
|
|
246
|
+
readonly prefs?: Readonly<Record<string, string>>;
|
|
247
|
+
/** Initial plugin+resId cache entries. */
|
|
248
|
+
readonly cache?: Readonly<Record<string, string>>;
|
|
249
|
+
readonly logger?: MockHostLogger;
|
|
250
|
+
/** Called after a plugin writes a pref. */
|
|
251
|
+
readonly onPrefChanged?: (key: string, value: string) => void;
|
|
252
|
+
/** Called after a plugin writes a cache entry. */
|
|
253
|
+
readonly onCacheChanged?: (resId: string, key: string, value: string) => void;
|
|
254
|
+
/**
|
|
255
|
+
* Plugin asset vault implementation (workbench only). Absent → the
|
|
256
|
+
* asset methods answer `UNAVAILABLE` (tests, jsdom hosts). The real
|
|
257
|
+
* app routes these through its server pipeline via tRPC — the mock
|
|
258
|
+
* never talks to it.
|
|
259
|
+
*/
|
|
260
|
+
readonly assetVault?: PluginAssetVaultMock;
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* The workbench-side plugin asset vault: the mock hands `download` and
|
|
264
|
+
* `deleteAsset` to the host app's implementation (consent dialog + dev
|
|
265
|
+
* server fetch + local vault), mirroring the server pipeline's
|
|
266
|
+
* request/result vocabulary.
|
|
267
|
+
*/
|
|
268
|
+
type PluginAssetVaultMock = {
|
|
269
|
+
readonly download: (request: PluginDownloadRequest) => Promise<PluginDownloadResult>;
|
|
270
|
+
readonly deleteAsset: (path: string) => Promise<PluginAssetDeleteResult>;
|
|
271
|
+
};
|
|
272
|
+
type MockHost = {
|
|
273
|
+
/**
|
|
274
|
+
* Bind a message source to a plugin/resource. The real host binds
|
|
275
|
+
* iframe contentWindows; jsdom tests register the test window itself
|
|
276
|
+
* (plugin code posts to `window.parent`, which is itself).
|
|
277
|
+
*/
|
|
278
|
+
readonly register: (source: unknown, binding: HostBinding) => void;
|
|
279
|
+
readonly unregister: (source: unknown) => void;
|
|
280
|
+
/** Push a host event to one source. */
|
|
281
|
+
readonly push: (source: unknown, key: string, data?: unknown) => void;
|
|
282
|
+
/** Push the plugin context (the iframe mounts on this). */
|
|
283
|
+
readonly pushContext: (source: unknown, ctx: PluginIframeContext) => void;
|
|
284
|
+
readonly setVisibility: (source: unknown, visible: boolean) => void;
|
|
285
|
+
readonly messages: MockMessageStore;
|
|
286
|
+
readonly danmaku: MockDanmakuStore;
|
|
287
|
+
readonly prefs: ReadonlyMap<string, string>;
|
|
288
|
+
readonly cache: ReadonlyMap<string, string>;
|
|
289
|
+
readonly dispose: () => void;
|
|
290
|
+
};
|
|
291
|
+
declare function createMockHost(opts: MockHostOptions): MockHost;
|
|
292
|
+
|
|
293
|
+
export { type DownloadConsentEntry, type HostBinding, type HostHandlerContext, type HostHandlerEntry, type HostRouterDeps, type MockDanmakuStore, MockFileBackend, type MockHost, type MockHostLogger, type MockHostOptions, type MockMessageStore, type PluginAssetVaultMock, anchorData, closeDownloadConsent, createHostRouter, createMockDanmakuStore, createMockHost, createMockMessageStore, decideDownloadConsent, defineHandler, enqueueDownloadConsent, getDownloadConsentSnapshot, rehydrateDownloadConsent, requestDownloadConsent, requestSchemas, resetDownloadConsent, subscribeDownloadConsent };
|