@skillcdn/console 0.4.1 → 0.4.3

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 (299) hide show
  1. package/README.md +19 -2
  2. package/SKILLCDN.md +7 -5
  3. package/dist/api.d.ts +5 -4
  4. package/dist/api.d.ts.map +1 -1
  5. package/dist/api.js +5 -4
  6. package/dist/api.js.map +1 -1
  7. package/dist/cli/cli.d.ts.map +1 -1
  8. package/dist/cli/cli.js +569 -48
  9. package/dist/cli/cli.js.map +1 -1
  10. package/dist/cli/format.d.ts +34 -3
  11. package/dist/cli/format.d.ts.map +1 -1
  12. package/dist/cli/format.js +283 -7
  13. package/dist/cli/format.js.map +1 -1
  14. package/dist/cli/help.d.ts.map +1 -1
  15. package/dist/cli/help.js +44 -7
  16. package/dist/cli/help.js.map +1 -1
  17. package/dist/cli/plugin-check.d.ts +26 -0
  18. package/dist/cli/plugin-check.d.ts.map +1 -0
  19. package/dist/cli/plugin-check.js +396 -0
  20. package/dist/cli/plugin-check.js.map +1 -0
  21. package/dist/cli/plugin-cli.d.ts +20 -0
  22. package/dist/cli/plugin-cli.d.ts.map +1 -0
  23. package/dist/cli/plugin-cli.js +189 -0
  24. package/dist/cli/plugin-cli.js.map +1 -0
  25. package/dist/cli/plugin-init.d.ts +37 -0
  26. package/dist/cli/plugin-init.d.ts.map +1 -0
  27. package/dist/cli/plugin-init.js +206 -0
  28. package/dist/cli/plugin-init.js.map +1 -0
  29. package/dist/cli/plugin-main.d.ts +3 -0
  30. package/dist/cli/plugin-main.d.ts.map +1 -0
  31. package/dist/cli/plugin-main.js +28 -0
  32. package/dist/cli/plugin-main.js.map +1 -0
  33. package/dist/client.d.ts +100 -3
  34. package/dist/client.d.ts.map +1 -1
  35. package/dist/client.js +79 -7
  36. package/dist/client.js.map +1 -1
  37. package/dist/compat.d.ts +1 -1
  38. package/dist/compat.js +2 -2
  39. package/dist/components/board.d.ts +8 -0
  40. package/dist/components/board.d.ts.map +1 -1
  41. package/dist/components/board.js +59 -15
  42. package/dist/components/board.js.map +1 -1
  43. package/dist/components/comments.d.ts.map +1 -1
  44. package/dist/components/comments.js +1 -1
  45. package/dist/components/comments.js.map +1 -1
  46. package/dist/components/decision-form.d.ts +2 -1
  47. package/dist/components/decision-form.d.ts.map +1 -1
  48. package/dist/components/decision-form.js +36 -4
  49. package/dist/components/decision-form.js.map +1 -1
  50. package/dist/components/decision-list.d.ts +4 -0
  51. package/dist/components/decision-list.d.ts.map +1 -1
  52. package/dist/components/decision-list.js +29 -3
  53. package/dist/components/decision-list.js.map +1 -1
  54. package/dist/components/event-feed.d.ts +1 -1
  55. package/dist/components/event-feed.d.ts.map +1 -1
  56. package/dist/components/event-feed.js +33 -1
  57. package/dist/components/event-feed.js.map +1 -1
  58. package/dist/components/my-decisions.d.ts +2 -0
  59. package/dist/components/my-decisions.d.ts.map +1 -1
  60. package/dist/components/my-decisions.js +2 -2
  61. package/dist/components/my-decisions.js.map +1 -1
  62. package/dist/components/plugin-frame.d.ts +52 -0
  63. package/dist/components/plugin-frame.d.ts.map +1 -0
  64. package/dist/components/plugin-frame.js +314 -0
  65. package/dist/components/plugin-frame.js.map +1 -0
  66. package/dist/components/plugin-settings.d.ts +38 -0
  67. package/dist/components/plugin-settings.d.ts.map +1 -0
  68. package/dist/components/plugin-settings.js +348 -0
  69. package/dist/components/plugin-settings.js.map +1 -0
  70. package/dist/components/shell.d.ts +2 -0
  71. package/dist/components/shell.d.ts.map +1 -1
  72. package/dist/components/shell.js +26 -1
  73. package/dist/components/shell.js.map +1 -1
  74. package/dist/components/task-view.d.ts +2 -1
  75. package/dist/components/task-view.d.ts.map +1 -1
  76. package/dist/components/task-view.js.map +1 -1
  77. package/dist/components/workspace.d.ts +7 -1
  78. package/dist/components/workspace.d.ts.map +1 -1
  79. package/dist/components/workspace.js +1 -1
  80. package/dist/components/workspace.js.map +1 -1
  81. package/dist/console.css +330 -1
  82. package/dist/console.d.ts.map +1 -1
  83. package/dist/console.js +152 -41
  84. package/dist/console.js.map +1 -1
  85. package/dist/data.d.ts +9 -2
  86. package/dist/data.d.ts.map +1 -1
  87. package/dist/data.js +45 -9
  88. package/dist/data.js.map +1 -1
  89. package/dist/i18n/en.d.ts +155 -0
  90. package/dist/i18n/en.d.ts.map +1 -1
  91. package/dist/i18n/en.js +166 -0
  92. package/dist/i18n/en.js.map +1 -1
  93. package/dist/i18n/ko.d.ts.map +1 -1
  94. package/dist/i18n/ko.js +150 -0
  95. package/dist/i18n/ko.js.map +1 -1
  96. package/dist/index.d.ts +3 -1
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +3 -1
  99. package/dist/index.js.map +1 -1
  100. package/dist/limits.d.ts +2 -0
  101. package/dist/limits.d.ts.map +1 -1
  102. package/dist/limits.js +2 -0
  103. package/dist/limits.js.map +1 -1
  104. package/dist/plugin/args.d.ts +148 -0
  105. package/dist/plugin/args.d.ts.map +1 -0
  106. package/dist/plugin/args.js +369 -0
  107. package/dist/plugin/args.js.map +1 -0
  108. package/dist/plugin/bridge.d.ts +146 -0
  109. package/dist/plugin/bridge.d.ts.map +1 -0
  110. package/dist/plugin/bridge.js +125 -0
  111. package/dist/plugin/bridge.js.map +1 -0
  112. package/dist/plugin/capabilities.d.ts +20 -0
  113. package/dist/plugin/capabilities.d.ts.map +1 -0
  114. package/dist/plugin/capabilities.js +133 -0
  115. package/dist/plugin/capabilities.js.map +1 -0
  116. package/dist/plugin/context.d.ts +380 -0
  117. package/dist/plugin/context.d.ts.map +1 -0
  118. package/dist/plugin/context.js +2 -0
  119. package/dist/plugin/context.js.map +1 -0
  120. package/dist/plugin/define.d.ts +208 -0
  121. package/dist/plugin/define.d.ts.map +1 -0
  122. package/dist/plugin/define.js +482 -0
  123. package/dist/plugin/define.js.map +1 -0
  124. package/dist/plugin/definition-error.d.ts +11 -0
  125. package/dist/plugin/definition-error.d.ts.map +1 -0
  126. package/dist/plugin/definition-error.js +17 -0
  127. package/dist/plugin/definition-error.js.map +1 -0
  128. package/dist/plugin/limits.d.ts +67 -0
  129. package/dist/plugin/limits.d.ts.map +1 -0
  130. package/dist/plugin/limits.js +70 -0
  131. package/dist/plugin/limits.js.map +1 -0
  132. package/dist/plugin/load-worker.d.ts +7 -0
  133. package/dist/plugin/load-worker.d.ts.map +1 -0
  134. package/dist/plugin/load-worker.js +41 -0
  135. package/dist/plugin/load-worker.js.map +1 -0
  136. package/dist/plugin/load.d.ts +18 -0
  137. package/dist/plugin/load.d.ts.map +1 -0
  138. package/dist/plugin/load.js +62 -0
  139. package/dist/plugin/load.js.map +1 -0
  140. package/dist/plugin/manifest.d.ts +237 -0
  141. package/dist/plugin/manifest.d.ts.map +1 -0
  142. package/dist/plugin/manifest.js +411 -0
  143. package/dist/plugin/manifest.js.map +1 -0
  144. package/dist/plugin/refusals.d.ts +49 -0
  145. package/dist/plugin/refusals.d.ts.map +1 -0
  146. package/dist/plugin/refusals.js +79 -0
  147. package/dist/plugin/refusals.js.map +1 -0
  148. package/dist/plugin/rest-schemas.d.ts +556 -0
  149. package/dist/plugin/rest-schemas.d.ts.map +1 -0
  150. package/dist/plugin/rest-schemas.js +262 -0
  151. package/dist/plugin/rest-schemas.js.map +1 -0
  152. package/dist/plugin/sandbox.d.ts +23 -0
  153. package/dist/plugin/sandbox.d.ts.map +1 -0
  154. package/dist/plugin/sandbox.js +99 -0
  155. package/dist/plugin/sandbox.js.map +1 -0
  156. package/dist/plugin/testing.d.ts +45 -0
  157. package/dist/plugin/testing.d.ts.map +1 -0
  158. package/dist/plugin/testing.js +420 -0
  159. package/dist/plugin/testing.js.map +1 -0
  160. package/dist/plugin/web-react.d.ts +11 -0
  161. package/dist/plugin/web-react.d.ts.map +1 -0
  162. package/dist/plugin/web-react.js +34 -0
  163. package/dist/plugin/web-react.js.map +1 -0
  164. package/dist/plugin/web.d.ts +95 -0
  165. package/dist/plugin/web.d.ts.map +1 -0
  166. package/dist/plugin/web.js +245 -0
  167. package/dist/plugin/web.js.map +1 -0
  168. package/dist/plugin-nav.d.ts +29 -0
  169. package/dist/plugin-nav.d.ts.map +1 -0
  170. package/dist/plugin-nav.js +92 -0
  171. package/dist/plugin-nav.js.map +1 -0
  172. package/dist/plugin-testing.d.ts +2 -0
  173. package/dist/plugin-testing.d.ts.map +1 -0
  174. package/dist/plugin-testing.js +4 -0
  175. package/dist/plugin-testing.js.map +1 -0
  176. package/dist/plugin-web-react.d.ts +3 -0
  177. package/dist/plugin-web-react.d.ts.map +1 -0
  178. package/dist/plugin-web-react.js +3 -0
  179. package/dist/plugin-web-react.js.map +1 -0
  180. package/dist/plugin-web.d.ts +4 -0
  181. package/dist/plugin-web.d.ts.map +1 -0
  182. package/dist/plugin-web.js +5 -0
  183. package/dist/plugin-web.js.map +1 -0
  184. package/dist/plugin.d.ts +11 -0
  185. package/dist/plugin.d.ts.map +1 -0
  186. package/dist/plugin.js +15 -0
  187. package/dist/plugin.js.map +1 -0
  188. package/dist/router.d.ts +28 -0
  189. package/dist/router.d.ts.map +1 -1
  190. package/dist/router.js +47 -0
  191. package/dist/router.js.map +1 -1
  192. package/dist/routes.d.ts +4 -0
  193. package/dist/routes.d.ts.map +1 -1
  194. package/dist/routes.js +6 -0
  195. package/dist/routes.js.map +1 -1
  196. package/dist/schemas.d.ts +194 -9
  197. package/dist/schemas.d.ts.map +1 -1
  198. package/dist/schemas.js +98 -17
  199. package/dist/schemas.js.map +1 -1
  200. package/dist/tokens.d.ts +2 -0
  201. package/dist/tokens.d.ts.map +1 -0
  202. package/dist/tokens.js +101 -0
  203. package/dist/tokens.js.map +1 -0
  204. package/dist/vocabulary.d.ts +11 -1
  205. package/dist/vocabulary.d.ts.map +1 -1
  206. package/dist/vocabulary.js +24 -0
  207. package/dist/vocabulary.js.map +1 -1
  208. package/dist/web.d.ts.map +1 -1
  209. package/dist/web.js +2 -0
  210. package/dist/web.js.map +1 -1
  211. package/docs/specs/cli.md +12 -5
  212. package/docs/specs/plugins.md +488 -0
  213. package/docs/specs/rest.md +11 -9
  214. package/package.json +26 -8
  215. package/skills/building-a-console/SKILL.md +25 -26
  216. package/skills/building-a-console/references/configuring.md +40 -0
  217. package/skills/building-a-console/references/the-default-console.md +1 -1
  218. package/skills/building-a-console/references/the-look-from-a-website.md +5 -5
  219. package/skills/building-a-plugin/SKILL.md +137 -0
  220. package/skills/deploying-a-console/SKILL.md +24 -26
  221. package/skills/deploying-a-console/references/access.md +13 -9
  222. package/skills/deploying-a-console/references/resources.md +25 -10
  223. package/skills/deploying-a-console/references/running-it-again.md +15 -0
  224. package/skills/deploying-a-console/references/sizing.md +2 -0
  225. package/skills/planning-the-board/SKILL.md +96 -0
  226. package/skills/planning-the-board/references/a-task.md +36 -0
  227. package/skills/planning-the-board/references/setting-up.md +44 -0
  228. package/skills/working-the-board/SKILL.md +43 -34
  229. package/skills/working-the-board/references/the-pack.md +19 -0
  230. package/src/api.ts +12 -0
  231. package/src/cli/cli.ts +737 -55
  232. package/src/cli/format.ts +368 -10
  233. package/src/cli/help.ts +50 -6
  234. package/src/cli/plugin-check.ts +497 -0
  235. package/src/cli/plugin-cli.ts +237 -0
  236. package/src/cli/plugin-init.ts +257 -0
  237. package/src/cli/plugin-main.ts +30 -0
  238. package/src/client.ts +322 -9
  239. package/src/compat.ts +2 -2
  240. package/src/components/board.tsx +62 -14
  241. package/src/components/comments.tsx +1 -0
  242. package/src/components/decision-form.tsx +92 -11
  243. package/src/components/decision-list.tsx +71 -2
  244. package/src/components/event-feed.tsx +42 -1
  245. package/src/components/my-decisions.tsx +4 -1
  246. package/src/components/plugin-frame.tsx +437 -0
  247. package/src/components/plugin-settings.tsx +1111 -0
  248. package/src/components/shell.tsx +82 -14
  249. package/src/components/task-view.tsx +2 -1
  250. package/src/components/workspace.tsx +18 -0
  251. package/src/console.tsx +304 -31
  252. package/src/data.ts +59 -11
  253. package/src/i18n/en.ts +175 -0
  254. package/src/i18n/ko.ts +155 -0
  255. package/src/index.ts +12 -0
  256. package/src/limits.ts +2 -0
  257. package/src/plugin/args.ts +526 -0
  258. package/src/plugin/bridge.ts +314 -0
  259. package/src/plugin/capabilities.ts +150 -0
  260. package/src/plugin/context.ts +421 -0
  261. package/src/plugin/define.ts +792 -0
  262. package/src/plugin/definition-error.ts +19 -0
  263. package/src/plugin/limits.ts +70 -0
  264. package/src/plugin/load-worker.ts +50 -0
  265. package/src/plugin/load.ts +82 -0
  266. package/src/plugin/manifest.ts +561 -0
  267. package/src/plugin/refusals.ts +94 -0
  268. package/src/plugin/rest-schemas.ts +354 -0
  269. package/src/plugin/sandbox.ts +123 -0
  270. package/src/plugin/testing.ts +612 -0
  271. package/src/plugin/web-react.ts +45 -0
  272. package/src/plugin/web.ts +403 -0
  273. package/src/plugin-nav.ts +132 -0
  274. package/src/plugin-testing.ts +10 -0
  275. package/src/plugin-web-react.ts +4 -0
  276. package/src/plugin-web.ts +35 -0
  277. package/src/plugin.ts +126 -0
  278. package/src/router.ts +73 -0
  279. package/src/routes.ts +7 -0
  280. package/src/schemas.ts +115 -18
  281. package/src/styles/console.css +330 -1
  282. package/src/tokens.ts +101 -0
  283. package/src/vocabulary.ts +30 -0
  284. package/src/web.ts +2 -0
  285. package/template/plugin/.gitignore +2 -0
  286. package/template/plugin/README.md +26 -0
  287. package/template/plugin/SKILLCDN.md +13 -0
  288. package/template/plugin/build.mjs +40 -0
  289. package/template/plugin/console-plugin.json +50 -0
  290. package/template/plugin/package.json +27 -0
  291. package/template/plugin/skills/__key__/SKILL.md +23 -0
  292. package/template/plugin/src/check.test.ts +34 -0
  293. package/template/plugin/src/server/index.test.ts +41 -0
  294. package/template/plugin/src/server/index.ts +72 -0
  295. package/template/plugin/src/web/index.css +51 -0
  296. package/template/plugin/src/web/index.ts +115 -0
  297. package/template/plugin/tsconfig.json +17 -0
  298. package/skills/working-the-board/references/setting-up.md +0 -3
  299. /package/skills/{working-the-board → planning-the-board}/references/project-rules.md +0 -0
