@osdk/integration-testing 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/bin/postinstall.mjs +15 -0
  3. package/build/browser/cli-service/CliServiceLauncher.js +220 -0
  4. package/build/browser/cli-service/CliServiceLauncher.js.map +1 -0
  5. package/build/browser/cli-service/FoundryCliService.js +168 -0
  6. package/build/browser/cli-service/FoundryCliService.js.map +1 -0
  7. package/build/browser/cli-service/OntologyServer.js +32 -0
  8. package/build/browser/cli-service/OntologyServer.js.map +1 -0
  9. package/build/browser/cli-service/ServiceDiscoverer.js +100 -0
  10. package/build/browser/cli-service/ServiceDiscoverer.js.map +1 -0
  11. package/build/browser/cli-service/StatusServer.js +91 -0
  12. package/build/browser/cli-service/StatusServer.js.map +1 -0
  13. package/build/browser/createIntegrationClient.js +67 -0
  14. package/build/browser/createIntegrationClient.js.map +1 -0
  15. package/build/browser/createIntegrationServer.js +115 -0
  16. package/build/browser/createIntegrationServer.js.map +1 -0
  17. package/build/browser/createSeedClient.js +77 -0
  18. package/build/browser/createSeedClient.js.map +1 -0
  19. package/build/browser/generated/cli/OntologySeedingService/setSeed.js +28 -0
  20. package/build/browser/generated/cli/OntologySeedingService/setSeed.js.map +1 -0
  21. package/build/browser/generated/cli/OntologySeedingService.js +19 -0
  22. package/build/browser/generated/cli/OntologySeedingService.js.map +1 -0
  23. package/build/browser/generated/cli/StatusService/getStatus.js +25 -0
  24. package/build/browser/generated/cli/StatusService/getStatus.js.map +1 -0
  25. package/build/browser/generated/cli/StatusService/publishStatus.js +26 -0
  26. package/build/browser/generated/cli/StatusService/publishStatus.js.map +1 -0
  27. package/build/browser/generated/cli/StatusService.js +20 -0
  28. package/build/browser/generated/cli/StatusService.js.map +1 -0
  29. package/build/browser/generated/cli/__components.js +2 -0
  30. package/build/browser/generated/cli/__components.js.map +1 -0
  31. package/build/browser/generated/cli/index.js +20 -0
  32. package/build/browser/generated/cli/index.js.map +1 -0
  33. package/build/browser/index.js +27 -0
  34. package/build/browser/index.js.map +1 -0
  35. package/build/browser/scripts/download.js +92 -0
  36. package/build/browser/scripts/download.js.map +1 -0
  37. package/build/browser/scripts/foundry-host.js +59 -0
  38. package/build/browser/scripts/foundry-host.js.map +1 -0
  39. package/build/browser/scripts/foundry-token.js +50 -0
  40. package/build/browser/scripts/foundry-token.js.map +1 -0
  41. package/build/browser/scripts/gitRemote.js +39 -0
  42. package/build/browser/scripts/gitRemote.js.map +1 -0
  43. package/build/browser/scripts/postinstall.js +38 -0
  44. package/build/browser/scripts/postinstall.js.map +1 -0
  45. package/build/browser/test/NoSpawnStatusServer.js +33 -0
  46. package/build/browser/test/NoSpawnStatusServer.js.map +1 -0
  47. package/build/browser/test/StubService.js +61 -0
  48. package/build/browser/test/StubService.js.map +1 -0
  49. package/build/browser/test/emptyOntologyMetadata.js +32 -0
  50. package/build/browser/test/emptyOntologyMetadata.js.map +1 -0
  51. package/build/browser/test/stubStatusServer.js +74 -0
  52. package/build/browser/test/stubStatusServer.js.map +1 -0
  53. package/build/browser/test/writeDiscoveryFile.js +39 -0
  54. package/build/browser/test/writeDiscoveryFile.js.map +1 -0
  55. package/build/browser/types.js +2 -0
  56. package/build/browser/types.js.map +1 -0
  57. package/build/browser/utils/empty-ontology-block.js +61 -0
  58. package/build/browser/utils/empty-ontology-block.js.map +1 -0
  59. package/build/browser/utils/foundry-cli.js +46 -0
  60. package/build/browser/utils/foundry-cli.js.map +1 -0
  61. package/build/browser/utils/process.js +26 -0
  62. package/build/browser/utils/process.js.map +1 -0
  63. package/build/browser/utils/service.js +33 -0
  64. package/build/browser/utils/service.js.map +1 -0
  65. package/build/cjs/index.cjs +841 -0
  66. package/build/cjs/index.cjs.map +1 -0
  67. package/build/cjs/index.d.cts +118 -0
  68. package/build/esm/cli-service/CliServiceLauncher.js +220 -0
  69. package/build/esm/cli-service/CliServiceLauncher.js.map +1 -0
  70. package/build/esm/cli-service/FoundryCliService.js +168 -0
  71. package/build/esm/cli-service/FoundryCliService.js.map +1 -0
  72. package/build/esm/cli-service/OntologyServer.js +32 -0
  73. package/build/esm/cli-service/OntologyServer.js.map +1 -0
  74. package/build/esm/cli-service/ServiceDiscoverer.js +100 -0
  75. package/build/esm/cli-service/ServiceDiscoverer.js.map +1 -0
  76. package/build/esm/cli-service/StatusServer.js +91 -0
  77. package/build/esm/cli-service/StatusServer.js.map +1 -0
  78. package/build/esm/createIntegrationClient.js +67 -0
  79. package/build/esm/createIntegrationClient.js.map +1 -0
  80. package/build/esm/createIntegrationServer.js +115 -0
  81. package/build/esm/createIntegrationServer.js.map +1 -0
  82. package/build/esm/createSeedClient.js +77 -0
  83. package/build/esm/createSeedClient.js.map +1 -0
  84. package/build/esm/generated/cli/OntologySeedingService/setSeed.js +28 -0
  85. package/build/esm/generated/cli/OntologySeedingService/setSeed.js.map +1 -0
  86. package/build/esm/generated/cli/OntologySeedingService.js +19 -0
  87. package/build/esm/generated/cli/OntologySeedingService.js.map +1 -0
  88. package/build/esm/generated/cli/StatusService/getStatus.js +25 -0
  89. package/build/esm/generated/cli/StatusService/getStatus.js.map +1 -0
  90. package/build/esm/generated/cli/StatusService/publishStatus.js +26 -0
  91. package/build/esm/generated/cli/StatusService/publishStatus.js.map +1 -0
  92. package/build/esm/generated/cli/StatusService.js +20 -0
  93. package/build/esm/generated/cli/StatusService.js.map +1 -0
  94. package/build/esm/generated/cli/__components.js +2 -0
  95. package/build/esm/generated/cli/__components.js.map +1 -0
  96. package/build/esm/generated/cli/index.js +20 -0
  97. package/build/esm/generated/cli/index.js.map +1 -0
  98. package/build/esm/index.js +27 -0
  99. package/build/esm/index.js.map +1 -0
  100. package/build/esm/scripts/download.js +92 -0
  101. package/build/esm/scripts/download.js.map +1 -0
  102. package/build/esm/scripts/foundry-host.js +59 -0
  103. package/build/esm/scripts/foundry-host.js.map +1 -0
  104. package/build/esm/scripts/foundry-token.js +50 -0
  105. package/build/esm/scripts/foundry-token.js.map +1 -0
  106. package/build/esm/scripts/gitRemote.js +39 -0
  107. package/build/esm/scripts/gitRemote.js.map +1 -0
  108. package/build/esm/scripts/postinstall.js +38 -0
  109. package/build/esm/scripts/postinstall.js.map +1 -0
  110. package/build/esm/test/NoSpawnStatusServer.js +33 -0
  111. package/build/esm/test/NoSpawnStatusServer.js.map +1 -0
  112. package/build/esm/test/StubService.js +61 -0
  113. package/build/esm/test/StubService.js.map +1 -0
  114. package/build/esm/test/emptyOntologyMetadata.js +32 -0
  115. package/build/esm/test/emptyOntologyMetadata.js.map +1 -0
  116. package/build/esm/test/stubStatusServer.js +74 -0
  117. package/build/esm/test/stubStatusServer.js.map +1 -0
  118. package/build/esm/test/writeDiscoveryFile.js +39 -0
  119. package/build/esm/test/writeDiscoveryFile.js.map +1 -0
  120. package/build/esm/types.js +2 -0
  121. package/build/esm/types.js.map +1 -0
  122. package/build/esm/utils/empty-ontology-block.js +61 -0
  123. package/build/esm/utils/empty-ontology-block.js.map +1 -0
  124. package/build/esm/utils/foundry-cli.js +46 -0
  125. package/build/esm/utils/foundry-cli.js.map +1 -0
  126. package/build/esm/utils/process.js +26 -0
  127. package/build/esm/utils/process.js.map +1 -0
  128. package/build/esm/utils/service.js +33 -0
  129. package/build/esm/utils/service.js.map +1 -0
  130. package/build/types/cli-service/CliServiceLauncher.d.ts +36 -0
  131. package/build/types/cli-service/CliServiceLauncher.d.ts.map +1 -0
  132. package/build/types/cli-service/FoundryCliService.d.ts +60 -0
  133. package/build/types/cli-service/FoundryCliService.d.ts.map +1 -0
  134. package/build/types/cli-service/OntologyServer.d.ts +10 -0
  135. package/build/types/cli-service/OntologyServer.d.ts.map +1 -0
  136. package/build/types/cli-service/ServiceDiscoverer.d.ts +22 -0
  137. package/build/types/cli-service/ServiceDiscoverer.d.ts.map +1 -0
  138. package/build/types/cli-service/StatusServer.d.ts +17 -0
  139. package/build/types/cli-service/StatusServer.d.ts.map +1 -0
  140. package/build/types/createIntegrationClient.d.ts +2 -0
  141. package/build/types/createIntegrationClient.d.ts.map +1 -0
  142. package/build/types/createIntegrationServer.d.ts +2 -0
  143. package/build/types/createIntegrationServer.d.ts.map +1 -0
  144. package/build/types/createSeedClient.d.ts +9 -0
  145. package/build/types/createSeedClient.d.ts.map +1 -0
  146. package/build/types/generated/cli/OntologySeedingService/setSeed.d.ts +9 -0
  147. package/build/types/generated/cli/OntologySeedingService/setSeed.d.ts.map +1 -0
  148. package/build/types/generated/cli/OntologySeedingService.d.ts +1 -0
  149. package/build/types/generated/cli/OntologySeedingService.d.ts.map +1 -0
  150. package/build/types/generated/cli/StatusService/getStatus.d.ts +6 -0
  151. package/build/types/generated/cli/StatusService/getStatus.d.ts.map +1 -0
  152. package/build/types/generated/cli/StatusService/publishStatus.d.ts +7 -0
  153. package/build/types/generated/cli/StatusService/publishStatus.d.ts.map +1 -0
  154. package/build/types/generated/cli/StatusService.d.ts +2 -0
  155. package/build/types/generated/cli/StatusService.d.ts.map +1 -0
  156. package/build/types/generated/cli/__components.d.ts +189 -0
  157. package/build/types/generated/cli/__components.d.ts.map +1 -0
  158. package/build/types/generated/cli/index.d.ts +3 -0
  159. package/build/types/generated/cli/index.d.ts.map +1 -0
  160. package/build/types/index.d.ts +10 -0
  161. package/build/types/index.d.ts.map +1 -0
  162. package/build/types/scripts/download.d.ts +6 -0
  163. package/build/types/scripts/download.d.ts.map +1 -0
  164. package/build/types/scripts/foundry-host.d.ts +7 -0
  165. package/build/types/scripts/foundry-host.d.ts.map +1 -0
  166. package/build/types/scripts/foundry-token.d.ts +5 -0
  167. package/build/types/scripts/foundry-token.d.ts.map +1 -0
  168. package/build/types/scripts/gitRemote.d.ts +9 -0
  169. package/build/types/scripts/gitRemote.d.ts.map +1 -0
  170. package/build/types/scripts/postinstall.d.ts +1 -0
  171. package/build/types/scripts/postinstall.d.ts.map +1 -0
  172. package/build/types/test/NoSpawnStatusServer.d.ts +11 -0
  173. package/build/types/test/NoSpawnStatusServer.d.ts.map +1 -0
  174. package/build/types/test/StubService.d.ts +23 -0
  175. package/build/types/test/StubService.d.ts.map +1 -0
  176. package/build/types/test/emptyOntologyMetadata.d.ts +3 -0
  177. package/build/types/test/emptyOntologyMetadata.d.ts.map +1 -0
  178. package/build/types/test/stubStatusServer.d.ts +14 -0
  179. package/build/types/test/stubStatusServer.d.ts.map +1 -0
  180. package/build/types/test/writeDiscoveryFile.d.ts +8 -0
  181. package/build/types/test/writeDiscoveryFile.d.ts.map +1 -0
  182. package/build/types/types.d.ts +104 -0
  183. package/build/types/types.d.ts.map +1 -0
  184. package/build/types/utils/empty-ontology-block.d.ts +4 -0
  185. package/build/types/utils/empty-ontology-block.d.ts.map +1 -0
  186. package/build/types/utils/foundry-cli.d.ts +13 -0
  187. package/build/types/utils/foundry-cli.d.ts.map +1 -0
  188. package/build/types/utils/process.d.ts +1 -0
  189. package/build/types/utils/process.d.ts.map +1 -0
  190. package/build/types/utils/service.d.ts +4 -0
  191. package/build/types/utils/service.d.ts.map +1 -0
  192. package/package.json +93 -1
