@progmruansilva/omp-web 1.202608.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 (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +181 -0
  3. package/dist/cli.js +1015 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/client/assets/CodeViewer-Da66baHj.js +4 -0
  6. package/dist/client/assets/TerminalPanel-Bj9an79F.js +126 -0
  7. package/dist/client/assets/UnifiedDiffViewer-eK_kynTO.js +34 -0
  8. package/dist/client/assets/index-DytaeWNd.js +3070 -0
  9. package/dist/client/assets/vendor-editor-core-CL2gOCIg.js +12 -0
  10. package/dist/client/assets/vendor-editor-languages-zOM9I4iZ.js +26 -0
  11. package/dist/client/assets/vendor-editor-legacy-B4QLsWF8.js +1 -0
  12. package/dist/client/assets/vendor-terminal-DDGTF8rc.css +1 -0
  13. package/dist/client/assets/vendor-terminal-DjQ08hXu.js +16 -0
  14. package/dist/client/favicon-16x16.png +0 -0
  15. package/dist/client/favicon-180x180.png +0 -0
  16. package/dist/client/favicon-192x192.png +0 -0
  17. package/dist/client/favicon-32x32.png +0 -0
  18. package/dist/client/favicon-512x512.png +0 -0
  19. package/dist/client/favicon.ico +0 -0
  20. package/dist/client/favicon.png +0 -0
  21. package/dist/client/favicon.svg +11 -0
  22. package/dist/client/index.html +67 -0
  23. package/dist/client/manifest.webmanifest +36 -0
  24. package/dist/config.js +272 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/docker/ompWebDockerCommandPlan.js +211 -0
  27. package/dist/docker/ompWebDockerCommandPlan.js.map +1 -0
  28. package/dist/omp-web-plugins/info/omp-web-plugin.js +51 -0
  29. package/dist/omp-web-plugins/info/package.json +9 -0
  30. package/dist/omp-web-plugins/schedule-prompts/omp-web-plugin.js +43 -0
  31. package/dist/omp-web-plugins/schedule-prompts/package.json +9 -0
  32. package/dist/omp-web-plugins/schedule-prompts/schedulePromptsPanelElement.js +242 -0
  33. package/dist/omp-web-plugins/schedule-prompts/types.js +2 -0
  34. package/dist/omp-web-plugins/updates/omp-web-plugin.js +173 -0
  35. package/dist/omp-web-plugins/updates/package.json +9 -0
  36. package/dist/omp-web-plugins/updates/updatesLogic.js +97 -0
  37. package/dist/ompWebVersionReport.js +217 -0
  38. package/dist/ompWebVersionReport.js.map +1 -0
  39. package/dist/plugin-api/unstable.d.ts +22 -0
  40. package/dist/plugin-api.d.ts +197 -0
  41. package/dist/server/activity/workspaceActivityRoutes.js +4 -0
  42. package/dist/server/activity/workspaceActivityRoutes.js.map +1 -0
  43. package/dist/server/activity/workspaceActivityService.js +98 -0
  44. package/dist/server/activity/workspaceActivityService.js.map +1 -0
  45. package/dist/server/app.js +162 -0
  46. package/dist/server/app.js.map +1 -0
  47. package/dist/server/configRoutes.js +270 -0
  48. package/dist/server/configRoutes.js.map +1 -0
  49. package/dist/server/diagnostics/nodePtySpawnHelper.js +130 -0
  50. package/dist/server/diagnostics/nodePtySpawnHelper.js.map +1 -0
  51. package/dist/server/git/gitEnv.js +15 -0
  52. package/dist/server/git/gitEnv.js.map +1 -0
  53. package/dist/server/git/gitService.js +119 -0
  54. package/dist/server/git/gitService.js.map +1 -0
  55. package/dist/server/gitRoutes.js +23 -0
  56. package/dist/server/gitRoutes.js.map +1 -0
  57. package/dist/server/index.js +7 -0
  58. package/dist/server/index.js.map +1 -0
  59. package/dist/server/machines/machineClient.js +162 -0
  60. package/dist/server/machines/machineClient.js.map +1 -0
  61. package/dist/server/machines/machinePluginProxyRoutes.js +157 -0
  62. package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -0
  63. package/dist/server/machines/machineProxyRoutes.js +127 -0
  64. package/dist/server/machines/machineProxyRoutes.js.map +1 -0
  65. package/dist/server/machines/machineRoutes.js +54 -0
  66. package/dist/server/machines/machineRoutes.js.map +1 -0
  67. package/dist/server/machines/machineService.js +230 -0
  68. package/dist/server/machines/machineService.js.map +1 -0
  69. package/dist/server/machines/machineStore.js +123 -0
  70. package/dist/server/machines/machineStore.js.map +1 -0
  71. package/dist/server/machines/proxyUtils.js +30 -0
  72. package/dist/server/machines/proxyUtils.js.map +1 -0
  73. package/dist/server/ompWebPluginService.js +279 -0
  74. package/dist/server/ompWebPluginService.js.map +1 -0
  75. package/dist/server/ompWebStatus.js +601 -0
  76. package/dist/server/ompWebStatus.js.map +1 -0
  77. package/dist/server/ompWebStatusCache.js +31 -0
  78. package/dist/server/ompWebStatusCache.js.map +1 -0
  79. package/dist/server/piPackageRoutes.js +82 -0
  80. package/dist/server/piPackageRoutes.js.map +1 -0
  81. package/dist/server/piPackageService.js +65 -0
  82. package/dist/server/piPackageService.js.map +1 -0
  83. package/dist/server/projects/directorySuggestions.js +37 -0
  84. package/dist/server/projects/directorySuggestions.js.map +1 -0
  85. package/dist/server/projects/projectService.js +31 -0
  86. package/dist/server/projects/projectService.js.map +1 -0
  87. package/dist/server/push/PushNotificationService.js +137 -0
  88. package/dist/server/push/PushNotificationService.js.map +1 -0
  89. package/dist/server/push/pushRoutes.js +55 -0
  90. package/dist/server/push/pushRoutes.js.map +1 -0
  91. package/dist/server/realtime/sessionEventHub.js +39 -0
  92. package/dist/server/realtime/sessionEventHub.js.map +1 -0
  93. package/dist/server/sessiond/sessionProxyRoutes.js +61 -0
  94. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -0
  95. package/dist/server/sessiond.js +92 -0
  96. package/dist/server/sessiond.js.map +1 -0
  97. package/dist/server/sessions/attachmentService.js +112 -0
  98. package/dist/server/sessions/attachmentService.js.map +1 -0
  99. package/dist/server/sessions/authProviderOptions.js +52 -0
  100. package/dist/server/sessions/authProviderOptions.js.map +1 -0
  101. package/dist/server/sessions/authRoutes.js +59 -0
  102. package/dist/server/sessions/authRoutes.js.map +1 -0
  103. package/dist/server/sessions/authService.js +105 -0
  104. package/dist/server/sessions/authService.js.map +1 -0
  105. package/dist/server/sessions/builtinCommands.js +29 -0
  106. package/dist/server/sessions/builtinCommands.js.map +1 -0
  107. package/dist/server/sessions/editPreview.js +196 -0
  108. package/dist/server/sessions/editPreview.js.map +1 -0
  109. package/dist/server/sessions/messagePaging.js +41 -0
  110. package/dist/server/sessions/messagePaging.js.map +1 -0
  111. package/dist/server/sessions/oauthLoginFlowService.js +136 -0
  112. package/dist/server/sessions/oauthLoginFlowService.js.map +1 -0
  113. package/dist/server/sessions/piSessionManagerGateway.js +97 -0
  114. package/dist/server/sessions/piSessionManagerGateway.js.map +1 -0
  115. package/dist/server/sessions/piSessionService.js +2401 -0
  116. package/dist/server/sessions/piSessionService.js.map +1 -0
  117. package/dist/server/sessions/schedulePrompt/schedulePromptService.js +46 -0
  118. package/dist/server/sessions/schedulePrompt/schedulePromptService.js.map +1 -0
  119. package/dist/server/sessions/schedulePrompt/scheduler.js +315 -0
  120. package/dist/server/sessions/schedulePrompt/scheduler.js.map +1 -0
  121. package/dist/server/sessions/schedulePrompt/storage.js +118 -0
  122. package/dist/server/sessions/schedulePrompt/storage.js.map +1 -0
  123. package/dist/server/sessions/schedulePrompt/tool.js +252 -0
  124. package/dist/server/sessions/schedulePrompt/tool.js.map +1 -0
  125. package/dist/server/sessions/schedulePrompt/types.js +2 -0
  126. package/dist/server/sessions/schedulePrompt/types.js.map +1 -0
  127. package/dist/server/sessions/sessionArchiveStore.js +254 -0
  128. package/dist/server/sessions/sessionArchiveStore.js.map +1 -0
  129. package/dist/server/sessions/sessionArchiveTree.js +35 -0
  130. package/dist/server/sessions/sessionArchiveTree.js.map +1 -0
  131. package/dist/server/sessions/sessionCleanup.js +157 -0
  132. package/dist/server/sessions/sessionCleanup.js.map +1 -0
  133. package/dist/server/sessions/sessionCommandService.js +260 -0
  134. package/dist/server/sessions/sessionCommandService.js.map +1 -0
  135. package/dist/server/sessions/sessionNameGenerator.js +61 -0
  136. package/dist/server/sessions/sessionNameGenerator.js.map +1 -0
  137. package/dist/server/sessions/sessionRoutes.js +344 -0
  138. package/dist/server/sessions/sessionRoutes.js.map +1 -0
  139. package/dist/server/sessions/sessionRuntimeStore.js +2 -0
  140. package/dist/server/sessions/sessionRuntimeStore.js.map +1 -0
  141. package/dist/server/sessions/spawnSessionTool.js +41 -0
  142. package/dist/server/sessions/spawnSessionTool.js.map +1 -0
  143. package/dist/server/sessions/spawnSubsessionTool.js +203 -0
  144. package/dist/server/sessions/spawnSubsessionTool.js.map +1 -0
  145. package/dist/server/sessions/spawnTargetResolver.js +36 -0
  146. package/dist/server/sessions/spawnTargetResolver.js.map +1 -0
  147. package/dist/server/sessions/subsessionTranscript.js +233 -0
  148. package/dist/server/sessions/subsessionTranscript.js.map +1 -0
  149. package/dist/server/storage/projectStore.js +83 -0
  150. package/dist/server/storage/projectStore.js.map +1 -0
  151. package/dist/server/terminalProxyRoutes.js +140 -0
  152. package/dist/server/terminalProxyRoutes.js.map +1 -0
  153. package/dist/server/terminals/terminalRoutes.js +153 -0
  154. package/dist/server/terminals/terminalRoutes.js.map +1 -0
  155. package/dist/server/terminals/terminalService.js +320 -0
  156. package/dist/server/terminals/terminalService.js.map +1 -0
  157. package/dist/server/terminals/terminalSize.js +17 -0
  158. package/dist/server/terminals/terminalSize.js.map +1 -0
  159. package/dist/server/types.js +2 -0
  160. package/dist/server/types.js.map +1 -0
  161. package/dist/server/utils.js +8 -0
  162. package/dist/server/utils.js.map +1 -0
  163. package/dist/server/webSocketBridge.js +32 -0
  164. package/dist/server/webSocketBridge.js.map +1 -0
  165. package/dist/server/workingDirectory.js +44 -0
  166. package/dist/server/workingDirectory.js.map +1 -0
  167. package/dist/server/workspaceExplorerRoutes.js +109 -0
  168. package/dist/server/workspaceExplorerRoutes.js.map +1 -0
  169. package/dist/server/workspaces/effectivePathAccess.js +27 -0
  170. package/dist/server/workspaces/effectivePathAccess.js.map +1 -0
  171. package/dist/server/workspaces/fileContentService.js +181 -0
  172. package/dist/server/workspaces/fileContentService.js.map +1 -0
  173. package/dist/server/workspaces/fileSuggestions.js +512 -0
  174. package/dist/server/workspaces/fileSuggestions.js.map +1 -0
  175. package/dist/server/workspaces/fileTreeService.js +27 -0
  176. package/dist/server/workspaces/fileTreeService.js.map +1 -0
  177. package/dist/server/workspaces/gitWorktreeDiscovery.js +34 -0
  178. package/dist/server/workspaces/gitWorktreeDiscovery.js.map +1 -0
  179. package/dist/server/workspaces/imagePreviewService.js +40 -0
  180. package/dist/server/workspaces/imagePreviewService.js.map +1 -0
  181. package/dist/server/workspaces/pathAccessPolicy.js +87 -0
  182. package/dist/server/workspaces/pathAccessPolicy.js.map +1 -0
  183. package/dist/server/workspaces/pathSafety.js +54 -0
  184. package/dist/server/workspaces/pathSafety.js.map +1 -0
  185. package/dist/server/workspaces/projectOmpWebConfig.js +56 -0
  186. package/dist/server/workspaces/projectOmpWebConfig.js.map +1 -0
  187. package/dist/server/workspaces/workspaceContext.js +8 -0
  188. package/dist/server/workspaces/workspaceContext.js.map +1 -0
  189. package/dist/server/workspaces/workspaceDeletionRoutes.js +111 -0
  190. package/dist/server/workspaces/workspaceDeletionRoutes.js.map +1 -0
  191. package/dist/server/workspaces/workspaceService.js +39 -0
  192. package/dist/server/workspaces/workspaceService.js.map +1 -0
  193. package/dist/sessiond/config.js +9 -0
  194. package/dist/sessiond/config.js.map +1 -0
  195. package/dist/sessiond/sessionDaemonClient.js +65 -0
  196. package/dist/sessiond/sessionDaemonClient.js.map +1 -0
  197. package/dist/shared/activity.js +26 -0
  198. package/dist/shared/activity.js.map +1 -0
  199. package/dist/shared/apiTypes.d.ts +688 -0
  200. package/dist/shared/apiTypes.js +11 -0
  201. package/dist/shared/apiTypes.js.map +1 -0
  202. package/dist/shared/capabilities.js +52 -0
  203. package/dist/shared/capabilities.js.map +1 -0
  204. package/dist/shared/federatedRoutes.js +79 -0
  205. package/dist/shared/federatedRoutes.js.map +1 -0
  206. package/dist/shared/machinePluginIds.js +41 -0
  207. package/dist/shared/machinePluginIds.js.map +1 -0
  208. package/dist/shared/ompWebStatusParsing.js +100 -0
  209. package/dist/shared/ompWebStatusParsing.js.map +1 -0
  210. package/dist/shared/pluginIds.js +5 -0
  211. package/dist/shared/pluginIds.js.map +1 -0
  212. package/dist/shared/promptAttachments.js +90 -0
  213. package/dist/shared/promptAttachments.js.map +1 -0
  214. package/dist/shared/thinkingLevels.d.ts +19 -0
  215. package/dist/shared/thinkingLevels.js +24 -0
  216. package/dist/shared/thinkingLevels.js.map +1 -0
  217. package/dist/shared/utils.js +4 -0
  218. package/dist/shared/utils.js.map +1 -0
  219. package/dist/shared/workspaceDeletion.js +12 -0
  220. package/dist/shared/workspaceDeletion.js.map +1 -0
  221. package/dist/shared/workspaceFiles.js +3 -0
  222. package/dist/shared/workspaceFiles.js.map +1 -0
  223. package/docs/assets/favicon.svg +11 -0
  224. package/docs/assets/omp-web-banner.png +0 -0
  225. package/docs/assets/omp-web-desktop.png +0 -0
  226. package/docs/assets/omp-web-mobile.png +0 -0
  227. package/docs/assets/omp-web-tablet.png +0 -0
  228. package/docs/config.md +208 -0
  229. package/docs/plugins.md +916 -0
  230. package/extensions/omp-web.ts +133 -0
  231. package/install.sh +5 -0
  232. package/package.json +141 -0
  233. package/plugin-api/unstable.d.ts +1 -0
  234. package/plugin-api.d.ts +1 -0
@@ -0,0 +1,119 @@
1
+ import { createHash } from "node:crypto";
2
+ import { spawn } from "node:child_process";
3
+ import { normalizeRelativePath } from "../workspaces/pathSafety.js";
4
+ import { sanitizedGitEnv } from "./gitEnv.js";
5
+ const MAX_OUTPUT = 2 * 1024 * 1024;
6
+ export async function gitStatus(cwd) {
7
+ const result = await runGit(cwd, ["status", "--porcelain=v2", "--branch", "--untracked-files=all", "-z"]);
8
+ if (result.code !== 0)
9
+ return { isGitRepo: false, hash: hash(result.stdout + result.stderr), files: [] };
10
+ return parseStatus(result.stdout);
11
+ }
12
+ export async function gitDiff(cwd, options) {
13
+ const staged = options.staged === true;
14
+ let path;
15
+ if (options.path !== undefined && options.path !== "")
16
+ path = normalizeRelativePath(options.path);
17
+ const args = ["diff", "--no-ext-diff", "--color=never"];
18
+ if (staged)
19
+ args.push("--cached");
20
+ if (path !== undefined)
21
+ args.push("--", path);
22
+ const result = await runGit(cwd, args);
23
+ if (result.code !== 0)
24
+ throw new Error(result.stderr.trim() || "git diff failed");
25
+ if (!staged && path !== undefined && result.stdout === "" && await isUntracked(cwd, path)) {
26
+ const untracked = await runGit(cwd, ["diff", "--no-ext-diff", "--color=never", "--no-index", "/dev/null", "--", path]);
27
+ if (untracked.code !== 0 && untracked.code !== 1)
28
+ throw new Error(untracked.stderr.trim() || "git diff failed");
29
+ return { path, staged, hash: hash(untracked.stdout), diff: untracked.stdout, truncated: untracked.truncated };
30
+ }
31
+ return { ...(path === undefined ? {} : { path }), staged, hash: hash(result.stdout), diff: result.stdout, truncated: result.truncated };
32
+ }
33
+ async function isUntracked(cwd, path) {
34
+ const result = await runGit(cwd, ["ls-files", "--others", "--exclude-standard", "-z", "--", path]);
35
+ return result.code === 0 && result.stdout.split("\0").includes(path);
36
+ }
37
+ function parseStatus(raw) {
38
+ const records = raw.split("\0").filter((record) => record !== "");
39
+ const files = [];
40
+ let branch;
41
+ let upstream;
42
+ let ahead;
43
+ let behind;
44
+ for (let i = 0; i < records.length; i += 1) {
45
+ const record = records[i];
46
+ if (record === undefined)
47
+ continue;
48
+ if (record.startsWith("# branch.head "))
49
+ branch = normalizeBranch(record.slice("# branch.head ".length));
50
+ else if (record.startsWith("# branch.upstream "))
51
+ upstream = record.slice("# branch.upstream ".length);
52
+ else if (record.startsWith("# branch.ab ")) {
53
+ const match = /\+(\d+) -(\d+)/.exec(record);
54
+ if (match) {
55
+ ahead = Number(match[1]);
56
+ behind = Number(match[2]);
57
+ }
58
+ }
59
+ else if (record.startsWith("? "))
60
+ files.push({ path: record.slice(2), index: "untracked", workingTree: "untracked" });
61
+ else if (record.startsWith("! "))
62
+ files.push({ path: record.slice(2), index: "ignored", workingTree: "ignored" });
63
+ else if (record.startsWith("1 ")) {
64
+ const parts = record.split(" ");
65
+ files.push({ path: parts.slice(8).join(" "), index: stateFor(parts[1]?.[0]), workingTree: stateFor(parts[1]?.[1]) });
66
+ }
67
+ else if (record.startsWith("2 ")) {
68
+ const parts = record.split(" ");
69
+ const path = parts.slice(9).join(" ");
70
+ const oldPath = records[i + 1];
71
+ i += 1;
72
+ files.push({ path, ...(oldPath === undefined ? {} : { oldPath }), index: stateFor(parts[1]?.[0]), workingTree: stateFor(parts[1]?.[1]) });
73
+ }
74
+ else if (record.startsWith("u ")) {
75
+ const parts = record.split(" ");
76
+ files.push({ path: parts.slice(10).join(" "), index: "conflicted", workingTree: "conflicted" });
77
+ }
78
+ }
79
+ return { isGitRepo: true, hash: hash(raw), ...(branch === undefined ? {} : { branch }), ...(upstream === undefined ? {} : { upstream }), ...(ahead === undefined ? {} : { ahead }), ...(behind === undefined ? {} : { behind }), files };
80
+ }
81
+ function stateFor(code) {
82
+ if (code === undefined)
83
+ return "unmodified";
84
+ switch (code) {
85
+ case ".": return "unmodified";
86
+ case "M": return "modified";
87
+ case "A": return "added";
88
+ case "D": return "deleted";
89
+ case "R": return "renamed";
90
+ case "C": return "copied";
91
+ case "U": return "conflicted";
92
+ default: return "unmodified";
93
+ }
94
+ }
95
+ function normalizeBranch(value) {
96
+ return value === "(detached)" ? undefined : value;
97
+ }
98
+ function hash(value) {
99
+ return createHash("sha1").update(value).digest("hex");
100
+ }
101
+ async function runGit(cwd, args) {
102
+ return new Promise((resolve, reject) => {
103
+ const child = spawn("git", args, { cwd, env: sanitizedGitEnv(), stdio: ["ignore", "pipe", "pipe"] });
104
+ const timer = setTimeout(() => { child.kill("SIGKILL"); }, 10000);
105
+ let stdout = Buffer.alloc(0);
106
+ let stderr = Buffer.alloc(0);
107
+ let truncated = false;
108
+ child.stdout.on("data", (chunk) => {
109
+ if (stdout.length + chunk.length > MAX_OUTPUT)
110
+ truncated = true;
111
+ if (stdout.length < MAX_OUTPUT)
112
+ stdout = Buffer.concat([stdout, chunk]).subarray(0, MAX_OUTPUT);
113
+ });
114
+ child.stderr.on("data", (chunk) => { stderr = Buffer.concat([stderr, chunk]).subarray(0, 64 * 1024); });
115
+ child.on("error", (error) => { clearTimeout(timer); reject(error); });
116
+ child.on("close", (code) => { clearTimeout(timer); resolve({ code: code ?? 1, stdout: stdout.toString("utf8"), stderr: stderr.toString("utf8"), truncated }); });
117
+ });
118
+ }
119
+ //# sourceMappingURL=gitService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitService.js","sourceRoot":"","sources":["../../../src/server/git/gitService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { resolveWorkspaceContext } from "./workspaces/workspaceContext.js";
2
+ import { gitDiff, gitStatus } from "./git/gitService.js";
3
+ export function registerGitRoutes(app, projects, workspaces, prefix = "/api") {
4
+ app.get(`${prefix}/projects/:projectId/workspaces/:workspaceId/git/status`, async (request, reply) => {
5
+ try {
6
+ const context = await resolveWorkspaceContext(projects, workspaces, request.params.projectId, request.params.workspaceId);
7
+ return await gitStatus(context.root);
8
+ }
9
+ catch (error) {
10
+ return reply.code(400).send({ error: error instanceof Error ? error.message : String(error) });
11
+ }
12
+ });
13
+ app.get(`${prefix}/projects/:projectId/workspaces/:workspaceId/git/diff`, async (request, reply) => {
14
+ try {
15
+ const context = await resolveWorkspaceContext(projects, workspaces, request.params.projectId, request.params.workspaceId);
16
+ return await gitDiff(context.root, { ...(request.query.path === undefined ? {} : { path: request.query.path }), staged: request.query.staged === "true" });
17
+ }
18
+ catch (error) {
19
+ return reply.code(400).send({ error: error instanceof Error ? error.message : String(error) });
20
+ }
21
+ });
22
+ }
23
+ //# sourceMappingURL=gitRoutes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitRoutes.js","sourceRoot":"","sources":["../../src/server/gitRoutes.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,UAAU,iBAAiB,CAAC,GAAoB,EAAE,QAAwB,EAAE,UAA4B,EAAE,MAAM,GAAG,MAAM;IAC7H,GAAG,CAAC,GAAG,CAAyD,GAAG,MAAM,yDAAyD,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC3J,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAC1H,OAAO,MAAM,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjG,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAA0G,GAAG,MAAM,uDAAuD,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC1M,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAC1H,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC;QAC7J,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjG,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { effectiveOmpWebConfig, maxUploadBytes } from "../config.js";
3
+ import { buildApp } from "./app.js";
4
+ const { config } = effectiveOmpWebConfig();
5
+ const app = await buildApp({ bodyLimit: maxUploadBytes(process.env, config) });
6
+ await app.listen({ port: config.port ?? 8504, host: config.host ?? "127.0.0.1" });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,MAAM,EAAE,MAAM,EAAE,GAAG,qBAAqB,EAAE,CAAC;AAC3C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,EAAE,SAAS,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAC/E,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC,CAAC"}
@@ -0,0 +1,162 @@
1
+ import { Readable } from "node:stream";
2
+ import { WebSocket } from "ws";
3
+ export const DEFAULT_REMOTE_REQUEST_TIMEOUT_MS = 30_000;
4
+ export const DEFAULT_REMOTE_HEALTH_TIMEOUT_MS = 3_000;
5
+ const BLOCKED_CONFIGURED_HEADER_NAMES = new Set([
6
+ "host",
7
+ "connection",
8
+ "upgrade",
9
+ "transfer-encoding",
10
+ "content-length",
11
+ "keep-alive",
12
+ "proxy-authenticate",
13
+ "proxy-authorization",
14
+ "te",
15
+ "trailer",
16
+ "authorization",
17
+ "cookie",
18
+ ]);
19
+ export class RemoteMachineRequestError extends Error {
20
+ constructor(message, statusCode) {
21
+ super(message);
22
+ this.statusCode = statusCode;
23
+ this.name = "RemoteMachineRequestError";
24
+ }
25
+ }
26
+ export class RemoteMachineClient {
27
+ constructor(machine, fetchImpl = fetch) {
28
+ this.machine = machine;
29
+ this.fetchImpl = fetchImpl;
30
+ }
31
+ async request(method, path, body, options = {}) {
32
+ const response = await this.fetchResponse(method, path, body, options);
33
+ return {
34
+ statusCode: response.status,
35
+ headers: headersToRecord(response.headers),
36
+ ...(response.body === null ? {} : { body: readableFromWebResponseBody(response.body) }),
37
+ };
38
+ }
39
+ async requestJson(method, path, body, options = {}) {
40
+ const response = await this.fetchResponse(method, path, body, options);
41
+ const text = await response.text();
42
+ const parsed = text === "" ? undefined : JSON.parse(text);
43
+ return {
44
+ statusCode: response.status,
45
+ headers: headersToRecord(response.headers),
46
+ body: parsed,
47
+ };
48
+ }
49
+ connectWebSocket(path) {
50
+ const url = this.remoteUrl(path);
51
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
52
+ return new WebSocket(url, { headers: this.remoteHeaders() });
53
+ }
54
+ async fetchResponse(method, path, body, options) {
55
+ const controller = new AbortController();
56
+ const timeout = setTimeout(() => { controller.abort(); }, options.timeoutMs ?? DEFAULT_REMOTE_REQUEST_TIMEOUT_MS);
57
+ try {
58
+ const requestBody = serializeRequestBody(method, body);
59
+ const init = {
60
+ method,
61
+ headers: this.requestHeaders(body, options),
62
+ signal: controller.signal,
63
+ redirect: "manual",
64
+ };
65
+ if (requestBody !== undefined)
66
+ init.body = requestBody;
67
+ return await this.fetchImpl(this.remoteUrl(path), init);
68
+ }
69
+ catch (error) {
70
+ if (isAbortError(error))
71
+ throw new RemoteMachineRequestError("Remote machine request timed out", 504);
72
+ throw new RemoteMachineRequestError(error instanceof Error ? error.message : String(error), 502);
73
+ }
74
+ finally {
75
+ clearTimeout(timeout);
76
+ }
77
+ }
78
+ requestHeaders(body, options) {
79
+ return {
80
+ ...this.remoteHeaders(),
81
+ accept: "*/*",
82
+ ...(body === undefined ? {} : { "content-type": options.contentType ?? defaultContentTypeForBody(body) }),
83
+ };
84
+ }
85
+ remoteHeaders() {
86
+ return {
87
+ ...(this.machine.token === undefined || this.machine.token === "" ? {} : { authorization: `Bearer ${this.machine.token}` }),
88
+ ...filterConfiguredHeaders(this.machine.headers),
89
+ };
90
+ }
91
+ remoteUrl(path) {
92
+ const url = new URL(this.machine.baseUrl);
93
+ const separator = path.indexOf("?");
94
+ const rawPath = separator === -1 ? path : path.slice(0, separator);
95
+ const rawQuery = separator === -1 ? "" : path.slice(separator + 1);
96
+ const basePath = url.pathname.replace(/\/$/u, "");
97
+ const nextPath = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
98
+ url.pathname = `${basePath}${nextPath}`;
99
+ url.search = rawQuery === "" ? "" : `?${rawQuery}`;
100
+ url.hash = "";
101
+ return url;
102
+ }
103
+ }
104
+ export function validateConfiguredMachineHeaders(headers) {
105
+ if (headers === undefined)
106
+ return undefined;
107
+ return Object.fromEntries(Object.entries(headers).map(([key, value]) => {
108
+ const name = key.trim();
109
+ if (name === "")
110
+ throw new Error("Machine header names must not be empty");
111
+ if (typeof value !== "string")
112
+ throw new Error("Machine headers must be strings");
113
+ if (BLOCKED_CONFIGURED_HEADER_NAMES.has(name.toLowerCase()))
114
+ throw new Error(`Machine header is not allowed: ${name}`);
115
+ return [name, value];
116
+ }));
117
+ }
118
+ function filterConfiguredHeaders(headers) {
119
+ if (headers === undefined)
120
+ return {};
121
+ return Object.fromEntries(Object.entries(headers).filter(([key]) => !BLOCKED_CONFIGURED_HEADER_NAMES.has(key.toLowerCase())));
122
+ }
123
+ function headersToRecord(headers) {
124
+ return Object.fromEntries(headers.entries());
125
+ }
126
+ function serializeRequestBody(method, body) {
127
+ if (body === undefined || method === "GET" || method === "HEAD")
128
+ return undefined;
129
+ if (isRawRequestBody(body))
130
+ return body;
131
+ if (ArrayBuffer.isView(body))
132
+ return copyArrayBufferView(body);
133
+ const serialized = JSON.stringify(body);
134
+ return serialized;
135
+ }
136
+ function defaultContentTypeForBody(body) {
137
+ return isRawRequestBody(body) || ArrayBuffer.isView(body) ? "application/octet-stream" : "application/json";
138
+ }
139
+ function isRawRequestBody(body) {
140
+ return typeof body === "string"
141
+ || body instanceof URLSearchParams
142
+ || body instanceof Blob
143
+ || body instanceof FormData
144
+ || body instanceof ReadableStream
145
+ || body instanceof ArrayBuffer;
146
+ }
147
+ function copyArrayBufferView(view) {
148
+ const bytes = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
149
+ const copy = new Uint8Array(bytes.byteLength);
150
+ copy.set(bytes);
151
+ return copy.buffer;
152
+ }
153
+ function readableFromWebResponseBody(body) {
154
+ if (body === null)
155
+ throw new Error("Response body is not readable");
156
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Node fetch returns a web stream that is runtime-compatible with Readable.fromWeb, but DOM and node:stream/web types are not structurally identical in this TS config.
157
+ return Readable.fromWeb(body);
158
+ }
159
+ function isAbortError(error) {
160
+ return error instanceof DOMException && error.name === "AbortError";
161
+ }
162
+ //# sourceMappingURL=machineClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machineClient.js","sourceRoot":"","sources":["../../../src/server/machines/machineClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ import { machineScopedPluginId, parseMachineScopedPluginId } from "../../shared/machinePluginIds.js";
2
+ import { isOmpWebPluginId } from "../../shared/pluginIds.js";
3
+ import { MachineService } from "./machineService.js";
4
+ import { applySafeHeaders, sendGatewayError } from "./proxyUtils.js";
5
+ import { isRecord } from "../utils.js";
6
+ const MACHINE_PLUGIN_MANIFEST_TIMEOUT_MS = 10_000;
7
+ export function registerMachinePluginProxyRoutes(app, machines = new MachineService()) {
8
+ app.get("/api/machines/:machineId/omp-web-plugins/manifest.json", async (request, reply) => {
9
+ if (request.params.machineId === "local")
10
+ return { plugins: [] };
11
+ const client = await machines.remoteClient(request.params.machineId);
12
+ if (client === undefined)
13
+ return reply.code(404).send({ error: "Machine not found" });
14
+ try {
15
+ const response = await client.requestJson("GET", "/omp-web-plugins/manifest.json", undefined, { timeoutMs: MACHINE_PLUGIN_MANIFEST_TIMEOUT_MS });
16
+ if (response.statusCode === 404)
17
+ return { plugins: [] };
18
+ if (response.statusCode < 200 || response.statusCode >= 300)
19
+ return await reply.code(response.statusCode).send(response.body);
20
+ return rewriteRemotePluginManifest(request.params.machineId, parseRemoteManifest(response.body));
21
+ }
22
+ catch (error) {
23
+ return sendGatewayError(reply, request.params.machineId, error);
24
+ }
25
+ });
26
+ }
27
+ export async function proxyMachinePluginAsset(machines, scopedPluginId, assetPath, requestUrl, reply) {
28
+ const remotePlugin = parseMachineScopedPluginId(scopedPluginId);
29
+ if (remotePlugin === undefined)
30
+ return false;
31
+ const client = await machines.remoteClient(remotePlugin.machineId);
32
+ if (client === undefined) {
33
+ await reply.code(404).send({ error: "Machine not found" });
34
+ return true;
35
+ }
36
+ const requestPath = remotePluginAssetRequestPath(remotePlugin, assetPath, requestUrl);
37
+ if (requestPath === undefined) {
38
+ await reply.code(400).send({ error: "Invalid remote PI WEB plugin asset path" });
39
+ return true;
40
+ }
41
+ try {
42
+ const upstream = await client.request("GET", requestPath);
43
+ reply.code(upstream.statusCode);
44
+ applySafeHeaders(reply, upstream.headers);
45
+ if (upstream.body === undefined)
46
+ await reply.send();
47
+ else
48
+ await reply.send(upstream.body);
49
+ return true;
50
+ }
51
+ catch (error) {
52
+ sendGatewayError(reply, remotePlugin.machineId, error);
53
+ return true;
54
+ }
55
+ }
56
+ function rewriteRemotePluginManifest(machineId, manifest) {
57
+ return {
58
+ plugins: manifest.plugins.flatMap((plugin) => {
59
+ const modulePath = remotePluginModulePath(plugin.id, plugin.module);
60
+ if (modulePath === undefined)
61
+ return [];
62
+ return [{
63
+ ...plugin,
64
+ module: `/omp-web-plugins/${encodeURIComponent(machineScopedPluginId(machineId, plugin.id))}/${modulePath.path}${modulePath.query}`,
65
+ }];
66
+ }),
67
+ };
68
+ }
69
+ function remotePluginModulePath(pluginId, module) {
70
+ if (!isOmpWebPluginId(pluginId))
71
+ return undefined;
72
+ const prefix = `/omp-web-plugins/${encodeURIComponent(pluginId)}/`;
73
+ const base = new URL(prefix, "http://omp-web.local");
74
+ try {
75
+ const url = new URL(module, base);
76
+ if (url.origin !== base.origin || !url.pathname.startsWith(prefix))
77
+ return undefined;
78
+ const path = safeRemotePluginAssetPath(url.pathname.slice(prefix.length));
79
+ return path === undefined ? undefined : { path, query: url.search };
80
+ }
81
+ catch {
82
+ return undefined;
83
+ }
84
+ }
85
+ function remotePluginAssetRequestPath(remotePlugin, assetPath, requestUrl) {
86
+ const path = safeRemotePluginAssetPath(assetPath);
87
+ if (path === undefined)
88
+ return undefined;
89
+ const query = requestUrl.includes("?") ? requestUrl.slice(requestUrl.indexOf("?")) : "";
90
+ return `/omp-web-plugins/${encodeURIComponent(remotePlugin.pluginId)}/${path}${query}`;
91
+ }
92
+ function safeRemotePluginAssetPath(path) {
93
+ const segments = [];
94
+ for (const rawSegment of path.split("/")) {
95
+ const segment = safeRemotePluginAssetPathSegment(rawSegment);
96
+ if (segment === undefined)
97
+ return undefined;
98
+ if (segment === "")
99
+ continue;
100
+ segments.push(segment);
101
+ }
102
+ if (segments.length === 0)
103
+ return undefined;
104
+ return segments.map((segment) => encodeURIComponent(segment)).join("/");
105
+ }
106
+ function safeRemotePluginAssetPathSegment(rawSegment) {
107
+ if (rawSegment === "" || rawSegment === ".")
108
+ return "";
109
+ if (/%(?:2f|5c)/iu.test(rawSegment))
110
+ return undefined;
111
+ let segment;
112
+ try {
113
+ segment = decodeURIComponent(rawSegment);
114
+ }
115
+ catch {
116
+ return undefined;
117
+ }
118
+ if (segment === "" || segment === ".")
119
+ return "";
120
+ if (segment === ".." || segment.includes("/") || segment.includes("\\") || hasControlCharacter(segment))
121
+ return undefined;
122
+ return segment;
123
+ }
124
+ function hasControlCharacter(value) {
125
+ for (let index = 0; index < value.length; index += 1) {
126
+ const code = value.charCodeAt(index);
127
+ if (code <= 0x1f || code === 0x7f)
128
+ return true;
129
+ }
130
+ return false;
131
+ }
132
+ function parseRemoteManifest(value) {
133
+ if (!isRecord(value) || !Array.isArray(value["plugins"]))
134
+ throw new Error("Invalid remote PI WEB plugin manifest");
135
+ return {
136
+ plugins: value["plugins"].map((entry) => {
137
+ if (!isRecord(entry) || typeof entry["id"] !== "string" || !isOmpWebPluginId(entry["id"]) || typeof entry["module"] !== "string" || entry["module"] === "") {
138
+ throw new Error("Invalid remote PI WEB plugin manifest entry");
139
+ }
140
+ return {
141
+ id: entry["id"],
142
+ module: entry["module"],
143
+ ...(typeof entry["source"] === "string" ? { source: entry["source"] } : {}),
144
+ ...(typeof entry["scope"] === "string" ? { scope: entry["scope"] } : {}),
145
+ ...(parseRemoteMachineSpecific(entry["machineSpecific"])),
146
+ };
147
+ }),
148
+ };
149
+ }
150
+ function parseRemoteMachineSpecific(value) {
151
+ if (value === undefined)
152
+ return {};
153
+ if (typeof value !== "boolean")
154
+ throw new Error("Invalid remote PI WEB plugin manifest entry");
155
+ return { machineSpecific: value };
156
+ }
157
+ //# sourceMappingURL=machinePluginProxyRoutes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machinePluginProxyRoutes.js","sourceRoot":"","sources":["../../../src/server/machines/machinePluginProxyRoutes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ import { FEDERATED_HTTP_ROUTES, FEDERATED_WEBSOCKET_ROUTES } from "../../shared/federatedRoutes.js";
2
+ import { mergeSelectedMachineConfig, parseOmpWebConfigResponseBody, parseSelectedMachineConfigRequest, selectedMachineConfigResponse } from "../configRoutes.js";
3
+ import { bridgeSockets } from "../webSocketBridge.js";
4
+ import { MachineService } from "./machineService.js";
5
+ import { applySafeHeaders, sendGatewayError } from "./proxyUtils.js";
6
+ import { errorMessage, isRecord } from "../utils.js";
7
+ export const REMOTE_HTTP_ROUTES = FEDERATED_HTTP_ROUTES;
8
+ export const REMOTE_WEBSOCKET_ROUTES = FEDERATED_WEBSOCKET_ROUTES;
9
+ export function registerMachineProxyRoutes(app, machines = new MachineService()) {
10
+ for (const spec of REMOTE_HTTP_ROUTES) {
11
+ app.route({
12
+ method: spec.method,
13
+ url: `/api/machines/:machineId${spec.path}`,
14
+ handler: (request, reply) => proxyHttpRequest(machines, spec, request.params.machineId, request.method, request.url, request.body, request.headers["content-type"], reply),
15
+ });
16
+ }
17
+ for (const path of REMOTE_WEBSOCKET_ROUTES) {
18
+ app.get(`/api/machines/:machineId${path}`, { websocket: true }, async (socket, request) => {
19
+ await proxyWebSocket(machines, request.params.machineId, request.url, socket);
20
+ });
21
+ }
22
+ }
23
+ async function proxyHttpRequest(machines, spec, machineId, method, requestUrl, body, contentType, reply) {
24
+ if (machineId === "local") {
25
+ return reply.code(501).send({ error: "Local machine route is not registered for this endpoint" });
26
+ }
27
+ const client = await machines.remoteClient(machineId);
28
+ if (client === undefined) {
29
+ return reply.code(404).send({ error: "Machine not found" });
30
+ }
31
+ try {
32
+ const remotePath = remoteApiPath(machineId, requestUrl);
33
+ if (spec.path === "/config")
34
+ return await proxySelectedMachineConfigRequest(client, machineId, method, remotePath, body, reply);
35
+ const requestOptions = proxyRequestOptions(spec, body, contentType);
36
+ const upstream = requestOptions === undefined
37
+ ? await client.request(method, remotePath, body)
38
+ : await client.request(method, remotePath, body, requestOptions);
39
+ reply.code(upstream.statusCode);
40
+ applySafeHeaders(reply, upstream.headers);
41
+ if (upstream.body === undefined)
42
+ return await reply.send();
43
+ return await reply.send(upstream.body);
44
+ }
45
+ catch (error) {
46
+ if (isSelectedMachineConfigRequestError(error))
47
+ return reply.code(400).send({ error: errorMessage(error) });
48
+ return sendGatewayError(reply, machineId, error);
49
+ }
50
+ }
51
+ async function proxySelectedMachineConfigRequest(client, machineId, method, remotePath, body, reply) {
52
+ if (method === "GET") {
53
+ return sendSelectedMachineConfigResponse(reply, await client.requestJson("GET", remotePath), machineId);
54
+ }
55
+ if (method === "PUT") {
56
+ const patch = parseSelectedMachineConfigRequest(configPayload(body));
57
+ const currentResponse = await client.requestJson("GET", remotePath);
58
+ if (!isSuccessfulStatus(currentResponse.statusCode))
59
+ return sendUpstreamJsonResponse(reply, currentResponse, machineId);
60
+ const current = parseOmpWebConfigResponseBody(currentResponse.body, "Remote machine config response");
61
+ const merged = mergeSelectedMachineConfig(current.config, patch);
62
+ return sendSelectedMachineConfigResponse(reply, await client.requestJson("PUT", remotePath, { config: merged }), machineId);
63
+ }
64
+ return reply.code(405).send({ error: "Method not allowed" });
65
+ }
66
+ function configPayload(body) {
67
+ return isRecord(body) ? body["config"] : undefined;
68
+ }
69
+ function sendSelectedMachineConfigResponse(reply, upstream, machineId) {
70
+ if (!isSuccessfulStatus(upstream.statusCode))
71
+ return sendUpstreamJsonResponse(reply, upstream, machineId);
72
+ reply.code(upstream.statusCode);
73
+ applySafeHeaders(reply, upstream.headers);
74
+ return reply.send(selectedMachineConfigResponse(parseOmpWebConfigResponseBody(upstream.body, "Remote machine config response")));
75
+ }
76
+ function sendUpstreamJsonResponse(reply, upstream, machineId) {
77
+ reply.code(upstream.statusCode);
78
+ applySafeHeaders(reply, upstream.headers);
79
+ return reply.send(upstream.body ?? { error: "Remote machine config request failed", machineId, statusCode: upstream.statusCode });
80
+ }
81
+ function isSuccessfulStatus(statusCode) {
82
+ return statusCode >= 200 && statusCode < 300;
83
+ }
84
+ async function proxyWebSocket(machines, machineId, requestUrl, socket) {
85
+ if (machineId === "local") {
86
+ socket.close(1011, "Local machine route is not registered for this endpoint");
87
+ return;
88
+ }
89
+ const client = await machines.remoteClient(machineId);
90
+ if (client === undefined) {
91
+ socket.close(1008, "Machine not found");
92
+ return;
93
+ }
94
+ try {
95
+ bridgeSockets(socket, client.connectWebSocket(remoteApiPath(machineId, requestUrl)));
96
+ }
97
+ catch {
98
+ socket.close(1011, "Remote machine unavailable");
99
+ }
100
+ }
101
+ function remoteApiPath(machineId, requestUrl) {
102
+ const machinePrefix = `/api/machines/${encodeURIComponent(machineId)}`;
103
+ const stripped = requestUrl.startsWith(machinePrefix) ? requestUrl.slice(machinePrefix.length) : requestUrl;
104
+ const compatPath = stripped.startsWith("/") ? stripped : `/${stripped}`;
105
+ return `/api${compatPath}`;
106
+ }
107
+ function proxyRequestOptions(spec, body, contentType) {
108
+ const options = {};
109
+ if (spec.timeoutMs !== undefined)
110
+ options.timeoutMs = spec.timeoutMs;
111
+ if (isRawProxyBody(body)) {
112
+ const value = firstHeaderValue(contentType);
113
+ if (value !== undefined && value !== "")
114
+ options.contentType = value;
115
+ }
116
+ return Object.keys(options).length === 0 ? undefined : options;
117
+ }
118
+ function isRawProxyBody(body) {
119
+ return typeof body === "string" || body instanceof ArrayBuffer || ArrayBuffer.isView(body);
120
+ }
121
+ function firstHeaderValue(value) {
122
+ return Array.isArray(value) ? value[0] : value;
123
+ }
124
+ function isSelectedMachineConfigRequestError(error) {
125
+ return error instanceof Error && error.message.startsWith("PI WEB selected-machine config");
126
+ }
127
+ //# sourceMappingURL=machineProxyRoutes.js.map