@@ -0,0 +1,19 @@
1
+ /**
2
+ * What `definePlugin` and its definers throw when a definition is not one the console can hold: a
3
+ * name that is not a key, a command named as a subcommand, more of something than the bound. It
4
+ * is thrown when the server module loads, so that a plugin's own tests and `console-plugin check`
5
+ * meet it before any console does; `problems` names every one found.
6
+ */
7
+ export class PluginDefinitionError extends Error {
8
+ readonly problems: readonly string[];
9
+
10
+ constructor(problems: readonly string[]) {
11
+ super(
12
+ problems.length === 1
13
+ ? `the plugin's definition is invalid: ${problems[0]}`
14
+ : `the plugin's definition is invalid:\n${problems.map((problem) => ` - ${problem}`).join("\n")}`,
15
+ );
16
+ this.name = "PluginDefinitionError";
17
+ this.problems = problems;
18
+ }
19
+ }
@@ -0,0 +1,70 @@
1
+ // How much a plugin may ask of a console (docs/specs/plugins.md, "Limits and refusals"): the
2
+ // bounds the manifest's schema, the definers, the host and the pages hold a plugin to. One source,
3
+ // so that `console-plugin check` says before an administrator finds out.
4
+
5
+ /** A plugin's name in one language, its description, and the sentence agents read with the rules. */
6
+ export const MAX_PLUGIN_NAME_LENGTH = 40;
7
+ export const MAX_PLUGIN_DESCRIPTION_LENGTH = 200;
8
+ export const MAX_PLUGIN_AGENT_NOTE_LENGTH = 200;
9
+ /** A plugin's key, a role's, a page's, a widget's, a setting's, a collection's, a command's: `^[a-z][a-z0-9-]{1,31}$`. */
10
+ export const MAX_PLUGIN_KEY_LENGTH = 32;
11
+ /** How many roles, settings, pages and widgets one manifest declares. */
12
+ export const MAX_PLUGIN_ROLES = 10;
13
+ export const MAX_PLUGIN_SETTINGS = 50;
14
+ export const MAX_PLUGIN_PAGES = 12;
15
+ export const MAX_PLUGIN_WIDGETS = 4;
16
+ /** How many collections, commands and queries together, endpoints, and indexes of one collection a server module defines. */
17
+ export const MAX_PLUGIN_COLLECTIONS = 50;
18
+ export const MAX_PLUGIN_OPERATIONS = 100;
19
+ export const MAX_PLUGIN_ENDPOINTS = 20;
20
+ export const MAX_PLUGIN_INDEXES = 8;
21
+ /** One line about a command, a query, a job or an argument, as help prints it. */
22
+ export const MAX_PLUGIN_ABOUT_LENGTH = 200;
23
+ /** The options of an `enum` setting or argument. */
24
+ export const MAX_PLUGIN_OPTIONS = 50;
25
+ /** A record, how many a plugin keeps, and how many versions one record keeps. */
26
+ export const MAX_PLUGIN_RECORD_BYTES = 64 * 1024;
27
+ export const MAX_PLUGIN_RECORDS = 100_000;
28
+ export const MAX_PLUGIN_RECORD_VERSIONS = 100;
29
+ /** A message between the host and the parent, a query's answer, an endpoint's answer. */
30
+ export const MAX_PLUGIN_MESSAGE_BYTES = 4 * 1024 * 1024;
31
+ /** What an endpoint takes in. */
32
+ export const MAX_PLUGIN_ENDPOINT_BODY_BYTES = 1024 * 1024;
33
+ /** The words of one command line sent to `invoke`, and the characters of one word. */
34
+ export const MAX_PLUGIN_ARGV_WORDS = 200;
35
+ export const MAX_PLUGIN_ARGV_WORD_LENGTH = 50_000;
36
+ /** The files one command takes at once. */
37
+ export const MAX_PLUGIN_COMMAND_FILES = 20;
38
+ /** An event of the plugin's own, how many are kept, and for how long. */
39
+ export const MAX_PLUGIN_EVENT_BYTES = 16 * 1024;
40
+ export const PLUGIN_EVENTS_KEPT = 100_000;
41
+ export const PLUGIN_EVENT_DAYS = 90;
42
+ /** How many records one page of a list carries at most. */
43
+ export const PLUGIN_LIST_LIMIT = 200;
44
+ /** How long plugin code may run: a command; a query or an endpoint; a hook; a job; `onEnable`, `onDisable` and an upgrade. */
45
+ export const PLUGIN_COMMAND_MS = 30_000;
46
+ export const PLUGIN_QUERY_MS = 10_000;
47
+ export const PLUGIN_ENDPOINT_MS = 10_000;
48
+ export const PLUGIN_HOOK_MS = 30_000;
49
+ export const PLUGIN_JOB_MS = 5 * 60_000;
50
+ export const PLUGIN_LIFECYCLE_MS = 10 * 60_000;
51
+ /** A job runs no more often than this. */
52
+ export const MIN_PLUGIN_JOB_INTERVAL_MS = 5 * 60_000;
53
+ /** Outbound requests a minute per plugin, the bytes of an answer, and its time. */
54
+ export const PLUGIN_OUTBOUND_PER_MINUTE = 60;
55
+ export const MAX_PLUGIN_OUTBOUND_BYTES = 10 * 1024 * 1024;
56
+ export const PLUGIN_OUTBOUND_MS = 10_000;
57
+ /** Webhook requests a minute per plugin. */
58
+ export const PLUGIN_WEBHOOKS_PER_MINUTE = 600;
59
+ /** Lines `ctx.log` writes a minute. */
60
+ export const PLUGIN_LOG_LINES_PER_MINUTE = 100;
61
+ /** SQL, with `storage:sql`: a statement's time, a result's rows, the connections of the plugin's role. */
62
+ export const PLUGIN_SQL_STATEMENT_MS = 10_000;
63
+ export const MAX_PLUGIN_SQL_ROWS = 10_000;
64
+ export const PLUGIN_SQL_CONNECTIONS = 4;
65
+ /** The memory a plugin's thread may hold, in megabytes, where the deployment says nothing. */
66
+ export const DEFAULT_PLUGIN_MEMORY_MB = 256;
67
+ /** How tall a widget's frame may grow, in pixels. */
68
+ export const MAX_PLUGIN_WIDGET_HEIGHT = 480;
69
+ /** How many retries a hook gets before its event is skipped with a `plugin.failed` event. */
70
+ export const PLUGIN_HOOK_RETRIES = 5;
@@ -0,0 +1,50 @@
1
+ // The thread a server module is loaded in to be described (docs/specs/plugins.md, "The host" and
2
+ // "Authoring"): hardened first, then the module imported and its default export described as
3
+ // JSON for the parent. `console-plugin check` runs this; the host loads plugins the same way and
4
+ // then keeps the thread. Nothing of the console is reachable from here: no database, no
5
+ // configuration, an empty environment.
6
+ import * as moduleApi from "node:module";
7
+ import { pathToFileURL } from "node:url";
8
+ import { parentPort, workerData } from "node:worker_threads";
9
+ import { describePlugin, isPluginDefinition } from "./define.js";
10
+ import { PluginDefinitionError } from "./definition-error.js";
11
+ import { hardenThread } from "./sandbox.js";
12
+
13
+ export interface LoadOutcome {
14
+ readonly ok: boolean;
15
+ readonly description?: unknown;
16
+ readonly error?: string;
17
+ readonly problems?: readonly string[];
18
+ }
19
+
20
+ function errorText(error: unknown): { error: string; problems?: readonly string[] } {
21
+ if (error instanceof PluginDefinitionError) {
22
+ return { error: "the definition is invalid", problems: error.problems };
23
+ }
24
+ if (error instanceof Error) {
25
+ const code = (error as { code?: unknown }).code;
26
+ return { error: typeof code === "string" ? `${code}: ${error.message}` : error.message };
27
+ }
28
+ return { error: String(error) };
29
+ }
30
+
31
+ const { file } = workerData as { file: string };
32
+
33
+ let outcome: LoadOutcome;
34
+ try {
35
+ if (typeof moduleApi.registerHooks !== "function") {
36
+ throw new Error(
37
+ "the host needs Node.js 24 or newer, which has module hooks that run in a thread",
38
+ );
39
+ }
40
+ hardenThread(moduleApi);
41
+ const loaded = (await import(pathToFileURL(file).href)) as { default?: unknown };
42
+ if (!isPluginDefinition(loaded.default)) {
43
+ outcome = { ok: false, error: "the default export is not what definePlugin({...}) yields" };
44
+ } else {
45
+ outcome = { ok: true, description: describePlugin(loaded.default) };
46
+ }
47
+ } catch (error) {
48
+ outcome = { ok: false, ...errorText(error) };
49
+ }
50
+ parentPort?.postMessage(outcome);
@@ -0,0 +1,82 @@
1
+ // Loads a plugin's server module in a hardened worker thread and answers its description, or why
2
+ // it did not load. What `console-plugin check` does to a package; the host does the same before
3
+ // keeping the thread. Node only.
4
+ import { Worker } from "node:worker_threads";
5
+ import type { PluginDescription } from "./define.js";
6
+ import { DEFAULT_PLUGIN_MEMORY_MB } from "./limits.js";
7
+
8
+ export type ServerLoad =
9
+ | { readonly ok: true; readonly description: PluginDescription }
10
+ | { readonly ok: false; readonly error: string; readonly problems: readonly string[] };
11
+
12
+ export interface LoadOptions {
13
+ /** How long the module gets to load; ten seconds unless said. */
14
+ readonly timeoutMs?: number;
15
+ /** The memory the thread may hold, in megabytes. */
16
+ readonly memoryMb?: number;
17
+ }
18
+
19
+ const DEFAULT_LOAD_MS = 10_000;
20
+
21
+ /** The description of the server module at `file`, loaded in a thread of its own under the host's hardening. */
22
+ export function loadServerModule(file: string, options: LoadOptions = {}): Promise<ServerLoad> {
23
+ const timeoutMs = options.timeoutMs ?? DEFAULT_LOAD_MS;
24
+ return new Promise((resolve) => {
25
+ let settled = false;
26
+ const settle = (load: ServerLoad) => {
27
+ if (!settled) {
28
+ settled = true;
29
+ clearTimeout(timer);
30
+ resolve(load);
31
+ }
32
+ };
33
+ const worker = new Worker(new URL("./load-worker.js", import.meta.url), {
34
+ workerData: { file },
35
+ env: {},
36
+ resourceLimits: { maxOldGenerationSizeMb: options.memoryMb ?? DEFAULT_PLUGIN_MEMORY_MB },
37
+ stdout: true,
38
+ stderr: true,
39
+ });
40
+ // What the module prints while loading goes nowhere: the check speaks for itself.
41
+ worker.stdout.resume();
42
+ worker.stderr.resume();
43
+ const timer = setTimeout(() => {
44
+ settle({
45
+ ok: false,
46
+ error: `the server module did not load within ${timeoutMs} ms`,
47
+ problems: [],
48
+ });
49
+ void worker.terminate();
50
+ }, timeoutMs);
51
+ worker.on(
52
+ "message",
53
+ (outcome: {
54
+ ok: boolean;
55
+ description?: PluginDescription;
56
+ error?: string;
57
+ problems?: readonly string[];
58
+ }) => {
59
+ if (outcome.ok && outcome.description !== undefined) {
60
+ settle({ ok: true, description: outcome.description });
61
+ } else {
62
+ settle({
63
+ ok: false,
64
+ error: outcome.error ?? "the server module did not load",
65
+ problems: outcome.problems ?? [],
66
+ });
67
+ }
68
+ void worker.terminate();
69
+ },
70
+ );
71
+ worker.on("error", (error) => {
72
+ settle({ ok: false, error: error.message, problems: [] });
73
+ });
74
+ worker.on("exit", (code) => {
75
+ settle({
76
+ ok: false,
77
+ error: `the server module's thread ended with ${code} before describing it`,
78
+ problems: [],
79
+ });
80
+ });
81
+ });
82
+ }