@ekrooh/bare 0.4.0 → 0.6.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.
@@ -1,9 +1,11 @@
1
- import { ErrorCode, definePlugin, err, ok } from "./index.mjs";
1
+ import { g as ErrorCode, m as ok, p as err, r as definePlugin } from "./messages-CevD8qkV.mjs";
2
2
  import { discoverySpecs } from "./plugins-discovery-events.mjs";
3
3
  import { healthSpecs } from "./plugins-health-events.mjs";
4
+ import { logsSpecs } from "./plugins-logs-events.mjs";
4
5
  import { mediaSpecs } from "./plugins-media-events.mjs";
5
6
  import { permissionSpecs } from "./plugins-permissions-events.mjs";
6
- //#region plugins/discovery/plugin.ts
7
+ import crypto from "bare-crypto";
8
+ // plugins/discovery/plugin.ts
7
9
  function mergeCapabilityRows(a, b) {
8
10
  const map = /* @__PURE__ */ new Map();
9
11
  for (const row of [...a, ...b]) {
@@ -40,8 +42,7 @@ function createDiscoveryPlugin(deps) {
40
42
  } }
41
43
  });
42
44
  }
43
- //#endregion
44
- //#region plugins/health/plugin.ts
45
+ // plugins/health/plugin.ts
45
46
  function createHealthPlugin() {
46
47
  return definePlugin("core.health", healthSpecs, {
47
48
  capabilities: ["health"],
@@ -61,10 +62,32 @@ function createHealthPlugin() {
61
62
  }
62
63
  });
63
64
  }
64
- //#endregion
65
- //#region plugins/media/plugin.ts
65
+ const LOGS_VIEW_DEFAULT_TAIL = 20;
66
+ function createLogsPlugin(deps) {
67
+ return definePlugin("core.logs", logsSpecs, {
68
+ capabilities: ["logs"],
69
+ invoke: {
70
+ view: (args) => {
71
+ const tail = args?.tail === void 0 ? LOGS_VIEW_DEFAULT_TAIL : Math.max(0, Math.min(args.tail, 100));
72
+ return ok({ entries: deps.store.view({
73
+ tail,
74
+ level: args?.level,
75
+ source: args?.source
76
+ }) });
77
+ },
78
+ clear: () => ok({ cleared: deps.store.clear() })
79
+ }
80
+ });
81
+ }
82
+ // plugins/media/plugin.ts
83
+ /** Most media mounts are consumed once and then linger. Cap how many stay
84
+ * mounted at once and evict the least-recently-used so picked/captured files
85
+ * do not accumulate on the loopback server for the whole session. */
86
+ const MEDIA_MOUNT_CAP = 4;
87
+ const MEDIA_KINDS = ["image", "video"];
66
88
  function newRequestId() {
67
- return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
89
+ const rand = crypto.randomBytes(16).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
90
+ return `${Date.now().toString(36)}-${rand}`;
68
91
  }
69
92
  /**
70
93
  * `vendor.media` — reference plugin demonstrating out-of-band binary transfer.
@@ -74,25 +97,35 @@ function newRequestId() {
74
97
  * is identical on every runtime.
75
98
  */
