@botiverse/porthole 0.0.0-stage → 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 (150) hide show
  1. package/LICENSE +217 -0
  2. package/dist/bridge/bridge.d.ts +39 -0
  3. package/dist/bridge/bridge.js +184 -0
  4. package/dist/bridge/types.d.ts +67 -0
  5. package/dist/bridge/types.js +1 -0
  6. package/dist/compile/compile.d.ts +35 -0
  7. package/dist/compile/compile.js +30 -0
  8. package/dist/compile/policy.d.ts +55 -0
  9. package/dist/compile/policy.js +106 -0
  10. package/dist/config/capabilities.d.ts +154 -0
  11. package/dist/config/capabilities.js +63 -0
  12. package/dist/config/schema.d.ts +131 -0
  13. package/dist/config/schema.js +1 -0
  14. package/dist/config/validate.d.ts +20 -0
  15. package/dist/config/validate.js +230 -0
  16. package/dist/conformance/behavior.d.ts +2 -0
  17. package/dist/conformance/behavior.js +376 -0
  18. package/dist/conformance/index.d.ts +95 -0
  19. package/dist/conformance/index.js +4 -0
  20. package/dist/conformance/kit.d.ts +42 -0
  21. package/dist/conformance/kit.js +24 -0
  22. package/dist/conformance/oracles.d.ts +35 -0
  23. package/dist/conformance/oracles.js +77 -0
  24. package/dist/conformance/probes.d.ts +9 -0
  25. package/dist/conformance/probes.js +865 -0
  26. package/dist/conformance/served.d.ts +68 -0
  27. package/dist/conformance/served.js +311 -0
  28. package/dist/guide/examples.d.ts +70 -0
  29. package/dist/guide/examples.js +69 -0
  30. package/dist/guide/guide.d.ts +16 -0
  31. package/dist/guide/guide.js +261 -0
  32. package/dist/host/create-host.d.ts +8 -0
  33. package/dist/host/create-host.js +248 -0
  34. package/dist/host/locate.d.ts +8 -0
  35. package/dist/host/locate.js +11 -0
  36. package/dist/host/types.d.ts +95 -0
  37. package/dist/host/types.js +1 -0
  38. package/dist/index.d.ts +23 -0
  39. package/dist/index.js +19 -0
  40. package/dist/isolation/served.d.ts +32 -0
  41. package/dist/isolation/served.js +97 -0
  42. package/dist/isolation/types.d.ts +87 -0
  43. package/dist/isolation/types.js +1 -0
  44. package/dist/mcp/adapter.d.ts +43 -0
  45. package/dist/mcp/adapter.js +327 -0
  46. package/dist/mcp/index.d.ts +27 -0
  47. package/dist/mcp/index.js +25 -0
  48. package/dist/mcp/proxy.d.ts +25 -0
  49. package/dist/mcp/proxy.js +106 -0
  50. package/dist/mcp/view.d.ts +31 -0
  51. package/dist/mcp/view.js +72 -0
  52. package/dist/platform/types.d.ts +44 -0
  53. package/dist/platform/types.js +1 -0
  54. package/dist/platform/web.d.ts +8 -0
  55. package/dist/platform/web.js +72 -0
  56. package/dist/presets/presets.d.ts +65 -0
  57. package/dist/presets/presets.js +125 -0
  58. package/dist/protocol/adapter.d.ts +73 -0
  59. package/dist/protocol/adapter.js +1 -0
  60. package/dist/protocol/jsonrpc.d.ts +43 -0
  61. package/dist/protocol/jsonrpc.js +50 -0
  62. package/dist/protocol/mcp-apps.d.ts +79 -0
  63. package/dist/protocol/mcp-apps.js +99 -0
  64. package/dist/protocol/shell-adapter.d.ts +5 -0
  65. package/dist/protocol/shell-adapter.js +228 -0
  66. package/dist/react/dialog.d.ts +20 -0
  67. package/dist/react/dialog.js +98 -0
  68. package/dist/react/frame.d.ts +75 -0
  69. package/dist/react/frame.js +221 -0
  70. package/dist/react/index.d.ts +13 -0
  71. package/dist/react/index.js +13 -0
  72. package/dist/react/live.d.ts +24 -0
  73. package/dist/react/live.js +57 -0
  74. package/dist/server/index.d.ts +27 -0
  75. package/dist/server/index.js +26 -0
  76. package/dist/server/keys.d.ts +19 -0
  77. package/dist/server/keys.js +78 -0
  78. package/dist/server/pages.d.ts +6 -0
  79. package/dist/server/pages.js +20 -0
  80. package/dist/server/proxy.d.ts +21 -0
  81. package/dist/server/proxy.js +107 -0
  82. package/dist/server/server.d.ts +7 -0
  83. package/dist/server/server.js +518 -0
  84. package/dist/server/tickets.d.ts +8 -0
  85. package/dist/server/tickets.js +28 -0
  86. package/dist/server/types.d.ts +97 -0
  87. package/dist/server/types.js +1 -0
  88. package/dist/shell/document.d.ts +28 -0
  89. package/dist/shell/document.js +84 -0
  90. package/dist/shell/plan.d.ts +35 -0
  91. package/dist/shell/plan.js +34 -0
  92. package/dist/shell/runtime.d.ts +28 -0
  93. package/dist/shell/runtime.js +832 -0
  94. package/dist/theme/variables.d.ts +73 -0
  95. package/dist/theme/variables.js +171 -0
  96. package/dist/transport/post-message.d.ts +9 -0
  97. package/dist/transport/post-message.js +38 -0
  98. package/dist/transport/types.d.ts +15 -0
  99. package/dist/transport/types.js +1 -0
  100. package/package.json +68 -3
  101. package/src/bridge/bridge.ts +256 -0
  102. package/src/bridge/types.ts +77 -0
  103. package/src/compile/compile.ts +68 -0
  104. package/src/compile/policy.ts +133 -0
  105. package/src/config/capabilities.ts +138 -0
  106. package/src/config/schema.ts +140 -0
  107. package/src/config/validate.ts +284 -0
  108. package/src/conformance/behavior.ts +430 -0
  109. package/src/conformance/index.ts +102 -0
  110. package/src/conformance/kit.ts +63 -0
  111. package/src/conformance/oracles.ts +126 -0
  112. package/src/conformance/probes.ts +1093 -0
  113. package/src/conformance/served.ts +472 -0
  114. package/src/guide/examples.ts +74 -0
  115. package/src/guide/guide.ts +424 -0
  116. package/src/host/create-host.ts +290 -0
  117. package/src/host/locate.ts +20 -0
  118. package/src/host/types.ts +95 -0
  119. package/src/index.ts +118 -0
  120. package/src/isolation/served.ts +127 -0
  121. package/src/isolation/types.ts +77 -0
  122. package/src/mcp/adapter.ts +441 -0
  123. package/src/mcp/index.ts +50 -0
  124. package/src/mcp/proxy.ts +117 -0
  125. package/src/mcp/view.ts +97 -0
  126. package/src/platform/types.ts +48 -0
  127. package/src/platform/web.ts +78 -0
  128. package/src/presets/presets.ts +193 -0
  129. package/src/protocol/adapter.ts +67 -0
  130. package/src/protocol/jsonrpc.ts +83 -0
  131. package/src/protocol/mcp-apps.ts +138 -0
  132. package/src/protocol/shell-adapter.ts +261 -0
  133. package/src/react/dialog.tsx +158 -0
  134. package/src/react/frame.tsx +422 -0
  135. package/src/react/index.ts +20 -0
  136. package/src/react/live.ts +76 -0
  137. package/src/server/index.ts +37 -0
  138. package/src/server/keys.ts +100 -0
  139. package/src/server/pages.ts +31 -0
  140. package/src/server/proxy.ts +131 -0
  141. package/src/server/server.ts +617 -0
  142. package/src/server/tickets.ts +30 -0
  143. package/src/server/types.ts +104 -0
  144. package/src/shell/document.ts +120 -0
  145. package/src/shell/plan.ts +66 -0
  146. package/src/shell/runtime.ts +832 -0
  147. package/src/theme/variables.ts +190 -0
  148. package/src/transport/post-message.ts +45 -0
  149. package/src/transport/types.ts +16 -0
  150. package/README.md +0 -3
