hive-am 1.1.0 → 1.2.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 (261) hide show
  1. package/CHANGELOG.md +83 -1
  2. package/README.md +9 -1
  3. package/package.json +13 -2
  4. package/server/dist/api.js +42 -762
  5. package/server/dist/connections/channel-skill.js +13 -1
  6. package/server/dist/connections/files.js +45 -1
  7. package/server/dist/connections/manager.js +41 -3
  8. package/server/dist/connections/outbound.js +2 -1
  9. package/server/dist/connections/prompt.js +4 -0
  10. package/server/dist/connections/router.js +3 -2
  11. package/server/dist/connections/store.js +4 -43
  12. package/server/dist/connections/telegram.js +43 -3
  13. package/server/dist/cron.js +2 -1
  14. package/server/dist/db/json.js +16 -0
  15. package/server/dist/db/migrations.js +199 -0
  16. package/server/dist/db.js +98 -196
  17. package/server/dist/errors.js +11 -0
  18. package/server/dist/git/browse.js +99 -0
  19. package/server/dist/git/ops.js +136 -19
  20. package/server/dist/git/repo.js +2 -1
  21. package/server/dist/history/claude.js +21 -21
  22. package/server/dist/history/index.js +17 -9
  23. package/server/dist/history/kiro.js +17 -12
  24. package/server/dist/history/lines.js +12 -0
  25. package/server/dist/history/opencode.js +18 -1
  26. package/server/dist/http/body.js +46 -0
  27. package/server/dist/http/errors.js +21 -0
  28. package/server/dist/http/guards.js +44 -0
  29. package/server/dist/http/router.js +24 -0
  30. package/server/dist/http/routes/agents.js +103 -0
  31. package/server/dist/http/routes/channel.js +16 -0
  32. package/server/dist/http/routes/colonies.js +9 -0
  33. package/server/dist/http/routes/connections.js +36 -0
  34. package/server/dist/http/routes/fs.js +22 -0
  35. package/server/dist/http/routes/git.js +90 -0
  36. package/server/dist/http/routes/meta.js +11 -0
  37. package/server/dist/http/routes/notebook.js +34 -0
  38. package/server/dist/http/routes/orchestration.js +32 -0
  39. package/server/dist/http/routes/resources.js +68 -0
  40. package/server/dist/http/routes/schedules.js +40 -0
  41. package/server/dist/http/routes/skills.js +47 -0
  42. package/server/dist/http/routes/terminals.js +18 -0
  43. package/server/dist/http/routes/types.js +36 -0
  44. package/server/dist/http/validate.js +65 -0
  45. package/server/dist/index.js +67 -5
  46. package/server/dist/instructions.js +8 -2
  47. package/server/dist/objects/agent.js +49 -0
  48. package/server/dist/objects/database.js +451 -0
  49. package/server/dist/objects/db-history.js +79 -0
  50. package/server/dist/objects/docker-info.js +75 -0
  51. package/server/dist/objects/docker.js +285 -0
  52. package/server/dist/objects/driver-props.js +196 -0
  53. package/server/dist/objects/exec.js +16 -0
  54. package/server/dist/objects/http-history.js +44 -0
  55. package/server/dist/objects/http-script.js +644 -0
  56. package/server/dist/objects/http.js +735 -0
  57. package/server/dist/objects/index.js +445 -0
  58. package/server/dist/objects/model.js +250 -0
  59. package/server/dist/objects/runner.js +211 -0
  60. package/server/dist/objects/stats.js +106 -0
  61. package/server/dist/objects/store.js +115 -0
  62. package/server/dist/objects/supervisor.js +111 -0
  63. package/server/dist/objects/templates.js +67 -0
  64. package/server/dist/providers/claude.js +3 -13
  65. package/server/dist/providers/index.js +7 -1
  66. package/server/dist/providers/kiro.js +2 -5
  67. package/server/dist/providers/opencode.js +2 -5
  68. package/server/dist/providers/preamble.js +2 -0
  69. package/server/dist/providers/spawn.js +31 -3
  70. package/server/dist/runtime.js +8 -6
  71. package/server/dist/schedules.js +2 -21
  72. package/server/dist/seed.js +15 -11
  73. package/server/dist/services/agents.js +90 -0
  74. package/server/dist/services/colonies.js +38 -0
  75. package/server/dist/services/connections.js +76 -0
  76. package/server/dist/services/notebook.js +22 -0
  77. package/server/dist/services/providers.js +27 -0
  78. package/server/dist/services/schedules.js +18 -0
  79. package/server/dist/sessions-summary.js +51 -0
  80. package/server/dist/skills/defaults.js +37 -0
  81. package/server/dist/skills/notebook.js +3 -8
  82. package/server/dist/terminals.js +177 -0
  83. package/server/dist/wake.js +13 -16
  84. package/server/dist/watch.js +2 -8
  85. package/server/mcp/dispatch.mjs +70 -1
  86. package/web/.next/BUILD_ID +1 -1
  87. package/web/.next/app-build-manifest.json +150 -98
  88. package/web/.next/app-path-routes-manifest.json +7 -5
  89. package/web/.next/build-manifest.json +14 -14
  90. package/web/.next/prerender-manifest.json +67 -43
  91. package/web/.next/react-loadable-manifest.json +26 -1
  92. package/web/.next/required-server-files.json +13 -1
  93. package/web/.next/routes-manifest.json +26 -0
  94. package/web/.next/server/app/_not-found/page.js +2 -2
  95. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  96. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  97. package/web/.next/server/app/_not-found.html +1 -1
  98. package/web/.next/server/app/_not-found.rsc +12 -11
  99. package/web/.next/server/app/agents/[id]/page.js +4 -4
  100. package/web/.next/server/app/agents/[id]/page.js.nft.json +1 -1
  101. package/web/.next/server/app/agents/[id]/page_client-reference-manifest.js +1 -1
  102. package/web/.next/server/app/agents/page.js +2 -2
  103. package/web/.next/server/app/agents/page.js.nft.json +1 -1
  104. package/web/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  105. package/web/.next/server/app/agents.html +1 -1
  106. package/web/.next/server/app/agents.rsc +14 -13
  107. package/web/.next/server/app/connections/page.js +2 -2
  108. package/web/.next/server/app/connections/page.js.nft.json +1 -1
  109. package/web/.next/server/app/connections/page_client-reference-manifest.js +1 -1
  110. package/web/.next/server/app/connections.html +1 -1
  111. package/web/.next/server/app/connections.rsc +14 -13
  112. package/web/.next/server/app/index.html +1 -1
  113. package/web/.next/server/app/index.rsc +14 -13
  114. package/web/.next/server/app/page.js +2 -2
  115. package/web/.next/server/app/page.js.nft.json +1 -1
  116. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  117. package/web/.next/server/app/relations/page.js +2 -2
  118. package/web/.next/server/app/relations/page.js.nft.json +1 -1
  119. package/web/.next/server/app/relations/page_client-reference-manifest.js +1 -1
  120. package/web/.next/server/app/relations.html +1 -1
  121. package/web/.next/server/app/relations.rsc +14 -13
  122. package/web/.next/server/app/resources/[id]/page.js +2 -0
  123. package/web/.next/server/app/resources/[id]/page.js.nft.json +1 -0
  124. package/web/.next/server/app/resources/[id]/page_client-reference-manifest.js +1 -0
  125. package/web/.next/server/app/resources/page.js +2 -0
  126. package/web/.next/server/app/resources/page.js.nft.json +1 -0
  127. package/web/.next/server/app/resources/page_client-reference-manifest.js +1 -0
  128. package/web/.next/server/app/resources.html +1 -0
  129. package/web/.next/server/app/resources.meta +15 -0
  130. package/web/.next/server/app/resources.rsc +25 -0
  131. package/web/.next/server/app/schedules/page.js +2 -2
  132. package/web/.next/server/app/schedules/page.js.nft.json +1 -1
  133. package/web/.next/server/app/schedules/page_client-reference-manifest.js +1 -1
  134. package/web/.next/server/app/schedules.html +1 -1
  135. package/web/.next/server/app/schedules.rsc +14 -13
  136. package/web/.next/server/app/sessions/page.js +2 -2
  137. package/web/.next/server/app/sessions/page.js.nft.json +1 -1
  138. package/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  139. package/web/.next/server/app/sessions.html +1 -1
  140. package/web/.next/server/app/sessions.rsc +14 -13
  141. package/web/.next/server/app/skills/page.js +2 -2
  142. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  143. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  144. package/web/.next/server/app/skills.html +1 -1
  145. package/web/.next/server/app/skills.rsc +14 -13
  146. package/web/.next/server/app/types/page.js +2 -2
  147. package/web/.next/server/app/types/page.js.nft.json +1 -1
  148. package/web/.next/server/app/types/page_client-reference-manifest.js +1 -1
  149. package/web/.next/server/app/types.html +1 -1
  150. package/web/.next/server/app/types.rsc +14 -13
  151. package/web/.next/server/app-paths-manifest.json +7 -5
  152. package/web/.next/server/chunks/143.js +1 -1
  153. package/web/.next/server/chunks/274.js +1 -0
  154. package/web/.next/server/chunks/306.js +1 -0
  155. package/web/.next/server/chunks/423.js +1 -0
  156. package/web/.next/server/chunks/505.js +6 -0
  157. package/web/.next/server/chunks/555.js +1 -0
  158. package/web/.next/server/chunks/612.js +1 -0
  159. package/web/.next/server/chunks/638.js +1 -0
  160. package/web/.next/server/chunks/692.js +18 -0
  161. package/web/.next/server/chunks/716.js +2 -0
  162. package/web/.next/server/chunks/790.js +11 -0
  163. package/web/.next/server/chunks/802.js +1 -0
  164. package/web/.next/server/chunks/890.js +1 -1
  165. package/web/.next/server/chunks/919.js +1 -0
  166. package/web/.next/server/chunks/950.js +6 -0
  167. package/web/.next/server/middleware-build-manifest.js +1 -1
  168. package/web/.next/server/middleware-react-loadable-manifest.js +1 -1
  169. package/web/.next/server/next-font-manifest.js +1 -1
  170. package/web/.next/server/next-font-manifest.json +1 -1
  171. package/web/.next/server/pages/404.html +1 -1
  172. package/web/.next/server/pages/500.html +1 -1
  173. package/web/.next/server/server-reference-manifest.json +1 -1
  174. package/web/.next/static/chunks/0937d497-114a2a3de515565e.js +1 -0
  175. package/web/.next/static/chunks/176-aeaf907a6ea5627d.js +1 -0
  176. package/web/.next/static/chunks/291-efae53ea5f7ee92d.js +1 -0
  177. package/web/.next/static/chunks/2b9ff8ee-969e65cc354b2150.js +1 -0
  178. package/web/.next/static/chunks/30-9adcbe92b15a6815.js +1 -0
  179. package/web/.next/static/chunks/316-26da9cc233ba7557.js +1 -0
  180. package/web/.next/static/chunks/350-56599dc3bf06066d.js +1 -0
  181. package/web/.next/static/chunks/486-13e08542f3a1cbac.js +1 -0
  182. package/web/.next/static/chunks/491-6b4e6201f5110dff.js +1 -0
  183. package/web/.next/static/chunks/517-ccaf8cc5c733cbd8.js +1 -0
  184. package/web/.next/static/chunks/545.bfbd92b7632c09de.js +1 -0
  185. package/web/.next/static/chunks/{805-d946ebedb7e85f73.js → 562-7c2e33d838e869bf.js} +1 -1
  186. package/web/.next/static/chunks/581-3ad5c4343dad3f50.js +1 -0
  187. package/web/.next/static/chunks/586-f7017d585a84738d.js +1 -0
  188. package/web/.next/static/chunks/657.b4c39e676c3e20dc.js +1 -0
  189. package/web/.next/static/chunks/701.6abcaf5e60463eef.js +6 -0
  190. package/web/.next/static/chunks/705-a16e1fe09be1ac7f.js +1 -0
  191. package/web/.next/static/chunks/706-fa2be0f10ffebe6a.js +1 -0
  192. package/web/.next/static/chunks/837-33c7480524f48577.js +1 -0
  193. package/web/.next/static/chunks/839-23c5508622fae942.js +1 -0
  194. package/web/.next/static/chunks/844-fe55292e0701f436.js +1 -0
  195. package/web/.next/static/chunks/89-b194fcffe5120c44.js +1 -0
  196. package/web/.next/static/chunks/97.594543c2196de524.js +1 -0
  197. package/web/.next/static/chunks/app/_not-found/page-238a7b80bda6b4ae.js +1 -0
  198. package/web/.next/static/chunks/app/agents/[id]/page-4af6c246c4ca7a97.js +1 -0
  199. package/web/.next/static/chunks/app/agents/page-f4c4c80f955f3967.js +1 -0
  200. package/web/.next/static/chunks/app/connections/page-0936beaf02d863c6.js +1 -0
  201. package/web/.next/static/chunks/app/layout-87ebb70bd9cb8443.js +1 -0
  202. package/web/.next/static/chunks/app/page-a7f292117b7d76bf.js +1 -0
  203. package/web/.next/static/chunks/app/relations/page-fba25393c8688714.js +1 -0
  204. package/web/.next/static/chunks/app/resources/[id]/page-d110d89bb8b5fca7.js +1 -0
  205. package/web/.next/static/chunks/app/resources/page-bbd0b450d3f3131d.js +1 -0
  206. package/web/.next/static/chunks/app/schedules/page-a1124397fc760413.js +1 -0
  207. package/web/.next/static/chunks/app/sessions/page-0e322811b0cde724.js +1 -0
  208. package/web/.next/static/chunks/app/skills/page-22ea0ef89d9f7a13.js +1 -0
  209. package/web/.next/static/chunks/app/types/page-18c4e1db2724d41d.js +1 -0
  210. package/web/.next/static/chunks/fcafe1ac.366e4950d3b0d4b7.js +18 -0
  211. package/web/.next/static/chunks/framework-bbac72adbbe2d328.js +1 -0
  212. package/web/.next/static/chunks/main-app-6086068e5fb5eacd.js +1 -0
  213. package/web/.next/static/chunks/main-c15f3fee674e0303.js +1 -0
  214. package/web/.next/static/chunks/pages/_app-d1670a2c6ce392fc.js +1 -0
  215. package/web/.next/static/chunks/pages/_error-95aac014d202fa7a.js +1 -0
  216. package/web/.next/static/chunks/webpack-ef515e41a83a16ac.js +1 -0
  217. package/web/.next/static/css/945795da867f5250.css +1 -0
  218. package/web/.next/static/css/dd4e32c285f75776.css +1 -0
  219. package/web/.next/static/p4S3i9kvO359GW91DQiHu/_buildManifest.js +1 -0
  220. package/web/.next/trace +29 -23
  221. package/web/.next/types/app/resources/[id]/page.ts +84 -0
  222. package/web/.next/types/app/resources/page.ts +84 -0
  223. package/web/.next/types/routes.d.ts +6 -2
  224. package/web/.next/types/validator.ts +18 -0
  225. package/web/next.config.mjs +4 -0
  226. package/web/.next/server/chunks/247.js +0 -1
  227. package/web/.next/server/chunks/484.js +0 -11
  228. package/web/.next/server/chunks/851.js +0 -1
  229. package/web/.next/server/chunks/932.js +0 -2
  230. package/web/.next/static/_z2hBOHhwiR5ytdI_8alh/_buildManifest.js +0 -1
  231. package/web/.next/static/chunks/0937d497-44abb0f9355ace92.js +0 -1
  232. package/web/.next/static/chunks/2b9ff8ee-c3b61ac1e608c57d.js +0 -1
  233. package/web/.next/static/chunks/463-6ae35cdefdc59169.js +0 -1
  234. package/web/.next/static/chunks/493-50d2adf9fd5ec680.js +0 -1
  235. package/web/.next/static/chunks/517-eb26c72f6059aa26.js +0 -1
  236. package/web/.next/static/chunks/589-8bf536f331de4269.js +0 -1
  237. package/web/.next/static/chunks/657.f1e03b7b65eba1d9.js +0 -1
  238. package/web/.next/static/chunks/687-3a4205f51be38602.js +0 -1
  239. package/web/.next/static/chunks/837-fd7623601dc78ed8.js +0 -1
  240. package/web/.next/static/chunks/850-318f32484989dd59.js +0 -1
  241. package/web/.next/static/chunks/89-ace2e1aa63babfdf.js +0 -1
  242. package/web/.next/static/chunks/951-e250b541b67da7ce.js +0 -1
  243. package/web/.next/static/chunks/app/_not-found/page-bbd54d7b9a55d7ae.js +0 -1
  244. package/web/.next/static/chunks/app/agents/[id]/page-a8b7a43d2c18483f.js +0 -1
  245. package/web/.next/static/chunks/app/agents/page-e9b17f1c3439ef98.js +0 -1
  246. package/web/.next/static/chunks/app/connections/page-477f36fcd5b13d78.js +0 -1
  247. package/web/.next/static/chunks/app/layout-a2d38e3de5911b1b.js +0 -1
  248. package/web/.next/static/chunks/app/page-6fc87fc5a128a204.js +0 -1
  249. package/web/.next/static/chunks/app/relations/page-0355a93a8eb67989.js +0 -1
  250. package/web/.next/static/chunks/app/schedules/page-39befd15b3b20586.js +0 -1
  251. package/web/.next/static/chunks/app/sessions/page-beae9a74a07d69e0.js +0 -1
  252. package/web/.next/static/chunks/app/skills/page-4f839ac913e26d32.js +0 -1
  253. package/web/.next/static/chunks/app/types/page-4f6b99af3232f861.js +0 -1
  254. package/web/.next/static/chunks/framework-0e68884e76d9a8d3.js +0 -1
  255. package/web/.next/static/chunks/main-app-d6f73ccd41f325c5.js +0 -1
  256. package/web/.next/static/chunks/main-cd22509db15764e2.js +0 -1
  257. package/web/.next/static/chunks/pages/_app-0f75d689c738a6fc.js +0 -1
  258. package/web/.next/static/chunks/pages/_error-d481f6d49fb4455d.js +0 -1
  259. package/web/.next/static/chunks/webpack-d40de72e52f65f79.js +0 -1
  260. package/web/.next/static/css/da22f0402b1c40ae.css +0 -1
  261. /package/web/.next/static/{_z2hBOHhwiR5ytdI_8alh → p4S3i9kvO359GW91DQiHu}/_ssgManifest.js +0 -0
