@jterrazz/test 18.2.0 → 18.3.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @jterrazz/test
2
2
 
3
- A testing framework on vitest for whole products: HTTP APIs, background jobs, CLIs, websites, running deployments, native mobile apps, rendered components, modules against real databases, and the lint rules a project ships. You declare what a test needs (Postgres, a built binary, a real Chromium, an iOS simulator), and the framework starts it, isolates it per worker and cleans it up. Each test is one sentence: a few setups, one action, and the whole result compared with `expect()`.
3
+ A testing framework on vitest for whole products: HTTP APIs, background jobs, CLIs, websites, native mobile apps, rendered components, modules against real databases, and the lint rules a project ships. You declare what a test needs (Postgres, a built binary, a real Chromium, an iOS simulator), and the framework starts it, isolates it per worker and cleans it up. Each test is one sentence: a few setups, one action, and the whole result compared with `expect()`.
4
4
 
5
5
  ```typescript
6
6
  // specs/api/users/list/shape.spec.ts
@@ -52,8 +52,7 @@ An ES module project on Node 24, vitest 5 and `@jterrazz/typescript` 11 is requi
52
52
  | [Component](docs/guides/component-specs.md) | A React component, hook or DOM function in a real Chromium | `component.render()` |
53
53
  | [Website](docs/guides/website-specs.md) | A served page, fetched or driven in a browser | `specification.website()` |
54
54
  | [Mobile](docs/guides/mobile-specs.md) | A native app on an iOS simulator | `specification.mobile()` |
55
- | [Deployment](docs/guides/deployment-specs.md) | A running deployment, probed over the network, no browser | `specification.deployment()` |
56
- | [API](docs/guides/api-specs.md) | An HTTP app, through complete requests | `specification.api()` |
55
+ | [API](docs/guides/api-specs.md) | An HTTP app, in this process or deployed at a `url` | `specification.api()` |
57
56
  | [Job](docs/guides/job-specs.md) | A pipeline triggered by name | `specification.job()` |
58
57
  | [CLI](docs/guides/cli-specs.md) | A binary in a fresh working directory, often as a YAML document | `specification.cli()` |
59
58
  | [Lint](docs/guides/lint-specs.md) | The rules a project ships, over fixture trees | `specification.lint()` |
@@ -3211,11 +3211,10 @@ async function waitUntil(predicate, options = {}) {
3211
3211
  }
3212
3212
  //#endregion
3213
3213
  //#region src/index.browser.ts
3214
- /** The eight constructors, present and refusing in a page. */
3214
+ /** The seven constructors, present and refusing in a page. */
3215
3215
  const specification = {
3216
3216
  api: () => refuse("specification.api()"),
3217
3217
  cli: () => refuse("specification.cli()"),
3218
- deployment: () => refuse("specification.deployment()"),
3219
3218
  integration: () => refuse("specification.integration()"),
3220
3219
  job: () => refuse("specification.job()"),
3221
3220
  lint: () => refuse("specification.lint()"),
package/dist/checker.js CHANGED
@@ -1,5 +1,5 @@
1
- import { n as parsedJson } from "./shared-json-shape.js";
2
1
  import { t as CATALOGUE_CHAPTER } from "./shared-chapter.js";
2
+ import { n as parsedJson } from "./shared-json-shape.js";
3
3
  import { i as findUnknownTokens, n as findKnownTokens, r as findMalformedRefs, t as TOKEN_KINDS } from "./shared-tokens.js";
4
4
  import { a as RUN_KEYS, c as isRelativePath, o as SPEC_EXTENSION, s as SpecSyntaxError, t as DOCUMENT_KEYS } from "./shared-spec-grammar.js";
5
5
  import { i as literalEnd, n as argumentsOf, o as openersAt, r as closingOf, s as skipString, t as argumentSpans } from "./shared-source-scan.js";
package/dist/config.d.ts CHANGED
@@ -22,7 +22,7 @@ type TestSettings = {
22
22
  specifications?: readonly string[];
23
23
  };
24
24
  /** The helpers a project is built by, named by their specification. */
25
- type TestSpecification = 'api' | 'cli' | 'component' | 'deployment' | 'integration' | 'job' | 'lint' | 'mobile' | 'unit' | 'website';
25
+ type TestSpecification = 'api' | 'cli' | 'component' | 'integration' | 'job' | 'lint' | 'mobile' | 'unit' | 'website';
26
26
  /** What a declared project states beyond its derived one: the global setups it runs, the options its helper takes, and why. */
27
27
  type TestProject = {
28
28
  readonly reason: string;
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
- import { t as isRecord } from "./shared-json-shape.js";
2
1
  import { t as CATALOGUE_CHAPTER } from "./shared-chapter.js";
2
+ import { t as isRecord } from "./shared-json-shape.js";
3
3
  import { n as specificationModules, t as derivedProjects } from "./shared-derived-projects.js";
4
4
  import { t as TEST_SECTION } from "./shared-test-section.js";
5
5
  import { n as recommendedRules, t as consumerRows } from "./shared-manifest.js";
@@ -13,7 +13,6 @@ var standard_default = defineStandard({ test: {
13
13
  "api",
14
14
  "cli",
15
15
  "component",
16
- "deployment",
17
16
  "integration",
18
17
  "job",
19
18
  "lint",
package/dist/index.d.ts CHANGED
@@ -307,6 +307,163 @@ declare class ResponseAccessor {
307
307
  constructor(response: ServerResponse, testDir: string, captures?: CaptureScope, recording?: ResponseRecording);
308
308
  }
309
309
  //#endregion
310
+ //#region src/specifications/api/deployed/tls-facts.d.ts
311
+ /** The certificate an HTTPS exchange was presented, and what the client made of it. */
312
+ type TlsFacts = {
313
+ /** The names the certificate is valid for (its subjectAltName), each without its `DNS:` or `IP Address:` prefix. */
314
+ readonly altNames: readonly string[];
315
+ /** The code the trust check refused with (`DEPTH_ZERO_SELF_SIGNED_CERT`, `CERT_HAS_EXPIRED`, `ERR_TLS_CERT_ALTNAME_INVALID` ...), undefined when trusted. */
316
+ readonly authorizationError: string | undefined;
317
+ /** Whether the certificate chains to a trusted authority and covers the URL's host. */
318
+ readonly authorized: boolean;
319
+ /** Whole days from the exchange to `validTo`, negative once it has expired. */
320
+ readonly daysRemaining: number;
321
+ /** The issuer's common name, or its organisation when it states none. */
322
+ readonly issuer: string;
323
+ /** The TLS version negotiated (`TLSv1.3`). */
324
+ readonly protocol: string | undefined;
325
+ /** The subject's common name; empty when it states none. */
326
+ readonly subject: string;
327
+ readonly validFrom: Date;
328
+ readonly validTo: Date;
329
+ /** Whether the certificate is valid for `host`, wildcards read as a client reads them. */
330
+ covers: (host: string) => boolean;
331
+ };
332
+ //#endregion
333
+ //#region src/specifications/api/deployed/exchange.result.d.ts
334
+ /** What one request to a deployed api hands back: the response, or why none came, and the certificate it came over; no table and no disk, which a deployed api keeps to itself. */
335
+ declare class ExchangeResult {
336
+ private readonly answer;
337
+ private readonly recording;
338
+ private readonly scope;
339
+ private readonly testDir;
340
+ /** The certificate an https request was presented and the trust check's verdict; undefined over http, or when no handshake completed. */
341
+ readonly tls: TlsFacts | undefined;
342
+ constructor(options: {
343
+ recording: ResponseRecording;
344
+ response: ServerResponse;
345
+ testDir: string;
346
+ tls: TlsFacts | undefined;
347
+ });
348
+ /** The whole response (status, headers, body), or `unreachable: <reason>`, compared whole: `toMatch(<.http text>)` or `toMatch(file(...))`. */
349
+ get response(): ResponseAccessor;
350
+ }
351
+ //#endregion
352
+ //#region src/chain/action.d.ts
353
+ type SliceReader = <Slice>(capability: {
354
+ readonly initial: Slice;
355
+ readonly name: string;
356
+ }) => Slice;
357
+ type Action<Name extends string, Args extends readonly unknown[], Result, Signature extends ChainSignature = ChainSignature, Needs extends object = Record<never, never>, Config extends ChainConfig = ChainConfig> = {
358
+ readonly accessors: readonly MatrixRow[];
359
+ readonly targets?: readonly MatrixRow[];
360
+ readonly kind: 'action';
361
+ readonly name: Name;
362
+ readonly options?: readonly ActionOption<string>[];
363
+ readonly row: MatrixRow;
364
+ /** A type alone, never set at runtime: `ChainOf` reads it. */
365
+ readonly signature?: Signature;
366
+ readonly verbs?: readonly MatrixRow[];
367
+ prepare?(args: Args, read: SliceReader): Promise<{
368
+ readonly workDir: null | string;
369
+ }> | {
370
+ readonly workDir: null | string;
371
+ };
372
+ perform(args: Args, read: SliceReader, adapters: Needs, run: Run<Config>): Promise<Result>;
373
+ };
374
+ type AnyAction = Action<string, readonly unknown[], unknown, ChainSignature, object>;
375
+ //#endregion
376
+ //#region src/specifications/api/deployed/request.action.d.ts
377
+ type ExchangeSignature = ChainSignature & {
378
+ readonly chain: {
379
+ /** Send a GET to a URL, written whole or as a path from the specification's `url`, and resolve with what came back. */
380
+ get: (target: string) => Promise<ExchangeResult>;
381
+ /** Send a complete request: its `.http` text written in the test, or `file('./__requests__/<name>.http')`; its first line names the URL whole or a path. */
382
+ request: (source: DiskFile<'.http'> | string) => Promise<ExchangeResult>;
383
+ };
384
+ };
385
+ //#endregion
386
+ //#region src/specifications/api/deployed/connect.capability.d.ts
387
+ type ConnectChain<Self> = {
388
+ /** Open the socket on this address instead of the URL's host and port, as curl's `--connect-to`: the Host header and the TLS server name stay the URL's; a later call wins. */
389
+ connect: (address: string) => Self;
390
+ };
391
+ interface ConnectSignature extends ChainSignature {
392
+ readonly chain: ConnectChain<this['self']>;
393
+ }
394
+ //#endregion
395
+ //#region src/chain/context/headers.capability.d.ts
396
+ type HeadersMethod<Self> = (headers: Record<string, string>) => Self;
397
+ type HeadersChain<Self> = {
398
+ /** Set HTTP headers for the exchange. Multiple calls merge. */
399
+ headers: HeadersMethod<Self>;
400
+ };
401
+ interface HeadersSignature extends ChainSignature {
402
+ readonly chain: HeadersChain<this['self']>;
403
+ }
404
+ //#endregion
405
+ //#region src/chain/define-specification.d.ts
406
+ type Composition = {
407
+ readonly actions: readonly AnyAction[];
408
+ readonly capabilities: readonly (AnyCapability | Sharing)[];
409
+ readonly options: Readonly<Record<string, MatrixRow>>;
410
+ };
411
+ //#endregion
412
+ //#region src/chain/chain.d.ts
413
+ type Names<List extends readonly {
414
+ readonly name: string;
415
+ }[]> = List[number]['name'];
416
+ type ContextOf<C extends Composition> = C['capabilities'][number] extends (infer Member) ? Member extends Capability<string, infer _Slice, infer _Args, infer _Signature, infer _Needs, infer Key> ? Key : never : never;
417
+ type SharingOf<C extends Composition, Self> = 'with' extends Names<C['capabilities']> ? {
418
+ with: (context: Pick<ChainContext, ContextOf<C>>) => Self;
419
+ } : unknown;
420
+ type MethodsOf<Member, P extends SpecificationParams, Self> = Member extends {
421
+ readonly signature?: infer Signature;
422
+ } ? Signature extends ChainSignature ? (Signature & {
423
+ readonly params: P;
424
+ readonly self: Self;
425
+ })['chain'] : never : never;
426
+ type Methods<C extends Composition, P extends SpecificationParams, Self> = Intersect<MethodsOf<C['actions'][number] | C['capabilities'][number], P, Self>>;
427
+ type ChainOf<C extends Composition, P extends SpecificationParams, Self> = Pick<Methods<C, P, Self>, Extract<Names<C['actions']> | Names<C['capabilities']>, keyof Methods<C, P, Self>>> & SharingOf<C, Self>;
428
+ //#endregion
429
+ //#region src/specifications/api/deployed/deployed.composition.d.ts
430
+ declare const composition$8: {
431
+ readonly actions: readonly [Action<"request", [source: string | DiskFile<".http">], ExchangeResult, ExchangeSignature, Record<never, never>, ApiDeployedConfig>, Action<"get", [target: string], ExchangeResult, ExchangeSignature, Record<never, never>, ApiDeployedConfig>];
432
+ readonly capabilities: readonly [Capability<"connect", string | null, [address: string], ConnectSignature, Record<never, never>, never, ChainConfig>, Capability<"headers", Readonly<Record<string, string>>, [headers: Record<string, string>], HeadersSignature, Record<never, never>, "headers", ChainConfig>, Sharing];
433
+ readonly options: {
434
+ ca: {
435
+ group: "Constructor option";
436
+ name: string;
437
+ probe: string;
438
+ };
439
+ insecure: {
440
+ group: "Constructor option";
441
+ name: string;
442
+ probe: string;
443
+ };
444
+ recordedHeaders: {
445
+ group: "Constructor option";
446
+ name: string;
447
+ probe: string;
448
+ };
449
+ timeout: {
450
+ group: "Constructor option";
451
+ name: string;
452
+ probe: string;
453
+ };
454
+ url: {
455
+ group: "Constructor option";
456
+ name: string;
457
+ probe: string;
458
+ };
459
+ };
460
+ };
461
+ /** The chain `specification.api({ url })` hands out: requests to the deployed api, over the network. */
462
+ interface ApiDeployedSpecification extends ChainOf<typeof composition$8, {
463
+ databaseKey: string;
464
+ services: Record<string, unknown>;
465
+ }, ApiDeployedSpecification> {}
466
+ //#endregion
310
467
  //#region src/specifications/api/server/server.port.d.ts
311
468
  /** What a request carries beside its method, path and body. */
312
469
  type ServerRequestOptions = {
@@ -347,30 +504,6 @@ type HonoApp = {
347
504
  routes?: readonly TableEntry[];
348
505
  };
349
506
  //#endregion
350
- //#region src/chain/action.d.ts
351
- type SliceReader = <Slice>(capability: {
352
- readonly initial: Slice;
353
- readonly name: string;
354
- }) => Slice;
355
- type Action<Name extends string, Args extends readonly unknown[], Result, Signature extends ChainSignature = ChainSignature, Needs extends object = Record<never, never>, Config extends ChainConfig = ChainConfig> = {
356
- readonly accessors: readonly MatrixRow[];
357
- readonly targets?: readonly MatrixRow[];
358
- readonly kind: 'action';
359
- readonly name: Name;
360
- readonly options?: readonly ActionOption<string>[];
361
- readonly row: MatrixRow;
362
- /** A type alone, never set at runtime: `ChainOf` reads it. */
363
- readonly signature?: Signature;
364
- readonly verbs?: readonly MatrixRow[];
365
- prepare?(args: Args, read: SliceReader): Promise<{
366
- readonly workDir: null | string;
367
- }> | {
368
- readonly workDir: null | string;
369
- };
370
- perform(args: Args, read: SliceReader, adapters: Needs, run: Run<Config>): Promise<Result>;
371
- };
372
- type AnyAction = Action<string, readonly unknown[], unknown, ChainSignature, object>;
373
- //#endregion
374
507
  //#region src/specifications/api/request/route.d.ts
375
508
  type RouteParamNames<Path extends string> = Path extends `${infer Route}?${string}` ? RouteParamNames<Route> : Path extends `${string}/:${infer Rest}` ? Rest extends `${infer Name}/${infer Tail}` ? Name | RouteParamNames<`/${Tail}`> : Rest : never;
376
509
  type RouteOptions<Path extends string> = [RouteParamNames<Path>] extends [never] ? {
@@ -415,16 +548,6 @@ interface ClockSignature extends ChainSignature {
415
548
  readonly chain: ClockChain<this['self']>;
416
549
  }
417
550
  //#endregion
418
- //#region src/chain/context/headers.capability.d.ts
419
- type HeadersMethod<Self> = (headers: Record<string, string>) => Self;
420
- type HeadersChain<Self> = {
421
- /** Set HTTP headers for the exchange. Multiple calls merge. */
422
- headers: HeadersMethod<Self>;
423
- };
424
- interface HeadersSignature extends ChainSignature {
425
- readonly chain: HeadersChain<this['self']>;
426
- }
427
- //#endregion
428
551
  //#region src/stubs/intercept/intercept.port.d.ts
429
552
  type InterceptPort = {
430
553
  /** Refuse the setup when this adapter cannot serve a stub at all. */
@@ -453,32 +576,8 @@ type SeedPort = {
453
576
  readonly target: (database?: string) => DatabasePort;
454
577
  };
455
578
  //#endregion
456
- //#region src/chain/define-specification.d.ts
457
- type Composition = {
458
- readonly actions: readonly AnyAction[];
459
- readonly capabilities: readonly (AnyCapability | Sharing)[];
460
- readonly options: Readonly<Record<string, MatrixRow>>;
461
- };
462
- //#endregion
463
- //#region src/chain/chain.d.ts
464
- type Names<List extends readonly {
465
- readonly name: string;
466
- }[]> = List[number]['name'];
467
- type ContextOf<C extends Composition> = C['capabilities'][number] extends (infer Member) ? Member extends Capability<string, infer _Slice, infer _Args, infer _Signature, infer _Needs, infer Key> ? Key : never : never;
468
- type SharingOf<C extends Composition, Self> = 'with' extends Names<C['capabilities']> ? {
469
- with: (context: Pick<ChainContext, ContextOf<C>>) => Self;
470
- } : unknown;
471
- type MethodsOf<Member, P extends SpecificationParams, Self> = Member extends {
472
- readonly signature?: infer Signature;
473
- } ? Signature extends ChainSignature ? (Signature & {
474
- readonly params: P;
475
- readonly self: Self;
476
- })['chain'] : never : never;
477
- type Methods<C extends Composition, P extends SpecificationParams, Self> = Intersect<MethodsOf<C['actions'][number] | C['capabilities'][number], P, Self>>;
478
- type ChainOf<C extends Composition, P extends SpecificationParams, Self> = Pick<Methods<C, P, Self>, Extract<Names<C['actions']> | Names<C['capabilities']>, keyof Methods<C, P, Self>>> & SharingOf<C, Self>;
479
- //#endregion
480
579
  //#region src/specifications/api/api.composition.d.ts
481
- declare const composition$8: {
580
+ declare const composition$7: {
482
581
  readonly actions: readonly [Action<"request", [source: string | DiskFile<".http">], HttpResult, RequestSignature, {
483
582
  server: ServerPort;
484
583
  }, ChainConfig>, Action<"get", [path: string, options?: RouteOptionsAny], HttpResult, RequestSignature, {
@@ -521,14 +620,14 @@ declare const composition$8: {
521
620
  };
522
621
  };
523
622
  /** The chain `specification.api()` hands out; the app answers in this process (`server-sees-declared-services`). */
524
- interface ApiSpecification<DatabaseKey extends string = string> extends ChainOf<typeof composition$8, {
623
+ interface ApiSpecification<DatabaseKey extends string = string> extends ChainOf<typeof composition$7, {
525
624
  databaseKey: DatabaseKey;
526
625
  services: Record<string, unknown>;
527
626
  }, ApiSpecification<DatabaseKey>> {}
528
627
  //#endregion
529
628
  //#region src/specifications/api/api.handle.d.ts
530
- /** Options for {@link startApi | specification.api}. */
531
- type ApiSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
629
+ /** The app built in this process, from the services the specification starts. */
630
+ type ApiServedOptions<Services extends ServiceRecord = ServiceRecord> = {
532
631
  /** Project root override; by default the nearest `package.json` above the specification file (`no-redundant-root`). */
533
632
  root?: string;
534
633
  /** The app factory: receives the started services record, returns the Hono app. */
@@ -536,7 +635,30 @@ type ApiSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
536
635
  /** Named infrastructure record: the keys are the `database` vocabulary, and name the init-script folder. */
537
636
  services?: Services;
538
637
  };
539
- /** What `specification.api()` returns: `const { api, cleanup, docker } = ...` (`no-runner-alias`). */
638
+ /** The api already deployed, met over the network at its URL. */
639
+ type ApiDeployedOptions = {
640
+ /** A certificate authority trusted beside the ones node trusts: its PEM text, a value like any string. */
641
+ ca?: string;
642
+ /** Accept a certificate the trust check refuses (self-signed, expired, another host's); `result.tls` still says why. Default `false`. */
643
+ insecure?: boolean;
644
+ /** The headers update mode records into a golden that states none yet, those the response carries. Default `['content-type', 'location']`. */
645
+ recordedHeaders?: readonly string[];
646
+ /** The milliseconds one request may take, connection to last byte, before it reads `unreachable: timeout`. Default `5000`. */
647
+ timeout?: number;
648
+ /** The deployed api's base URL: a path is read from it (`.get('/health')`), a URL written whole reaches any host. */
649
+ url: string;
650
+ };
651
+ type Absent<Options> = { [Key in keyof Options]?: never; };
652
+ /** Options for {@link startApi | specification.api}: `server` or `url`, exclusive by type. */
653
+ type ApiSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = (Absent<ApiDeployedOptions> & ApiServedOptions<Services>) | (Absent<ApiServedOptions> & ApiDeployedOptions);
654
+ type ApiDeployedConfig = ChainConfig & {
655
+ baseUrl: string;
656
+ ca: string | undefined;
657
+ insecure: boolean;
658
+ recording: ResponseRecording;
659
+ timeout: number;
660
+ };
661
+ /** What `specification.api({ server })` returns: `const { api, cleanup, docker } = ...` (`no-runner-alias`). */
540
662
  type ApiHandle<DatabaseKey extends string = string> = {
541
663
  api: ApiSpecification<DatabaseKey>;
542
664
  /** Stop all infrastructure started by this specification. */
@@ -544,7 +666,13 @@ type ApiHandle<DatabaseKey extends string = string> = {
544
666
  /** Read a running container by id. */
545
667
  docker: (containerId: string) => ContainerAccessor;
546
668
  };
547
- declare function startApi<Services extends ServiceRecord>(options: ApiSpecificationOptions<Services>): Promise<ApiHandle<DatabaseKeys<Services>>>;
669
+ /** What `specification.api({ url })` returns: `const { api, cleanup } = ...`; it starts nothing, so `cleanup` releases nothing and there is no container to read. */
670
+ type ApiDeployedHandle = {
671
+ api: ApiDeployedSpecification;
672
+ cleanup: () => Promise<void>;
673
+ };
674
+ declare function startApi(options: Absent<ApiServedOptions> & ApiDeployedOptions): Promise<ApiDeployedHandle>;
675
+ declare function startApi<Services extends ServiceRecord = ServiceRecord>(options: Absent<ApiDeployedOptions> & ApiServedOptions<Services>): Promise<ApiHandle<DatabaseKeys<Services>>>;
548
676
  //#endregion
549
677
  //#region src/services/startup/startup-report.d.ts
550
678
  type AppInfo = {
@@ -733,7 +861,7 @@ interface PrepareSignature extends ChainSignature {
733
861
  }
734
862
  //#endregion
735
863
  //#region src/specifications/cli/cli.composition.d.ts
736
- declare const composition$7: {
864
+ declare const composition$6: {
737
865
  readonly actions: readonly [Action<"exec", [args?: string | string[], options?: ExecOptions], CliResult, ExecSignature, {
738
866
  command: CliPort;
739
867
  }, CliConfig>, Action<"run", [document: DiskFile<".spec.yaml">, options?: LiterateRunFlags], CliResult, RunSignature$1, Record<never, never>, CliConfig>];
@@ -806,7 +934,7 @@ declare const composition$7: {
806
934
  };
807
935
  };
808
936
  /** The chain `specification.cli()` hands out: a binary run in a fresh, empty working directory, in its own process. */
809
- interface CliSpecification<DatabaseKey extends string = string> extends ChainOf<typeof composition$7, {
937
+ interface CliSpecification<DatabaseKey extends string = string> extends ChainOf<typeof composition$6, {
810
938
  databaseKey: DatabaseKey;
811
939
  services: Record<string, unknown>;
812
940
  }, CliSpecification<DatabaseKey>> {}
@@ -874,131 +1002,6 @@ type CliHandle<DatabaseKey extends string = string> = {
874
1002
  };
875
1003
  declare function startCli<Services extends ServiceRecord>(bin: string, options?: CliSpecificationOptions<Services>): Promise<CliHandle<DatabaseKeys<Services>>>;
876
1004
  //#endregion
877
- //#region src/specifications/deployment/exchange/tls-facts.d.ts
878
- /** The certificate an HTTPS exchange was presented, and what the client made of it. */
879
- type TlsFacts = {
880
- /** The names the certificate is valid for (its subjectAltName), each without its `DNS:` or `IP Address:` prefix. */
881
- readonly altNames: readonly string[];
882
- /** The code the trust check refused with (`DEPTH_ZERO_SELF_SIGNED_CERT`, `CERT_HAS_EXPIRED`, `ERR_TLS_CERT_ALTNAME_INVALID` ...), undefined when trusted. */
883
- readonly authorizationError: string | undefined;
884
- /** Whether the certificate chains to a trusted authority and covers the URL's host. */
885
- readonly authorized: boolean;
886
- /** Whole days from the exchange to `validTo`, negative once it has expired. */
887
- readonly daysRemaining: number;
888
- /** The issuer's common name, or its organisation when it states none. */
889
- readonly issuer: string;
890
- /** The TLS version negotiated (`TLSv1.3`). */
891
- readonly protocol: string | undefined;
892
- /** The subject's common name; empty when it states none. */
893
- readonly subject: string;
894
- readonly validFrom: Date;
895
- readonly validTo: Date;
896
- /** Whether the certificate is valid for `host`, wildcards read as a client reads them. */
897
- covers: (host: string) => boolean;
898
- };
899
- //#endregion
900
- //#region src/specifications/deployment/exchange/exchange.result.d.ts
901
- /** What one exchange with a deployment hands back: the response, or why none came, and the certificate it was presented. */
902
- declare class ExchangeResult extends BaseResult {
903
- private readonly answer;
904
- private readonly recording;
905
- /** The certificate an https exchange was presented and the trust check's verdict; undefined over http, or when no handshake completed. */
906
- readonly tls: TlsFacts | undefined;
907
- constructor(options: BaseResultOptions & {
908
- recording: ResponseRecording;
909
- response: ServerResponse;
910
- tls: TlsFacts | undefined;
911
- });
912
- /** The whole response (status, headers, body), or `unreachable: <reason>`, compared whole: `toMatch(<.http text>)` or `toMatch(file(...))`. */
913
- get response(): ResponseAccessor;
914
- }
915
- //#endregion
916
- //#region src/specifications/deployment/exchange/request.action.d.ts
917
- type ExchangeSignature = ChainSignature & {
918
- readonly chain: {
919
- /** Send a GET to a URL, written whole or as a path from the specification's `url`, and resolve with what came back. */
920
- get: (target: string) => Promise<ExchangeResult>;
921
- /** Send a complete request: its `.http` text written in the test, or `file('./__requests__/<name>.http')`; its first line names the URL whole or a path. */
922
- request: (source: DiskFile<'.http'> | string) => Promise<ExchangeResult>;
923
- };
924
- };
925
- //#endregion
926
- //#region src/specifications/deployment/exchange/connect.capability.d.ts
927
- type ConnectChain<Self> = {
928
- /** Open the socket on this address instead of the URL's host and port, as curl's `--connect-to`: the Host header and the TLS server name stay the URL's; a later call wins. */
929
- connect: (address: string) => Self;
930
- };
931
- interface ConnectSignature extends ChainSignature {
932
- readonly chain: ConnectChain<this['self']>;
933
- }
934
- //#endregion
935
- //#region src/specifications/deployment/deployment.composition.d.ts
936
- declare const composition$6: {
937
- readonly actions: readonly [Action<"request", [source: string | DiskFile<".http">], ExchangeResult, ExchangeSignature, Record<never, never>, DeploymentConfig>, Action<"get", [target: string], ExchangeResult, ExchangeSignature, Record<never, never>, DeploymentConfig>];
938
- readonly capabilities: readonly [Capability<"connect", string | null, [address: string], ConnectSignature, Record<never, never>, never, ChainConfig>, Capability<"headers", Readonly<Record<string, string>>, [headers: Record<string, string>], HeadersSignature, Record<never, never>, "headers", ChainConfig>, Sharing];
939
- readonly options: {
940
- ca: {
941
- group: "Constructor option";
942
- name: string;
943
- probe: string;
944
- };
945
- insecure: {
946
- group: "Constructor option";
947
- name: string;
948
- probe: string;
949
- };
950
- recordedHeaders: {
951
- group: "Constructor option";
952
- name: string;
953
- probe: string;
954
- };
955
- timeout: {
956
- group: "Constructor option";
957
- name: string;
958
- probe: string;
959
- };
960
- url: {
961
- group: "Constructor option";
962
- name: string;
963
- probe: string;
964
- };
965
- };
966
- };
967
- /** The chain `specification.deployment()` hands out: one HTTP exchange with a running deployment, over the network. */
968
- interface DeploymentSpecification extends ChainOf<typeof composition$6, {
969
- databaseKey: string;
970
- services: Record<string, unknown>;
971
- }, DeploymentSpecification> {}
972
- //#endregion
973
- //#region src/specifications/deployment/deployment.handle.d.ts
974
- /** Options for {@link startDeployment | specification.deployment}. */
975
- type DeploymentSpecificationOptions = {
976
- /** A certificate authority trusted beside the ones node trusts: its PEM text, a value like any string. */
977
- ca?: string;
978
- /** Accept a certificate the trust check refuses (self-signed, expired, another host's); `result.tls` still says why. Default `false`. */
979
- insecure?: boolean;
980
- /** The headers update mode records into a golden that states none yet, those the response carries. Default `['content-type', 'location']`. */
981
- recordedHeaders?: readonly string[];
982
- /** The milliseconds one exchange may take, connection to last byte, before it reads `unreachable: timeout`. Default `5000`. */
983
- timeout?: number;
984
- /** The base URL a path is read from (`.get('/health')`); a URL written whole needs none. */
985
- url?: string;
986
- };
987
- type DeploymentConfig = ChainConfig & {
988
- baseUrl: string | undefined;
989
- ca: string | undefined;
990
- insecure: boolean;
991
- recording: ResponseRecording;
992
- timeout: number;
993
- };
994
- /** What `specification.deployment()` returns: `const { deployment, cleanup } = ...` (`no-runner-alias`). */
995
- type DeploymentHandle = {
996
- /** Starts nothing, so releases nothing: passed to `afterAll` like every specification's. */
997
- cleanup: () => Promise<void>;
998
- deployment: DeploymentSpecification;
999
- };
1000
- declare function startDeployment(options?: DeploymentSpecificationOptions): Promise<DeploymentHandle>;
1001
- //#endregion
1002
1005
  //#region src/specifications/integration/call.result.d.ts
1003
1006
  type CallOutcome = {
1004
1007
  error: unknown;
@@ -1690,11 +1693,10 @@ type WebsiteHandle = {
1690
1693
  declare function startWebsite<Services extends ServiceRecord>(options: WebsiteSpecificationOptions<Services>): Promise<WebsiteHandle>;
1691
1694
  //#endregion
1692
1695
  //#region src/specifications/specification.d.ts
1693
- /** The eight constructors, and only eight: the framework's whole entry surface. */
1696
+ /** The seven constructors, and only seven: the framework's whole entry surface. */
1694
1697
  type Specification = {
1695
1698
  api: typeof startApi;
1696
1699
  cli: typeof startCli;
1697
- deployment: typeof startDeployment;
1698
1700
  integration: typeof startIntegration;
1699
1701
  job: typeof startJob;
1700
1702
  lint: typeof startLint;
@@ -2051,5 +2053,5 @@ declare module 'vitest' {
2051
2053
  }
2052
2054
  }
2053
2055
  //#endregion
2054
- export { type ApiHandle, type ApiSpecification, type ApiSpecificationOptions, type BaseResult, type BrowserConsoleMessage, type BrowserLinkElement, type BrowserMetaElement, type BrowserOpenOptions, type BrowserPage, type BrowserPort, type CallResult, type CaptureScope, type CliEnv, type CliHandle, type CliInput, type CliOutput, type CliPort, type CliResult, type CliSpecification, type CliSpecificationOptions, type ComponentChain, type ComponentScenario, type ComponentUi, type ComponentVisitor, type ContainerAccessor, type DeploymentHandle, type DeploymentSpecification, type DeploymentSpecificationOptions, type DeviceOpenOptions, type DevicePort, type DeviceScreen, type DeviceTimeouts, type DirectoryAccessor, type DiskDirectory, type DiskFile, type DiskTarget, type DockerSpecConfig, type DomMount, type ElementKind, type ElementMatch, type ExchangeResult, type ExecOptions, type FetchResult, type FileAccessor, type FileAt, type FilesystemAccessor, type HonoApp, type HttpResult, type IntegrationHandle, type IntegrationSpecification, type IntegrationSpecificationOptions, type Job, type JobHandle, type JobResult, type JobSpecification, type JobSpecificationOptions, type JsonAccessor, type LandmarkKind, type LintConfig, type LintHandle, type LintResult, type LintRules, type LintRunOptions, type LintSpecification, type LintSpecificationOptions, type LiterateRunFlags, type LiterateServeRegistration, type MatchFixtureOptions, Matcher, type MatcherKind, type MobileBackendOptions, type MobileElementKind, type MobileElementMatch, type MobileHandle, type MobileScenario, type MobileSpecification, type MobileSpecificationOptions, type MobileVisitor, type MockOfOptions, type MockPort, type PackedPackage, type PageResult, type PinnedClock, type PositionedCases, type PositionedRuleTester, type PrepareStep, type RelativePath, type RenderResult, type RenderSubject, type RenderedText, type ResponseAccessor, type ScreenNode, type ScreenResult, type ServerPort, type ServerRequestOptions, type ServerResponse, type ServerSpec, type SpecDocument, type SpecEnvToken, type SpecFileAssertion, type SpecFixture, type SpecRun, type SpecServeEntry, type SpecStream, type TableAccessor, type Target, type TargetOptions, type TextAccessor, type TlsFacts, type VisitScenario, type WaitUntilOptions, type WebsiteBackendOptions, type WebsiteHandle, type WebsiteSpecification, type WebsiteSpecificationOptions, type WebsiteVisitor, directory, file, match };
2056
+ export { type ApiDeployedHandle, type ApiDeployedOptions, type ApiDeployedSpecification, type ApiHandle, type ApiServedOptions, type ApiSpecification, type ApiSpecificationOptions, type BaseResult, type BrowserConsoleMessage, type BrowserLinkElement, type BrowserMetaElement, type BrowserOpenOptions, type BrowserPage, type BrowserPort, type CallResult, type CaptureScope, type CliEnv, type CliHandle, type CliInput, type CliOutput, type CliPort, type CliResult, type CliSpecification, type CliSpecificationOptions, type ComponentChain, type ComponentScenario, type ComponentUi, type ComponentVisitor, type ContainerAccessor, type DeviceOpenOptions, type DevicePort, type DeviceScreen, type DeviceTimeouts, type DirectoryAccessor, type DiskDirectory, type DiskFile, type DiskTarget, type DockerSpecConfig, type DomMount, type ElementKind, type ElementMatch, type ExchangeResult, type ExecOptions, type FetchResult, type FileAccessor, type FileAt, type FilesystemAccessor, type HonoApp, type HttpResult, type IntegrationHandle, type IntegrationSpecification, type IntegrationSpecificationOptions, type Job, type JobHandle, type JobResult, type JobSpecification, type JobSpecificationOptions, type JsonAccessor, type LandmarkKind, type LintConfig, type LintHandle, type LintResult, type LintRules, type LintRunOptions, type LintSpecification, type LintSpecificationOptions, type LiterateRunFlags, type LiterateServeRegistration, type MatchFixtureOptions, Matcher, type MatcherKind, type MobileBackendOptions, type MobileElementKind, type MobileElementMatch, type MobileHandle, type MobileScenario, type MobileSpecification, type MobileSpecificationOptions, type MobileVisitor, type MockOfOptions, type MockPort, type PackedPackage, type PageResult, type PinnedClock, type PositionedCases, type PositionedRuleTester, type PrepareStep, type RelativePath, type RenderResult, type RenderSubject, type RenderedText, type ResponseAccessor, type ScreenNode, type ScreenResult, type ServerPort, type ServerRequestOptions, type ServerResponse, type ServerSpec, type SpecDocument, type SpecEnvToken, type SpecFileAssertion, type SpecFixture, type SpecRun, type SpecServeEntry, type SpecStream, type TableAccessor, type Target, type TargetOptions, type TextAccessor, type TlsFacts, type VisitScenario, type WaitUntilOptions, type WebsiteBackendOptions, type WebsiteHandle, type WebsiteSpecification, type WebsiteSpecificationOptions, type WebsiteVisitor, directory, file, match };
2055
2057
  //# sourceMappingURL=index.d.ts.map