@sponson/sim 0.4.0 → 0.5.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 +5 -0
- package/dist/auth.d.ts +60 -0
- package/dist/auth.js +195 -0
- package/dist/auth.js.map +1 -0
- package/dist/bin.js +9 -14
- package/dist/bin.js.map +1 -1
- package/dist/chaos.d.ts +4 -0
- package/dist/chaos.js +2 -0
- package/dist/chaos.js.map +1 -1
- package/dist/cli.d.ts +29 -0
- package/dist/cli.js +99 -0
- package/dist/cli.js.map +1 -0
- package/dist/demo.d.ts +39 -0
- package/dist/demo.js +168 -0
- package/dist/demo.js.map +1 -0
- package/dist/graphql.d.ts +22 -0
- package/dist/graphql.js +36 -0
- package/dist/graphql.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +43 -4
- package/dist/provider.js +12 -6
- package/dist/provider.js.map +1 -1
- package/dist/routes/algolia.d.ts +37 -0
- package/dist/routes/algolia.js +83 -0
- package/dist/routes/algolia.js.map +1 -0
- package/dist/routes/aws.d.ts +43 -0
- package/dist/routes/aws.js +211 -0
- package/dist/routes/aws.js.map +1 -0
- package/dist/routes/cloudflare.d.ts +80 -0
- package/dist/routes/cloudflare.js +176 -0
- package/dist/routes/cloudflare.js.map +1 -0
- package/dist/routes/digitalocean.d.ts +58 -0
- package/dist/routes/digitalocean.js +158 -0
- package/dist/routes/digitalocean.js.map +1 -0
- package/dist/routes/fly.d.ts +22 -0
- package/dist/routes/fly.js +113 -0
- package/dist/routes/fly.js.map +1 -0
- package/dist/routes/launchdarkly.d.ts +98 -0
- package/dist/routes/launchdarkly.js +213 -0
- package/dist/routes/launchdarkly.js.map +1 -0
- package/dist/routes/netlify.d.ts +126 -0
- package/dist/routes/netlify.js +347 -0
- package/dist/routes/netlify.js.map +1 -0
- package/dist/routes/planetscale.d.ts +95 -0
- package/dist/routes/planetscale.js +234 -0
- package/dist/routes/planetscale.js.map +1 -0
- package/dist/routes/railway.d.ts +24 -0
- package/dist/routes/railway.js +112 -0
- package/dist/routes/railway.js.map +1 -0
- package/dist/routes/rest.d.ts +138 -0
- package/dist/routes/rest.js +462 -0
- package/dist/routes/rest.js.map +1 -0
- package/dist/routes/supabase.d.ts +103 -0
- package/dist/routes/supabase.js +234 -0
- package/dist/routes/supabase.js.map +1 -0
- package/dist/routes/xata.d.ts +57 -0
- package/dist/routes/xata.js +115 -0
- package/dist/routes/xata.js.map +1 -0
- package/dist/server.js +71 -12
- package/dist/server.js.map +1 -1
- package/dist/state.d.ts +12 -0
- package/dist/state.js +13 -1
- package/dist/state.js.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -2,4 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A local fake cloud for testing [Sponson](https://github.com/MishaBear94/Sponson#readme): subsets of the Vercel, Neon and Clerk APIs with chaos injection, started in-process with `startSim()` or from the command line with `sponson-sim`.
|
|
4
4
|
|
|
5
|
+
- `npx --yes @sponson/sim --demo sponson-demo`: the fake cloud plus a ready demo repository, and the commands to run
|
|
6
|
+
next (the "Try it in 60 seconds" section of Sponson's README).
|
|
7
|
+
- `npx --yes @sponson/sim --port 4777`: just the fake cloud.
|
|
8
|
+
- `eval "$(npx --yes @sponson/sim env)"`: point `sponson` at a sim already running on that port.
|
|
9
|
+
|
|
5
10
|
Documentation: <https://sponson.mintlify.site>. Source and issues: [GitHub](https://github.com/MishaBear94/Sponson).
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { IncomingHttpHeaders } from "node:http";
|
|
2
|
+
import { Reply, type AuthRequest } from "./provider.js";
|
|
3
|
+
/** What a SigV4 signature must be made with: the access keys the "account" has, and the expected scope. */
|
|
4
|
+
export interface SigV4Config {
|
|
5
|
+
/** Access key id → secret access key. */
|
|
6
|
+
keys: Record<string, string>;
|
|
7
|
+
region: string;
|
|
8
|
+
/** The signing name the request's path belongs to (`s3`, `amplify`). */
|
|
9
|
+
service: string;
|
|
10
|
+
/** The clock, for the 15-minute skew AWS allows. */
|
|
11
|
+
now?: () => number;
|
|
12
|
+
}
|
|
13
|
+
/** The signature AWS would compute for this request with `secret` (exported for the sim's own tests). */
|
|
14
|
+
export declare function expectedSigV4(req: AuthRequest, headers: IncomingHttpHeaders, secret: string, scope: {
|
|
15
|
+
date: string;
|
|
16
|
+
region: string;
|
|
17
|
+
service: string;
|
|
18
|
+
signed: string[];
|
|
19
|
+
amzDate: string;
|
|
20
|
+
}): string;
|
|
21
|
+
/** Why a SigV4 request is refused, or null when its signature is valid for `config`. */
|
|
22
|
+
export declare function sigV4Problem(headers: IncomingHttpHeaders, req: AuthRequest, config: SigV4Config): string | null;
|
|
23
|
+
/** Digest users and the challenge the sim issues. */
|
|
24
|
+
export interface DigestConfig {
|
|
25
|
+
users: Record<string, string>;
|
|
26
|
+
algorithm?: "MD5" | "SHA-256";
|
|
27
|
+
realm?: string;
|
|
28
|
+
}
|
|
29
|
+
/** Server-side Digest state: the nonces handed out. */
|
|
30
|
+
export interface DigestState {
|
|
31
|
+
nonces: string[];
|
|
32
|
+
}
|
|
33
|
+
/** A 401 carrying a fresh Digest challenge. */
|
|
34
|
+
export declare function digestChallenge(config: DigestConfig, state: DigestState, n: number, stale?: boolean): Reply;
|
|
35
|
+
/** Why a Digest `Authorization` does not authenticate this request, or null when it does. */
|
|
36
|
+
export declare function digestProblem(headers: IncomingHttpHeaders, req: AuthRequest, config: DigestConfig, state: DigestState): string | null;
|
|
37
|
+
/** A token the sim's token endpoint issued. */
|
|
38
|
+
export interface IssuedToken {
|
|
39
|
+
token: string;
|
|
40
|
+
client: string;
|
|
41
|
+
/** How the client authenticated to the token endpoint. */
|
|
42
|
+
method: "client_secret_basic" | "client_secret_post";
|
|
43
|
+
audience?: string;
|
|
44
|
+
scope?: string;
|
|
45
|
+
expiresAt: number;
|
|
46
|
+
revoked?: true;
|
|
47
|
+
}
|
|
48
|
+
/** OAuth2 clients and the tokens issued to them. */
|
|
49
|
+
export interface OAuthState {
|
|
50
|
+
clients: Record<string, string>;
|
|
51
|
+
ttlSeconds: number;
|
|
52
|
+
issued: IssuedToken[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* RFC 6749 §4.4 at a token endpoint: `grant_type=client_credentials`, the client authenticated by HTTP Basic
|
|
56
|
+
* (`client_secret_basic`) or by `client_id`/`client_secret` in the form (`client_secret_post`), never both.
|
|
57
|
+
*/
|
|
58
|
+
export declare function issueToken(state: OAuthState, headers: Record<string, string>, body: unknown, now?: number): Reply;
|
|
59
|
+
/** True when the bearer token was issued by the endpoint, is not revoked and has not expired. */
|
|
60
|
+
export declare function tokenValid(state: OAuthState, token: string, now?: number): boolean;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential checks a simulated provider can configure, server side: an OAuth2 client-credentials token endpoint,
|
|
3
|
+
* HTTP Digest challenges (RFC 7616), and AWS Signature Version 4 verification. They are written here from the
|
|
4
|
+
* specifications, independently of the client code in @sponson/adapters (the sim depends on nothing in the repo),
|
|
5
|
+
* and both sides are checked against the same published vectors (AWS's SigV4 test suite, RFC 7616 §3.9.1); a
|
|
6
|
+
* client bug therefore fails against the sim instead of being mirrored by it.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
9
|
+
import { Reply } from "./provider.js";
|
|
10
|
+
function sha256Hex(s) {
|
|
11
|
+
return createHash("sha256").update(s, "utf8").digest("hex");
|
|
12
|
+
}
|
|
13
|
+
function sameText(a, b) {
|
|
14
|
+
const x = Buffer.from(a);
|
|
15
|
+
const y = Buffer.from(b);
|
|
16
|
+
return x.length === y.length && timingSafeEqual(x, y);
|
|
17
|
+
}
|
|
18
|
+
function header(headers, name) {
|
|
19
|
+
const v = headers[name];
|
|
20
|
+
return Array.isArray(v) ? v.join(", ") : v;
|
|
21
|
+
}
|
|
22
|
+
/** RFC 3986 percent-encoding of every byte but the unreserved characters, upper-case hex. */
|
|
23
|
+
function awsEncode(s) {
|
|
24
|
+
let out = "";
|
|
25
|
+
for (const byte of Buffer.from(s, "utf8")) {
|
|
26
|
+
const c = String.fromCharCode(byte);
|
|
27
|
+
out += /[A-Za-z0-9\-._~]/.test(c) ? c : `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
function decoded(s) {
|
|
32
|
+
try {
|
|
33
|
+
return decodeURIComponent(s);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return s;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Canonical URI from the request target: segments encoded once for S3, twice for every other service. */
|
|
40
|
+
function sigv4Uri(path, service) {
|
|
41
|
+
if (path === "" || path === "/")
|
|
42
|
+
return "/";
|
|
43
|
+
return path
|
|
44
|
+
.split("/")
|
|
45
|
+
.map((seg) => (service === "s3" ? awsEncode(decoded(seg)) : awsEncode(awsEncode(decoded(seg)))))
|
|
46
|
+
.join("/");
|
|
47
|
+
}
|
|
48
|
+
function sigv4Query(query) {
|
|
49
|
+
if (query === "")
|
|
50
|
+
return "";
|
|
51
|
+
return query
|
|
52
|
+
.split("&")
|
|
53
|
+
.filter((p) => p !== "")
|
|
54
|
+
.map((p) => {
|
|
55
|
+
const i = p.indexOf("=");
|
|
56
|
+
return [awsEncode(decoded(i < 0 ? p : p.slice(0, i))), awsEncode(decoded(i < 0 ? "" : p.slice(i + 1)))];
|
|
57
|
+
})
|
|
58
|
+
.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0))
|
|
59
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
60
|
+
.join("&");
|
|
61
|
+
}
|
|
62
|
+
/** The parts of a SigV4 `Authorization` header. */
|
|
63
|
+
function parseSigV4(value) {
|
|
64
|
+
const m = /^AWS4-HMAC-SHA256\s+Credential=([^/,\s]+)\/(\d{8})\/([^/,\s]+)\/([^/,\s]+)\/aws4_request,\s*SignedHeaders=([a-z0-9;-]+),\s*Signature=([0-9a-f]{64})$/.exec(value.trim());
|
|
65
|
+
return m ? { key: m[1], date: m[2], region: m[3], service: m[4], signed: m[5].split(";"), signature: m[6] } : null;
|
|
66
|
+
}
|
|
67
|
+
/** The signature AWS would compute for this request with `secret` (exported for the sim's own tests). */
|
|
68
|
+
export function expectedSigV4(req, headers, secret, scope) {
|
|
69
|
+
const q = req.target.indexOf("?");
|
|
70
|
+
const path = q < 0 ? req.target : req.target.slice(0, q);
|
|
71
|
+
const query = q < 0 ? "" : req.target.slice(q + 1);
|
|
72
|
+
const canonicalHeaders = scope.signed.map((h) => `${h}:${(header(headers, h) ?? "").trim().replace(/\s+/g, " ")}\n`).join("");
|
|
73
|
+
const payload = header(headers, "x-amz-content-sha256") ?? sha256Hex(req.raw);
|
|
74
|
+
const canonical = [req.method, sigv4Uri(path, scope.service), sigv4Query(query), canonicalHeaders, scope.signed.join(";"), payload].join("\n");
|
|
75
|
+
const credentialScope = `${scope.date}/${scope.region}/${scope.service}/aws4_request`;
|
|
76
|
+
const toSign = ["AWS4-HMAC-SHA256", scope.amzDate, credentialScope, sha256Hex(canonical)].join("\n");
|
|
77
|
+
let key = `AWS4${secret}`;
|
|
78
|
+
for (const part of [scope.date, scope.region, scope.service, "aws4_request"])
|
|
79
|
+
key = createHmac("sha256", key).update(part).digest();
|
|
80
|
+
return createHmac("sha256", key).update(toSign).digest("hex");
|
|
81
|
+
}
|
|
82
|
+
/** X-Amz-Date must be there, match the credential scope's day and be within the 15 minutes AWS allows. */
|
|
83
|
+
function amzDateProblem(amzDate, day, now) {
|
|
84
|
+
if (!/^\d{8}T\d{6}Z$/.test(amzDate) || amzDate.slice(0, 8) !== day)
|
|
85
|
+
return "X-Amz-Date is missing or does not match the credential scope";
|
|
86
|
+
const at = Date.UTC(+amzDate.slice(0, 4), +amzDate.slice(4, 6) - 1, +amzDate.slice(6, 8), +amzDate.slice(9, 11), +amzDate.slice(11, 13), +amzDate.slice(13, 15));
|
|
87
|
+
return Math.abs(at - now()) > 15 * 60_000 ? "RequestTimeTooSkewed" : null;
|
|
88
|
+
}
|
|
89
|
+
/** Why a SigV4 request is refused, or null when its signature is valid for `config`. */
|
|
90
|
+
export function sigV4Problem(headers, req, config) {
|
|
91
|
+
const auth = parseSigV4(header(headers, "authorization") ?? "");
|
|
92
|
+
if (!auth)
|
|
93
|
+
return "missing or malformed AWS4-HMAC-SHA256 Authorization header";
|
|
94
|
+
const secret = config.keys[auth.key];
|
|
95
|
+
if (secret === undefined)
|
|
96
|
+
return "InvalidAccessKeyId";
|
|
97
|
+
if (auth.region !== config.region || auth.service !== config.service)
|
|
98
|
+
return `credential scope ${auth.region}/${auth.service} is not ${config.region}/${config.service}`;
|
|
99
|
+
const amzDate = header(headers, "x-amz-date") ?? "";
|
|
100
|
+
const dateProblem = amzDateProblem(amzDate, auth.date, config.now ?? Date.now);
|
|
101
|
+
if (dateProblem)
|
|
102
|
+
return dateProblem;
|
|
103
|
+
if (!auth.signed.includes("host") || !auth.signed.includes("x-amz-date"))
|
|
104
|
+
return "SignedHeaders must include host and x-amz-date";
|
|
105
|
+
const claimed = header(headers, "x-amz-content-sha256");
|
|
106
|
+
if (claimed !== undefined && claimed !== sha256Hex(req.raw))
|
|
107
|
+
return "XAmzContentSHA256Mismatch";
|
|
108
|
+
const expected = expectedSigV4(req, headers, secret, { date: auth.date, region: auth.region, service: auth.service, signed: auth.signed, amzDate });
|
|
109
|
+
return sameText(expected, auth.signature) ? null : "SignatureDoesNotMatch";
|
|
110
|
+
}
|
|
111
|
+
const DEFAULT_REALM = "Sponson Sim API";
|
|
112
|
+
function digestParams(value) {
|
|
113
|
+
const out = {};
|
|
114
|
+
for (const m of value.replace(/^Digest\s+/i, "").matchAll(/([a-z0-9-]+)\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^\s,]+))/gi))
|
|
115
|
+
out[m[1].toLowerCase()] = m[2] !== undefined ? m[2].replace(/\\(.)/g, "$1") : m[3];
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
/** A 401 carrying a fresh Digest challenge. */
|
|
119
|
+
export function digestChallenge(config, state, n, stale = false) {
|
|
120
|
+
const nonce = `sim-nonce-${n}-${createHash("sha256").update(String(n)).digest("hex").slice(0, 16)}`;
|
|
121
|
+
state.nonces.push(nonce);
|
|
122
|
+
const challenge = `Digest realm="${config.realm ?? DEFAULT_REALM}", domain="", nonce="${nonce}", algorithm=${config.algorithm ?? "MD5"}, qop="auth", stale=${stale ? "TRUE" : "FALSE"}`;
|
|
123
|
+
return new Reply(401, { error: "unauthorized", detail: "Digest authentication required" }, { "www-authenticate": challenge });
|
|
124
|
+
}
|
|
125
|
+
/** What is wrong with a Digest answer's parameters, before its response is checked. */
|
|
126
|
+
function digestFormProblem(p, req, algorithm, state) {
|
|
127
|
+
if (!p.nonce || !state.nonces.includes(p.nonce))
|
|
128
|
+
return "unknown nonce";
|
|
129
|
+
if (p.qop !== "auth" || !/^[0-9a-f]{8}$/.test(p.nc ?? "") || !p.cnonce)
|
|
130
|
+
return "qop=auth with nc and cnonce is required";
|
|
131
|
+
if ((p.algorithm ?? "MD5").toUpperCase() !== algorithm)
|
|
132
|
+
return "wrong algorithm";
|
|
133
|
+
if (p.uri !== req.target)
|
|
134
|
+
return "uri does not match the request";
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
/** Why a Digest `Authorization` does not authenticate this request, or null when it does. */
|
|
138
|
+
export function digestProblem(headers, req, config, state) {
|
|
139
|
+
const value = header(headers, "authorization") ?? "";
|
|
140
|
+
if (!/^Digest\s/i.test(value))
|
|
141
|
+
return "no Digest credentials";
|
|
142
|
+
const p = digestParams(value);
|
|
143
|
+
const algorithm = config.algorithm ?? "MD5";
|
|
144
|
+
const password = p.username === undefined ? undefined : config.users[p.username];
|
|
145
|
+
if (password === undefined)
|
|
146
|
+
return "unknown user";
|
|
147
|
+
const problem = digestFormProblem(p, req, algorithm, state);
|
|
148
|
+
if (problem)
|
|
149
|
+
return problem;
|
|
150
|
+
const h = (s) => createHash(algorithm === "MD5" ? "md5" : "sha256").update(s, "utf8").digest("hex");
|
|
151
|
+
const ha1 = h(`${p.username}:${config.realm ?? DEFAULT_REALM}:${password}`);
|
|
152
|
+
const ha2 = h(`${req.method}:${p.uri}`);
|
|
153
|
+
const expected = h(`${ha1}:${p.nonce}:${p.nc}:${p.cnonce}:auth:${ha2}`);
|
|
154
|
+
return sameText(expected, p.response ?? "") ? null : "wrong response";
|
|
155
|
+
}
|
|
156
|
+
function form(v) {
|
|
157
|
+
if (typeof v !== "object" || v === null)
|
|
158
|
+
return {};
|
|
159
|
+
return Object.fromEntries(Object.entries(v).filter(([, x]) => typeof x === "string"));
|
|
160
|
+
}
|
|
161
|
+
function oauthError(status, error, description) {
|
|
162
|
+
return new Reply(status, { error, error_description: description });
|
|
163
|
+
}
|
|
164
|
+
/** The client a token request authenticates as (Basic or form, never both); the refusal otherwise. */
|
|
165
|
+
function clientOf(state, headers, f) {
|
|
166
|
+
const basic = /^Basic\s+(\S+)$/i.exec(headers.authorization ?? "");
|
|
167
|
+
if (basic && (f.client_id !== undefined || f.client_secret !== undefined))
|
|
168
|
+
return oauthError(400, "invalid_request", "client authenticated twice");
|
|
169
|
+
const [client, secret] = basic ? Buffer.from(basic[1], "base64").toString("utf8").split(/:(.*)/s) : [f.client_id, f.client_secret];
|
|
170
|
+
const expected = client === undefined ? undefined : state.clients[client];
|
|
171
|
+
if (!client || secret === undefined || expected === undefined || !sameText(expected, secret))
|
|
172
|
+
return oauthError(401, "invalid_client", "client authentication failed");
|
|
173
|
+
return { client, basic: basic !== null };
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* RFC 6749 §4.4 at a token endpoint: `grant_type=client_credentials`, the client authenticated by HTTP Basic
|
|
177
|
+
* (`client_secret_basic`) or by `client_id`/`client_secret` in the form (`client_secret_post`), never both.
|
|
178
|
+
*/
|
|
179
|
+
export function issueToken(state, headers, body, now = Date.now()) {
|
|
180
|
+
const f = form(body);
|
|
181
|
+
if (f.grant_type !== "client_credentials")
|
|
182
|
+
return oauthError(400, "unsupported_grant_type", "only client_credentials is supported");
|
|
183
|
+
const who = clientOf(state, headers, f);
|
|
184
|
+
if (who instanceof Reply)
|
|
185
|
+
return who;
|
|
186
|
+
const { client, basic } = who;
|
|
187
|
+
const token = `oauth-access-token-${state.issued.length + 1}`;
|
|
188
|
+
state.issued.push({ token, client, method: basic ? "client_secret_basic" : "client_secret_post", ...(f.audience ? { audience: f.audience } : {}), ...(f.scope ? { scope: f.scope } : {}), expiresAt: now + state.ttlSeconds * 1000 });
|
|
189
|
+
return new Reply(200, { access_token: token, token_type: "Bearer", expires_in: state.ttlSeconds, ...(f.scope ? { scope: f.scope } : {}) });
|
|
190
|
+
}
|
|
191
|
+
/** True when the bearer token was issued by the endpoint, is not revoked and has not expired. */
|
|
192
|
+
export function tokenValid(state, token, now = Date.now()) {
|
|
193
|
+
return state.issued.some((t) => t.token === token && !t.revoked && t.expiresAt > now);
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/bin.js
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
console.log(`sponson-sim listening on ${sim.url}`);
|
|
12
|
-
// Everything the adapters need to talk to the sim, base URLs and placeholder tokens alike, ready to paste into a shell.
|
|
13
|
-
console.log("# paste into another shell to point sponson at the sim:");
|
|
14
|
-
for (const [k, v] of Object.entries(simEnv(sim)))
|
|
15
|
-
console.log(`export ${k}=${v}`);
|
|
2
|
+
import { runSimCli } from "./cli.js";
|
|
3
|
+
const { code, sim } = await runSimCli(process.argv.slice(2), {
|
|
4
|
+
stdout: (s) => process.stdout.write(s),
|
|
5
|
+
stderr: (s) => process.stderr.write(s),
|
|
6
|
+
env: process.env,
|
|
7
|
+
cwd: process.cwd(),
|
|
8
|
+
});
|
|
9
|
+
if (!sim)
|
|
10
|
+
process.exit(code);
|
|
16
11
|
const stop = () => {
|
|
17
12
|
void sim.close().finally(() => process.exit(0));
|
|
18
13
|
};
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IAC3D,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtC,GAAG,EAAE,OAAO,CAAC,GAAG;IAChB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;CACnB,CAAC,CAAC;AACH,IAAI,CAAC,GAAG;IAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAE7B,MAAM,IAAI,GAAG,GAAG,EAAE;IAChB,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC;AACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC3B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC"}
|
package/dist/chaos.d.ts
CHANGED
|
@@ -30,6 +30,10 @@ export interface ChaosConfig {
|
|
|
30
30
|
deploy_ms: number;
|
|
31
31
|
/** After a Neon branch create, writes to that branch and further creates in the project answer 423 for this long. */
|
|
32
32
|
neon_op_ms: number;
|
|
33
|
+
/** A PlanetScale branch created through the API reports `ready: false` for this long (0: ready at its first read). */
|
|
34
|
+
planetscale_ready_ms: number;
|
|
35
|
+
/** A Supabase branch created through the API reports `COMING_UP` for this long, then `ACTIVE_HEALTHY`. */
|
|
36
|
+
supabase_ready_ms: number;
|
|
33
37
|
/** When > 0, Neon branches, Vercel envs and Clerk redirect URLs are listed in pages of this size. */
|
|
34
38
|
page_size: number;
|
|
35
39
|
/** Keys a Vercel bulk upsert reports under `failed` (and does not write). */
|
package/dist/chaos.js
CHANGED
package/dist/chaos.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chaos.js","sourceRoot":"","sources":["../src/chaos.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chaos.js","sourceRoot":"","sources":["../src/chaos.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type SimHandle } from "./index.js";
|
|
2
|
+
/** Where the command line writes and what it reads; the bin passes the process's. */
|
|
3
|
+
export interface SimCliIO {
|
|
4
|
+
stdout(s: string): void;
|
|
5
|
+
stderr(s: string): void;
|
|
6
|
+
env: NodeJS.ProcessEnv;
|
|
7
|
+
cwd: string;
|
|
8
|
+
}
|
|
9
|
+
/** What the arguments ask for. */
|
|
10
|
+
export type SimCommand = {
|
|
11
|
+
kind: "serve";
|
|
12
|
+
port: number;
|
|
13
|
+
demo?: string;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "env";
|
|
16
|
+
port: number;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "help";
|
|
19
|
+
};
|
|
20
|
+
/** How the command ended: an exit code, or a running sim the caller keeps alive until a signal. */
|
|
21
|
+
export type SimCliResult = {
|
|
22
|
+
code: number;
|
|
23
|
+
sim?: SimHandle;
|
|
24
|
+
};
|
|
25
|
+
export declare const USAGE = "usage: sponson-sim [--port N] [--demo <dir>]\n sponson-sim env [--port N]\n\n --port N listen on 127.0.0.1:N (default: $SPONSON_SIM_PORT, else 4777)\n --demo <dir> also write a ready demo repository into <dir> (new or empty) and print what to run next\n env print the `export` lines that point sponson at a sim on that port, for eval \"$(sponson-sim env)\"\n";
|
|
26
|
+
/** Parse argv (without node and the script). Throws with a message for the user on anything it does not know. */
|
|
27
|
+
export declare function parseSimArgs(argv: string[], env: NodeJS.ProcessEnv): SimCommand;
|
|
28
|
+
/** Run the command line. A started sim is returned running; the caller decides when to close it. */
|
|
29
|
+
export declare function runSimCli(argv: string[], io: SimCliIO): Promise<SimCliResult>;
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `sponson-sim` command line, kept out of bin.ts so it can be tested in-process:
|
|
3
|
+
* sponson-sim [--port N] start the fake cloud and print the env that points sponson at it
|
|
4
|
+
* sponson-sim --demo <dir> [--port N] the same, plus a ready demo repository in <dir> and what to run next
|
|
5
|
+
* sponson-sim env [--port N] print only the `export` lines, for `eval "$(sponson-sim env)"`
|
|
6
|
+
* The demo lives here rather than in the `sponson` CLI, whose command set is fixed (docs/adr/0002-three-commands.md),
|
|
7
|
+
* and because it is about the fake cloud: it only makes sense with a sim running.
|
|
8
|
+
*/
|
|
9
|
+
import { resolve } from "node:path";
|
|
10
|
+
import { parseArgs } from "node:util";
|
|
11
|
+
import { demoInstructions, envExports, writeDemo } from "./demo.js";
|
|
12
|
+
import { startSim } from "./index.js";
|
|
13
|
+
export const USAGE = `usage: sponson-sim [--port N] [--demo <dir>]
|
|
14
|
+
sponson-sim env [--port N]
|
|
15
|
+
|
|
16
|
+
--port N listen on 127.0.0.1:N (default: $SPONSON_SIM_PORT, else 4777)
|
|
17
|
+
--demo <dir> also write a ready demo repository into <dir> (new or empty) and print what to run next
|
|
18
|
+
env print the \`export\` lines that point sponson at a sim on that port, for eval "$(sponson-sim env)"
|
|
19
|
+
`;
|
|
20
|
+
/** Parse argv (without node and the script). Throws with a message for the user on anything it does not know. */
|
|
21
|
+
export function parseSimArgs(argv, env) {
|
|
22
|
+
const { values, positionals } = parseArgs({
|
|
23
|
+
args: argv,
|
|
24
|
+
options: { port: { type: "string" }, demo: { type: "string" }, help: { type: "boolean", short: "h" } },
|
|
25
|
+
allowPositionals: true,
|
|
26
|
+
strict: true,
|
|
27
|
+
});
|
|
28
|
+
if (values.help)
|
|
29
|
+
return { kind: "help" };
|
|
30
|
+
const port = portFrom(values.port, env);
|
|
31
|
+
const [command, ...rest] = positionals;
|
|
32
|
+
if (rest.length > 0 || (command !== undefined && command !== "env"))
|
|
33
|
+
throw new Error(`unexpected argument: ${[command, ...rest].join(" ")}`);
|
|
34
|
+
if (command === "env") {
|
|
35
|
+
if (values.demo !== undefined)
|
|
36
|
+
throw new Error("--demo starts a sim; it cannot be combined with `env`");
|
|
37
|
+
return { kind: "env", port };
|
|
38
|
+
}
|
|
39
|
+
if (values.demo !== undefined && values.demo.trim() === "")
|
|
40
|
+
throw new Error("--demo needs a directory");
|
|
41
|
+
return { kind: "serve", port, ...(values.demo !== undefined ? { demo: values.demo } : {}) };
|
|
42
|
+
}
|
|
43
|
+
/** `--port`, else SPONSON_SIM_PORT, else 4777. */
|
|
44
|
+
function portFrom(flag, env) {
|
|
45
|
+
// A blank SPONSON_SIM_PORT is "not set", as CI systems export variables that do not apply.
|
|
46
|
+
const fromEnv = env.SPONSON_SIM_PORT?.trim();
|
|
47
|
+
const raw = flag ?? (fromEnv === undefined || fromEnv === "" ? "4777" : fromEnv);
|
|
48
|
+
const port = Number(raw);
|
|
49
|
+
if (raw.trim() === "" || !Number.isInteger(port) || port < 0 || port > 65535)
|
|
50
|
+
throw new Error(`invalid port: ${raw}`);
|
|
51
|
+
return port;
|
|
52
|
+
}
|
|
53
|
+
/** Run the command line. A started sim is returned running; the caller decides when to close it. */
|
|
54
|
+
export async function runSimCli(argv, io) {
|
|
55
|
+
let cmd;
|
|
56
|
+
try {
|
|
57
|
+
cmd = parseSimArgs(argv, io.env);
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
io.stderr(`sponson-sim: ${e.message}\n${USAGE}`);
|
|
61
|
+
return { code: 2 };
|
|
62
|
+
}
|
|
63
|
+
if (cmd.kind === "help") {
|
|
64
|
+
io.stdout(USAGE);
|
|
65
|
+
return { code: 0 };
|
|
66
|
+
}
|
|
67
|
+
if (cmd.kind === "env") {
|
|
68
|
+
io.stdout(`${envExports(`http://127.0.0.1:${String(cmd.port)}`).join("\n")}\n`);
|
|
69
|
+
return { code: 0 };
|
|
70
|
+
}
|
|
71
|
+
return serve(cmd, io);
|
|
72
|
+
}
|
|
73
|
+
async function serve(cmd, io) {
|
|
74
|
+
let sim;
|
|
75
|
+
try {
|
|
76
|
+
sim = await startSim({ port: cmd.port });
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
const busy = e.code === "EADDRINUSE";
|
|
80
|
+
io.stderr(`sponson-sim: ${busy ? `port ${String(cmd.port)} is in use (another sponson-sim?); pass --port N or set SPONSON_SIM_PORT` : e.message}\n`);
|
|
81
|
+
return { code: 1 };
|
|
82
|
+
}
|
|
83
|
+
if (cmd.demo === undefined) {
|
|
84
|
+
io.stdout(`sponson-sim listening on ${sim.url}\n# paste into another shell to point sponson at the sim:\n${envExports(sim.url).join("\n")}\n`);
|
|
85
|
+
return { code: 0, sim };
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
// Written after the port is ours: a busy port must not leave a demo behind that points at someone else's sim.
|
|
89
|
+
await writeDemo(resolve(io.cwd, cmd.demo), sim.url);
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
await sim.close();
|
|
93
|
+
io.stderr(`sponson-sim: ${e.message}\n`);
|
|
94
|
+
return { code: 1 };
|
|
95
|
+
}
|
|
96
|
+
io.stdout(demoInstructions(cmd.demo, sim.url));
|
|
97
|
+
return { code: 0, sim };
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/demo.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** The branch the demo commit is on; Vercel variables are written for it. */
|
|
2
|
+
export declare const DEMO_BRANCH = "feat/checkout";
|
|
3
|
+
/** The pull request the demo pretends to be, so the scope reads `pr-42` as in the README. */
|
|
4
|
+
export declare const DEMO_PR = "42";
|
|
5
|
+
/** The file `source` loads in the second terminal. */
|
|
6
|
+
export declare const DEMO_ENV_FILE = "sim.env";
|
|
7
|
+
/**
|
|
8
|
+
* Comments carry the explanation, because a newcomer reads this file before running anything. It uses only the
|
|
9
|
+
* projects every provider's default seed creates (`prj_demo`, `proj_demo`; Clerk needs none).
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEMO_PLAN = "# A release plan for a preview of this branch, against the fake cloud started by `sponson-sim --demo`.\nversion: 1\n# Receipts (what each run did) go to .sponson/receipts in this directory: the demo has no git remote.\nreceipts: local\nproviders:\n vercel: { project: prj_demo }\n neon: { project: proj_demo }\n\nchanges:\n # 1. A Neon database branch for this preview, forked from main.\n - id: db\n adapter: neon\n op: branch\n parent: main\n environments: [preview]\n\n # 2. The branch's connection string as the preview's DATABASE_URL. A reference, never a value: nobody copies\n # a password between consoles, and it is masked in every line Sponson prints.\n - id: env\n adapter: vercel\n op: env\n target: preview\n values:\n DATABASE_URL: { from: db.connection_string }\n environments: [preview]\n\n # 3. The preview's URL as an allowed Clerk redirect. The URL exists only once Vercel has deployed this commit,\n # so this line waits for the deploy.\n - id: callback\n adapter: clerk\n op: redirect_allow\n url: { from: env.preview_url }\n environments: [preview]\n";
|
|
12
|
+
/** A console edit, as the sim's drift control applies it: someone pastes another database into DATABASE_URL. */
|
|
13
|
+
export declare const DEMO_DRIFT: {
|
|
14
|
+
"vercel.env.preview.DATABASE_URL": string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* What to run in the second terminal, in order. No inline comments: interactive zsh (macOS's default shell)
|
|
18
|
+
* treats `#` as an argument unless `interactivecomments` is set, so a pasted comment would break the command.
|
|
19
|
+
*/
|
|
20
|
+
export declare function demoSteps(dir: string): string[];
|
|
21
|
+
/**
|
|
22
|
+
* The env file: the sim's URLs and placeholder tokens (`simEnv`), `SPONSON_SIM_URL` for the drift command, and the
|
|
23
|
+
* pull request number. Setting `SPONSON_CTX_PR` also keeps `sponson` from asking `gh` which pull request this is,
|
|
24
|
+
* which in a repository without a remote only costs time. Without a global install, `sponson` falls back to npx.
|
|
25
|
+
*/
|
|
26
|
+
export declare function demoEnvFile(url: string): string;
|
|
27
|
+
/** `export NAME=value` for everything a shell needs to point `sponson` at the sim at `url`. */
|
|
28
|
+
export declare function envExports(url: string): string[];
|
|
29
|
+
/**
|
|
30
|
+
* Write the demo into `dir`: the plan, a .gitignore, the env file, and one commit on `DEMO_BRANCH`. The commit's
|
|
31
|
+
* author, dates and contents are fixed, so its sha (and with it the preview URL the sim derives from it) is the
|
|
32
|
+
* same on every machine. The env file is ignored: it holds the port, which differs between runs.
|
|
33
|
+
* Refuses a non-empty directory rather than mixing the demo into someone's files.
|
|
34
|
+
*/
|
|
35
|
+
export declare function writeDemo(dir: string, url: string): Promise<void>;
|
|
36
|
+
/** The walkthrough printed once the sim is up and the demo is written. */
|
|
37
|
+
export declare function demoInstructions(dir: string, url: string): string;
|
|
38
|
+
/** Quote a path for a POSIX shell only when it needs it, so the common case reads naturally. */
|
|
39
|
+
export declare function shellQuote(s: string): string;
|