@@ -0,0 +1,644 @@
1
+ import { DomainError } from '../errors.js';
2
+ /**
3
+ * The response handlers of a .http file (`> {% … %}`, the IntelliJ / VS Code REST client format), run safely. They are little scripts
4
+ * that read the answer and keep values for the next requests (`client.global.set("token", response.body.token)`) or check it
5
+ * (`client.test("ok", function () { client.assert(response.status === 200); })`).
6
+ *
7
+ * Nothing here runs JavaScript: the script is read by a small parser and evaluated by a small interpreter that only knows what such
8
+ * handlers need — values, `response`, `client.global`, `client.test` / `client.assert` / `client.log`, `JSON`, local `var`/`let`/`const`,
9
+ * `if`, functions and arrows, comparisons, `&&`, `||`, `? :`, `+`, and a short list of string and array methods. No `require`, no
10
+ * `process`, no loops, no access to prototypes. Something outside of that is reported ("not supported") instead of being run, and a script
11
+ * is limited in how much it may compute.
12
+ */
13
+ export class ScriptError extends DomainError {
14
+ }
15
+ const OPS3 = ['===', '!=='], OPS2 = ['==', '!=', '<=', '>=', '&&', '||', '??', '=>'];
16
+ function tokenize(src) {
17
+ const out = [];
18
+ let i = 0;
19
+ const fail = (m) => { throw new ScriptError(m); };
20
+ while (i < src.length) {
21
+ const c = src[i];
22
+ if (/\s/.test(c)) {
23
+ i++;
24
+ continue;
25
+ }
26
+ if (c === '/' && src[i + 1] === '/') {
27
+ while (i < src.length && src[i] !== '\n')
28
+ i++;
29
+ continue;
30
+ }
31
+ if (c === '/' && src[i + 1] === '*') {
32
+ const e = src.indexOf('*/', i + 2);
33
+ if (e < 0)
34
+ fail('A comment is not closed');
35
+ i = e + 2;
36
+ continue;
37
+ }
38
+ if (/[0-9]/.test(c) || (c === '.' && /[0-9]/.test(src[i + 1] ?? ''))) {
39
+ const m = /^(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?/.exec(src.slice(i));
40
+ out.push({ t: 'num', v: m[0], at: i });
41
+ i += m[0].length;
42
+ continue;
43
+ }
44
+ if (/[A-Za-z_$]/.test(c)) {
45
+ const m = /^[A-Za-z0-9_$]+/.exec(src.slice(i));
46
+ out.push({ t: 'id', v: m[0], at: i });
47
+ i += m[0].length;
48
+ continue;
49
+ }
50
+ if (c === '"' || c === "'") {
51
+ let s = '';
52
+ const at = i;
53
+ i++;
54
+ while (i < src.length && src[i] !== c) {
55
+ if (src[i] === '\\') {
56
+ const n = src[++i];
57
+ s += n === 'n' ? '\n' : n === 't' ? '\t' : n === 'r' ? '\r' : n;
58
+ i++;
59
+ }
60
+ else
61
+ s += src[i++];
62
+ }
63
+ if (i >= src.length)
64
+ fail('A string is not closed');
65
+ i++;
66
+ out.push({ t: 'str', v: s, at });
67
+ continue;
68
+ }
69
+ if (c === '`') {
70
+ const at = i;
71
+ i++;
72
+ const parts = [];
73
+ let s = '';
74
+ while (i < src.length && src[i] !== '`') {
75
+ if (src[i] === '\\') {
76
+ const n = src[++i];
77
+ s += n === 'n' ? '\n' : n;
78
+ i++;
79
+ }
80
+ else if (src[i] === '$' && src[i + 1] === '{') {
81
+ let depth = 1, j = i + 2;
82
+ while (j < src.length && depth) {
83
+ if (src[j] === '{')
84
+ depth++;
85
+ else if (src[j] === '}')
86
+ depth--;
87
+ j++;
88
+ }
89
+ if (depth)
90
+ fail('A template is not closed');
91
+ parts.push(s);
92
+ s = '';
93
+ parts.push(tokenize(src.slice(i + 2, j - 1)));
94
+ i = j;
95
+ }
96
+ else
97
+ s += src[i++];
98
+ }
99
+ if (i >= src.length)
100
+ fail('A template is not closed');
101
+ i++;
102
+ parts.push(s);
103
+ out.push({ t: 'tpl', v: '', parts, at });
104
+ continue;
105
+ }
106
+ const three = src.slice(i, i + 3), two = src.slice(i, i + 2);
107
+ if (OPS3.includes(three)) {
108
+ out.push({ t: 'op', v: three, at: i });
109
+ i += 3;
110
+ continue;
111
+ }
112
+ if (OPS2.includes(two)) {
113
+ out.push({ t: 'op', v: two, at: i });
114
+ i += 2;
115
+ continue;
116
+ }
117
+ if ('(){}[],;.:?!+-*/%<>='.includes(c)) {
118
+ out.push({ t: 'op', v: c, at: i });
119
+ i++;
120
+ continue;
121
+ }
122
+ fail(`Unexpected character "${c}"`);
123
+ }
124
+ out.push({ t: 'eof', v: '', at: src.length });
125
+ return out;
126
+ }
127
+ const KEYWORDS_NOT_SUPPORTED = new Set(['for', 'while', 'do', 'switch', 'try', 'catch', 'throw', 'class', 'new', 'import', 'export', 'async', 'await', 'yield', 'with', 'delete', 'void', 'in', 'of', 'instanceof', 'debugger']);
128
+ class Parser {
129
+ toks;
130
+ i = 0;
131
+ constructor(toks) {
132
+ this.toks = toks;
133
+ }
134
+ get cur() { return this.toks[this.i]; }
135
+ is(v) { return this.cur.t === 'op' && this.cur.v === v; }
136
+ idIs(v) { return this.cur.t === 'id' && this.cur.v === v; }
137
+ eat(v) { if (!this.is(v))
138
+ throw new ScriptError(`Expected "${v}" but found "${this.cur.v || 'the end'}"`); this.i++; }
139
+ maybe(v) { if (this.is(v)) {
140
+ this.i++;
141
+ return true;
142
+ } return false; }
143
+ program() { const out = []; while (this.cur.t !== 'eof')
144
+ out.push(this.stmt()); return out; }
145
+ block() {
146
+ if (this.maybe('{')) {
147
+ const out = [];
148
+ while (!this.is('}')) {
149
+ if (this.cur.t === 'eof')
150
+ throw new ScriptError('A block is not closed');
151
+ out.push(this.stmt());
152
+ }
153
+ this.eat('}');
154
+ return out;
155
+ }
156
+ return [this.stmt()];
157
+ }
158
+ stmt() {
159
+ if (this.maybe(';'))
160
+ return { s: 'expr', e: { k: 'lit', v: undefined } };
161
+ const c = this.cur;
162
+ if (c.t === 'id' && KEYWORDS_NOT_SUPPORTED.has(c.v))
163
+ throw new ScriptError(`"${c.v}" is not supported in hive-am response handlers`);
164
+ if (c.t === 'id' && (c.v === 'var' || c.v === 'let' || c.v === 'const')) {
165
+ this.i++;
166
+ if (this.cur.t !== 'id')
167
+ throw new ScriptError('Only a plain name can be declared');
168
+ const n = this.cur.v;
169
+ this.i++;
170
+ let e = null;
171
+ if (this.maybe('='))
172
+ e = this.expr();
173
+ this.maybe(';');
174
+ return { s: 'decl', n, e };
175
+ }
176
+ if (c.t === 'id' && c.v === 'if') {
177
+ this.i++;
178
+ this.eat('(');
179
+ const cond = this.expr();
180
+ this.eat(')');
181
+ const a = this.block();
182
+ let b = [];
183
+ if (this.idIs('else')) {
184
+ this.i++;
185
+ b = this.idIs('if') ? [this.stmt()] : this.block();
186
+ }
187
+ return { s: 'if', c: cond, a, b };
188
+ }
189
+ if (c.t === 'id' && c.v === 'return') {
190
+ this.i++;
191
+ let e = null;
192
+ if (!this.is(';') && !this.is('}') && this.cur.t !== 'eof')
193
+ e = this.expr();
194
+ this.maybe(';');
195
+ return { s: 'ret', e };
196
+ }
197
+ const e = this.expr();
198
+ this.maybe(';');
199
+ return { s: 'expr', e };
200
+ }
201
+ expr() {
202
+ // an arrow function: `x => …` or `(a, b) => …`
203
+ if (this.cur.t === 'id' && this.toks[this.i + 1]?.t === 'op' && this.toks[this.i + 1].v === '=>') {
204
+ const p = this.cur.v;
205
+ this.i += 2;
206
+ return this.arrowBody([p]);
207
+ }
208
+ if (this.is('(')) {
209
+ let j = this.i + 1;
210
+ const params = [];
211
+ while (this.toks[j]?.t === 'id') {
212
+ params.push(this.toks[j].v);
213
+ j++;
214
+ if (this.toks[j]?.v === ',')
215
+ j++;
216
+ else
217
+ break;
218
+ }
219
+ if (this.toks[j]?.v === ')' && this.toks[j + 1]?.v === '=>') {
220
+ this.i = j + 2;
221
+ return this.arrowBody(params);
222
+ }
223
+ }
224
+ if (this.cur.t === 'id' && this.toks[this.i + 1]?.v === '=' && this.toks[this.i + 1].t === 'op') {
225
+ const n = this.cur.v;
226
+ this.i += 2;
227
+ return { k: 'asg', n, e: this.expr() };
228
+ }
229
+ return this.ternary();
230
+ }
231
+ arrowBody(params) { if (this.is('{'))
232
+ return { k: 'fn', params, body: this.block() }; return { k: 'fn', params, body: this.expr() }; }
233
+ ternary() { const c = this.or(); if (this.maybe('?')) {
234
+ const a = this.expr();
235
+ this.eat(':');
236
+ const b = this.expr();
237
+ return { k: 'cond', c, a, b };
238
+ } return c; }
239
+ or() { let l = this.and(); while (this.is('||') || this.is('??')) {
240
+ const op = this.cur.v;
241
+ this.i++;
242
+ l = { k: 'bin', op, l, r: this.and() };
243
+ } return l; }
244
+ and() { let l = this.eq(); while (this.is('&&')) {
245
+ this.i++;
246
+ l = { k: 'bin', op: '&&', l, r: this.eq() };
247
+ } return l; }
248
+ eq() { let l = this.rel(); while (['===', '!==', '==', '!='].includes(this.cur.v) && this.cur.t === 'op') {
249
+ const op = this.cur.v;
250
+ this.i++;
251
+ l = { k: 'bin', op, l, r: this.rel() };
252
+ } return l; }
253
+ rel() { let l = this.add(); while (['<', '>', '<=', '>='].includes(this.cur.v) && this.cur.t === 'op') {
254
+ const op = this.cur.v;
255
+ this.i++;
256
+ l = { k: 'bin', op, l, r: this.add() };
257
+ } return l; }
258
+ add() { let l = this.mul(); while ((this.is('+') || this.is('-'))) {
259
+ const op = this.cur.v;
260
+ this.i++;
261
+ l = { k: 'bin', op, l, r: this.mul() };
262
+ } return l; }
263
+ mul() { let l = this.unary(); while (this.is('*') || this.is('/') || this.is('%')) {
264
+ const op = this.cur.v;
265
+ this.i++;
266
+ l = { k: 'bin', op, l, r: this.unary() };
267
+ } return l; }
268
+ unary() {
269
+ if (this.is('!') || this.is('-') || this.is('+')) {
270
+ const op = this.cur.v;
271
+ this.i++;
272
+ return { k: 'un', op, e: this.unary() };
273
+ }
274
+ if (this.idIs('typeof')) {
275
+ this.i++;
276
+ return { k: 'un', op: 'typeof', e: this.unary() };
277
+ }
278
+ return this.postfix();
279
+ }
280
+ postfix() {
281
+ let e = this.primary();
282
+ for (;;) {
283
+ if (this.maybe('.')) {
284
+ if (this.cur.t !== 'id')
285
+ throw new ScriptError('A property name was expected after "."');
286
+ e = { k: 'mem', o: e, p: { k: 'lit', v: this.cur.v } };
287
+ this.i++;
288
+ }
289
+ else if (this.maybe('[')) {
290
+ const p = this.expr();
291
+ this.eat(']');
292
+ e = { k: 'mem', o: e, p };
293
+ }
294
+ else if (this.maybe('(')) {
295
+ const a = [];
296
+ while (!this.is(')')) {
297
+ a.push(this.expr());
298
+ if (!this.maybe(','))
299
+ break;
300
+ }
301
+ this.eat(')');
302
+ e = { k: 'call', f: e, a };
303
+ }
304
+ else
305
+ return e;
306
+ }
307
+ }
308
+ primary() {
309
+ const c = this.cur;
310
+ if (c.t === 'num') {
311
+ this.i++;
312
+ return { k: 'lit', v: Number(c.v) };
313
+ }
314
+ if (c.t === 'str') {
315
+ this.i++;
316
+ return { k: 'lit', v: c.v };
317
+ }
318
+ if (c.t === 'tpl') {
319
+ this.i++;
320
+ return { k: 'tpl', parts: c.parts.map((p) => (typeof p === 'string' ? p : (() => { const sub = new Parser(p); const e = sub.expr(); if (sub.cur.t !== 'eof')
321
+ throw new ScriptError('Unexpected text in a template'); return e; })())) };
322
+ }
323
+ if (c.t === 'id') {
324
+ if (c.v === 'true') {
325
+ this.i++;
326
+ return { k: 'lit', v: true };
327
+ }
328
+ if (c.v === 'false') {
329
+ this.i++;
330
+ return { k: 'lit', v: false };
331
+ }
332
+ if (c.v === 'null') {
333
+ this.i++;
334
+ return { k: 'lit', v: null };
335
+ }
336
+ if (c.v === 'undefined') {
337
+ this.i++;
338
+ return { k: 'lit', v: undefined };
339
+ }
340
+ if (c.v === 'function') {
341
+ this.i++;
342
+ if (this.cur.t === 'id')
343
+ this.i++;
344
+ this.eat('(');
345
+ const params = [];
346
+ while (this.cur.t === 'id') {
347
+ params.push(this.cur.v);
348
+ this.i++;
349
+ if (!this.maybe(','))
350
+ break;
351
+ }
352
+ this.eat(')');
353
+ return { k: 'fn', params, body: this.block() };
354
+ }
355
+ if (KEYWORDS_NOT_SUPPORTED.has(c.v))
356
+ throw new ScriptError(`"${c.v}" is not supported in hive-am response handlers`);
357
+ this.i++;
358
+ return { k: 'id', n: c.v };
359
+ }
360
+ if (this.maybe('(')) {
361
+ const e = this.expr();
362
+ this.eat(')');
363
+ return e;
364
+ }
365
+ if (this.maybe('[')) {
366
+ const items = [];
367
+ while (!this.is(']')) {
368
+ items.push(this.expr());
369
+ if (!this.maybe(','))
370
+ break;
371
+ }
372
+ this.eat(']');
373
+ return { k: 'arr', items };
374
+ }
375
+ if (this.maybe('{')) {
376
+ const props = [];
377
+ while (!this.is('}')) {
378
+ const key = this.cur.t === 'id' || this.cur.t === 'str' ? this.cur.v : (() => { throw new ScriptError('A property name was expected'); })();
379
+ this.i++;
380
+ if (this.maybe(':'))
381
+ props.push([key, this.expr()]);
382
+ else
383
+ props.push([key, { k: 'id', n: key }]);
384
+ if (!this.maybe(','))
385
+ break;
386
+ }
387
+ this.eat('}');
388
+ return { k: 'obj', props };
389
+ }
390
+ throw new ScriptError(`Unexpected "${c.v || 'end of the script'}"`);
391
+ }
392
+ }
393
+ // ------------------------------------------------------------------ evaluation
394
+ class Fn {
395
+ params;
396
+ body;
397
+ env;
398
+ constructor(params, body, env) {
399
+ this.params = params;
400
+ this.body = body;
401
+ this.env = env;
402
+ }
403
+ }
404
+ class Native {
405
+ name;
406
+ fn;
407
+ constructor(name, fn) {
408
+ this.name = name;
409
+ this.fn = fn;
410
+ }
411
+ }
412
+ class Return {
413
+ value;
414
+ constructor(value) {
415
+ this.value = value;
416
+ }
417
+ }
418
+ class Assertion extends Error {
419
+ }
420
+ class Env {
421
+ parent;
422
+ vars = new Map();
423
+ constructor(parent) {
424
+ this.parent = parent;
425
+ }
426
+ get(n) { return this.vars.has(n) ? this.vars.get(n) : this.parent?.get(n); }
427
+ has(n) { return this.vars.has(n) || !!this.parent?.has(n); }
428
+ set(n, v) { let e = this; while (e) {
429
+ if (e.vars.has(n)) {
430
+ e.vars.set(n, v);
431
+ return;
432
+ }
433
+ e = e.parent;
434
+ } this.vars.set(n, v); }
435
+ }
436
+ const BAD_PROPS = new Set(['__proto__', 'constructor', 'prototype', '__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__']);
437
+ const MAX_STEPS = 60_000;
438
+ const text = (v) => (v === undefined ? 'undefined' : v === null ? 'null' : typeof v === 'string' ? v : typeof v === 'object' ? JSON.stringify(v) : String(v));
439
+ export function runScript(script, response, globals) {
440
+ const result = { tests: [], logs: [], set: [], cleared: [] };
441
+ let program;
442
+ try {
443
+ program = new Parser(tokenize(script)).program();
444
+ }
445
+ catch (e) {
446
+ result.error = `This handler uses something hive-am does not support: ${e.message}`;
447
+ return result;
448
+ }
449
+ let steps = 0, depth = 0;
450
+ const tick = () => { if (++steps > MAX_STEPS)
451
+ throw new ScriptError('The handler did more work than it is allowed to'); };
452
+ const callFn = (f, args) => {
453
+ tick();
454
+ if (f instanceof Native)
455
+ return f.fn(args);
456
+ if (!(f instanceof Fn))
457
+ throw new ScriptError('That is not a function');
458
+ if (depth >= 100)
459
+ throw new ScriptError('The handler did more work than it is allowed to (functions call each other too deeply)');
460
+ const env = new Env(f.env);
461
+ f.params.forEach((p, i) => env.vars.set(p, args[i]));
462
+ depth++;
463
+ try {
464
+ if (!Array.isArray(f.body))
465
+ return ev(f.body, env);
466
+ try {
467
+ run(f.body, env);
468
+ }
469
+ catch (r) {
470
+ if (r instanceof Return)
471
+ return r.value;
472
+ throw r;
473
+ }
474
+ return undefined;
475
+ }
476
+ finally {
477
+ depth--;
478
+ }
479
+ };
480
+ const headersObj = { valueOf: new Native('valueOf', ([n]) => response.headers[String(n).toLowerCase()]), valuesOf: new Native('valuesOf', ([n]) => (response.headers[String(n).toLowerCase()] === undefined ? [] : [response.headers[String(n).toLowerCase()]])) };
481
+ const responseObj = { status: response.status, time: response.time ?? 0, text: response.text, body: response.body, headers: headersObj, contentType: { mimeType: response.contentType.split(';')[0].trim(), charset: /charset=([^;]+)/i.exec(response.contentType)?.[1] ?? 'utf-8' } };
482
+ const clientObj = {
483
+ global: {
484
+ set: new Native('set', ([n, v]) => { const name = text(n); if (!/^[A-Za-z_][\w.-]{0,80}$/.test(name))
485
+ throw new ScriptError(`"${name}" is not a valid variable name`); globals[name] = text(v); if (!result.set.includes(name))
486
+ result.set.push(name); return undefined; }),
487
+ get: new Native('get', ([n]) => globals[text(n)]),
488
+ clear: new Native('clear', ([n]) => { delete globals[text(n)]; result.cleared.push(text(n)); return undefined; }),
489
+ clearAll: new Native('clearAll', () => { for (const k of Object.keys(globals)) {
490
+ delete globals[k];
491
+ result.cleared.push(k);
492
+ } return undefined; }),
493
+ isEmpty: new Native('isEmpty', () => Object.keys(globals).length === 0),
494
+ },
495
+ log: new Native('log', (a) => { result.logs.push(a.map(text).join(' ')); return undefined; }),
496
+ assert: new Native('assert', ([c, m]) => { if (!c)
497
+ throw new Assertion(m === undefined ? 'Assertion failed' : text(m)); return undefined; }),
498
+ test: new Native('test', ([n, f]) => {
499
+ const name = text(n);
500
+ try {
501
+ callFn(f, []);
502
+ result.tests.push({ name, passed: true });
503
+ }
504
+ catch (e) {
505
+ if (e instanceof Assertion)
506
+ result.tests.push({ name, passed: false, message: e.message });
507
+ else if (e instanceof ScriptError)
508
+ result.tests.push({ name, passed: false, message: e.message });
509
+ else
510
+ throw e;
511
+ }
512
+ return undefined;
513
+ }),
514
+ };
515
+ const root = new Env();
516
+ root.vars.set('response', responseObj);
517
+ root.vars.set('client', clientObj);
518
+ root.vars.set('JSON', { parse: new Native('parse', ([s]) => { try {
519
+ return JSON.parse(text(s));
520
+ }
521
+ catch {
522
+ throw new ScriptError('JSON.parse: the text is not valid JSON');
523
+ } }), stringify: new Native('stringify', ([v]) => JSON.stringify(v)) });
524
+ root.vars.set('String', new Native('String', ([v]) => text(v)));
525
+ root.vars.set('Number', new Native('Number', ([v]) => Number(v)));
526
+ root.vars.set('parseInt', new Native('parseInt', ([v]) => Number.parseInt(text(v), 10)));
527
+ root.vars.set('parseFloat', new Native('parseFloat', ([v]) => Number.parseFloat(text(v))));
528
+ root.vars.set('Math', { floor: new Native('floor', ([v]) => Math.floor(Number(v))), round: new Native('round', ([v]) => Math.round(Number(v))), min: new Native('min', (a) => Math.min(...a.map(Number))), max: new Native('max', (a) => Math.max(...a.map(Number))) });
529
+ const prop = (o, p) => {
530
+ const key = typeof p === 'number' ? p : text(p);
531
+ if (typeof key === 'string' && BAD_PROPS.has(key))
532
+ throw new ScriptError(`"${key}" is not available`);
533
+ if (o === null || o === undefined)
534
+ throw new ScriptError(`Cannot read "${text(key)}" of ${o === null ? 'null' : 'undefined'}`);
535
+ if (typeof o === 'string') {
536
+ if (key === 'length')
537
+ return o.length;
538
+ if (typeof key === 'number')
539
+ return o[key];
540
+ const m = { includes: (x) => o.includes(text(x)), startsWith: (x) => o.startsWith(text(x)), endsWith: (x) => o.endsWith(text(x)), indexOf: (x) => o.indexOf(text(x)), toLowerCase: () => o.toLowerCase(), toUpperCase: () => o.toUpperCase(), trim: () => o.trim(), split: (x) => o.split(text(x)), slice: (a, b) => o.slice(Number(a), b === undefined ? undefined : Number(b)), substring: (a, b) => o.substring(Number(a), b === undefined ? undefined : Number(b)), toString: () => o, replace: (a, b) => o.replace(text(a), text(b)) };
541
+ return key in m ? new Native(String(key), (a) => m[key](...a)) : undefined;
542
+ }
543
+ if (Array.isArray(o)) {
544
+ if (key === 'length')
545
+ return o.length;
546
+ if (typeof key === 'number')
547
+ return o[key];
548
+ const fnArg = (f) => (x, i) => callFn(f, [x, i]);
549
+ const m = { includes: (x) => o.includes(x), indexOf: (x) => o.indexOf(x), join: (s) => o.map(text).join(s === undefined ? ',' : text(s)), slice: (a, b) => o.slice(Number(a), b === undefined ? undefined : Number(b)), map: (f) => o.map(fnArg(f)), filter: (f) => o.filter((x, i) => !!callFn(f, [x, i])), find: (f) => o.find((x, i) => !!callFn(f, [x, i])), some: (f) => o.some((x, i) => !!callFn(f, [x, i])), every: (f) => o.every((x, i) => !!callFn(f, [x, i])) };
550
+ return key in m ? new Native(String(key), (a) => m[key](...a)) : undefined;
551
+ }
552
+ if (o instanceof Native || o instanceof Fn)
553
+ return undefined;
554
+ if (typeof o === 'object')
555
+ return Object.prototype.hasOwnProperty.call(o, key) ? o[key] : undefined;
556
+ if (typeof o === 'number' && key === 'toString')
557
+ return new Native('toString', () => String(o));
558
+ return undefined;
559
+ };
560
+ const ev = (n, env) => {
561
+ tick();
562
+ switch (n.k) {
563
+ case 'lit': return n.v;
564
+ case 'id':
565
+ if (!env.has(n.n)) {
566
+ if (n.n === 'undefined')
567
+ return undefined;
568
+ throw new ScriptError(`"${n.n}" is not defined`);
569
+ }
570
+ return env.get(n.n);
571
+ case 'tpl': return n.parts.map((p) => (typeof p === 'string' ? p : text(ev(p, env)))).join('');
572
+ case 'arr': return n.items.map((x) => ev(x, env));
573
+ case 'obj': return Object.fromEntries(n.props.filter(([k]) => !BAD_PROPS.has(k)).map(([k, v]) => [k, ev(v, env)]));
574
+ case 'mem': return prop(ev(n.o, env), ev(n.p, env));
575
+ case 'call': return callFn(ev(n.f, env), n.a.map((x) => ev(x, env)));
576
+ case 'fn': return new Fn(n.params, n.body, env);
577
+ case 'asg': {
578
+ if (!env.has(n.n))
579
+ throw new ScriptError(`"${n.n}" is not declared`);
580
+ const v = ev(n.e, env);
581
+ env.set(n.n, v);
582
+ return v;
583
+ }
584
+ case 'cond': return ev(n.c, env) ? ev(n.a, env) : ev(n.b, env);
585
+ case 'un': {
586
+ const v = ev(n.e, env);
587
+ return n.op === '!' ? !v : n.op === '-' ? -Number(v) : n.op === '+' ? Number(v) : typeof v === 'object' && v instanceof Fn ? 'function' : v === null ? 'object' : typeof v;
588
+ }
589
+ case 'bin': {
590
+ if (n.op === '&&') {
591
+ const l = ev(n.l, env);
592
+ return l ? ev(n.r, env) : l;
593
+ }
594
+ if (n.op === '||') {
595
+ const l = ev(n.l, env);
596
+ return l ? l : ev(n.r, env);
597
+ }
598
+ if (n.op === '??') {
599
+ const l = ev(n.l, env);
600
+ return l ?? ev(n.r, env);
601
+ }
602
+ const l = ev(n.l, env), r = ev(n.r, env);
603
+ switch (n.op) {
604
+ case '===': return l === r;
605
+ case '!==': return l !== r;
606
+ case '==': return l == r;
607
+ case '!=': return l != r; // eslint-disable-line eqeqeq
608
+ case '<': return l < r;
609
+ case '>': return l > r;
610
+ case '<=': return l <= r;
611
+ case '>=': return l >= r;
612
+ case '+': return typeof l === 'string' || typeof r === 'string' ? text(l) + text(r) : Number(l) + Number(r);
613
+ case '-': return Number(l) - Number(r);
614
+ case '*': return Number(l) * Number(r);
615
+ case '/': return Number(l) / Number(r);
616
+ case '%': return Number(l) % Number(r);
617
+ }
618
+ throw new ScriptError(`Unknown operator ${n.op}`);
619
+ }
620
+ }
621
+ };
622
+ const run = (stmts, env) => {
623
+ for (const s of stmts) {
624
+ tick();
625
+ if (s.s === 'decl')
626
+ env.vars.set(s.n, s.e ? ev(s.e, env) : undefined);
627
+ else if (s.s === 'expr')
628
+ ev(s.e, env);
629
+ else if (s.s === 'if')
630
+ run(ev(s.c, env) ? s.a : s.b, new Env(env));
631
+ else
632
+ throw new Return(s.e ? ev(s.e, env) : undefined);
633
+ }
634
+ };
635
+ try {
636
+ run(program, root);
637
+ }
638
+ catch (e) {
639
+ if (e instanceof Return)
640
+ return result;
641
+ result.error = e instanceof Assertion ? `Assertion failed: ${e.message}` : e instanceof ScriptError ? e.message : `The handler failed: ${e.message}`;
642
+ }
643
+ return result;
644
+ }