@ai-switch/tauri-plugin-runtime 0.1.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 (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +327 -0
  3. package/THIRD_PARTY_NOTICES.md +210 -0
  4. package/dist/bridge/handshake.d.ts +11 -0
  5. package/dist/bridge/json-codec.d.ts +4 -0
  6. package/dist/bridge/rpc-peer.d.ts +7 -0
  7. package/dist/bridge/rpc-types.d.ts +20 -0
  8. package/dist/chunk-CFQSUF5W.js +1794 -0
  9. package/dist/chunk-JSBRDJBE.js +30 -0
  10. package/dist/chunk-K5YWIJN6.js +389 -0
  11. package/dist/chunk-PW7XHHWG.js +403 -0
  12. package/dist/chunk-RKQEK7DY.js +13879 -0
  13. package/dist/chunk-WT62GTMC.js +18 -0
  14. package/dist/chunk-YI6NQ6WR.js +513 -0
  15. package/dist/host/event-router.d.ts +19 -0
  16. package/dist/host/file-handles.d.ts +15 -0
  17. package/dist/host/host.d.ts +2 -0
  18. package/dist/host/index.d.ts +4 -0
  19. package/dist/host/index.js +791 -0
  20. package/dist/host/policy.d.ts +7 -0
  21. package/dist/host/requests.d.ts +13 -0
  22. package/dist/host/types.d.ts +19 -0
  23. package/dist/host/view.d.ts +18 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +9 -0
  26. package/dist/node/buffer.d.ts +7 -0
  27. package/dist/node/buffer.js +8 -0
  28. package/dist/node/events.d.ts +12 -0
  29. package/dist/node/events.js +458 -0
  30. package/dist/node/fs/backend.d.ts +8 -0
  31. package/dist/node/fs/callback-types.d.ts +43 -0
  32. package/dist/node/fs/callbacks.d.ts +3 -0
  33. package/dist/node/fs/client.d.ts +3 -0
  34. package/dist/node/fs/errors.d.ts +5 -0
  35. package/dist/node/fs/lifecycle.d.ts +11 -0
  36. package/dist/node/fs/options.d.ts +7 -0
  37. package/dist/node/fs/promises.d.ts +33 -0
  38. package/dist/node/fs/promises.js +30 -0
  39. package/dist/node/fs/transfer.d.ts +7 -0
  40. package/dist/node/fs/types.d.ts +86 -0
  41. package/dist/node/fs.d.ts +36 -0
  42. package/dist/node/fs.js +92 -0
  43. package/dist/node/path.d.ts +20 -0
  44. package/dist/node/path.js +434 -0
  45. package/dist/plugin/client.d.ts +4 -0
  46. package/dist/plugin/connection.d.ts +6 -0
  47. package/dist/plugin/errors.d.ts +3 -0
  48. package/dist/plugin/index.d.ts +6 -0
  49. package/dist/plugin/index.js +12 -0
  50. package/dist/plugin/types.d.ts +28 -0
  51. package/dist/protocol/capabilities.d.ts +8 -0
  52. package/dist/protocol/errors.d.ts +14 -0
  53. package/dist/protocol/generated/capabilities.generated.d.ts +56 -0
  54. package/dist/protocol/generated/fs.generated.d.ts +178 -0
  55. package/dist/protocol/generated/host-event.generated.d.ts +17 -0
  56. package/dist/protocol/generated/manifest.generated.d.ts +64 -0
  57. package/dist/protocol/generated/session.generated.d.ts +93 -0
  58. package/dist/protocol/generated/types.generated.d.ts +6 -0
  59. package/dist/protocol/generated/validators.generated.d.mts +24 -0
  60. package/dist/protocol/generated/wire.generated.d.ts +63 -0
  61. package/dist/protocol/index.d.ts +18 -0
  62. package/dist/protocol/index.js +746 -0
  63. package/dist/protocol/json-safety.d.ts +3 -0
  64. package/dist/protocol/limits.d.ts +11 -0
  65. package/dist/protocol/manifest.d.ts +5 -0
  66. package/dist/protocol/path-policy.d.ts +2 -0
  67. package/dist/protocol/schema/capabilities.schema.json +301 -0
  68. package/dist/protocol/schema/fs.schema.json +900 -0
  69. package/dist/protocol/schema/host-event.schema.json +116 -0
  70. package/dist/protocol/schema/manifest.schema.json +60 -0
  71. package/dist/protocol/schema/session.schema.json +145 -0
  72. package/dist/protocol/schema/wire.schema.json +358 -0
  73. package/dist/protocol/session.d.ts +3 -0
  74. package/dist/protocol/types.d.ts +27 -0
  75. package/dist/protocol/validation.d.ts +2 -0
  76. package/dist/protocol/wire.d.ts +16 -0
  77. package/package.json +95 -0
@@ -0,0 +1,30 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
+ // If the importer is in node compatibility mode or this is not an ESM
20
+ // file that has been converted to a CommonJS file using a Babel-
21
+ // compatible transform (i.e. "__esModule" has not been set), then set
22
+ // "default" to the CommonJS "module.exports" for node compatibility.
23
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
+ mod
25
+ ));
26
+
27
+ export {
28
+ __commonJS,
29
+ __toESM
30
+ };
@@ -0,0 +1,389 @@
1
+ import {
2
+ createRpcPeer,
3
+ readBootstrapHint,
4
+ validateConnectMessage
5
+ } from "./chunk-PW7XHHWG.js";
6
+ import {
7
+ AplgError,
8
+ satisfiesApiRange,
9
+ standardCapabilities,
10
+ validateCapabilityRequest,
11
+ validateCapabilityResult,
12
+ validateJson
13
+ } from "./chunk-RKQEK7DY.js";
14
+ import {
15
+ protocolVersion
16
+ } from "./chunk-WT62GTMC.js";
17
+
18
+ // src/plugin/client.ts
19
+ function frozenSnapshot(input) {
20
+ const copy = JSON.parse(JSON.stringify(input));
21
+ const freeze = (value) => {
22
+ if (value !== null && typeof value === "object") {
23
+ Object.values(value).forEach(freeze);
24
+ Object.freeze(value);
25
+ }
26
+ };
27
+ freeze(copy);
28
+ return copy;
29
+ }
30
+ function createPluginClient(peer, sessionInfo) {
31
+ if (!validateJson(sessionInfo).ok) throw new AplgError("E_INVALID_MESSAGE", "Invalid public session information.");
32
+ const info = frozenSnapshot(sessionInfo);
33
+ let state = "connected";
34
+ let opening = 0;
35
+ const subscriptions = /* @__PURE__ */ new Map();
36
+ const listeners2 = /* @__PURE__ */ new Set();
37
+ const earlyEvents = [];
38
+ let bufferTimer;
39
+ let removePeerListener = () => {
40
+ };
41
+ function setState(next) {
42
+ if (state === "closed" || state === next) return;
43
+ state = next;
44
+ if (next === "closed") {
45
+ subscriptions.clear();
46
+ earlyEvents.length = 0;
47
+ clearTimeout(bufferTimer);
48
+ bufferTimer = void 0;
49
+ removePeerListener();
50
+ }
51
+ for (const callback of [...listeners2]) {
52
+ try {
53
+ callback(next);
54
+ } catch {
55
+ }
56
+ }
57
+ if (next === "closed") listeners2.clear();
58
+ }
59
+ function assertConnected() {
60
+ if (state === "closed") throw new AplgError("E_SESSION_CLOSED", "The plugin session is closed.");
61
+ if (state === "disconnected") throw new AplgError("E_HOST_UNAVAILABLE", "The plugin host is disconnected.");
62
+ }
63
+ function supports(name, range) {
64
+ const capability = Object.hasOwn(info.capabilities, name) ? info.capabilities[name] : void 0;
65
+ return state !== "closed" && Boolean(capability && (range === void 0 || satisfiesApiRange(capability.version, range)));
66
+ }
67
+ function requireCapability(name, method) {
68
+ assertConnected();
69
+ if (!supports(name) || method !== void 0 && !info.capabilities[name].methods.includes(method)) {
70
+ throw new AplgError("E_CAPABILITY_UNAVAILABLE", "The requested capability or method is unavailable.");
71
+ }
72
+ }
73
+ async function call(capability, method, params = null, options) {
74
+ requireCapability(capability, method);
75
+ const standard = Object.hasOwn(standardCapabilities, capability);
76
+ if (standard && !validateCapabilityRequest(capability, method, params).ok) {
77
+ throw new AplgError("E_INVALID_ARGUMENT", "The capability request is invalid.");
78
+ }
79
+ const value = await peer.request("capability.call", { capability, method, params }, options);
80
+ if (state === "closed") throw new AplgError("E_SESSION_CLOSED", "The plugin session is closed.");
81
+ if (standard && !validateCapabilityResult(capability, method, value).ok) {
82
+ throw new AplgError("E_INVALID_MESSAGE", "The host returned an invalid capability result.");
83
+ }
84
+ return value;
85
+ }
86
+ function deliver(event, subscription) {
87
+ if (event.seq <= subscription.seq) return;
88
+ if (event.seq !== subscription.seq + 1) {
89
+ setState("disconnected");
90
+ setState("connected");
91
+ }
92
+ subscription.seq = event.seq;
93
+ try {
94
+ subscription.callback(event.payload);
95
+ } catch {
96
+ }
97
+ }
98
+ function clearExpired() {
99
+ const now = Date.now();
100
+ for (let index = earlyEvents.length - 1; index >= 0; index--) if (earlyEvents[index].expires <= now) earlyEvents.splice(index, 1);
101
+ clearTimeout(bufferTimer);
102
+ bufferTimer = void 0;
103
+ if (earlyEvents.length) bufferTimer = setTimeout(clearExpired, Math.max(1, earlyEvents[0].expires - now));
104
+ }
105
+ removePeerListener = peer.onEvent((event) => {
106
+ if (event.kind === "connection") {
107
+ setState(event.state);
108
+ return;
109
+ }
110
+ if (state !== "connected") return;
111
+ const subscription = subscriptions.get(event.subscriptionId);
112
+ if (subscription) {
113
+ deliver(event, subscription);
114
+ return;
115
+ }
116
+ if (opening > 0 && earlyEvents.length < 32) {
117
+ earlyEvents.push({ event, expires: Date.now() + 2e3 });
118
+ if (!bufferTimer) bufferTimer = setTimeout(clearExpired, 2e3);
119
+ }
120
+ });
121
+ return {
122
+ async ready() {
123
+ assertConnected();
124
+ return info;
125
+ },
126
+ capabilities: { supports },
127
+ call,
128
+ async subscribe(capability, topic, callback) {
129
+ requireCapability(capability);
130
+ if (typeof callback !== "function") throw new AplgError("E_INVALID_ARGUMENT", "An event callback is required.");
131
+ if (subscriptions.size + opening >= 64) throw new AplgError("E_LIMIT_EXCEEDED", "Too many plugin subscriptions.");
132
+ opening++;
133
+ try {
134
+ const value = await peer.request("subscription.open", { capability, topic });
135
+ if (state === "closed") throw new AplgError("E_SESSION_CLOSED", "The plugin session is closed.");
136
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).length !== 1 || typeof value.subscriptionId !== "string" || !/^[\x21-\x7e]{1,128}$/.test(value.subscriptionId) || subscriptions.has(value.subscriptionId)) {
137
+ peer.close(new AplgError("E_INVALID_MESSAGE", "Invalid subscription reply."));
138
+ throw new AplgError("E_INVALID_MESSAGE", "Invalid subscription reply.");
139
+ }
140
+ const id = value.subscriptionId;
141
+ if (state !== "connected") {
142
+ void peer.request("subscription.close", { subscriptionId: id }).catch(() => {
143
+ });
144
+ assertConnected();
145
+ }
146
+ const subscription = { seq: 0, callback };
147
+ subscriptions.set(id, subscription);
148
+ clearExpired();
149
+ for (let index = 0; index < earlyEvents.length; ) {
150
+ const item = earlyEvents[index];
151
+ if (item.event.subscriptionId === id) {
152
+ earlyEvents.splice(index, 1);
153
+ deliver(item.event, subscription);
154
+ } else index++;
155
+ }
156
+ return () => {
157
+ if (!subscriptions.delete(id)) return;
158
+ void peer.request("subscription.close", { subscriptionId: id }).catch(() => {
159
+ });
160
+ };
161
+ } finally {
162
+ opening--;
163
+ if (opening === 0) {
164
+ earlyEvents.length = 0;
165
+ clearTimeout(bufferTimer);
166
+ bufferTimer = void 0;
167
+ }
168
+ }
169
+ },
170
+ onConnectionChange(callback) {
171
+ if (state === "closed") {
172
+ callback("closed");
173
+ return () => {
174
+ };
175
+ }
176
+ listeners2.add(callback);
177
+ return () => {
178
+ listeners2.delete(callback);
179
+ };
180
+ },
181
+ storage: {
182
+ get: (key) => call("aplg.storage", "get", { key }),
183
+ async set(key, value) {
184
+ await call("aplg.storage", "set", { key, value });
185
+ },
186
+ async remove(key) {
187
+ await call("aplg.storage", "remove", { key });
188
+ }
189
+ },
190
+ dialog: {
191
+ async pickDirectory(options = {}) {
192
+ if (!validateCapabilityRequest("aplg.dialog", "pickDirectory", options).ok) {
193
+ throw new AplgError("E_INVALID_ARGUMENT", "The directory picker options are invalid.");
194
+ }
195
+ return call("aplg.dialog", "pickDirectory", { access: options.access ?? "read" });
196
+ }
197
+ }
198
+ };
199
+ }
200
+
201
+ // src/plugin/connection.ts
202
+ var client;
203
+ var connecting;
204
+ var ready;
205
+ var currentState = "idle";
206
+ var listeners = /* @__PURE__ */ new Set();
207
+ function closeTransferredPorts(event) {
208
+ for (const port of event.ports) port.close();
209
+ }
210
+ function connectWindow(target) {
211
+ if (target.parent === target) return Promise.reject(new AplgError("E_HOST_UNAVAILABLE", "A plugin must be opened by an APLG host."));
212
+ let hint;
213
+ try {
214
+ hint = readBootstrapHint(target.location.href);
215
+ } catch (error) {
216
+ return Promise.reject(error);
217
+ }
218
+ return new Promise((resolve, reject) => {
219
+ let peer;
220
+ let settled = false;
221
+ let handshakeAccepted = false;
222
+ let removeAckListener = () => {
223
+ };
224
+ let removeCloseListener = () => {
225
+ };
226
+ const timer = setTimeout(() => fail(new AplgError("E_TIMEOUT", "The plugin host did not complete the handshake.")), 1e4);
227
+ function clearHandshake() {
228
+ clearTimeout(timer);
229
+ target.removeEventListener("message", receive);
230
+ removeAckListener();
231
+ }
232
+ function fail(error) {
233
+ if (settled) return;
234
+ settled = true;
235
+ clearHandshake();
236
+ target.removeEventListener("pagehide", leave);
237
+ removeCloseListener();
238
+ peer?.close(error);
239
+ reject(error);
240
+ }
241
+ function leave() {
242
+ if (!settled) fail(new AplgError("E_SESSION_CLOSED", "The plugin view was unloaded."));
243
+ else peer?.close();
244
+ }
245
+ function receive(event) {
246
+ if (event.source !== target.parent || event.origin !== hint.parentOrigin) {
247
+ closeTransferredPorts(event);
248
+ return;
249
+ }
250
+ const data = event.data;
251
+ if (data === null || typeof data !== "object" || Array.isArray(data) || !Object.hasOwn(data, "nonce") || data.nonce !== hint.nonce) {
252
+ closeTransferredPorts(event);
253
+ return;
254
+ }
255
+ if (handshakeAccepted) {
256
+ closeTransferredPorts(event);
257
+ return;
258
+ }
259
+ let info;
260
+ try {
261
+ info = validateConnectMessage(data, hint.nonce);
262
+ if (event.ports.length !== 1) throw new AplgError("E_PROTOCOL_MISMATCH", "The host must provide exactly one RPC port.");
263
+ } catch {
264
+ closeTransferredPorts(event);
265
+ fail(new AplgError("E_PROTOCOL_MISMATCH", "The bootstrap response was invalid."));
266
+ return;
267
+ }
268
+ handshakeAccepted = true;
269
+ peer = createRpcPeer(event.ports[0], { maxBytes: info.limits.controlBytes });
270
+ removeCloseListener = peer.onEvent((message) => {
271
+ if (message.kind === "connection" && message.state === "closed") {
272
+ target.removeEventListener("pagehide", leave);
273
+ if (!settled) fail(new AplgError("E_SESSION_CLOSED", "The host closed during the handshake."));
274
+ removeCloseListener();
275
+ }
276
+ });
277
+ removeAckListener = peer.onEvent((message) => {
278
+ if (settled || message.kind !== "connection" || message.state !== "connected") return;
279
+ try {
280
+ const connectedClient = createPluginClient(peer, info);
281
+ try {
282
+ target.history.replaceState(target.history.state, "", `${target.location.pathname}${target.location.search}${hint.originalHash}`);
283
+ } catch {
284
+ target.location.hash = hint.originalHash;
285
+ }
286
+ settled = true;
287
+ clearHandshake();
288
+ resolve(connectedClient);
289
+ } catch {
290
+ fail(new AplgError("E_PROTOCOL_MISMATCH", "The plugin connection could not be initialized."));
291
+ }
292
+ });
293
+ try {
294
+ peer.sendEvent({ protocol: protocolVersion, kind: "connection", state: "connected" });
295
+ } catch {
296
+ fail(new AplgError("E_SESSION_CLOSED", "The handshake port is unavailable."));
297
+ }
298
+ }
299
+ target.addEventListener("message", receive);
300
+ target.addEventListener("pagehide", leave, { once: true });
301
+ try {
302
+ target.parent.postMessage({ channel: "aplg.bootstrap", protocol: protocolVersion, kind: "ready", nonce: hint.nonce }, hint.parentOrigin);
303
+ } catch {
304
+ fail(new AplgError("E_HOST_UNAVAILABLE", "The plugin host cannot be reached."));
305
+ }
306
+ });
307
+ }
308
+ function getPluginClient() {
309
+ connecting ??= (typeof window === "undefined" ? Promise.reject(new AplgError("E_HOST_UNAVAILABLE", "A plugin connection requires a browser host.")) : connectWindow(window)).then((value) => {
310
+ client = value;
311
+ currentState = "connected";
312
+ value.onConnectionChange((state) => {
313
+ currentState = state;
314
+ for (const callback of [...listeners]) {
315
+ try {
316
+ callback(state);
317
+ } catch {
318
+ }
319
+ }
320
+ if (state === "closed") listeners.clear();
321
+ });
322
+ return value;
323
+ }).catch((error) => {
324
+ currentState = "closed";
325
+ for (const callback of [...listeners]) {
326
+ try {
327
+ callback("closed");
328
+ } catch {
329
+ }
330
+ }
331
+ listeners.clear();
332
+ throw error;
333
+ });
334
+ return connecting;
335
+ }
336
+ function connectPlugin() {
337
+ if (client) return client.ready();
338
+ ready ??= getPluginClient().then((value) => value.ready());
339
+ return ready;
340
+ }
341
+ function supportsCapability(name, range) {
342
+ return client?.capabilities.supports(name, range) ?? false;
343
+ }
344
+ function onConnectionChange(callback) {
345
+ if (currentState === "closed") {
346
+ try {
347
+ callback("closed");
348
+ } catch {
349
+ }
350
+ return () => {
351
+ };
352
+ }
353
+ listeners.add(callback);
354
+ return () => {
355
+ listeners.delete(callback);
356
+ };
357
+ }
358
+
359
+ // src/plugin/index.ts
360
+ var aplg = {
361
+ ready: connectPlugin,
362
+ capabilities: { supports: supportsCapability },
363
+ async call(capability, method, params, options) {
364
+ return (await getPluginClient()).call(capability, method, params, options);
365
+ },
366
+ async subscribe(capability, topic, callback) {
367
+ return (await getPluginClient()).subscribe(capability, topic, callback);
368
+ },
369
+ onConnectionChange,
370
+ storage: {
371
+ async get(key) {
372
+ return (await getPluginClient()).storage.get(key);
373
+ },
374
+ async set(key, value) {
375
+ return (await getPluginClient()).storage.set(key, value);
376
+ },
377
+ async remove(key) {
378
+ return (await getPluginClient()).storage.remove(key);
379
+ }
380
+ },
381
+ dialog: { async pickDirectory(options) {
382
+ return (await getPluginClient()).dialog.pickDirectory(options);
383
+ } }
384
+ };
385
+
386
+ export {
387
+ connectPlugin,
388
+ aplg
389
+ };