76
99
  function createMediaPlugin(deps) {
100
+ const mounted = /* @__PURE__ */ new Map();
101
+ const mountMedia = (id, path) => {
102
+ deps.staticServer.mount(`/media/${id}`, path);
103
+ mounted.set(id, path);
104
+ while (mounted.size > MEDIA_MOUNT_CAP) {
105
+ const oldestId = mounted.keys().next().value;
106
+ const oldestPath = mounted.get(oldestId);
107
+ mounted.delete(oldestId);
108
+ if (oldestPath !== void 0) deps.staticServer.unmount(`/media/${oldestId}`);
109
+ }
110
+ };
77
111
  const serve = async (event, args) => {
112
+ const kind = args?.kind;
113
+ if (kind !== void 0 && !MEDIA_KINDS.includes(kind)) return err(ErrorCode.PLUGIN_ERROR, `Unknown media kind for ${event}`);
78
114
  const host = await deps.invokeOnHost({
79
115
  type: "INVOKE_REQUEST",
80
116
  pluginId: "vendor.media",
81
117
  event,
82
118
  requestId: newRequestId(),
83
- args
119
+ args: kind === void 0 ? {} : { kind }
84
120
  }, /* @__PURE__ */ new Uint8Array(0));
85
121
  if (!host) return err(ErrorCode.HOST_ERROR, `Host did not answer ${event}`);
86
122
  if (host.error) return err(host.error.code || ErrorCode.HOST_ERROR, host.error.message ?? `Host failed ${event}`);
87
123
  const path = host.result?.path;
88
124
  if (!path) return err(ErrorCode.HOST_ERROR, `Host returned no path for ${event}`);
89
- const id = `${args?.kind ?? "media"}-${newRequestId()}`;
90
- deps.staticServer.mount(`/media/${id}`, path);
125
+ const id = `${kind ?? "media"}-${newRequestId()}`;
126
+ mountMedia(id, path);
91
127
  const url = await deps.staticServer.url(`/media/${id}`);
92
- return ok({
93
- url,
94
- path
95
- });
128
+ return ok({ url });
96
129
  };
97
130
  return definePlugin("vendor.media", mediaSpecs, {
98
131
  capabilities: ["media"],
@@ -102,8 +135,7 @@ function createMediaPlugin(deps) {
102
135
  }
103
136
  });
104
137
  }
