@jterrazz/test 16.1.1 → 18.0.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 (309) hide show
  1. package/README.md +45 -171
  2. package/dist/browser/index.js +1 -2980
  3. package/dist/browser/services.js +1 -0
  4. package/dist/browser/stubs.js +1 -0
  5. package/dist/browser-shared-index.browser.js +3233 -0
  6. package/dist/checker.d.ts +6 -1
  7. package/dist/checker.js +3721 -2624
  8. package/dist/config.d.ts +40 -0
  9. package/dist/config.js +309 -0
  10. package/dist/in-place.global-setup.d.ts +12 -0
  11. package/dist/in-place.global-setup.js +21 -0
  12. package/dist/index.d.ts +1641 -3004
  13. package/dist/index.js +5095 -3835
  14. package/dist/mobile-session.global-setup.d.ts +15 -0
  15. package/dist/mobile-session.global-setup.js +31 -0
  16. package/dist/oxlint.cjs +6069 -5634
  17. package/dist/oxlint.d.cts +43 -7212
  18. package/dist/oxlint.d.ts +43 -7212
  19. package/dist/oxlint.js +3979 -5799
  20. package/dist/route-coverage.global-setup.d.ts +43 -0
  21. package/dist/route-coverage.global-setup.js +1 -0
  22. package/dist/services.d.ts +3 -0
  23. package/dist/services.global-setup.d.ts +43 -0
  24. package/dist/services.global-setup.js +1 -0
  25. package/dist/services.js +597 -0
  26. package/dist/shared-appium.adapter.js +428 -0
  27. package/dist/shared-artifacts.js +34 -0
  28. package/dist/shared-chapter.js +7 -0
  29. package/dist/shared-container.port.d.ts +31 -0
  30. package/dist/shared-derived-projects.js +73 -0
  31. package/dist/shared-device.port.d.ts +189 -0
  32. package/dist/shared-exchange.js +447 -0
  33. package/dist/shared-in-place.js +172 -0
  34. package/dist/shared-index.services.d.ts +346 -0
  35. package/dist/shared-index.stubs.d.ts +287 -0
  36. package/dist/shared-json-shape.js +17 -0
  37. package/dist/shared-landmarks.js +71 -0
  38. package/dist/shared-ledger.js +68 -0
  39. package/dist/shared-listened-port.js +19 -0
  40. package/dist/shared-literate-plugin.js +184 -0
  41. package/dist/shared-manifest.js +1321 -0
  42. package/dist/shared-pause.js +22 -0
  43. package/dist/shared-peer.js +88 -0
  44. package/dist/shared-playwright.adapter.js +328 -0
  45. package/dist/shared-process-alive.js +13 -0
  46. package/dist/shared-process.adapter.js +74 -0
  47. package/dist/shared-record-key.js +13 -0
  48. package/dist/shared-refusal.js +35 -0
  49. package/dist/shared-resolve.js +24 -0
  50. package/dist/shared-route-coverage.global-setup.js +187 -0
  51. package/dist/shared-scenario-failure.js +198 -0
  52. package/dist/shared-serve.js +407 -0
  53. package/dist/shared-service-images.js +10 -0
  54. package/dist/shared-services.global-setup.js +174 -0
  55. package/dist/shared-session-ledger.js +305 -0
  56. package/dist/shared-setup-entry.js +12 -0
  57. package/dist/shared-source-scan.js +133 -0
  58. package/dist/shared-spec-document.js +303 -0
  59. package/dist/shared-spec-grammar.js +66 -0
  60. package/dist/shared-specifications.js +26 -0
  61. package/dist/shared-specs-modules.js +1033 -0
  62. package/dist/shared-stub-reply.js +167 -0
  63. package/dist/shared-stub-server.js +142 -0
  64. package/dist/shared-temp-root.global-setup.js +73 -0
  65. package/dist/shared-test-baseline.js +26 -0
  66. package/dist/shared-test-section.js +58 -0
  67. package/dist/shared-testcontainers.adapter.js +306 -0
  68. package/dist/shared-tokens.js +55 -0
  69. package/dist/shared-yaml-document.js +119 -0
  70. package/dist/stubs.d.ts +2 -0
  71. package/dist/stubs.js +657 -0
  72. package/dist/temp-root.global-setup.d.ts +7 -0
  73. package/dist/temp-root.global-setup.js +1 -0
  74. package/dist/vitest.d.ts +93 -164
  75. package/dist/vitest.js +382 -550
  76. package/docs/README.md +82 -36
  77. package/docs/concepts/architecture.md +118 -0
  78. package/docs/concepts/conventions.md +333 -0
  79. package/docs/guides/api-specs.md +374 -0
  80. package/docs/guides/cli-specs.md +566 -0
  81. package/docs/guides/component-specs.md +252 -0
  82. package/docs/guides/develop.md +97 -0
  83. package/docs/guides/integration-specs.md +181 -0
  84. package/docs/guides/job-specs.md +180 -0
  85. package/docs/guides/lint-specs.md +174 -0
  86. package/docs/guides/mobile-specs.md +319 -0
  87. package/docs/guides/module-tests.md +149 -0
  88. package/docs/guides/release.md +44 -0
  89. package/docs/guides/spec-documents.md +189 -0
  90. package/docs/guides/website-specs.md +413 -0
  91. package/docs/reference/assertions.md +345 -0
  92. package/docs/reference/glossary.md +20 -0
  93. package/docs/reference/linting.md +483 -0
  94. package/docs/reference/services.md +236 -0
  95. package/docs/reference/stubs.md +500 -0
  96. package/docs/reference/time-and-doubles.md +137 -0
  97. package/docs/reference/tokens.md +258 -0
  98. package/docs/reference/visitor.md +221 -0
  99. package/docs/start/getting-started.md +187 -0
  100. package/docs/start/set-up-a-project.md +228 -0
  101. package/package.json +56 -36
  102. package/schema/spec.schema.json +43 -17
  103. package/dist/appium.adapter.js +0 -489
  104. package/dist/artifacts.js +0 -32
  105. package/dist/fixtures.js +0 -110
  106. package/dist/literate.js +0 -1747
  107. package/dist/match.js +0 -804
  108. package/dist/playwright.adapter.js +0 -438
  109. package/dist/server.js +0 -160
  110. package/dist/stream.js +0 -321
  111. package/dist/substring-warning.js +0 -282
  112. package/docs/01-architecture.md +0 -95
  113. package/docs/02-developing.md +0 -351
  114. package/docs/03-testing.md +0 -495
  115. package/docs/04-operating.md +0 -101
  116. package/docs/05-module-tests.md +0 -152
  117. package/docs/06-integration.md +0 -180
  118. package/docs/07-component.md +0 -246
  119. package/docs/08-website.md +0 -404
  120. package/docs/09-mobile.md +0 -270
  121. package/docs/10-api.md +0 -264
  122. package/docs/11-jobs.md +0 -157
  123. package/docs/12-cli.md +0 -677
  124. package/docs/13-elements.md +0 -248
  125. package/docs/14-assertions.md +0 -314
  126. package/docs/15-tokens.md +0 -253
  127. package/docs/16-contracts.md +0 -438
  128. package/docs/17-services.md +0 -188
  129. package/docs/18-conventions.md +0 -332
  130. package/docs/19-linting.md +0 -512
  131. package/docs/decisions/001-v9-conventions-on-three-channels.md +0 -50
  132. package/docs/decisions/002-the-statique-channel-holds-only-what-upstream-does-not.md +0 -49
  133. package/docs/decisions/003-a-rendered-component-is-a-facet-on-vitest-browser-mode.md +0 -84
  134. package/docs/decisions/004-a-module-against-real-services-or-a-golden-is-the-integration-facet.md +0 -81
  135. package/docs/decisions/005-the-doubles-ladder-is-closed.md +0 -86
  136. package/docs/decisions/006-the-catalogue-reaches-a-file-by-its-role.md +0 -245
  137. package/docs/decisions/007-compose-mode-leaves-the-package.md +0 -53
  138. package/docs/decisions/008-vitest-5-node-24-and-the-native-seams-as-optional-peers.md +0 -75
  139. package/docs/decisions/_template.md +0 -22
  140. package/docs/reference/classes/Matcher.md +0 -120
  141. package/docs/reference/classes/ProcessHandle.md +0 -368
  142. package/docs/reference/functions/defineContract.md +0 -39
  143. package/docs/reference/functions/defineContracts.md +0 -36
  144. package/docs/reference/functions/disabled.md +0 -28
  145. package/docs/reference/functions/enabled.md +0 -20
  146. package/docs/reference/functions/focused.md +0 -26
  147. package/docs/reference/functions/mockOf.md +0 -79
  148. package/docs/reference/functions/postgres.md +0 -31
  149. package/docs/reference/functions/process.md +0 -33
  150. package/docs/reference/functions/redis.md +0 -28
  151. package/docs/reference/functions/required.md +0 -41
  152. package/docs/reference/functions/selected.md +0 -26
  153. package/docs/reference/functions/sqlite.md +0 -33
  154. package/docs/reference/functions/testId.md +0 -20
  155. package/docs/reference/functions/text.md +0 -40
  156. package/docs/reference/functions/valued.md +0 -28
  157. package/docs/reference/functions/waitUntil.md +0 -46
  158. package/docs/reference/functions/within.md +0 -29
  159. package/docs/reference/index.md +0 -196
  160. package/docs/reference/interfaces/BaseResult.md +0 -87
  161. package/docs/reference/interfaces/CallResult.md +0 -160
  162. package/docs/reference/interfaces/CaptureScope.md +0 -82
  163. package/docs/reference/interfaces/CliResult.md +0 -253
  164. package/docs/reference/interfaces/ContainerAccessor.md +0 -166
  165. package/docs/reference/interfaces/DirectoryAccessor.md +0 -33
  166. package/docs/reference/interfaces/FetchResult.md +0 -180
  167. package/docs/reference/interfaces/FilesystemAccessor.md +0 -46
  168. package/docs/reference/interfaces/HttpResult.md +0 -126
  169. package/docs/reference/interfaces/JsonAccessor.md +0 -46
  170. package/docs/reference/interfaces/PageResult.md +0 -356
  171. package/docs/reference/interfaces/RenderResult.md +0 -72
  172. package/docs/reference/interfaces/RenderedText.md +0 -110
  173. package/docs/reference/interfaces/ResponseAccessor.md +0 -47
  174. package/docs/reference/interfaces/ScreenResult.md +0 -128
  175. package/docs/reference/interfaces/TableAccessor.md +0 -26
  176. package/docs/reference/interfaces/TextAccessor.md +0 -96
  177. package/docs/reference/type-aliases/ApiHandle.md +0 -68
  178. package/docs/reference/type-aliases/ApiSpecification.md +0 -213
  179. package/docs/reference/type-aliases/ApiSpecificationOptions.md +0 -68
  180. package/docs/reference/type-aliases/BrowserConsoleMessage.md +0 -30
  181. package/docs/reference/type-aliases/BrowserLinkElement.md +0 -50
  182. package/docs/reference/type-aliases/BrowserMetaElement.md +0 -40
  183. package/docs/reference/type-aliases/BrowserOpenOptions.md +0 -87
  184. package/docs/reference/type-aliases/BrowserPage.md +0 -132
  185. package/docs/reference/type-aliases/BrowserPort.md +0 -51
  186. package/docs/reference/type-aliases/CliEnv.md +0 -11
  187. package/docs/reference/type-aliases/CliHandle.md +0 -80
  188. package/docs/reference/type-aliases/CliInput.md +0 -36
  189. package/docs/reference/type-aliases/CliOutput.md +0 -46
  190. package/docs/reference/type-aliases/CliPort.md +0 -58
  191. package/docs/reference/type-aliases/CliSpecification.md +0 -144
  192. package/docs/reference/type-aliases/CliSpecificationOptions.md +0 -134
  193. package/docs/reference/type-aliases/ComponentChain.md +0 -156
  194. package/docs/reference/type-aliases/ComponentScenario.md +0 -20
  195. package/docs/reference/type-aliases/ComponentUi.md +0 -47
  196. package/docs/reference/type-aliases/ComponentVisitor.md +0 -10
  197. package/docs/reference/type-aliases/ContainerPort.md +0 -113
  198. package/docs/reference/type-aliases/Contract.md +0 -68
  199. package/docs/reference/type-aliases/ContractInput.md +0 -13
  200. package/docs/reference/type-aliases/ContractRequest.md +0 -95
  201. package/docs/reference/type-aliases/ContractResponder.md +0 -23
  202. package/docs/reference/type-aliases/ContractResponse.md +0 -78
  203. package/docs/reference/type-aliases/ContractResponseValue.md +0 -13
  204. package/docs/reference/type-aliases/Contracts.md +0 -48
  205. package/docs/reference/type-aliases/DatabaseKeys.md +0 -16
  206. package/docs/reference/type-aliases/DatabasePort.md +0 -72
  207. package/docs/reference/type-aliases/DeviceOpenOptions.md +0 -46
  208. package/docs/reference/type-aliases/DevicePort.md +0 -51
  209. package/docs/reference/type-aliases/DeviceScreen.md +0 -32
  210. package/docs/reference/type-aliases/DeviceTimeouts.md +0 -39
  211. package/docs/reference/type-aliases/DockerSpecConfig.md +0 -43
  212. package/docs/reference/type-aliases/DomMount.md +0 -21
  213. package/docs/reference/type-aliases/ElementKind.md +0 -27
  214. package/docs/reference/type-aliases/ElementMatch.md +0 -74
  215. package/docs/reference/type-aliases/ElementOptions.md +0 -29
  216. package/docs/reference/type-aliases/ElementRef.md +0 -128
  217. package/docs/reference/type-aliases/ExecOptions.md +0 -37
  218. package/docs/reference/type-aliases/FileAccessor.md +0 -54
  219. package/docs/reference/type-aliases/HonoApp.md +0 -31
  220. package/docs/reference/type-aliases/HttpContractFilter.md +0 -49
  221. package/docs/reference/type-aliases/HttpResponseInit.md +0 -46
  222. package/docs/reference/type-aliases/HttpStreamInit.md +0 -58
  223. package/docs/reference/type-aliases/IntegrationHandle.md +0 -46
  224. package/docs/reference/type-aliases/IntegrationSpecification.md +0 -111
  225. package/docs/reference/type-aliases/IntegrationSpecificationOptions.md +0 -42
  226. package/docs/reference/type-aliases/Intercept.md +0 -19
  227. package/docs/reference/type-aliases/InterceptOptions.md +0 -28
  228. package/docs/reference/type-aliases/InterceptScope.md +0 -11
  229. package/docs/reference/type-aliases/IsolationStrategy.md +0 -75
  230. package/docs/reference/type-aliases/JobHandle.md +0 -34
  231. package/docs/reference/type-aliases/JobsHandle.md +0 -57
  232. package/docs/reference/type-aliases/JobsResult.md +0 -16
  233. package/docs/reference/type-aliases/JobsSpecification.md +0 -94
  234. package/docs/reference/type-aliases/JobsSpecificationOptions.md +0 -56
  235. package/docs/reference/type-aliases/LandmarkKind.md +0 -20
  236. package/docs/reference/type-aliases/LiterateRunFlags.md +0 -27
  237. package/docs/reference/type-aliases/LiterateServeRegistration.md +0 -70
  238. package/docs/reference/type-aliases/MatchFixtureOptions.md +0 -27
  239. package/docs/reference/type-aliases/MatchableRequest.md +0 -61
  240. package/docs/reference/type-aliases/MatcherKind.md +0 -34
  241. package/docs/reference/type-aliases/MobileBackendOptions.md +0 -28
  242. package/docs/reference/type-aliases/MobileElementKind.md +0 -14
  243. package/docs/reference/type-aliases/MobileElementMatch.md +0 -60
  244. package/docs/reference/type-aliases/MobileElementRef.md +0 -20
  245. package/docs/reference/type-aliases/MobileHandle.md +0 -65
  246. package/docs/reference/type-aliases/MobileScenario.md +0 -20
  247. package/docs/reference/type-aliases/MobileSpecification.md +0 -51
  248. package/docs/reference/type-aliases/MobileSpecificationOptions.md +0 -126
  249. package/docs/reference/type-aliases/MobileVisitor.md +0 -81
  250. package/docs/reference/type-aliases/MockOfOptions.md +0 -26
  251. package/docs/reference/type-aliases/MockPort.md +0 -10
  252. package/docs/reference/type-aliases/PinnedClock.md +0 -10
  253. package/docs/reference/type-aliases/PostgresOptions.md +0 -32
  254. package/docs/reference/type-aliases/ProcessOptions.md +0 -112
  255. package/docs/reference/type-aliases/RedisOptions.md +0 -20
  256. package/docs/reference/type-aliases/RenderSubject.md +0 -12
  257. package/docs/reference/type-aliases/ScreenNode.md +0 -67
  258. package/docs/reference/type-aliases/ServerPort.md +0 -36
  259. package/docs/reference/type-aliases/ServerResponse.md +0 -46
  260. package/docs/reference/type-aliases/ServerSpec.md +0 -21
  261. package/docs/reference/type-aliases/ServiceHandle.md +0 -216
  262. package/docs/reference/type-aliases/ServiceRecord.md +0 -12
  263. package/docs/reference/type-aliases/SpecDocument.md +0 -84
  264. package/docs/reference/type-aliases/SpecEnvToken.md +0 -21
  265. package/docs/reference/type-aliases/SpecFileAssertion.md +0 -27
  266. package/docs/reference/type-aliases/SpecFixture.md +0 -30
  267. package/docs/reference/type-aliases/SpecKind.md +0 -8
  268. package/docs/reference/type-aliases/SpecRun.md +0 -108
  269. package/docs/reference/type-aliases/SpecServeEntry.md +0 -40
  270. package/docs/reference/type-aliases/SpecStream.md +0 -32
  271. package/docs/reference/type-aliases/SpecificationConfig.md +0 -290
  272. package/docs/reference/type-aliases/SqliteOptions.md +0 -36
  273. package/docs/reference/type-aliases/SseEvent.md +0 -58
  274. package/docs/reference/type-aliases/StreamBody.md +0 -61
  275. package/docs/reference/type-aliases/TextFilter.md +0 -22
  276. package/docs/reference/type-aliases/VisitScenario.md +0 -20
  277. package/docs/reference/type-aliases/Visitor.md +0 -215
  278. package/docs/reference/type-aliases/WaitUntilOptions.md +0 -46
  279. package/docs/reference/type-aliases/WebsiteBackendOptions.md +0 -37
  280. package/docs/reference/type-aliases/WebsiteHandle.md +0 -51
  281. package/docs/reference/type-aliases/WebsiteSpecification.md +0 -118
  282. package/docs/reference/type-aliases/WebsiteSpecificationOptions.md +0 -40
  283. package/docs/reference/variables/anthropic.md +0 -19
  284. package/docs/reference/variables/banner.md +0 -10
  285. package/docs/reference/variables/button.md +0 -10
  286. package/docs/reference/variables/clock.md +0 -16
  287. package/docs/reference/variables/complementary.md +0 -10
  288. package/docs/reference/variables/component.md +0 -10
  289. package/docs/reference/variables/content.md +0 -10
  290. package/docs/reference/variables/contentinfo.md +0 -10
  291. package/docs/reference/variables/dialog.md +0 -10
  292. package/docs/reference/variables/field.md +0 -10
  293. package/docs/reference/variables/form.md +0 -10
  294. package/docs/reference/variables/heading.md +0 -10
  295. package/docs/reference/variables/http.md +0 -40
  296. package/docs/reference/variables/intercept.md +0 -11
  297. package/docs/reference/variables/link.md +0 -10
  298. package/docs/reference/variables/listitem.md +0 -10
  299. package/docs/reference/variables/main.md +0 -10
  300. package/docs/reference/variables/match.md +0 -8
  301. package/docs/reference/variables/navigation.md +0 -10
  302. package/docs/reference/variables/openai.md +0 -21
  303. package/docs/reference/variables/option.md +0 -17
  304. package/docs/reference/variables/region.md +0 -10
  305. package/docs/reference/variables/row.md +0 -10
  306. package/docs/reference/variables/search.md +0 -10
  307. package/docs/reference/variables/specification.md +0 -8
  308. package/docs/reference/variables/status.md +0 -10
  309. package/docs/reference/variables/table.md +0 -10