@@ -0,0 +1,168 @@
1
+ /*
2
+ * Copyright 2026 Palantir Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { spawn } from "node:child_process";
18
+ import { once } from "node:events";
19
+ import invariant from "tiny-invariant";
20
+ const MAX_CAPTURED_STDERR_CHUNKS = 32;
21
+ export const DEFAULT_READY_TIMEOUT_MS = 30_000;
22
+ export const DEFAULT_STOP_GRACE_MS = 5_000;
23
+
24
+ /**
25
+ * The shared collaborators a service needs to answer questions about itself.
26
+ * Injected by the launcher via {@link FoundryCliService.attach} so services do
27
+ * not have to construct — or know how to reach — either one.
28
+ */
29
+
30
+ const TERMINAL_STATES = new Set(["FAILED", "STOPPED"]);
31
+
32
+ /**
33
+ * One Foundry CLI service subprocess.
34
+ *
35
+ * Subclasses supply the `foundry` subcommand to run and, where the default is
36
+ * wrong, how to tell that the service is up.
37
+ *
38
+ * Dependencies are declared but not enforced here: a service names what it needs
39
+ * and {@link CliServiceLauncher} is what orders and awaits them.
40
+ */
41
+ export class FoundryCliService {
42
+ #foundryCliPath;
43
+ #projectPath;
44
+ #child;
45
+ #context;
46
+ #stderr = [];
47
+ #exit;
48
+ constructor(name, config) {
49
+ this.name = name;
50
+ this.dependencies = config.dependencies ?? [];
51
+ this.#foundryCliPath = config.foundryCliPath ?? "foundry";
52
+ this.#projectPath = config.projectPath;
53
+ }
54
+ getProjectPath() {
55
+ return this.#projectPath;
56
+ }
57
+ getCaCertPath() {
58
+ return this.#context?.discoverer.get(this.name)?.caCertPath ?? undefined;
59
+ }
60
+ getUrl() {
61
+ return this.#context?.discoverer.get(this.name)?.url;
62
+ }
63
+ getExitInfo() {
64
+ if (this.#exit === undefined) {
65
+ return undefined;
66
+ }
67
+ const {
68
+ code,
69
+ signal
70
+ } = this.#exit;
71
+ return signal ?? `code ${code}`;
72
+ }
73
+ getCapturedStderr() {
74
+ return this.#stderr.join("").trim();
75
+ }
76
+ getContext() {
77
+ const context = this.#context;
78
+ !(context !== undefined) ? process.env.NODE_ENV !== "production" ? invariant(false, `${this.name} is not registered with a CliServiceLauncher, so it has ` + `no discoverer or status server to consult`) : invariant(false) : void 0;
79
+ return context;
80
+ }
81
+ attach(context) {
82
+ this.#context = context;
83
+ }
84
+ async start() {
85
+ if (this.#child !== undefined) {
86
+ return;
87
+ }
88
+ await this.getContext().discoverer.refresh();
89
+ !!(await this.checkHealth()).ready ? process.env.NODE_ENV !== "production" ? invariant(false, `${this.name} is already running; stop it before starting a new one`) : invariant(false) : void 0;
90
+ await this.#spawn();
91
+ }
92
+ async #spawn() {
93
+ this.#exit = undefined;
94
+ this.#stderr = [];
95
+ const child = spawn(this.#foundryCliPath, [...this.getArgs()], {
96
+ cwd: this.#projectPath
97
+ });
98
+ this.#child = child;
99
+ child.stderr.setEncoding("utf-8");
100
+ child.stderr.on("data", chunk => {
101
+ if (this.#stderr.push(chunk) > MAX_CAPTURED_STDERR_CHUNKS) {
102
+ this.#stderr.shift();
103
+ }
104
+ });
105
+ child.stdout.resume(); // flush, since we don't read from stdout
106
+ child.on("exit", (code, signal) => {
107
+ this.#exit = {
108
+ code,
109
+ signal
110
+ };
111
+ });
112
+ await new Promise((resolve, reject) => {
113
+ child.once("spawn", resolve);
114
+ child.once("error", error => reject(new Error(`Failed to spawn ${this.name} via ${this.#foundryCliPath}`, {
115
+ cause: error
116
+ })));
117
+ });
118
+ }
119
+ async checkHealth() {
120
+ const {
121
+ discoverer,
122
+ statusServer
123
+ } = this.getContext();
124
+ const discovery = discoverer.get(this.name);
125
+ if (typeof discovery === "undefined") {
126
+ return {
127
+ service: this.name,
128
+ state: "UNDISCOVERED",
129
+ ready: false,
130
+ terminal: false
131
+ };
132
+ }
133
+ const status = await statusServer.getServiceStatus(this.name);
134
+ const state = status?.status ?? "DISCOVERED";
135
+ return {
136
+ service: this.name,
137
+ state,
138
+ ready: state === "READY",
139
+ terminal: TERMINAL_STATES.has(state),
140
+ url: discovery.url,
141
+ ...(status?.message != null ? {
142
+ message: status.message
143
+ } : {})
144
+ };
145
+ }
146
+
147
+ /**
148
+ * Signal the service and wait for the process to actually be gone.
149
+ */
150
+ async stop() {
151
+ const child = this.#child;
152
+ this.#child = undefined;
153
+ if (child === undefined || child.exitCode != null || child.signalCode != null) {
154
+ return;
155
+ }
156
+ const exited = once(child, "exit");
157
+ child.kill("SIGINT");
158
+ const escalation = setTimeout(() => {
159
+ child.kill("SIGKILL");
160
+ }, DEFAULT_STOP_GRACE_MS);
161
+ try {
162
+ await exited;
163
+ } finally {
164
+ clearTimeout(escalation);
165
+ }
166
+ }
167
+ }
168
+ //# sourceMappingURL=FoundryCliService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FoundryCliService.js","names":["spawn","once","invariant","MAX_CAPTURED_STDERR_CHUNKS","DEFAULT_READY_TIMEOUT_MS","DEFAULT_STOP_GRACE_MS","TERMINAL_STATES","Set","FoundryCliService","foundryCliPath","projectPath","child","context","stderr","exit","constructor","name","config","dependencies","getProjectPath","getCaCertPath","discoverer","get","caCertPath","undefined","getUrl","url","getExitInfo","code","signal","getCapturedStderr","join","trim","getContext","process","env","NODE_ENV","attach","start","refresh","checkHealth","ready","#spawn","getArgs","cwd","setEncoding","on","chunk","push","shift","stdout","resume","Promise","resolve","reject","error","Error","cause","statusServer","discovery","service","state","terminal","status","getServiceStatus","has","message","stop","exitCode","signalCode","exited","kill","escalation","setTimeout","clearTimeout"],"sources":["FoundryCliService.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { spawn, type ChildProcessWithoutNullStreams } from \"node:child_process\";\nimport { once } from \"node:events\";\n\nimport invariant from \"tiny-invariant\";\n\nimport type { ServiceLifecycle, ServiceName } from \"../generated/cli/index.js\";\nimport type { ServiceDiscoverer } from \"./ServiceDiscoverer.js\";\nimport type { StatusServer } from \"./StatusServer.js\";\n\nconst MAX_CAPTURED_STDERR_CHUNKS = 32;\n\nexport const DEFAULT_READY_TIMEOUT_MS = 30_000;\n\nexport const DEFAULT_STOP_GRACE_MS = 5_000;\n\nexport type ServiceState = ServiceLifecycle | \"UNDISCOVERED\" | \"DISCOVERED\";\n\nexport interface ServiceHealth {\n service: ServiceName;\n state: ServiceState;\n ready: boolean;\n terminal: boolean; // Whether `state` is terminal, so waiting for readiness is unnecessary.\n url?: string;\n message?: string;\n}\n\n/**\n * The shared collaborators a service needs to answer questions about itself.\n * Injected by the launcher via {@link FoundryCliService.attach} so services do\n * not have to construct — or know how to reach — either one.\n */\nexport interface ServiceContext {\n discoverer: ServiceDiscoverer;\n statusServer: StatusServer;\n}\n\nexport interface FoundryServiceConfig {\n /** Path to the `foundry` binary. */\n foundryCliPath?: string;\n /** Working directory the CLI runs in; the `.palantir/` dir hangs off it. */\n projectPath: string;\n /** Services that must be ready before this one may be started. */\n dependencies?: readonly FoundryCliService[];\n}\n\nconst TERMINAL_STATES: ReadonlySet<ServiceState> = new Set<ServiceState>([\n \"FAILED\",\n \"STOPPED\",\n]);\n\n/**\n * One Foundry CLI service subprocess.\n *\n * Subclasses supply the `foundry` subcommand to run and, where the default is\n * wrong, how to tell that the service is up.\n *\n * Dependencies are declared but not enforced here: a service names what it needs\n * and {@link CliServiceLauncher} is what orders and awaits them.\n */\nexport abstract class FoundryCliService {\n readonly name: ServiceName;\n readonly dependencies: readonly FoundryCliService[];\n\n #foundryCliPath: string;\n #projectPath: string;\n #child: ChildProcessWithoutNullStreams | undefined;\n #context: ServiceContext | undefined;\n #stderr: string[] = [];\n #exit: { code: number | null; signal: NodeJS.Signals | null } | undefined;\n\n protected constructor(name: ServiceName, config: FoundryServiceConfig) {\n this.name = name;\n this.dependencies = config.dependencies ?? [];\n this.#foundryCliPath = config.foundryCliPath ?? \"foundry\";\n this.#projectPath = config.projectPath;\n }\n\n protected abstract getArgs(): readonly string[];\n\n getProjectPath(): string {\n return this.#projectPath;\n }\n\n getCaCertPath(): string | undefined {\n return this.#context?.discoverer.get(this.name)?.caCertPath ?? undefined;\n }\n\n getUrl(): string | undefined {\n return this.#context?.discoverer.get(this.name)?.url;\n }\n\n getExitInfo(): string | undefined {\n if (this.#exit === undefined) {\n return undefined;\n }\n const { code, signal } = this.#exit;\n return signal ?? `code ${code}`;\n }\n\n getCapturedStderr(): string {\n return this.#stderr.join(\"\").trim();\n }\n\n protected getContext(): ServiceContext {\n const context = this.#context;\n invariant(\n context !== undefined,\n `${this.name} is not registered with a CliServiceLauncher, so it has ` +\n `no discoverer or status server to consult`,\n );\n return context;\n }\n\n attach(context: ServiceContext): void {\n this.#context = context;\n }\n\n async start(): Promise<void> {\n if (this.#child !== undefined) {\n return;\n }\n await this.getContext().discoverer.refresh();\n invariant(\n !(await this.checkHealth()).ready,\n `${this.name} is already running; stop it before starting a new one`,\n );\n await this.#spawn();\n }\n\n async #spawn(): Promise<void> {\n this.#exit = undefined;\n this.#stderr = [];\n const child = spawn(this.#foundryCliPath, [...this.getArgs()], {\n cwd: this.#projectPath,\n });\n this.#child = child;\n child.stderr.setEncoding(\"utf-8\");\n child.stderr.on(\"data\", (chunk: string) => {\n if (this.#stderr.push(chunk) > MAX_CAPTURED_STDERR_CHUNKS) {\n this.#stderr.shift();\n }\n });\n child.stdout.resume(); // flush, since we don't read from stdout\n child.on(\"exit\", (code, signal) => {\n this.#exit = { code, signal };\n });\n await new Promise<void>((resolve, reject) => {\n child.once(\"spawn\", resolve);\n child.once(\"error\", (error) =>\n reject(\n new Error(\n `Failed to spawn ${this.name} via ${this.#foundryCliPath}`,\n {\n cause: error,\n },\n ),\n ),\n );\n });\n }\n\n async checkHealth(): Promise<ServiceHealth> {\n const { discoverer, statusServer } = this.getContext();\n const discovery = discoverer.get(this.name);\n if (typeof discovery === \"undefined\") {\n return {\n service: this.name,\n state: \"UNDISCOVERED\",\n ready: false,\n terminal: false,\n };\n }\n const status = await statusServer.getServiceStatus(this.name);\n const state: ServiceState = status?.status ?? \"DISCOVERED\";\n return {\n service: this.name,\n state,\n ready: state === \"READY\",\n terminal: TERMINAL_STATES.has(state),\n url: discovery.url,\n ...(status?.message != null ? { message: status.message } : {}),\n };\n }\n\n /**\n * Signal the service and wait for the process to actually be gone.\n */\n async stop(): Promise<void> {\n const child = this.#child;\n this.#child = undefined;\n if (\n child === undefined ||\n child.exitCode != null ||\n child.signalCode != null\n ) {\n return;\n }\n const exited = once(child, \"exit\");\n child.kill(\"SIGINT\");\n const escalation = setTimeout(() => {\n child.kill(\"SIGKILL\");\n }, DEFAULT_STOP_GRACE_MS);\n try {\n await exited;\n } finally {\n clearTimeout(escalation);\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Copyright 2026 Palantir Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import path, { isAbsolute, resolve } from "node:path";
18
+ import { FoundryCliService } from "./FoundryCliService.js";
19
+ export class OntologyServer extends FoundryCliService {
20
+ #metadataPath;
21
+ constructor(config) {
22
+ super("ONTOLOGY", config);
23
+ this.#metadataPath = isAbsolute(config.metadataPath) ? config.metadataPath : resolve(config.projectPath, config.metadataPath);
24
+ }
25
+ getMetadataPath() {
26
+ return this.#metadataPath;
27
+ }
28
+ getArgs() {
29
+ return ["start", "ontology", "--skip-build", "--metadata", this.#metadataPath, "--discovery-path", path.resolve(this.getProjectPath(), ".palantir")];
30
+ }
31
+ }
32
+ //# sourceMappingURL=OntologyServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OntologyServer.js","names":["path","isAbsolute","resolve","FoundryCliService","OntologyServer","metadataPath","constructor","config","projectPath","getMetadataPath","getArgs","getProjectPath"],"sources":["OntologyServer.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport path, { isAbsolute, resolve } from \"node:path\";\n\nimport {\n FoundryCliService,\n type FoundryServiceConfig,\n} from \"./FoundryCliService.js\";\n\nexport interface OntologyServerConfig extends FoundryServiceConfig {\n metadataPath: string;\n}\n\nexport class OntologyServer extends FoundryCliService {\n #metadataPath: string;\n\n constructor(config: OntologyServerConfig) {\n super(\"ONTOLOGY\", config);\n this.#metadataPath = isAbsolute(config.metadataPath)\n ? config.metadataPath\n : resolve(config.projectPath, config.metadataPath);\n }\n\n getMetadataPath(): string {\n return this.#metadataPath;\n }\n\n protected override getArgs(): readonly string[] {\n return [\n \"start\",\n \"ontology\",\n \"--skip-build\",\n \"--metadata\",\n this.#metadataPath,\n \"--discovery-path\",\n path.resolve(this.getProjectPath(), \".palantir\"),\n ];\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,IAAI,IAAIC,UAAU,EAAEC,OAAO,QAAQ,WAAW;AAErD,SACEC,iBAAiB,QAEZ,wBAAwB;AAM/B,OAAO,MAAMC,cAAc,SAASD,iBAAiB,CAAC;EACpD,CAACE,YAAY;EAEbC,WAAWA,CAACC,MAA4B,EAAE;IACxC,KAAK,CAAC,UAAU,EAAEA,MAAM,CAAC;IACzB,IAAI,CAAC,CAACF,YAAY,GAAGJ,UAAU,CAACM,MAAM,CAACF,YAAY,CAAC,GAChDE,MAAM,CAACF,YAAY,GACnBH,OAAO,CAACK,MAAM,CAACC,WAAW,EAAED,MAAM,CAACF,YAAY,CAAC;EACtD;EAEAI,eAAeA,CAAA,EAAW;IACxB,OAAO,IAAI,CAAC,CAACJ,YAAY;EAC3B;EAEmBK,OAAOA,CAAA,EAAsB;IAC9C,OAAO,CACL,OAAO,EACP,UAAU,EACV,cAAc,EACd,YAAY,EACZ,IAAI,CAAC,CAACL,YAAY,EAClB,kBAAkB,EAClBL,IAAI,CAACE,OAAO,CAAC,IAAI,CAACS,cAAc,CAAC,CAAC,EAAE,WAAW,CAAC,CACjD;EACH;AACF","ignoreList":[]}
@@ -0,0 +1,100 @@
1
+ /*
2
+ * Copyright 2026 Palantir Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import * as fs from "node:fs/promises";
18
+ import { join } from "node:path";
19
+ import invariant from "tiny-invariant";
20
+ import { isProcessAlive } from "../utils/process.js";
21
+ import { serviceNameFromFileName } from "../utils/service.js";
22
+ /**
23
+ * Reads the discovery files that running Foundry services publish into
24
+ * `basePath`.
25
+ */
26
+ export class ServiceDiscoverer {
27
+ #basePath;
28
+ #discovered = new Map();
29
+ constructor(args) {
30
+ this.#basePath = args.basePath;
31
+ }
32
+ get discoveryDir() {
33
+ return this.#basePath;
34
+ }
35
+ async start() {
36
+ await fs.mkdir(this.#basePath, {
37
+ recursive: true
38
+ });
39
+ await this.refresh();
40
+ }
41
+
42
+ /**
43
+ * Re-read every discovery file in the directory.
44
+ */
45
+ async refresh() {
46
+ const fileNames = await fs.readdir(this.#basePath);
47
+ const discoveries = await Promise.all(fileNames.map(fileName => this.#read(fileName)));
48
+ return discoveries.filter(discovery => discovery !== undefined);
49
+ }
50
+ get(name) {
51
+ const discovery = this.#discovered.get(name);
52
+ if (typeof discovery === "undefined") {
53
+ return undefined;
54
+ }
55
+ if (!isProcessAlive(discovery.pid)) {
56
+ this.#discovered.delete(name); // Stale: the publisher died without cleaning up after itself.
57
+ return undefined;
58
+ }
59
+ return discovery;
60
+ }
61
+ isDiscovered(name) {
62
+ return this.get(name) !== undefined;
63
+ }
64
+ all() {
65
+ const live = new Map();
66
+ for (const name of this.#discovered.keys()) {
67
+ const discovery = this.get(name);
68
+ if (discovery !== undefined) {
69
+ live.set(name, discovery);
70
+ }
71
+ }
72
+ return live;
73
+ }
74
+ stop() {
75
+ this.#discovered.clear();
76
+ }
77
+ async #read(fileName) {
78
+ const serviceName = serviceNameFromFileName(fileName);
79
+ if (typeof serviceName === "undefined") {
80
+ return undefined;
81
+ }
82
+ let contents;
83
+ try {
84
+ contents = await fs.readFile(join(this.#basePath, fileName), "utf-8");
85
+ } catch {
86
+ this.#discovered.delete(serviceName);
87
+ return undefined;
88
+ }
89
+ let parsed;
90
+ try {
91
+ parsed = JSON.parse(contents);
92
+ } catch {
93
+ return undefined;
94
+ }
95
+ !parsed.url ? process.env.NODE_ENV !== "production" ? invariant(false, `Service URL not found`) : invariant(false) : void 0;
96
+ this.#discovered.set(serviceName, parsed);
97
+ return parsed;
98
+ }
99
+ }
100
+ //# sourceMappingURL=ServiceDiscoverer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceDiscoverer.js","names":["fs","join","invariant","isProcessAlive","serviceNameFromFileName","ServiceDiscoverer","basePath","discovered","Map","constructor","args","discoveryDir","start","mkdir","recursive","refresh","fileNames","readdir","discoveries","Promise","all","map","fileName","read","filter","discovery","undefined","get","name","pid","delete","isDiscovered","live","keys","set","stop","clear","#read","serviceName","contents","readFile","parsed","JSON","parse","url","process","env","NODE_ENV"],"sources":["ServiceDiscoverer.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as fs from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport invariant from \"tiny-invariant\";\n\nimport type {\n ComponentDiscovery,\n ServiceName,\n} from \"../generated/cli/index.js\";\nimport { isProcessAlive } from \"../utils/process.js\";\nimport { serviceNameFromFileName } from \"../utils/service.js\";\n\nexport type ServiceDiscovererConfig = {\n basePath: string;\n};\n\n/**\n * Reads the discovery files that running Foundry services publish into\n * `basePath`.\n */\nexport class ServiceDiscoverer {\n #basePath: string;\n #discovered = new Map<ServiceName, ComponentDiscovery>();\n\n constructor(args: ServiceDiscovererConfig) {\n this.#basePath = args.basePath;\n }\n\n get discoveryDir(): string {\n return this.#basePath;\n }\n\n async start(): Promise<void> {\n await fs.mkdir(this.#basePath, { recursive: true });\n await this.refresh();\n }\n\n /**\n * Re-read every discovery file in the directory.\n */\n async refresh(): Promise<ComponentDiscovery[]> {\n const fileNames = await fs.readdir(this.#basePath);\n const discoveries = await Promise.all(\n fileNames.map((fileName) => this.#read(fileName)),\n );\n return discoveries.filter(\n (discovery): discovery is ComponentDiscovery => discovery !== undefined,\n );\n }\n\n get(name: ServiceName): ComponentDiscovery | undefined {\n const discovery = this.#discovered.get(name);\n if (typeof discovery === \"undefined\") {\n return undefined;\n }\n if (!isProcessAlive(discovery.pid)) {\n this.#discovered.delete(name); // Stale: the publisher died without cleaning up after itself.\n return undefined;\n }\n return discovery;\n }\n\n isDiscovered(name: ServiceName): boolean {\n return this.get(name) !== undefined;\n }\n\n all(): Map<ServiceName, ComponentDiscovery> {\n const live = new Map<ServiceName, ComponentDiscovery>();\n for (const name of this.#discovered.keys()) {\n const discovery = this.get(name);\n if (discovery !== undefined) {\n live.set(name, discovery);\n }\n }\n return live;\n }\n\n stop(): void {\n this.#discovered.clear();\n }\n\n async #read(fileName: string): Promise<ComponentDiscovery | undefined> {\n const serviceName = serviceNameFromFileName(fileName);\n if (typeof serviceName === \"undefined\") {\n return undefined;\n }\n let contents: string;\n try {\n contents = await fs.readFile(join(this.#basePath, fileName), \"utf-8\");\n } catch {\n this.#discovered.delete(serviceName);\n return undefined;\n }\n let parsed: ComponentDiscovery;\n try {\n parsed = JSON.parse(contents) as ComponentDiscovery;\n } catch {\n return undefined;\n }\n invariant(parsed.url, `Service URL not found`);\n this.#discovered.set(serviceName, parsed);\n return parsed;\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,91 @@
1
+ /*
2
+ * Copyright 2026 Palantir Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import path from "node:path";
18
+ import invariant from "tiny-invariant";
19
+ import { StatusService } from "../generated/cli/index.js";
20
+ import { FoundryCliService } from "./FoundryCliService.js";
21
+ const HEALTH_REQUEST_TIMEOUT_MS = 2_000;
22
+ /**
23
+ * The local status server, and the health authority for every other service.
24
+ */
25
+ export class StatusServer extends FoundryCliService {
26
+ /** Shared by callers that ask while a fetch is already outstanding. */
27
+ #inFlight;
28
+ constructor(config) {
29
+ super("STATUS_SERVER", config);
30
+ }
31
+ getArgs() {
32
+ // force project path to cwd
33
+ return ["start", "status-server", "--discovery-path", path.resolve(this.getProjectPath(), ".palantir")];
34
+ }
35
+ async checkHealth() {
36
+ const discovery = this.getContext().discoverer.get("STATUS_SERVER");
37
+ if (discovery === undefined) {
38
+ return {
39
+ service: "STATUS_SERVER",
40
+ state: "UNDISCOVERED",
41
+ ready: false,
42
+ terminal: false
43
+ };
44
+ }
45
+ const healthy = await this.#isHealthy(discovery.url);
46
+ return {
47
+ service: "STATUS_SERVER",
48
+ state: healthy ? "READY" : "DISCOVERED",
49
+ ready: healthy,
50
+ terminal: false,
51
+ url: discovery.url
52
+ };
53
+ }
54
+ async #isHealthy(baseUrl) {
55
+ try {
56
+ const response = await fetch(new URL("/api/health", baseUrl), {
57
+ signal: AbortSignal.timeout(HEALTH_REQUEST_TIMEOUT_MS)
58
+ });
59
+ if (!response.ok) {
60
+ return false;
61
+ }
62
+ const body = await response.json();
63
+ return body.status === "healthy";
64
+ } catch {
65
+ return false;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * The lifecycle snapshot for every service.
71
+ */
72
+ async getServiceStatuses() {
73
+ const baseUrl = this.getContext().discoverer.get("STATUS_SERVER")?.url;
74
+ !baseUrl ? process.env.NODE_ENV !== "production" ? invariant(false, "Cannot get service status because the status server is not discovered yet") : invariant(false) : void 0;
75
+ this.#inFlight ??= StatusService.getStatus({
76
+ baseUrl,
77
+ servicePath: ""
78
+ }).catch(() => undefined).finally(() => {
79
+ this.#inFlight = undefined;
80
+ });
81
+ const result = await this.#inFlight;
82
+ return result ?? [];
83
+ }
84
+ async getServiceStatus(name) {
85
+ const statuses = await this.getServiceStatuses();
86
+ return statuses.find(({
87
+ service
88
+ }) => service === name);
89
+ }
90
+ }
91
+ //# sourceMappingURL=StatusServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusServer.js","names":["path","invariant","StatusService","FoundryCliService","HEALTH_REQUEST_TIMEOUT_MS","StatusServer","inFlight","constructor","config","getArgs","resolve","getProjectPath","checkHealth","discovery","getContext","discoverer","get","undefined","service","state","ready","terminal","healthy","isHealthy","url","#isHealthy","baseUrl","response","fetch","URL","signal","AbortSignal","timeout","ok","body","json","status","getServiceStatuses","process","env","NODE_ENV","getStatus","servicePath","catch","finally","result","getServiceStatus","name","statuses","find"],"sources":["StatusServer.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport path from \"node:path\";\n\nimport invariant from \"tiny-invariant\";\n\nimport {\n type ServiceName,\n type ServiceStatus,\n StatusService,\n} from \"../generated/cli/index.js\";\nimport {\n FoundryCliService,\n type FoundryServiceConfig,\n type ServiceHealth,\n} from \"./FoundryCliService.js\";\n\nconst HEALTH_REQUEST_TIMEOUT_MS = 2_000;\n\nexport type StatusServerConfig = FoundryServiceConfig;\n\n/**\n * The local status server, and the health authority for every other service.\n */\nexport class StatusServer extends FoundryCliService {\n /** Shared by callers that ask while a fetch is already outstanding. */\n #inFlight: Promise<ServiceStatus[] | undefined> | undefined;\n\n constructor(config: StatusServerConfig) {\n super(\"STATUS_SERVER\", config);\n }\n\n protected override getArgs(): readonly string[] {\n // force project path to cwd\n return [\n \"start\",\n \"status-server\",\n \"--discovery-path\",\n path.resolve(this.getProjectPath(), \".palantir\"),\n ];\n }\n\n override async checkHealth(): Promise<ServiceHealth> {\n const discovery = this.getContext().discoverer.get(\"STATUS_SERVER\");\n if (discovery === undefined) {\n return {\n service: \"STATUS_SERVER\",\n state: \"UNDISCOVERED\",\n ready: false,\n terminal: false,\n };\n }\n const healthy = await this.#isHealthy(discovery.url);\n return {\n service: \"STATUS_SERVER\",\n state: healthy ? \"READY\" : \"DISCOVERED\",\n ready: healthy,\n terminal: false,\n url: discovery.url,\n };\n }\n\n async #isHealthy(baseUrl: string): Promise<boolean> {\n try {\n const response = await fetch(new URL(\"/api/health\", baseUrl), {\n signal: AbortSignal.timeout(HEALTH_REQUEST_TIMEOUT_MS),\n });\n if (!response.ok) {\n return false;\n }\n const body: { status?: unknown } = await response.json();\n return body.status === \"healthy\";\n } catch {\n return false;\n }\n }\n\n /**\n * The lifecycle snapshot for every service.\n */\n async getServiceStatuses(): Promise<ServiceStatus[]> {\n const baseUrl = this.getContext().discoverer.get(\"STATUS_SERVER\")?.url;\n invariant(\n baseUrl,\n \"Cannot get service status because the status server is not discovered yet\",\n );\n this.#inFlight ??= StatusService.getStatus({ baseUrl, servicePath: \"\" })\n .catch(() => undefined)\n .finally(() => {\n this.#inFlight = undefined;\n });\n const result = await this.#inFlight;\n return result ?? [];\n }\n\n async getServiceStatus(\n name: ServiceName,\n ): Promise<ServiceStatus | undefined> {\n const statuses = await this.getServiceStatuses();\n return statuses.find(({ service }) => service === name);\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,67 @@
1
+ /*
2
+ * Copyright 2026 Palantir Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import fs from "node:fs/promises";
18
+ import { createClient } from "@osdk/client";
19
+ import { createMockClient } from "@osdk/unit-testing";
20
+ import { fetch as undiciFetch, Agent } from "undici";
21
+
22
+ /** The definition kinds accepted by {@link Client}'s call signatures. */
23
+
24
+ export async function createIntegrationClient(config) {
25
+ const {
26
+ baseUrl,
27
+ metadata,
28
+ caCertPath
29
+ } = config;
30
+ const agent = new Agent({
31
+ connect: caCertPath ? {
32
+ ca: await fs.readFile(caCertPath)
33
+ } : {
34
+ rejectUnauthorized: false
35
+ }
36
+ });
37
+ const realClient = createClient(baseUrl, metadata.ontology.rid, () => Promise.resolve("integration-client-token"), {}, (input, init) => undiciFetch(input, {
38
+ ...init,
39
+ dispatcher: agent
40
+ }));
41
+ const mockClient = createMockClient();
42
+ const client = Object.defineProperties(def => {
43
+ switch (def.type) {
44
+ case "query":
45
+ return mockClient(def);
46
+ case "action":
47
+ return realClient(def);
48
+ case "interface":
49
+ return realClient(def);
50
+ case "object":
51
+ return realClient(def);
52
+ case "experiment":
53
+ default:
54
+ return realClient(def);
55
+ }
56
+ }, {
57
+ ...Object.getOwnPropertyDescriptors(realClient),
58
+ whenQuery: {
59
+ value: mockClient.whenQuery.bind(undefined)
60
+ },
61
+ clearStubs: {
62
+ value: mockClient.clearStubs.bind(undefined)
63
+ }
64
+ });
65
+ return client;
66
+ }
67
+ //# sourceMappingURL=createIntegrationClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createIntegrationClient.js","names":["fs","createClient","createMockClient","fetch","undiciFetch","Agent","createIntegrationClient","config","baseUrl","metadata","caCertPath","agent","connect","ca","readFile","rejectUnauthorized","realClient","ontology","rid","Promise","resolve","input","init","dispatcher","mockClient","client","Object","defineProperties","def","type","getOwnPropertyDescriptors","whenQuery","value","bind","undefined","clearStubs"],"sources":["createIntegrationClient.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from \"node:fs/promises\";\n\nimport type {\n ActionDefinition,\n InterfaceDefinition,\n ObjectTypeDefinition,\n QueryDefinition,\n} from \"@osdk/api\";\nimport type { Experiment } from \"@osdk/api/unstable\";\nimport { createClient, type Client } from \"@osdk/client\";\nimport { createMockClient } from \"@osdk/unit-testing\";\nimport { fetch as undiciFetch, Agent } from \"undici\";\n\nimport type { IntegrationClient, IntegrationClientConfig } from \"./types.js\";\n\n/** The definition kinds accepted by {@link Client}'s call signatures. */\ntype ClientArg =\n | ObjectTypeDefinition\n | InterfaceDefinition\n | ActionDefinition\n | QueryDefinition\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | Experiment<any>;\n\nexport async function createIntegrationClient(\n config: IntegrationClientConfig,\n): Promise<IntegrationClient> {\n const { baseUrl, metadata, caCertPath } = config;\n const agent = new Agent({\n connect: caCertPath\n ? {\n ca: await fs.readFile(caCertPath),\n }\n : {\n rejectUnauthorized: false,\n },\n });\n const fetchWithCert = ((input, init) =>\n undiciFetch(input, {\n ...init,\n dispatcher: agent,\n })) satisfies typeof undiciFetch as unknown as typeof fetch;\n const realClient = createClient(\n baseUrl,\n metadata.ontology.rid,\n () => Promise.resolve(\"integration-client-token\"),\n {},\n fetchWithCert,\n );\n const mockClient = createMockClient();\n const clientInternal = ((def: ClientArg) => {\n switch (def.type) {\n case \"query\":\n return mockClient(def);\n case \"action\":\n return realClient(def);\n case \"interface\":\n return realClient(def);\n case \"object\":\n return realClient(def);\n case \"experiment\":\n default:\n return realClient(def);\n }\n }) as Client;\n const client = Object.defineProperties<IntegrationClient>(\n clientInternal as IntegrationClient,\n {\n ...Object.getOwnPropertyDescriptors(realClient),\n whenQuery: {\n value: mockClient.whenQuery.bind(undefined),\n },\n clearStubs: {\n value: mockClient.clearStubs.bind(undefined),\n },\n },\n );\n return client;\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,EAAE,MAAM,kBAAkB;AASjC,SAASC,YAAY,QAAqB,cAAc;AACxD,SAASC,gBAAgB,QAAQ,oBAAoB;AACrD,SAASC,KAAK,IAAIC,WAAW,EAAEC,KAAK,QAAQ,QAAQ;;AAIpD;;AASA,OAAO,eAAeC,uBAAuBA,CAC3CC,MAA+B,EACH;EAC5B,MAAM;IAAEC,OAAO;IAAEC,QAAQ;IAAEC;EAAW,CAAC,GAAGH,MAAM;EAChD,MAAMI,KAAK,GAAG,IAAIN,KAAK,CAAC;IACtBO,OAAO,EAAEF,UAAU,GACf;MACEG,EAAE,EAAE,MAAMb,EAAE,CAACc,QAAQ,CAACJ,UAAU;IAClC,CAAC,GACD;MACEK,kBAAkB,EAAE;IACtB;EACN,CAAC,CAAC;EAMF,MAAMC,UAAU,GAAGf,YAAY,CAC7BO,OAAO,EACPC,QAAQ,CAACQ,QAAQ,CAACC,GAAG,EACrB,MAAMC,OAAO,CAACC,OAAO,CAAC,0BAA0B,CAAC,EACjD,CAAC,CAAC,EATmB,CAACC,KAAK,EAAEC,IAAI,KACjClB,WAAW,CAACiB,KAAK,EAAE;IACjB,GAAGC,IAAI;IACPC,UAAU,EAAEZ;EACd,CAAC,CAOH,CAAC;EACD,MAAMa,UAAU,GAAGtB,gBAAgB,CAAC,CAAC;EAgBrC,MAAMuB,MAAM,GAAGC,MAAM,CAACC,gBAAgB,CAfbC,GAAc,IAAK;IAC1C,QAAQA,GAAG,CAACC,IAAI;MACd,KAAK,OAAO;QACV,OAAOL,UAAU,CAACI,GAAG,CAAC;MACxB,KAAK,QAAQ;QACX,OAAOZ,UAAU,CAACY,GAAG,CAAC;MACxB,KAAK,WAAW;QACd,OAAOZ,UAAU,CAACY,GAAG,CAAC;MACxB,KAAK,QAAQ;QACX,OAAOZ,UAAU,CAACY,GAAG,CAAC;MACxB,KAAK,YAAY;MACjB;QACE,OAAOZ,UAAU,CAACY,GAAG,CAAC;IAC1B;EACF,CAAC,EAGC;IACE,GAAGF,MAAM,CAACI,yBAAyB,CAACd,UAAU,CAAC;IAC/Ce,SAAS,EAAE;MACTC,KAAK,EAAER,UAAU,CAACO,SAAS,CAACE,IAAI,CAACC,SAAS;IAC5C,CAAC;IACDC,UAAU,EAAE;MACVH,KAAK,EAAER,UAAU,CAACW,UAAU,CAACF,IAAI,CAACC,SAAS;IAC7C;EACF,CACF,CAAC;EACD,OAAOT,MAAM;AACf","ignoreList":[]}
@@ -0,0 +1,115 @@
1
+ /*
2
+ * Copyright 2026 Palantir Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import fs from "node:fs/promises";
18
+ import path from "node:path";
19
+ import { PreviewOntologyIrConverter } from "@osdk/generator-converters.preview";
20
+ import invariant from "tiny-invariant";
21
+ import { Agent, fetch as undiciFetch } from "undici";
22
+ import { CliServiceLauncher } from "./cli-service/CliServiceLauncher.js";
23
+ import { OntologyServer } from "./cli-service/OntologyServer.js";
24
+ import { createIntegrationClient } from "./createIntegrationClient.js";
25
+ import { createSeedClient } from "./createSeedClient.js";
26
+ import { EMPTY_ONTOLOGY_BLOCK_DATA } from "./utils/empty-ontology-block.js";
27
+ const transformMetadata = metadata => {
28
+ const transformed = PreviewOntologyIrConverter.getPreviewFullMetadataFromBlockData(EMPTY_ONTOLOGY_BLOCK_DATA, metadata);
29
+ return {
30
+ ...transformed,
31
+ ontology: metadata.ontology
32
+ };
33
+ };
34
+ const writeMetadata = async args => {
35
+ const {
36
+ metadataPath,
37
+ previewMetadata
38
+ } = args;
39
+ const stringified = JSON.stringify(previewMetadata);
40
+ await fs.writeFile(metadataPath, stringified);
41
+ };
42
+ export async function createIntegrationServer(config) {
43
+ const {
44
+ metadata,
45
+ projectPath = process.cwd(),
46
+ foundryCliPath
47
+ } = config;
48
+ const testPath = await fs.mkdtemp(path.join(projectPath, ".test-run-"));
49
+ const metadataPath = path.resolve(testPath, "ontology-metadata.json");
50
+ const previewMetadata = transformMetadata(metadata);
51
+ const serviceLauncher = new CliServiceLauncher({
52
+ projectDir: testPath,
53
+ foundryCliPath
54
+ });
55
+ // write metadata to metadataPath for foundry cli to read from
56
+ await writeMetadata({
57
+ previewMetadata,
58
+ metadataPath
59
+ });
60
+ const ontology = serviceLauncher.register(new OntologyServer({
61
+ projectPath: testPath,
62
+ metadataPath,
63
+ foundryCliPath
64
+ }));
65
+
66
+ // stateful cache of client and seed client
67
+ let client;
68
+ let seedClient;
69
+ return {
70
+ getOntologyUrl: () => ontology.getUrl(),
71
+ start: async () => {
72
+ await serviceLauncher.start();
73
+ },
74
+ stop: async () => {
75
+ await serviceLauncher.stop();
76
+ await fs.rm(testPath, {
77
+ recursive: true,
78
+ force: true
79
+ });
80
+ },
81
+ getSeedClient: async () => {
82
+ if (seedClient !== undefined) return seedClient;
83
+ const baseUrl = ontology.getUrl();
84
+ !baseUrl ? process.env.NODE_ENV !== "production" ? invariant(false, "Ontology server is not ready") : invariant(false) : void 0;
85
+ const caCertPath = ontology.getCaCertPath();
86
+ !caCertPath ? process.env.NODE_ENV !== "production" ? invariant(false, "Ontology server is not ready") : invariant(false) : void 0;
87
+ const agent = new Agent({
88
+ connect: caCertPath ? {
89
+ ca: await fs.readFile(caCertPath)
90
+ } : {
91
+ rejectUnauthorized: false
92
+ }
93
+ });
94
+ return seedClient = createSeedClient({
95
+ baseUrl,
96
+ metadata,
97
+ fetchFn: (input, init) => undiciFetch(input, {
98
+ ...init,
99
+ dispatcher: agent
100
+ })
101
+ });
102
+ },
103
+ getClient: async () => {
104
+ if (client !== undefined) return client;
105
+ const baseUrl = ontology.getUrl();
106
+ !baseUrl ? process.env.NODE_ENV !== "production" ? invariant(false, "Ontology server is not ready") : invariant(false) : void 0;
107
+ return client = await createIntegrationClient({
108
+ baseUrl,
109
+ metadata,
110
+ caCertPath: ontology.getCaCertPath()
111
+ });
112
+ }
113
+ };
114
+ }
115
+ //# sourceMappingURL=createIntegrationServer.js.map