105
- //#endregion
106
- //#region plugins/permissions/plugin.ts
138
+ // plugins/permissions/plugin.ts
107
139
  /**
108
140
  * Declares host-only permission events. Handlers are registered on the Android host
109
141
  * via {@code HostPluginRegistry}; the worklet delegates invokes here over IPC.
@@ -111,15 +143,14 @@ function createMediaPlugin(deps) {
111
143
  function createPermissionsPluginStub() {
112
144
  return definePlugin("core.permissions", permissionSpecs, { capabilities: ["permissions"] });
113
145
  }
114
- //#endregion
115
- //#region plugins/index.ts
146
+ // plugins/index.ts
116
147
  function createDefaultPlugins(deps) {
117
148
  return [
118
149
  createHealthPlugin(),
119
150
  createDiscoveryPlugin(deps),
120
151
  createPermissionsPluginStub(),
121
- createMediaPlugin(deps)
152
+ createMediaPlugin(deps),
153
+ createLogsPlugin(deps)
122
154
  ];
123
155
  }
124
- //#endregion
125
156
  export { createDefaultPlugins as t };
@@ -1,10 +1,9 @@
1
- import { A as CapabilityDescriptor, B as InvokeEnvelope } from "./index-DjulYFJL.mjs";
2
- //#region plugins/discovery/events.d.ts
3
- type DiscoveryListResult = {
1
+ import { F as CapabilityDescriptor, G as InvokeEnvelope } from "./index-BkwUzwVt.mjs";
2
+ export type DiscoveryListResult = {
4
3
  schemaVersion: 1;
5
4
  capabilities: CapabilityDescriptor[];
6
5
  };
7
- declare const discoverySpecs: {
6
+ export declare const discoverySpecs: {
8
7
  readonly list: {
9
8
  readonly pluginId: 'core.discovery';
10
9
  readonly name: 'discovery.list';
@@ -12,10 +11,8 @@ declare const discoverySpecs: {
12
11
  readonly result: DiscoveryListResult;
13
12
  };
14
13
  };
15
- declare const discoveryEvents: {
14
+ export declare const discoveryEvents: {
16
15
  discovery: {
17
16
  list(): InvokeEnvelope<"discovery.list", Record<string, never>, DiscoveryListResult>;
18
17
  };
19
- };
20
- //#endregion
21
- export { DiscoveryListResult, discoveryEvents, discoverySpecs };
18
+ };
@@ -1,5 +1,5 @@
1
- import { invokeEvent } from "./index.mjs";
2
- //#region plugins/discovery/events.ts
1
+ import { a as invokeEvent } from "./messages-CevD8qkV.mjs";
2
+ // plugins/discovery/events.ts
3
3
  const discoverySpecs = { list: {
4
4
  pluginId: "core.discovery",
5
5
  name: "discovery.list",
@@ -9,5 +9,4 @@ const discoverySpecs = { list: {
9
9
  const discoveryEvents = { discovery: { list() {
10
10
  return invokeEvent(discoverySpecs.list, {});
11
11
  } } };
12
- //#endregion
13
12
  export { discoveryEvents, discoverySpecs };
@@ -1,6 +1,5 @@
1
- import { B as InvokeEnvelope } from "./index-DjulYFJL.mjs";
2
- //#region plugins/health/events.d.ts
3
- declare const healthSpecs: {
1
+ import { G as InvokeEnvelope } from "./index-BkwUzwVt.mjs";
2
+ export declare const healthSpecs: {
4
3
  readonly ping: {
5
4
  readonly pluginId: 'core.health';
6
5
  readonly name: 'health.ping';
@@ -33,7 +32,7 @@ declare const healthSpecs: {
33
32
  };
34
33
  };
35
34
  };
36
- declare const healthEvents: {
35
+ export declare const healthEvents: {
37
36
  health: {
38
37
  ping(message?: string): InvokeEnvelope<'health.ping', {
39
38
  message?: string;
@@ -52,6 +51,4 @@ declare const healthEvents: {
52
51
  ts: number;
53
52
  }>;
54
53
  };
55
- };
56
- //#endregion
57
- export { healthEvents, healthSpecs };
54
+ };
@@ -1,5 +1,5 @@
1
- import { invokeEvent } from "./index.mjs";
2
- //#region plugins/health/events.ts
1
+ import { a as invokeEvent } from "./messages-CevD8qkV.mjs";
2
+ // plugins/health/events.ts
3
3
  const healthSpecs = {
4
4
  ping: {
5
5
  pluginId: "core.health",
@@ -31,5 +31,4 @@ const healthEvents = { health: {
31
31
  return invokeEvent(healthSpecs.roundtrip, {});
32
32
  }
33
33
  } };
34
- //#endregion
35
34
  export { healthEvents, healthSpecs };
@@ -0,0 +1,34 @@
1
+ import { G as InvokeEnvelope, i as LogSource, n as LogEntry, r as LogLevel } from "./index-BkwUzwVt.mjs";
2
+ export type LogsViewArgs = {
3
+ /** Most-recent N matching entries. Defaults to a small window. */
4
+ tail?: number;
5
+ level?: LogLevel;
6
+ source?: LogSource;
7
+ };
8
+ export type LogsViewResult = {
9
+ entries: LogEntry[];
10
+ };
11
+ export type LogsClearResult = {
12
+ cleared: number;
13
+ };
14
+ export declare const logsSpecs: {
15
+ readonly view: {
16
+ readonly pluginId: 'core.logs';
17
+ readonly name: 'logs.view';
18
+ readonly args: LogsViewArgs;
19
+ readonly result: LogsViewResult;
20
+ };
21
+ readonly clear: {
22
+ readonly pluginId: 'core.logs';
23
+ readonly name: 'logs.clear';
24
+ readonly args: Record<string, never>;
25
+ readonly result: LogsClearResult;
26
+ };
27
+ };
28
+ export declare const logEvents: {
29
+ logs: {
30
+ view(options?: LogsViewArgs): InvokeEnvelope<'logs.view', LogsViewArgs, LogsViewResult>;
31
+ clear(): InvokeEnvelope<'logs.clear', Record<string, never>, LogsClearResult>;
32
+ };
33
+ };
34
+ export type { LogEntry, LogLevel, LogSource };
@@ -0,0 +1,25 @@
1
+ import { a as invokeEvent } from "./messages-CevD8qkV.mjs";
2
+ // plugins/logs/events.ts
3
+ const logsSpecs = {
4
+ view: {
5
+ pluginId: "core.logs",
6
+ name: "logs.view",
7
+ args: {},
8
+ result: {}
9
+ },
10
+ clear: {
11
+ pluginId: "core.logs",
12
+ name: "logs.clear",
13
+ args: {},
14
+ result: {}
15
+ }
16
+ };
17
+ const logEvents = { logs: {
18
+ view(options = {}) {
19
+ return invokeEvent(logsSpecs.view, options);
20
+ },
21
+ clear() {
22
+ return invokeEvent(logsSpecs.clear, {});
23
+ }
24
+ } };
25
+ export { logEvents, logsSpecs };
@@ -1,13 +1,10 @@
1
- import { B as InvokeEnvelope } from "./index-DjulYFJL.mjs";
2
- //#region plugins/media/events.d.ts
3
- type MediaKind = 'image' | 'video';
4
- type MediaResult = {
1
+ import { G as InvokeEnvelope } from "./index-BkwUzwVt.mjs";
2
+ export type MediaKind = 'image' | 'video';
3
+ export type MediaResult = {
5
4
  /** URL served by the worklet's loopback HTTP server (no bytes on the wire). */
6
5
  url: string;
7
- /** Absolute filesystem path of the picked file on the host. */
8
- path: string;
9
6
  };
10
- declare const mediaSpecs: {
7
+ export declare const mediaSpecs: {
11
8
  readonly pick: {
12
9
  readonly pluginId: 'vendor.media';
13
10
  readonly name: 'media.pick';
@@ -25,7 +22,7 @@ declare const mediaSpecs: {
25
22
  readonly result: MediaResult;
26
23
  };
27
24
  };
28
- declare const mediaEvents: {
25
+ export declare const mediaEvents: {
29
26
  media: {
30
27
  pick(kind?: MediaKind): InvokeEnvelope<'media.pick', {
31
28
  kind?: MediaKind;
@@ -34,6 +31,4 @@ declare const mediaEvents: {
34
31
  kind?: MediaKind;
35
32
  }, MediaResult>;
36
33
  };
37
- };
38
- //#endregion
39
- export { MediaKind, MediaResult, mediaEvents, mediaSpecs };
34
+ };
@@ -1,5 +1,5 @@
1
- import { invokeEvent } from "./index.mjs";
2
- //#region plugins/media/events.ts
1
+ import { a as invokeEvent } from "./messages-CevD8qkV.mjs";
2
+ // plugins/media/events.ts
3
3
  const MEDIA_INVOKE_TIMEOUT_MS = 3e5;
4
4
  const mediaSpecs = {
5
5
  pick: {
@@ -23,5 +23,4 @@ const mediaEvents = { media: {
23
23
  return invokeEvent(mediaSpecs.capture, { kind }, null, MEDIA_INVOKE_TIMEOUT_MS);
24
24
  }
25
25
  } };
26
- //#endregion
27
26
  export { mediaEvents, mediaSpecs };
@@ -1,13 +1,12 @@
1
- import { B as InvokeEnvelope } from "./index-DjulYFJL.mjs";
2
- //#region plugins/permissions/events.d.ts
1
+ import { G as InvokeEnvelope } from "./index-BkwUzwVt.mjs";
3
2
  /** Canonical permission ids. Hosts map each to their platform equivalent. */
4
- type PermissionId = 'storage' | 'camera';
5
- type PermissionStatus = 'granted' | 'denied' | 'notDetermined' | 'unsupported';
6
- type PermissionResult = {
3
+ export type PermissionId = 'storage' | 'camera';
4
+ export type PermissionStatus = 'granted' | 'denied' | 'notDetermined' | 'unsupported';
5
+ export type PermissionResult = {
7
6
  permission: PermissionId;
8
7
  status: PermissionStatus;
9
8
  };
10
- declare const permissionSpecs: {
9
+ export declare const permissionSpecs: {
11
10
  readonly request: {
12
11
  readonly pluginId: 'core.permissions';
13
12
  readonly name: 'permissions.request';
@@ -25,7 +24,7 @@ declare const permissionSpecs: {
25
24
  readonly result: PermissionResult;
26
25
  };
27
26
  };
28
- declare const permissionEvents: {
27
+ export declare const permissionEvents: {
29
28
  permissions: {
30
29
  request(permission: PermissionId): InvokeEnvelope<'permissions.request', {
31
30
  permission: PermissionId;
@@ -34,6 +33,4 @@ declare const permissionEvents: {
34
33
  permission: PermissionId;
35
34
  }, PermissionResult>;
36
35
  };
37
- };
38
- //#endregion
39
- export { PermissionId, PermissionResult, PermissionStatus, permissionEvents, permissionSpecs };
36
+ };
@@ -1,5 +1,5 @@
1
- import { invokeEvent } from "./index.mjs";
2
- //#region plugins/permissions/events.ts
1
+ import { a as invokeEvent } from "./messages-CevD8qkV.mjs";
2
+ // plugins/permissions/events.ts
3
3
  const permissionSpecs = {
4
4
  request: {
5
5
  pluginId: "core.permissions",
@@ -22,5 +22,4 @@ const permissionEvents = { permissions: {
22
22
  return invokeEvent(permissionSpecs.status, { permission });
23
23
  }
24
24
  } };
25
- //#endregion
26
25
  export { permissionEvents, permissionSpecs };
@@ -1,6 +1,5 @@
1
- import { A as CapabilityDescriptor, G as PluginInvokeRequestHeader, K as PluginInvokeResponseHeader, Y as RuntimeTarget, q as PluginManifest } from "./index-DjulYFJL.mjs";
2
- import { n as LoopbackServer } from "./static-file-server-DY9EKEVf.mjs";
3
- //#region plugins/discovery/plugin.d.ts
1
+ import { F as CapabilityDescriptor, Q as PluginManifest, X as PluginInvokeRequestHeader, Z as PluginInvokeResponseHeader, a as LogStore, et as RuntimeTarget } from "./index-BkwUzwVt.mjs";
2
+ import { n as LoopbackServer } from "./static-file-server-COxd-PFR.mjs";
4
3
  type DiscoveryPluginDeps = {
5
4
  listBareCapabilities: () => Array<{
6
5
  pluginId: string;
@@ -10,17 +9,16 @@ type DiscoveryPluginDeps = {
10
9
  }>;
11
10
  queryHostCapabilities: () => Promise<CapabilityDescriptor[]>;
12
11
  };
13
- //#endregion
14
- //#region plugins/media/plugin.d.ts
12
+ type LogsPluginDeps = {
13
+ /** Shared ring buffer fed by the worklet capture seam and the ingest route. */
14
+ store: LogStore;
15
+ };
15
16
  type MediaPluginDeps = {
16
17
  /** Worklet-side loopback server exposing picked files to the web layer. */
17
18
  staticServer: LoopbackServer;
18
19
  /** Delegates the native pick/capture to the host (`HOST_INVOKE_REQUEST`). */
19
20
  invokeOnHost: (header: PluginInvokeRequestHeader, payload: Uint8Array) => Promise<PluginInvokeResponseHeader | null>;
20
21
  };
21
- //#endregion
22
- //#region plugins/index.d.ts
23
- type DefaultPluginsDeps = DiscoveryPluginDeps & MediaPluginDeps;
24
- declare function createDefaultPlugins(deps: DefaultPluginsDeps): PluginManifest[];
25
- //#endregion
26
- export { DefaultPluginsDeps, type DiscoveryPluginDeps, type MediaPluginDeps, createDefaultPlugins };
22
+ export type DefaultPluginsDeps = DiscoveryPluginDeps & MediaPluginDeps & LogsPluginDeps;
23
+ export declare function createDefaultPlugins(deps: DefaultPluginsDeps): PluginManifest[];
24
+ export type { DiscoveryPluginDeps, LogsPluginDeps, MediaPluginDeps };
package/dist/plugins.mjs CHANGED
@@ -1,2 +1 @@
1
- import { t as createDefaultPlugins } from "./plugins-1KweEBct.mjs";
2
- export { createDefaultPlugins };
1
+ export { t as createDefaultPlugins } from "./plugins-Ddp2AgOe.mjs";
@@ -1,75 +1,70 @@
1
- import { A as CapabilityDescriptor, G as PluginInvokeRequestHeader, K as PluginInvokeResponseHeader, V as MessageHeader, d as MessageProtocol, q as PluginManifest, t as BareRuntimeContext, v as createPluginRegistry, y as createPluginRouter } from "./index-DjulYFJL.mjs";
2
- import { i as createLoopbackServer, n as LoopbackServer, r as collectRequestBody, t as LoopbackRouteHandler } from "./static-file-server-DY9EKEVf.mjs";
3
- //#region core/messages/host-ipc.d.ts
1
+ import { C as createPluginRegistry, F as CapabilityDescriptor, K as MessageHeader, Q as PluginManifest, X as PluginInvokeRequestHeader, Z as PluginInvokeResponseHeader, g as MessageProtocol, o as BareRuntimeContext, tt as WireMessage, w as createPluginRouter } from "./index-BkwUzwVt.mjs";
2
+ import { i as createLoopbackServer, n as LoopbackServer, r as collectRequestBody, t as LoopbackRouteHandler } from "./static-file-server-COxd-PFR.mjs";
4
3
  type BareIpcLike = {
5
- write(data: Uint8Array | Buffer | string): boolean;
4
+ write(data: Uint8Array | string): boolean;
6
5
  };
7
6
  declare function createHostIpcBridge(config: {
8
7
  ipc: BareIpcLike;
9
8
  protocol: MessageProtocol;
10
9
  }): {
11
- tryConsumeDownstreamFromHost(raw: Uint8Array | ArrayBuffer | Buffer): boolean;
10
+ tryConsumeDownstream: (parsed: WireMessage) => boolean;
11
+ tryConsumeDownstreamFromHost(raw: Uint8Array | ArrayBuffer): boolean;
12
12
  queryCapabilities(timeoutMs?: number): Promise<CapabilityDescriptor[]>;
13
13
  invokeOnHost(header: PluginInvokeRequestHeader, payload: Uint8Array, timeoutMs?: number): Promise<PluginInvokeResponseHeader | null>;
14
14
  };
15
- //#endregion
16
- //#region core/server/websocket-server.d.ts
17
15
  /** Envelope encoder bound to a loopback server's connected protocol socket —
18
16
  * the server-initiated (backend → web) push seam. */
19
17
  type LoopbackPush = (header: MessageHeader, payload?: Uint8Array | ArrayBuffer | null) => boolean;
20
18
  /** Builds the push seam for the server's connected protocol socket: encodes a
21
19
  * `DISPATCH`-style envelope and writes it, mirroring how `attachWebSocketProtocol`
22
20
  * writes responses. Returns false when no socket is connected. */
23
- declare function createLoopbackPush(server: LoopbackServer, protocol: MessageProtocol): LoopbackPush;
21
+ export declare function createLoopbackPush(server: LoopbackServer, protocol: MessageProtocol): LoopbackPush;
24
22
  /**
25
23
  * Attaches the framed-protocol socket to the unified loopback server. The
26
24
  * server owns the WebSocket upgrade (origin check, cookie/token auth, single
27
- * client, idle timeout); this layer only routes decoded envelopes through the
28
- * plugin router and writes responses back as raw frames.
25
+ * client, idle timeout); this layer runs one frame channel per socket. A peer
26
+ * that sends a malformed frame is not recoverable on that socket, so it is
27
+ * torn down and the client reconnects.
29
28
  */
30
- declare function attachWebSocketProtocol(server: LoopbackServer, context: BareRuntimeContext): void;
31
- //#endregion
32
- //#region core/lib/get-ipc.d.ts
29
+ export declare function attachWebSocketProtocol(server: LoopbackServer, context: BareRuntimeContext): void;
33
30
  /**
34
31
  * @fileoverview Bare IPC provider for Android (BareKit) and Sidecar (Bare.IPC)
35
32
  */
36
33
  interface BareIPC extends NodeJS.EventEmitter {
37
34
  read(n?: number): Buffer | null;
38
- write(data: Buffer | string): boolean;
35
+ write(data: Uint8Array | string): boolean;
39
36
  resume?(): void;
40
37
  pause?(): void;
41
38
  }
42
39
  /**
43
- * Returns the active IPC channel.
44
- * In BareKit (Android), it uses BareKit.IPC.
40
+ * Returns the active IPC channel, or null when there is no host.
41
+ * In BareKit (Android, iOS), it uses BareKit.IPC.
45
42
  * In Bare (Sidecar), it uses Bare.IPC.
46
43
  */
47
- declare function getIPC(): BareIPC;
48
- //#endregion
49
- //#region core/runtime.d.ts
44
+ export declare function getIPC(): BareIPC | null;
50
45
  /** Resolves the host-provided worklet configuration from `start(...)`
51
46
  * arguments. On-device hosts pass `["<webAssets>", "<storage>", "<cache>"]`
52
- * (three existing directories, in that order), landing at `Bare.argv[0..2]`;
53
- * the Bare CLI (dev) passes the binary and the script path instead, so a
54
- * missing/absent config means dev mode (auth off, fixed port, no handoff
55
- * file). Falls back to the labeled CLI token syntax (see `resolveCliConfig`)
56
- * when the positional shape doesn't match, so the same entry works for both
57
- * device and dev runs. */
58
- declare function resolveWorkletConfig(): WorkletRuntimeOptions;
47
+ * (three existing directories, in that order), landing at `Bare.argv[0..2]`.
48
+ * Falls back to the labeled CLI token syntax (see `resolveCliConfig`) when the
49
+ * positional shape doesn't match, so the same entry works for device and dev
50
+ * runs. Nothing here turns auth off: the dev backend is selected only by an
51
+ * explicit `mode=dev` token. */
52
+ export declare function resolveWorkletConfig(): WorkletRuntimeOptions;
59
53
  /**
60
- * Parses the dev/CLI labeled-token configuration from bare CLI arguments:
61
- * `webassets=<dir>`, `storage=<dir>`, `cache=<dir>`, `host=<addr>`,
62
- * `port=<n>`, `auth=<on|off|true|false|1|0>` — a single `key=value` separator.
63
- * Unknown labels (e.g. `bootstrap=127.0.0.1:49737`) are ignored and stay
64
- * consumer-owned.
54
+ * Parses labeled-token configuration from bare CLI arguments, one `key=value`
55
+ * per token: `webassets=<dir>`, `storage=<dir>`, `cache=<dir>`,
56
+ * `host=<addr>`, `port=<n>`, `auth=<on|off|true|false|1|0>`,
57
+ * `mode=<device|dev>` and `origin=<scheme://host[:port]>` (repeatable; an
58
+ * extra allowed page origin, e.g. the Vite dev server). Unknown labels (e.g.
59
+ * `bootstrap=127.0.0.1:49737`) are ignored and stay consumer-owned.
65
60
  *
66
- * Returns the equivalent `WorkletRuntimeOptions` in **dev mode**: `deviceMode:
67
- * false` (so a `storage=` token does not flip auth on or make the port
68
- * ephemeral), `auth: false`, `port: 8080`, each overridable by a token. When
69
- * no labeled tokens are present it returns `{}` (plain dev defaults).
61
+ * Without `mode=dev` the result keeps the secure device defaults (auth on, an
62
+ * ephemeral port), and `auth=off` is ignored with a warning. `mode=dev` selects the dev backend: `deviceMode: false`,
63
+ * `auth: false`, `port: 8080`, each overridable by a token. Returns `{}` when
64
+ * no labeled tokens are present.
70
65
  */
71
- declare function resolveCliConfig(argv?: readonly string[]): WorkletRuntimeOptions;
72
- type WorkletRuntimeOptions = {
66
+ export declare function resolveCliConfig(argv?: readonly string[]): WorkletRuntimeOptions;
67
+ export type WorkletRuntimeOptions = {
73
68
  /** Directory to serve at `/` (the built web app). */
74
69
  webAssets?: string;
75
70
  /** Durable app-sandbox directory: `handoff.json` + the p2p corestore. */
@@ -81,25 +76,59 @@ type WorkletRuntimeOptions = {
81
76
  /** Port to bind; `0` picks an ephemeral port (on-device). Defaults to an
82
77
  * ephemeral port in device mode, 8080 in dev mode. */
83
78
  port?: number;
84
- /** Require the per-session token/cookie. Defaults to on in device mode. */
79
+ /** Require the per-session token/cookie. Defaults to on in device mode and
80
+ * off in dev mode. The origin check applies either way. */
85
81
  auth?: boolean;
86
- /** Explicit device-mode override. Defaults to on whenever `storage` is set
87
- * (the on-device 3-arg contract); `resolveCliConfig` resolves it to false so
88
- * a dev backend keeps auth off + fixed port even with a storage dir. */
82
+ /** Extra page origins allowed to call the loopback server, e.g. the Vite dev
83
+ * server (`http://localhost:5173`). The bound origin and its loopback
84
+ * aliases are always allowed. */
85
+ allowedOrigins?: readonly string[];
86
+ /** Write `{ origin, port, bootstrap }` to `<storage>/handoff.json` for the
87
+ * host to read (auth on only; the session token is never written). Defaults
88
+ * to true; a host that receives them over its own channel (the desktop host
89
+ * reads them from a pipe) sets false so nothing touches disk. */
90
+ handoffFile?: boolean;
91
+ /** Device mode (the default): auth on, an ephemeral port, and the handoff
92
+ * file when `storage` is set. Pass `false` (or the `mode=dev` CLI token) for
93
+ * the dev backend: auth off and port 8080 unless set explicitly. */
89
94
  deviceMode?: boolean;
90
95
  /** Additional plugin manifests to register after the canonical defaults
91
96
  * (consumer product plugins, e.g. `app.photos`). */
92
97
  plugins?: PluginManifest[];
93
98
  /** Idle timeout (ms) after which an authenticated WebSocket is dropped. */
94
99
  wsIdleTimeoutMs?: number;
100
+ /** Dead-peer timeout (ms): a protocol socket that answers no ping within it
101
+ * is destroyed, freeing the slot. Defaults to 10s. */
102
+ wsDeadPeerTimeoutMs?: number;
103
+ /** Minimum gap (ms) before an accepted protocol socket may be replaced by a
104
+ * new authenticated one; an upgrade that arrives sooner is held until then.
105
+ * Defaults to 1s. */
106
+ wsReplaceMinIntervalMs?: number;
107
+ /** Bytes queued behind a protocol socket whose reader stopped reading before
108
+ * server pushes are dropped (newest first). Defaults to 2 MiB. */
109
+ wsMaxQueuedBytes?: number;
110
+ /** Ring capacity for the `core.logs` capture store (retention knob; the
111
+ * rotating file sink is a consumer/app decision). Defaults to 500. */
112
+ logsCapacity?: number;
113
+ /** Global cap on calls routed at once; calls over it fail with a
114
+ * `TRANSPORT_ERROR`. Defaults to 64. */
115
+ maxInflight?: number;
116
+ /** Plugin ids whose calls must run one at a time, in arrival order. All
117
+ * other plugins run concurrently, so one slow call never blocks the rest. */
118
+ serialPlugins?: readonly string[];
119
+ /** Lowest level the `core.logs` capture store records (`debug` | `info` |
120
+ * `warn` | `error`). Lower-level console calls still reach stdout. Defaults
121
+ * to `debug` (record everything); raise it to stop routine debug traces
122
+ * from evicting warnings out of a small ring. */
123
+ logsMinLevel?: 'debug' | 'info' | 'warn' | 'error';
95
124
  };
96
- type WorkletRuntimeConfig = {
125
+ export type WorkletRuntimeConfig = {
97
126
  webAssets?: string;
98
127
  storage?: string;
99
128
  cache?: string;
100
129
  deviceMode: boolean;
101
130
  };
102
- interface WorkletRuntime {
131
+ export interface WorkletRuntime {
103
132
  protocol: MessageProtocol;
104
133
  pluginRegistry: ReturnType<typeof createPluginRegistry>;
105
134
  pluginRouter: ReturnType<typeof createPluginRouter>;
@@ -112,6 +141,7 @@ interface WorkletRuntime {
112
141
  origin: string;
113
142
  port: number;
114
143
  token: string;
144
+ bootstrap: string;
115
145
  }>;
116
146
  close(cb?: (err?: Error | null) => void): void;
117
147
  }
@@ -121,6 +151,5 @@ interface WorkletRuntime {
121
151
  * N of them and a consumer worklet entry can be just "register plugins +
122
152
  * wire p2p". Mirrors the reference wiring in `core/main.core.ts`.
123
153
  */
124
- declare function createWorkletRuntime(options?: WorkletRuntimeOptions): WorkletRuntime;
125
- //#endregion
126
- export { type LoopbackPush, type LoopbackRouteHandler, type LoopbackServer, WorkletRuntime, WorkletRuntimeConfig, WorkletRuntimeOptions, attachWebSocketProtocol, collectRequestBody, createLoopbackPush, createLoopbackServer, createWorkletRuntime, getIPC, resolveCliConfig, resolveWorkletConfig };
154
+ export declare function createWorkletRuntime(options?: WorkletRuntimeOptions): WorkletRuntime;
155
+ export { type LoopbackPush, type LoopbackRouteHandler, type LoopbackServer, collectRequestBody, createLoopbackServer };