@@ -0,0 +1,306 @@
1
+ import { t as isRecord } from "./shared-json-shape.js";
2
+ import { n as refusal, t as invariant } from "./shared-refusal.js";
3
+ import { t as listenedPort } from "./shared-listened-port.js";
4
+ import { t as loadPeer } from "./shared-peer.js";
5
+ import { execSync } from "node:child_process";
6
+ import { once } from "node:events";
7
+ import { createServer } from "node:http";
8
+ import { text } from "node:stream/consumers";
9
+ import { hostname } from "node:os";
10
+ //#region src/services/containers/docker-cli.ts
11
+ const DEFAULT_TIMEOUT = 1e4;
12
+ /** How every refusal of a run that asked for Docker names a daemon that did not answer. */
13
+ const DOCKER_ABSENT = "no Docker daemon answered";
14
+ /** Docker-aware mode reads what the daemon answers: a run where none answers is refused, never passed. */
15
+ function requireDockerDaemon() {
16
+ try {
17
+ execSync("docker version --format \"{{.Server.Version}}\"", {
18
+ stdio: "ignore",
19
+ timeout: DEFAULT_TIMEOUT
20
+ });
21
+ } catch (error) {
22
+ throw new Error(refusal({
23
+ fix: "start Docker (Docker Desktop, OrbStack, colima or another) and run again",
24
+ found: `specification.cli({ docker }) asked for Docker, and ${DOCKER_ABSENT}`,
25
+ read: "docs/guides/cli-specs.md#docker-aware-mode",
26
+ why: "Docker-aware mode reads the containers a run spawned, so it needs a Docker daemon."
27
+ }), { cause: error });
28
+ }
29
+ }
30
+ function findContainersByLabel(key, value) {
31
+ try {
32
+ return execSync(`docker ps -aq -f label=${key}=${value}`, {
33
+ encoding: "utf8",
34
+ timeout: DEFAULT_TIMEOUT
35
+ }).split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
36
+ } catch {
37
+ return [];
38
+ }
39
+ }
40
+ /** A field of a value read off docker's JSON or a failed process: absent wherever the value does not hold it. */
41
+ function fieldOf(value, ...keys) {
42
+ if (typeof value !== "object" || value === null) return;
43
+ const key = keys.find((candidate) => candidate in value);
44
+ return key === void 0 ? void 0 : Reflect.get(value, key);
45
+ }
46
+ const streamOf = (error, key) => {
47
+ const stream = fieldOf(error, key);
48
+ return typeof stream === "string" ? stream : void 0;
49
+ };
50
+ function inspectContainer(id) {
51
+ const raw = execSync(`docker inspect ${id}`, {
52
+ encoding: "utf8",
53
+ timeout: DEFAULT_TIMEOUT
54
+ });
55
+ const parsed = JSON.parse(raw);
56
+ if (!Array.isArray(parsed)) return parsed;
57
+ return parsed[0];
58
+ }
59
+ function removeContainers(ids) {
60
+ if (ids.length === 0) return;
61
+ try {
62
+ execSync(`docker rm -f ${ids.join(" ")}`, {
63
+ encoding: "utf8",
64
+ stdio: "pipe",
65
+ timeout: DEFAULT_TIMEOUT
66
+ });
67
+ } catch {}
68
+ }
69
+ function containerLogs(id) {
70
+ try {
71
+ return execSync(`docker logs ${id}`, {
72
+ encoding: "utf8",
73
+ stdio: [
74
+ "ignore",
75
+ "pipe",
76
+ "pipe"
77
+ ],
78
+ timeout: DEFAULT_TIMEOUT
79
+ });
80
+ } catch (error) {
81
+ return streamOf(error, "stdout") ?? streamOf(error, "stderr") ?? "";
82
+ }
83
+ }
84
+ function readContainerFile(id, path) {
85
+ return execSync(`docker exec ${id} cat ${JSON.stringify(path)}`, {
86
+ encoding: "utf8",
87
+ timeout: DEFAULT_TIMEOUT
88
+ });
89
+ }
90
+ function execInContainer(id, argv) {
91
+ try {
92
+ const quoted = argv.map((a) => JSON.stringify(a)).join(" ");
93
+ return {
94
+ exitCode: 0,
95
+ stderr: "",
96
+ stdout: execSync(`docker exec ${id} ${quoted}`, {
97
+ encoding: "utf8",
98
+ stdio: [
99
+ "ignore",
100
+ "pipe",
101
+ "pipe"
102
+ ],
103
+ timeout: DEFAULT_TIMEOUT
104
+ })
105
+ };
106
+ } catch (error) {
107
+ const status = fieldOf(error, "status");
108
+ return {
109
+ exitCode: typeof status === "number" ? status : 1,
110
+ stderr: streamOf(error, "stderr") ?? (error instanceof Error ? error.message : ""),
111
+ stdout: streamOf(error, "stdout") ?? ""
112
+ };
113
+ }
114
+ }
115
+ //#endregion
116
+ //#region src/services/containers/run-containers.ts
117
+ function canonical(value) {
118
+ return isRecord(value) ? Object.fromEntries(Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, entry]) => [key, canonical(entry)])) : value;
119
+ }
120
+ function keyOf(request) {
121
+ return JSON.stringify(canonical(request));
122
+ }
123
+ var RunContainers = class {
124
+ started = /* @__PURE__ */ new Map();
125
+ create;
126
+ ready;
127
+ /** `ready`'s rejection is the one answer every request gets, and no container is created. */
128
+ constructor(create, ready = async () => {}) {
129
+ this.create = create;
130
+ this.ready = ready;
131
+ }
132
+ async acquire(request) {
133
+ const key = keyOf(request);
134
+ let pending = this.started.get(key);
135
+ if (pending === void 0) {
136
+ pending = this.start(key, request);
137
+ this.started.set(key, pending);
138
+ }
139
+ const container = await pending;
140
+ return {
141
+ host: container.getHost(),
142
+ key,
143
+ port: container.getMappedPort(request.port)
144
+ };
145
+ }
146
+ async logs(key, since) {
147
+ const pending = this.started.get(key);
148
+ if (pending === void 0) return "";
149
+ return await (await pending).getLogs(since);
150
+ }
151
+ async stop() {
152
+ const pending = [...this.started.values()];
153
+ this.started.clear();
154
+ await Promise.allSettled(pending.map(async (starting) => {
155
+ await (await starting).stop();
156
+ }));
157
+ }
158
+ async start(key, request) {
159
+ try {
160
+ await this.ready();
161
+ const container = this.create(request);
162
+ await container.start();
163
+ return container;
164
+ } catch (error) {
165
+ this.started.delete(key);
166
+ throw error;
167
+ }
168
+ }
169
+ };
170
+ function field(value, name) {
171
+ if (typeof value !== "object" || value === null) return;
172
+ return Reflect.get(value, name);
173
+ }
174
+ function isContainerRequest(value) {
175
+ return typeof field(value, "image") === "string" && typeof field(value, "port") === "number";
176
+ }
177
+ async function respond(containers, request, response) {
178
+ const url = new URL(request.url ?? "/", "http://run");
179
+ try {
180
+ if (request.method === "POST" && url.pathname === "/containers") {
181
+ const asked = JSON.parse(await text(request));
182
+ if (!isContainerRequest(asked)) throw invariant(`a worker asked for ${JSON.stringify(asked)}, no container request`);
183
+ const address = await containers.acquire(asked);
184
+ response.writeHead(200, { "content-type": "application/json" });
185
+ response.end(JSON.stringify(address));
186
+ return;
187
+ }
188
+ if (request.method === "GET" && url.pathname === "/logs") {
189
+ response.writeHead(200, { "content-type": "text/plain" });
190
+ const key = url.searchParams.get("key") ?? "";
191
+ const since = url.searchParams.get("since");
192
+ const moment = since === null ? void 0 : new Date(Number(since));
193
+ response.end(await containers.logs(key, moment));
194
+ return;
195
+ }
196
+ response.writeHead(404).end();
197
+ } catch (error) {
198
+ response.writeHead(500, { "content-type": "application/json" });
199
+ response.end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
200
+ }
201
+ }
202
+ async function serveContainers(containers) {
203
+ const server = createServer((request, response) => {
204
+ respond(containers, request, response);
205
+ });
206
+ return {
207
+ close: async () => {
208
+ server.close();
209
+ await once(server, "close");
210
+ },
211
+ url: `http://127.0.0.1:${await listenedPort(server, { host: "127.0.0.1" })}`
212
+ };
213
+ }
214
+ //#endregion
215
+ //#region src/services/containers/testcontainers.adapter.ts
216
+ const CONTAINER_LABEL = "com.jterrazz.test";
217
+ const REUSED_LABEL = "com.jterrazz.test.reuse";
218
+ /** `<host>:<pid>`: a sweep removes the container once that process is dead, whatever reaper session holds it. */
219
+ const OWNER_LABEL = "com.jterrazz.test.owner";
220
+ function processOwner() {
221
+ return `${hostname()}:${process.pid}`;
222
+ }
223
+ /** Never on CI, where a run starts from nothing and leaves nothing. */
224
+ function reuseEnabled(env) {
225
+ const onCi = env.CI !== void 0 && env.CI !== "" && env.CI !== "false";
226
+ return env.TESTCONTAINERS_REUSE_ENABLE === "true" && !onCi;
227
+ }
228
+ /** A reused container names no owner: its definition hash must not change with the process asking. */
229
+ function containerLabels(reuse, owner) {
230
+ return reuse ? {
231
+ [CONTAINER_LABEL]: "true",
232
+ [REUSED_LABEL]: "true"
233
+ } : {
234
+ [CONTAINER_LABEL]: "true",
235
+ [OWNER_LABEL]: owner
236
+ };
237
+ }
238
+ async function loadTestcontainers() {
239
+ return await loadPeer("testcontainers", "a declared service", async () => await import("testcontainers"));
240
+ }
241
+ var TestcontainersAdapter = class {
242
+ image;
243
+ containerPort;
244
+ env;
245
+ command;
246
+ tmpfs;
247
+ reuse;
248
+ container = null;
249
+ peer;
250
+ constructor(options, peer = loadTestcontainers) {
251
+ this.peer = peer;
252
+ this.image = options.image;
253
+ this.containerPort = options.port;
254
+ this.env = options.env ?? {};
255
+ this.command = options.command;
256
+ this.tmpfs = options.tmpfs;
257
+ this.reuse = options.reuse ?? reuseEnabled(process.env);
258
+ }
259
+ async start() {
260
+ const { GenericContainer, Wait } = await this.peer();
261
+ let builder = new GenericContainer(this.image).withExposedPorts(this.containerPort).withLabels(containerLabels(this.reuse, processOwner()));
262
+ for (const [key, value] of Object.entries(this.env)) builder = builder.withEnvironment({ [key]: value });
263
+ if (this.command !== void 0) builder = builder.withCommand(this.command);
264
+ if (this.tmpfs !== void 0) builder = builder.withTmpFs(this.tmpfs);
265
+ if (this.image.startsWith("postgres")) builder = builder.withWaitStrategy(Wait.forLogMessage(/database system is ready to accept connections/u, 2));
266
+ if (this.reuse) builder = builder.withReuse();
267
+ this.container = await builder.start();
268
+ }
269
+ async stop() {
270
+ if (this.container && !this.reuse) {
271
+ await this.container.stop();
272
+ this.container = null;
273
+ }
274
+ }
275
+ getMappedPort(containerPort) {
276
+ if (!this.container) throw invariant("a container was read before it started");
277
+ return this.container.getMappedPort(containerPort);
278
+ }
279
+ getHost() {
280
+ if (!this.container) throw invariant("a container was read before it started");
281
+ return this.container.getHost();
282
+ }
283
+ getConnectionString() {
284
+ return `${this.getHost()}:${this.getMappedPort(this.containerPort)}`;
285
+ }
286
+ async getLogs(since) {
287
+ if (!this.container) return "";
288
+ const stream = await this.container.logs(since === void 0 ? void 0 : { since: since.getTime() / 1e3 });
289
+ return await new Promise((resolve) => {
290
+ let output = "";
291
+ stream.on("data", (chunk) => {
292
+ output += Buffer.isBuffer(chunk) ? chunk.toString() : String(chunk);
293
+ });
294
+ stream.on("end", () => {
295
+ resolve(output);
296
+ });
297
+ setTimeout(() => {
298
+ resolve(output);
299
+ }, 1e3);
300
+ });
301
+ }
302
+ };
303
+ //#endregion
304
+ export { field as a, containerLogs as c, findContainersByLabel as d, inspectContainer as f, requireDockerDaemon as h, RunContainers as i, execInContainer as l, removeContainers as m, REUSED_LABEL as n, serveContainers as o, readContainerFile as p, TestcontainersAdapter as r, DOCKER_ABSENT as s, OWNER_LABEL as t, fieldOf as u };
305
+
306
+ //# sourceMappingURL=shared-testcontainers.adapter.js.map
@@ -0,0 +1,55 @@
1
+ //#region lint/kit/project/tokens.ts
2
+ const TOKEN_KINDS = [
3
+ "any",
4
+ "base64",
5
+ "date",
6
+ "duration",
7
+ "email",
8
+ "float",
9
+ "hex",
10
+ "int",
11
+ "ip",
12
+ "iso8601",
13
+ "number",
14
+ "path",
15
+ "port",
16
+ "semver",
17
+ "sha",
18
+ "string",
19
+ "time",
20
+ "ulid",
21
+ "url",
22
+ "uuid",
23
+ "workdir"
24
+ ];
25
+ const VALID_TOKEN = /^[A-Za-z][A-Za-z0-9]*(?:#[\w.-]+)?$/u;
26
+ const BRACE_BLOCK = /\{\{[^{}]*\}\}/gu;
27
+ const LEADING_WORD = /^[A-Za-z][A-Za-z0-9]*/u;
28
+ const KNOWN = new Set(TOKEN_KINDS);
29
+ function verdictOf(inner) {
30
+ if (VALID_TOKEN.test(inner)) {
31
+ const [kind = ""] = inner.split("#");
32
+ return KNOWN.has(kind) ? "known" : "unknown";
33
+ }
34
+ const [word = ""] = LEADING_WORD.exec(inner) ?? [];
35
+ return KNOWN.has(word) ? "malformed" : void 0;
36
+ }
37
+ function tokensOf(text, verdict) {
38
+ return text.split("\n").flatMap((lineText, index) => [...lineText.matchAll(BRACE_BLOCK)].flatMap(([token]) => verdictOf(token.slice(2, -2)) === verdict ? [{
39
+ line: index + 1,
40
+ token
41
+ }] : []));
42
+ }
43
+ function findUnknownTokens(text) {
44
+ return tokensOf(text, "unknown");
45
+ }
46
+ function findMalformedRefs(text) {
47
+ return tokensOf(text, "malformed");
48
+ }
49
+ function findKnownTokens(text) {
50
+ return tokensOf(text, "known");
51
+ }
52
+ //#endregion
53
+ export { findUnknownTokens as i, findKnownTokens as n, findMalformedRefs as r, TOKEN_KINDS as t };
54
+
55
+ //# sourceMappingURL=shared-tokens.js.map
@@ -0,0 +1,119 @@
1
+ import { LineCounter, Scalar, Scalar as Scalar$1, isMap, isNode, isNode as isNode$1, isPair, isScalar, isSeq, parseDocument, visit } from "yaml";
2
+ //#region lint/kit/project/yaml-document.ts
3
+ function nodePairs(map) {
4
+ return map.items.filter((pair) => isNode(pair.key) && (pair.value === null || isNode(pair.value)));
5
+ }
6
+ function nodeItems(seq) {
7
+ return seq.items.filter((item) => isNode(item));
8
+ }
9
+ const KEY_LINE = /^(?<indent> +)(?:(?:- )?[A-Za-z_$'"][^\n]*:|- [[{])/u;
10
+ function detectIndent(text) {
11
+ let smallest = 0;
12
+ for (const line of text.split("\n")) {
13
+ const indent = KEY_LINE.exec(line)?.groups?.indent;
14
+ if (indent !== void 0 && (smallest === 0 || indent.length < smallest)) smallest = indent.length;
15
+ }
16
+ return smallest === 0 ? 2 : smallest;
17
+ }
18
+ const DEEPEST_STATABLE_STEP = 9;
19
+ function stateIndentation(written, ctx) {
20
+ if (!/^[|>][1-9]/u.test(written)) return written;
21
+ const step = ctx.indentStep.length;
22
+ if (step > DEEPEST_STATABLE_STEP) throw new Error(`A block scalar indented by ${step} spaces cannot state its indentation: YAML writes that indicator as a single digit, so ${DEEPEST_STATABLE_STEP} spaces is the deepest step a document may be written with.`);
23
+ return `${written[0]}${step}${written.slice(2)}`;
24
+ }
25
+ function isScalarTag(tag) {
26
+ return typeof tag !== "string" && tag.collection === void 0;
27
+ }
28
+ function statingItsIndentation(tag) {
29
+ const write = tag.stringify;
30
+ if (write === void 0) return tag;
31
+ return {
32
+ ...tag,
33
+ stringify: (item, ctx, onComment, onChompKeep) => stateIndentation(write(item, ctx, onComment, onChompKeep), ctx)
34
+ };
35
+ }
36
+ function parseYamlSource(text) {
37
+ const lineCounter = new LineCounter();
38
+ return {
39
+ document: parseDocument(text, {
40
+ customTags: (tags) => tags.map((tag) => isScalarTag(tag) ? statingItsIndentation(tag) : tag),
41
+ lineCounter
42
+ }),
43
+ indent: detectIndent(text),
44
+ lineAt: (offset) => lineCounter.linePos(offset).line,
45
+ text
46
+ };
47
+ }
48
+ function yamlSyntaxErrors(source) {
49
+ return source.document.errors.map((error) => ({
50
+ line: source.lineAt(error.pos[0]),
51
+ message: error.message
52
+ }));
53
+ }
54
+ function blockScalar(text) {
55
+ const scalar = new Scalar(text);
56
+ scalar.type = Scalar.BLOCK_LITERAL;
57
+ return scalar;
58
+ }
59
+ function lineStart(text, offset) {
60
+ return text.lastIndexOf("\n", offset - 1) + 1;
61
+ }
62
+ function afterOwner(text, offset) {
63
+ return text.slice(0, offset).trimEnd().length;
64
+ }
65
+ function indentOf(text, offset) {
66
+ const line = text.slice(lineStart(text, offset));
67
+ return line.length - line.trimStart().length;
68
+ }
69
+ function flowCollections(text) {
70
+ const found = [];
71
+ const take = (node) => {
72
+ if (node.flow !== true) return;
73
+ const { range } = node;
74
+ if (range === null || range === void 0) return;
75
+ const [start, end] = range;
76
+ const from = afterOwner(text, start);
77
+ found.push({
78
+ ownerIndent: indentOf(text, from),
79
+ range: [from, end],
80
+ text: text.slice(from, end),
81
+ value: JSON.stringify(node.toJSON())
82
+ });
83
+ return visit.SKIP;
84
+ };
85
+ visit(parseDocument(text), {
86
+ Map: (_key, node) => take(node),
87
+ Seq: (_key, node) => take(node)
88
+ });
89
+ return found;
90
+ }
91
+ function restoreUntouchedFlow(rendered, text) {
92
+ const sources = flowCollections(text);
93
+ const taken = /* @__PURE__ */ new Set();
94
+ const splices = [];
95
+ for (const target of flowCollections(rendered)) {
96
+ const at = sources.findIndex((candidate, index) => !taken.has(index) && candidate.value === target.value && candidate.ownerIndent === target.ownerIndent);
97
+ const source = sources[at];
98
+ if (source === void 0) continue;
99
+ taken.add(at);
100
+ splices.push({
101
+ range: target.range,
102
+ text: source.text
103
+ });
104
+ }
105
+ let out = rendered;
106
+ for (const splice of splices.toReversed()) out = out.slice(0, splice.range[0]) + splice.text + out.slice(splice.range[1]);
107
+ return out;
108
+ }
109
+ /** `lineWidth: 0`: a golden is compared byte for byte, so nothing folds a long line. */
110
+ function renderYamlSource(source) {
111
+ return restoreUntouchedFlow(source.document.toString({
112
+ indent: source.indent,
113
+ lineWidth: 0
114
+ }), source.text);
115
+ }
116
+ //#endregion
117
+ export { isPair as a, nodeItems as c, renderYamlSource as d, yamlSyntaxErrors as f, isNode$1 as i, nodePairs as l, blockScalar as n, isScalar as o, isMap as r, isSeq as s, Scalar$1 as t, parseYamlSource as u };
118
+
119
+ //# sourceMappingURL=shared-yaml-document.js.map
@@ -0,0 +1,2 @@
1
+ import { C as StubRequest, E as StubResponseValue, S as StreamBody, T as StubResponse, _ as StubInput, a as openai, b as defineStubs, c as SseEvent, d as anthropic, f as TextFilter, g as Stub, i as InterceptScope, l as http, n as Intercept, o as HttpResponseInit, r as InterceptOptions, s as HttpStreamInit, t as intercept, u as HttpStubFilter, v as Stubs, w as StubResponder, x as MatchableRequest, y as defineStub } from "./shared-index.stubs.js";
2
+ export { type HttpResponseInit, type HttpStreamInit, type HttpStubFilter, type Intercept, type InterceptOptions, type InterceptScope, type MatchableRequest, type SseEvent, type StreamBody, type Stub, type StubInput, type StubRequest, type StubResponder, type StubResponse, type StubResponseValue, type Stubs, type TextFilter, anthropic, defineStub, defineStubs, http, intercept, openai };