@@ -0,0 +1,126 @@
1
+ import { createSocket } from "node:dgram";
2
+ import { createServer } from "node:http";
3
+ import type { AddressInfo } from "node:net";
4
+
5
+ /**
6
+ * Out-of-band oracles: listeners outside the browser that see what actually left it. A probe
7
+ * points content at one and asserts it heard nothing; a positive control points something allowed
8
+ * at one and asserts it heard it, so a silent oracle is never mistaken for a wall.
9
+ */
10
+
11
+ export interface HeardRequest {
12
+ readonly method: string;
13
+ readonly path: string;
14
+ readonly origin: string | undefined;
15
+ }
16
+
17
+ export interface HttpOracle {
18
+ /** `http://127.0.0.1:<port>`: an exact origin a config can allow or leave out. */
19
+ readonly origin: string;
20
+ /** Every request it answered. */
21
+ requests(): readonly HeardRequest[];
22
+ /** Every TCP connection opened to it, whether or not a request followed (preconnects). */
23
+ connections(): number;
24
+ close(): Promise<void>;
25
+ }
26
+
27
+ const PIXEL = Buffer.from(
28
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
29
+ "base64",
30
+ );
31
+
32
+ /** What the oracle answers, by the path's extension: real enough for each kind of load to finish. */
33
+ function body(path: string): { type: string; data: string | Buffer } {
34
+ if (/\.m?js(\?|$)/u.test(path)) {
35
+ return {
36
+ type: "text/javascript",
37
+ data: "globalThis.__portholeOracleScript = (globalThis.__portholeOracleScript || 0) + 1;",
38
+ };
39
+ }
40
+ if (/\.css(\?|$)/u.test(path)) {
41
+ return { type: "text/css", data: "html { --porthole-oracle: 1; }" };
42
+ }
43
+ if (/\.(png|gif|jpg)(\?|$)/u.test(path)) {
44
+ return { type: "image/png", data: PIXEL };
45
+ }
46
+ if (/\.html(\?|$)/u.test(path)) {
47
+ return {
48
+ type: "text/html",
49
+ data: "<!doctype html><title>oracle</title><p id=oracle>oracle</p>",
50
+ };
51
+ }
52
+ return { type: "text/plain", data: "oracle" };
53
+ }
54
+
55
+ /** A file an oracle serves at a path, instead of its stand-in answer (a library, say). */
56
+ export interface ServedFile {
57
+ readonly type: string;
58
+ readonly data: string | Buffer;
59
+ }
60
+
61
+ export async function httpOracle(
62
+ files: Readonly<Record<string, ServedFile>> = {},
63
+ ): Promise<HttpOracle> {
64
+ const heard: HeardRequest[] = [];
65
+ let connections = 0;
66
+ const server = createServer((request, response) => {
67
+ heard.push({
68
+ method: request.method ?? "GET",
69
+ path: request.url ?? "/",
70
+ origin: request.headers.origin,
71
+ });
72
+ const { type, data } = files[request.url ?? "/"] ?? body(request.url ?? "/");
73
+ response.writeHead(200, {
74
+ "content-type": type,
75
+ "access-control-allow-origin": "*",
76
+ "cache-control": "no-store",
77
+ });
78
+ response.end(data);
79
+ });
80
+ server.on("connection", () => {
81
+ connections += 1;
82
+ });
83
+ server.on("upgrade", (request, socket) => {
84
+ heard.push({ method: "UPGRADE", path: request.url ?? "/", origin: request.headers.origin });
85
+ socket.destroy();
86
+ });
87
+ await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
88
+ const { port } = server.address() as AddressInfo;
89
+ return {
90
+ origin: `http://127.0.0.1:${port}`,
91
+ requests: () => [...heard],
92
+ connections: () => connections,
93
+ close: () =>
94
+ new Promise<void>((resolve) => {
95
+ server.closeAllConnections();
96
+ server.close(() => resolve());
97
+ }),
98
+ };
99
+ }
100
+
101
+ export interface UdpOracle {
102
+ /** `stun:127.0.0.1:<port>`, for an ICE server list. */
103
+ readonly stun: string;
104
+ /** The datagrams that reached it. */
105
+ packets(): number;
106
+ close(): Promise<void>;
107
+ }
108
+
109
+ export async function udpOracle(): Promise<UdpOracle> {
110
+ let packets = 0;
111
+ const socket = createSocket("udp4");
112
+ socket.on("message", () => {
113
+ packets += 1;
114
+ });
115
+ await new Promise<void>((resolve) => socket.bind(0, "127.0.0.1", resolve));
116
+ const { port } = socket.address();
117
+ return {
118
+ stun: `stun:127.0.0.1:${port}`,
119
+ packets: () => packets,
120
+ close: () => new Promise<void>((resolve) => socket.close(() => resolve())),
121
+ };
122
+ }
123
+
124
+ /** Waits `ms`, so a request that was going to leave has time to arrive. */
125
+ export const settle = (ms = 800): Promise<void> =>
126
+ new Promise((resolve) => setTimeout(resolve, ms));