@specific.dev/spectest 0.38.0 → 0.41.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/dist/components/k3s.js +1 -24
- package/dist/components/supabase.d.ts +87 -27
- package/dist/components/supabase.js +352 -69
- package/dist/daemon.d.ts +38 -0
- package/dist/daemon.js +405 -946
- package/dist/harness/build-context.d.ts +82 -0
- package/dist/harness/build-context.js +113 -0
- package/dist/harness/buildkit-progress.d.ts +37 -0
- package/dist/harness/buildkit-progress.js +66 -0
- package/dist/harness/container-run.d.ts +89 -0
- package/dist/harness/container-run.js +118 -0
- package/dist/harness/file-mounts.d.ts +91 -0
- package/dist/harness/file-mounts.js +119 -0
- package/dist/harness/hostmatch.d.ts +65 -0
- package/dist/harness/hostmatch.js +108 -0
- package/dist/harness/http-proxy.d.ts +62 -0
- package/dist/harness/http-proxy.js +104 -0
- package/dist/harness/ingress-table.d.ts +148 -0
- package/dist/harness/ingress-table.js +129 -0
- package/dist/harness/log-delta.d.ts +54 -0
- package/dist/harness/log-delta.js +83 -0
- package/dist/harness/main.d.ts +47 -0
- package/dist/harness/main.js +164 -0
- package/dist/harness/methods.d.ts +54 -0
- package/dist/harness/methods.js +65 -0
- package/dist/harness/names-registry.d.ts +63 -0
- package/dist/harness/names-registry.js +90 -0
- package/dist/harness/protocol.d.ts +88 -0
- package/dist/harness/protocol.js +96 -0
- package/dist/harness/ready-poll.d.ts +47 -0
- package/dist/harness/ready-poll.js +67 -0
- package/dist/harness/service-graph.d.ts +29 -0
- package/dist/harness/service-graph.js +92 -0
- package/dist/harness/volume-paths.d.ts +70 -0
- package/dist/harness/volume-paths.js +81 -0
- package/dist/index.d.ts +3 -3
- package/dist/ingress.d.ts +1 -1
- package/dist/inspect.d.ts +23 -0
- package/dist/inspect.js +65 -0
- package/dist/resolver.js +5 -8
- package/dist/vendor/rrweb-plugin-console-record.umd.js +521 -0
- package/dist/vendor/rrweb-record.min.js +5061 -0
- package/package.json +7 -1
- package/src/aws-sigv4.ts +218 -0
- package/src/browser.ts +2040 -0
- package/src/components/aws.ts +554 -0
- package/src/components/email.ts +398 -0
- package/src/components/expo.ts +167 -0
- package/src/components/index.ts +81 -0
- package/src/components/k3s.ts +2061 -0
- package/src/components/postgres.ts +132 -0
- package/src/components/replayFake.ts +1015 -0
- package/src/components/s3.ts +132 -0
- package/src/components/supabase.ts +1699 -0
- package/src/daemon.ts +5489 -0
- package/src/harness/build-context.test.ts +0 -0
- package/src/harness/build-context.ts +146 -0
- package/src/harness/buildkit-progress.test.ts +98 -0
- package/src/harness/buildkit-progress.ts +74 -0
- package/src/harness/container-run.test.ts +209 -0
- package/src/harness/container-run.ts +158 -0
- package/src/harness/file-mounts.test.ts +185 -0
- package/src/harness/file-mounts.ts +145 -0
- package/src/harness/hostmatch.test.ts +148 -0
- package/src/harness/hostmatch.ts +109 -0
- package/src/harness/http-proxy.test.ts +156 -0
- package/src/harness/http-proxy.ts +119 -0
- package/src/harness/ingress-rebind.test.ts +125 -0
- package/src/harness/ingress-table.test.ts +172 -0
- package/src/harness/ingress-table.ts +186 -0
- package/src/harness/log-delta.test.ts +125 -0
- package/src/harness/log-delta.ts +100 -0
- package/src/harness/main.test.ts +211 -0
- package/src/harness/main.ts +196 -0
- package/src/harness/methods.test.ts +63 -0
- package/src/harness/methods.ts +92 -0
- package/src/harness/names-registry.test.ts +137 -0
- package/src/harness/names-registry.ts +108 -0
- package/src/harness/protocol.test.ts +148 -0
- package/src/harness/protocol.ts +163 -0
- package/src/harness/ready-poll.test.ts +172 -0
- package/src/harness/ready-poll.ts +93 -0
- package/src/harness/service-graph.test.ts +97 -0
- package/src/harness/service-graph.ts +97 -0
- package/src/harness/volume-paths.test.ts +102 -0
- package/src/harness/volume-paths.ts +112 -0
- package/src/ids.ts +89 -0
- package/src/index.ts +2725 -0
- package/src/ingress.ts +305 -0
- package/src/inspect.ts +739 -0
- package/src/locator.ts +716 -0
- package/src/mobile.ts +133 -0
- package/src/record-secrets.ts +41 -0
- package/src/recorder.ts +846 -0
- package/src/redis.ts +202 -0
- package/src/replay-bundle.ts +108 -0
- package/src/resolver.ts +348 -0
- package/src/s3.ts +333 -0
- package/src/sql.ts +243 -0
- package/src/terminal.ts +740 -0
- package/src/url-match.ts +67 -0
- package/src/vendor/rrweb-plugin-console-record.umd.js +521 -0
- package/src/vendor/rrweb-record.min.js +5061 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { ServiceDefinition } from "../index.js";
|
|
2
|
+
import { S3Client, type S3ClientLike } from "../s3.js";
|
|
3
|
+
|
|
4
|
+
export interface S3Options {
|
|
5
|
+
/** HTTP port the S3 API is served on. Default `9090`. */
|
|
6
|
+
port?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Buckets to create on first boot. The backing server's own `initialBuckets`
|
|
9
|
+
* env is unreliable across versions, so the component creates them in `setup`
|
|
10
|
+
* (a plain CreateBucket `PUT`) — captured into the warm snapshot, never
|
|
11
|
+
* re-run on warm starts/forks.
|
|
12
|
+
*/
|
|
13
|
+
buckets?: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Default bucket the `helpers.client` targets (so `client.file("k")` resolves
|
|
16
|
+
* without a per-call `{ bucket }`). Defaults to the first entry of `buckets`.
|
|
17
|
+
*/
|
|
18
|
+
bucket?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Hostnames to additionally serve the store at over **HTTPS** (CA-trusted),
|
|
21
|
+
* via the daemon's TLS-terminating reverse proxy. Optional — defaults to none;
|
|
22
|
+
* the store is always reachable at `http://<key>:<port>` regardless. Set this
|
|
23
|
+
* only when the app under test hardcodes a specific prod S3 endpoint it can't
|
|
24
|
+
* be told to override (`https://<bucket>.s3.amazonaws.com`, a provider's
|
|
25
|
+
* storage host): the daemon mints a cert for each host and proxies to the
|
|
26
|
+
* store's plain HTTP. The store ignores SigV4, so the Host rewrite is harmless.
|
|
27
|
+
*/
|
|
28
|
+
hosts?: string[];
|
|
29
|
+
/** Access key id the helper client signs with. The store ignores SigV4, so
|
|
30
|
+
* any non-empty value works; default `"s3"`. */
|
|
31
|
+
accessKeyId?: string;
|
|
32
|
+
/** Secret key the helper client signs with (ignored by the store). Default
|
|
33
|
+
* `"s3"`. */
|
|
34
|
+
secretAccessKey?: string;
|
|
35
|
+
/** Region for the helper client. Default `"us-east-1"`. */
|
|
36
|
+
region?: string;
|
|
37
|
+
/** Extra environment variables forwarded to the container. */
|
|
38
|
+
env?: Record<string, string>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Helpers an `s3(...)` service exposes on `ctx.svc.<name>`. */
|
|
42
|
+
export interface S3Helpers {
|
|
43
|
+
/** An instrumented {@link S3Client} pointed at this store (path-style) — each
|
|
44
|
+
* object op lands on the test event log and its result comes back
|
|
45
|
+
* provenance-wrapped, so `expect(...)` on a read links to the op. */
|
|
46
|
+
client: S3ClientLike;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Backing image, pinned internally (not user-configurable). adobe/s3mock 5.1.0
|
|
50
|
+
// is the current release; avoid exactly 5.0.0, which crashed at startup on
|
|
51
|
+
// Java 25 (`NoClassDefFoundError: KotlinBuiltIns$2`) — fixed in 5.1.0.
|
|
52
|
+
const S3_IMAGE = "adobe/s3mock:5.1.0";
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A ready-to-use, S3-compatible object store (backed by
|
|
56
|
+
* [`adobe/s3mock`](https://github.com/adobe/S3Mock)), with an instrumented S3
|
|
57
|
+
* client on `ctx.svc.<key>.client`. Drop into `environment.services`:
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* import { s3 } from "@specific.dev/spectest/components";
|
|
61
|
+
*
|
|
62
|
+
* services: {
|
|
63
|
+
* storage: s3({ buckets: ["uploads"] }),
|
|
64
|
+
* },
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* Tests get an instrumented S3 client at `ctx.svc.<key>.client`:
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* await ctx.svc.storage.client.write("hello.txt", "hi there");
|
|
71
|
+
* const body = await ctx.svc.storage.client.file("hello.txt").text();
|
|
72
|
+
* expect(body).toBe("hi there"); // nests under the s3 read step
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* The store skips SigV4 validation and is path-style only (what S3-compatible
|
|
76
|
+
* clients use), so it stands in for AWS S3, R2, Spaces, etc. without credential
|
|
77
|
+
* plumbing. If — and only if — the app under test hardcodes a specific prod S3
|
|
78
|
+
* endpoint, pass `hosts` to also serve the store there over a CA-trusted cert:
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* // app hardcodes https://files.example.com — serve it there too:
|
|
82
|
+
* storage: s3({ hosts: ["files.example.com"] }),
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export function s3(opts: S3Options = {}) {
|
|
86
|
+
const port = opts.port ?? 9090;
|
|
87
|
+
const buckets = opts.buckets ?? [];
|
|
88
|
+
const defaultBucket = opts.bucket ?? buckets[0];
|
|
89
|
+
const accessKeyId = opts.accessKeyId ?? "s3";
|
|
90
|
+
const secretAccessKey = opts.secretAccessKey ?? "s3";
|
|
91
|
+
const region = opts.region ?? "us-east-1";
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
image: { type: "registry", reference: S3_IMAGE },
|
|
95
|
+
ports: [port],
|
|
96
|
+
...(opts.env ? { env: opts.env } : {}),
|
|
97
|
+
...(opts.hosts
|
|
98
|
+
? { tls: opts.hosts.map((hostname) => ({ hostname, port })) }
|
|
99
|
+
: {}),
|
|
100
|
+
// GET / returns the ListBuckets XML with 200 once the store is up.
|
|
101
|
+
readyCheck: { type: "http" as const, port, path: "/", timeoutSecs: 60 },
|
|
102
|
+
helpers: ({ name }: { name: string }): S3Helpers => ({
|
|
103
|
+
client: new S3Client({
|
|
104
|
+
endpoint: `http://${name}:${port}`,
|
|
105
|
+
region,
|
|
106
|
+
accessKeyId,
|
|
107
|
+
secretAccessKey,
|
|
108
|
+
...(defaultBucket ? { bucket: defaultBucket } : {}),
|
|
109
|
+
// Path-style (Bun's default) — the store is path-style only.
|
|
110
|
+
}),
|
|
111
|
+
}),
|
|
112
|
+
...(buckets.length > 0
|
|
113
|
+
? {
|
|
114
|
+
setup: async ({ name }: { name: string }) => {
|
|
115
|
+
for (const bucket of buckets) {
|
|
116
|
+
// CreateBucket is a plain `PUT` on the bucket root; the store
|
|
117
|
+
// returns 200 (or 409 if it already exists — idempotent enough to
|
|
118
|
+
// ignore).
|
|
119
|
+
const res = await fetch(`http://${name}:${port}/${bucket}`, {
|
|
120
|
+
method: "PUT",
|
|
121
|
+
});
|
|
122
|
+
if (!res.ok && res.status !== 409) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`s3: failed to create bucket ${bucket}: ${res.status}`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
: {}),
|
|
131
|
+
} satisfies ServiceDefinition<S3Helpers>;
|
|
132
|
+
}
|