@sponson/sim 0.0.0-stage → 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/LICENSE +202 -0
- package/README.md +9 -2
- package/dist/auth.d.ts +60 -0
- package/dist/auth.js +195 -0
- package/dist/auth.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +16 -0
- package/dist/bin.js.map +1 -0
- package/dist/chaos.d.ts +74 -0
- package/dist/chaos.js +80 -0
- package/dist/chaos.js.map +1 -0
- 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 +46 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +138 -0
- package/dist/provider.js +68 -0
- package/dist/provider.js.map +1 -0
- 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/clerk.d.ts +33 -0
- package/dist/routes/clerk.js +85 -0
- package/dist/routes/clerk.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/neon.d.ts +73 -0
- package/dist/routes/neon.js +184 -0
- package/dist/routes/neon.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/vercel.d.ts +114 -0
- package/dist/routes/vercel.js +370 -0
- package/dist/routes/vercel.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.d.ts +4 -0
- package/dist/server.js +189 -0
- package/dist/server.js.map +1 -0
- package/dist/state.d.ts +102 -0
- package/dist/state.js +121 -0
- package/dist/state.js.map +1 -0
- package/package.json +51 -3
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simulated Supabase Management API (https://api.supabase.com/v1): preview branches of a project, and the project's
|
|
3
|
+
* Auth redirect allow-list.
|
|
4
|
+
*
|
|
5
|
+
* Assumptions about the real API that this fake encodes, each marked with how far it is checked. "Verified" means
|
|
6
|
+
* against Supabase's published OpenAPI document (https://api.supabase.com/api/v1-json, fetched 2026-10-11; rendered
|
|
7
|
+
* at https://supabase.com/docs/reference/api/introduction) unless another source is named; see
|
|
8
|
+
* docs/api-verification.md:
|
|
9
|
+
* S1. POST /v1/projects/{ref}/branches takes `{ branch_name }` (required, the only required field) and answers
|
|
10
|
+
* 201 with a BranchResponse: `id` (uuid), `name` (= branch_name), `project_ref` (the branch's own project),
|
|
11
|
+
* `parent_project_ref`, `is_default`, `persistent`, `status`, `created_at` (verified: CreateBranchBody,
|
|
12
|
+
* BranchResponse). That `project_ref` is known in the 201 answer, before provisioning finishes, is implied by
|
|
13
|
+
* the schema (required) but unverified.
|
|
14
|
+
* S2. GET /v1/projects/{ref}/branches answers a bare array of BranchResponse, unpaged (verified: no page
|
|
15
|
+
* parameters, `type: array`). That the list includes the project's own default branch (`is_default: true`,
|
|
16
|
+
* `project_ref` = the parent) once branching is enabled is unverified; the adapter skips `is_default` either
|
|
17
|
+
* way and never manages it.
|
|
18
|
+
* S3. A branch is provisioned asynchronously: GET /v1/branches/{ref} answers BranchDetailResponse whose `status`
|
|
19
|
+
* (the project status enum) is `COMING_UP` until it is ready and `ACTIVE_HEALTHY` after (verified: schema and
|
|
20
|
+
* enum). Here this takes chaos `supabase_ready_ms` (default 0). That the detail answers 200 (not 404) while
|
|
21
|
+
* the branch is coming up, and that `ACTIVE_HEALTHY` is the right "ready" signal, are unverified: needs a
|
|
22
|
+
* live account. The BranchResponse `status` (CREATING_PROJECT, …) is deprecated in the spec and not used.
|
|
23
|
+
* S4. The detail carries `db_host`, `db_port` (required), `db_user` and `db_pass` (optional in the spec,
|
|
24
|
+
* verified). That `db_pass` is returned to a personal access token is unverified (pinned by the contract
|
|
25
|
+
* suite). The database is `postgres` (Supabase's default database name, verified in the connection docs,
|
|
26
|
+
* https://supabase.com/docs/guides/database/connecting-to-postgres) and the API URL is
|
|
27
|
+
* `https://<ref>.supabase.co` (verified: https://supabase.com/docs/guides/api).
|
|
28
|
+
* S5. Creating a branch whose name exists in the project answers 409. Unverified: the spec documents only 201,
|
|
29
|
+
* 401, 403, 429 and 500. The adapter re-reads the list after a 409, or a 400/422, before reporting it.
|
|
30
|
+
* S6. DELETE /v1/branches/{ref} answers 200 `{ message: "ok" }` and the branch is gone from the list at once
|
|
31
|
+
* (verified: BranchDeleteResponse; "by default, deletes immediately"). An unknown ref answers 404:
|
|
32
|
+
* unverified (the spec documents no 404).
|
|
33
|
+
* S7. GET /v1/projects/{ref}/config/auth answers the auth config with `uri_allow_list`, a nullable string
|
|
34
|
+
* (verified: AuthConfigResponse, required); PATCH with `{ uri_allow_list }` alone sets that field and
|
|
35
|
+
* leaves the others, answering the whole config (verified: UpdateAuthConfigBody has no required field).
|
|
36
|
+
* PATCH offers no precondition (no ETag or version), verified by its absence from the spec.
|
|
37
|
+
* S8. The allow-list is comma-separated URLs (verified: Supabase Auth's `URI_ALLOW_LIST`, "a comma separated
|
|
38
|
+
* list of URIs", https://github.com/supabase/auth#general-config). Whitespace around commas is ignored by
|
|
39
|
+
* Auth; whether the API stores the string verbatim (here: yes) is unverified.
|
|
40
|
+
* S9. A preview branch is a project with its own Auth config, read and written through the same
|
|
41
|
+
* /v1/projects/{ref}/config/auth with the branch's ref (`project_ref` is a "Project ref" in the spec,
|
|
42
|
+
* verified; branches have "their own Supabase instance and API credentials", verified in
|
|
43
|
+
* https://supabase.com/docs/guides/deployment/branching). That the endpoint accepts a branch's ref, and
|
|
44
|
+
* what the branch's allow-list starts as (here: empty), are unverified.
|
|
45
|
+
*/
|
|
46
|
+
import { Reply, route, router } from "../provider.js";
|
|
47
|
+
/** The parent project the default seed creates, a ref of 20 lowercase letters like Supabase's. */
|
|
48
|
+
export const SUPABASE_DEMO_PROJECT = "demoprojectrefabcdef";
|
|
49
|
+
/** The simulated Supabase Management API, registered in `PROVIDERS` (packages/sim/src/state.ts), served under `/supabase`. */
|
|
50
|
+
export const supabaseSim = {
|
|
51
|
+
env: { token: "SUPABASE_ACCESS_TOKEN", url: "SUPABASE_API_URL", testToken: "tok_supabase" },
|
|
52
|
+
defaultSeed: { projects: { [SUPABASE_DEMO_PROJECT]: { uri_allow_list: "http://localhost:3000/**" } } },
|
|
53
|
+
reset(core, seed) {
|
|
54
|
+
const projects = {};
|
|
55
|
+
for (const [ref, p] of Object.entries(seed?.projects ?? {})) {
|
|
56
|
+
const project = { branches: [], auth: { site_url: p.site_url ?? "http://localhost:3000", uri_allow_list: p.uri_allow_list ?? null } };
|
|
57
|
+
projects[ref] = project;
|
|
58
|
+
// With branching enabled the project itself is listed as its default branch (assumption S2).
|
|
59
|
+
project.branches.push({ ...newSupabaseBranch(core, ref, "main", "sim"), project_ref: ref, is_default: true });
|
|
60
|
+
for (const b of p.branches ?? [])
|
|
61
|
+
project.branches.push(newSupabaseBranch(core, ref, b.name, "sim"));
|
|
62
|
+
}
|
|
63
|
+
return { projects };
|
|
64
|
+
},
|
|
65
|
+
/**
|
|
66
|
+
* `branch.<name>`: "delete" | "recreate" (same name, new ref). `redirect.<url>`: "delete" | "add" — what a human
|
|
67
|
+
* in the Supabase dashboard would do. `supabase:<ref>.` limits either to one project.
|
|
68
|
+
*/
|
|
69
|
+
drift(core, state, { key, rest, value, only }) {
|
|
70
|
+
const projects = Object.entries(state.projects).filter(([ref]) => only === undefined || ref === only);
|
|
71
|
+
if (rest.startsWith("branch."))
|
|
72
|
+
return driftBranch(core, projects, key, rest.slice("branch.".length), value);
|
|
73
|
+
if (rest.startsWith("redirect."))
|
|
74
|
+
return driftRedirect(projects, key, rest.slice("redirect.".length), value);
|
|
75
|
+
return false;
|
|
76
|
+
},
|
|
77
|
+
routes(core, state, req) {
|
|
78
|
+
return routes(core, state, req);
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
function driftBranch(core, projects, key, name, value) {
|
|
82
|
+
if (value !== "delete" && value !== "recreate")
|
|
83
|
+
throw new Error(`drift ${key}: only "delete" and "recreate" are supported`);
|
|
84
|
+
for (const [ref, p] of projects) {
|
|
85
|
+
const hit = p.branches.filter((b) => b.name === name && !b.is_default);
|
|
86
|
+
p.branches = p.branches.filter((b) => !hit.includes(b));
|
|
87
|
+
if (value === "recreate")
|
|
88
|
+
for (const b of hit)
|
|
89
|
+
p.branches.push(newSupabaseBranch(core, ref, b.name, "sim"));
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
function driftRedirect(projects, key, url, value) {
|
|
94
|
+
if (value !== "delete" && value !== "add")
|
|
95
|
+
throw new Error(`drift ${key}: only "delete" and "add" are supported`);
|
|
96
|
+
for (const [, p] of projects) {
|
|
97
|
+
const rest = supabaseAllowList(p).filter((u) => u !== url);
|
|
98
|
+
p.auth.uri_allow_list = (value === "add" ? [...rest, url] : rest).join(",");
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
/** The allow-list's entries: comma-separated, whitespace around them ignored (assumption S8). */
|
|
103
|
+
export function supabaseAllowList(p) {
|
|
104
|
+
return (p.auth.uri_allow_list ?? "")
|
|
105
|
+
.split(",")
|
|
106
|
+
.map((s) => s.trim())
|
|
107
|
+
.filter((s) => s !== "");
|
|
108
|
+
}
|
|
109
|
+
/** The Management API, one route per method and path. Errors are `{ message }`, as Supabase's are. */
|
|
110
|
+
const routes = router([
|
|
111
|
+
route("GET", "/projects/:ref/branches", ({ state, params }) => {
|
|
112
|
+
const p = state.projects[params.ref];
|
|
113
|
+
return p ? new Reply(200, p.branches.map(publicBranch)) : notFound("project");
|
|
114
|
+
}),
|
|
115
|
+
route("POST", "/projects/:ref/branches", ({ core, state, params, body }) => {
|
|
116
|
+
const p = state.projects[params.ref];
|
|
117
|
+
if (!p)
|
|
118
|
+
return notFound("project");
|
|
119
|
+
const name = (body ?? {}).branch_name;
|
|
120
|
+
if (typeof name !== "string" || name === "")
|
|
121
|
+
return new Reply(400, { message: "branch_name must be a non-empty string" });
|
|
122
|
+
if (p.branches.some((b) => b.name === name))
|
|
123
|
+
return new Reply(409, { message: `Branch ${name} already exists` });
|
|
124
|
+
const b = newSupabaseBranch(core, params.ref, name, "api");
|
|
125
|
+
b.readyAt = Date.now() + core.chaos.supabase_ready_ms;
|
|
126
|
+
p.branches.push(b);
|
|
127
|
+
return new Reply(201, publicBranch(b));
|
|
128
|
+
}),
|
|
129
|
+
route("GET", "/branches/:ref", ({ state, params }) => {
|
|
130
|
+
const b = branchByRef(state, params.ref);
|
|
131
|
+
return b ? new Reply(200, branchDetail(b)) : notFound("branch");
|
|
132
|
+
}),
|
|
133
|
+
route("DELETE", "/branches/:ref", ({ state, params }) => {
|
|
134
|
+
const b = branchByRef(state, params.ref);
|
|
135
|
+
if (!b)
|
|
136
|
+
return notFound("branch");
|
|
137
|
+
if (b.is_default)
|
|
138
|
+
return new Reply(400, { message: "the default branch cannot be deleted" });
|
|
139
|
+
const p = state.projects[b.parent_project_ref];
|
|
140
|
+
p.branches = p.branches.filter((x) => x !== b);
|
|
141
|
+
return new Reply(200, { message: "ok" });
|
|
142
|
+
}),
|
|
143
|
+
route("GET", "/projects/:ref/config/auth", ({ state, params }) => {
|
|
144
|
+
const a = authOf(state, params.ref);
|
|
145
|
+
return a ? new Reply(200, authConfig(a)) : notFound("project");
|
|
146
|
+
}),
|
|
147
|
+
route("PATCH", "/projects/:ref/config/auth", ({ state, params, body }) => {
|
|
148
|
+
const a = authOf(state, params.ref);
|
|
149
|
+
if (!a)
|
|
150
|
+
return notFound("project");
|
|
151
|
+
const b = (body ?? {});
|
|
152
|
+
if (b.uri_allow_list !== undefined && b.uri_allow_list !== null && typeof b.uri_allow_list !== "string")
|
|
153
|
+
return new Reply(400, { message: "uri_allow_list must be a string" });
|
|
154
|
+
if (b.uri_allow_list !== undefined)
|
|
155
|
+
a.uri_allow_list = b.uri_allow_list;
|
|
156
|
+
if (typeof b.site_url === "string")
|
|
157
|
+
a.site_url = b.site_url;
|
|
158
|
+
return new Reply(200, authConfig(a));
|
|
159
|
+
}),
|
|
160
|
+
], () => notFound("route"));
|
|
161
|
+
/** A branch by its own project ref, in any project. */
|
|
162
|
+
function branchByRef(state, ref) {
|
|
163
|
+
for (const p of Object.values(state.projects)) {
|
|
164
|
+
const b = p.branches.find((x) => x.project_ref === ref);
|
|
165
|
+
if (b)
|
|
166
|
+
return b;
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* A new (not yet added) branch of project `parent`, ready at once. Tests use it to seed "someone else's" branch.
|
|
172
|
+
* Refs are 20 lowercase letters, deterministic after a reset.
|
|
173
|
+
*/
|
|
174
|
+
export function newSupabaseBranch(core, parent, name, createdBy) {
|
|
175
|
+
const n = core.nextId("");
|
|
176
|
+
const ref = `br${[...n].map((d) => "abcdefghij"[Number(d)]).join("")}`.padEnd(20, "x");
|
|
177
|
+
return {
|
|
178
|
+
id: `00000000-0000-4000-8000-${n.padStart(12, "0")}`,
|
|
179
|
+
name,
|
|
180
|
+
project_ref: ref,
|
|
181
|
+
parent_project_ref: parent,
|
|
182
|
+
is_default: false,
|
|
183
|
+
readyAt: 0,
|
|
184
|
+
db_pass: `pw_${ref}`,
|
|
185
|
+
auth: { site_url: "http://localhost:3000", uri_allow_list: null },
|
|
186
|
+
created_at: new Date().toISOString(),
|
|
187
|
+
createdAt: Date.now(),
|
|
188
|
+
createdBy,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/** The connection string the adapter builds from a branch's detail (assumption S4). */
|
|
192
|
+
export function supabaseConnectionString(b) {
|
|
193
|
+
return `postgresql://postgres:${b.db_pass}@db.${b.project_ref}.supabase.co:5432/postgres`;
|
|
194
|
+
}
|
|
195
|
+
function publicBranch(b) {
|
|
196
|
+
const ready = Date.now() >= b.readyAt;
|
|
197
|
+
return {
|
|
198
|
+
id: b.id,
|
|
199
|
+
name: b.name,
|
|
200
|
+
project_ref: b.project_ref,
|
|
201
|
+
parent_project_ref: b.parent_project_ref,
|
|
202
|
+
is_default: b.is_default,
|
|
203
|
+
persistent: b.is_default,
|
|
204
|
+
status: ready ? "FUNCTIONS_DEPLOYED" : "CREATING_PROJECT",
|
|
205
|
+
preview_project_status: ready ? "ACTIVE_HEALTHY" : "COMING_UP",
|
|
206
|
+
with_data: false,
|
|
207
|
+
created_at: b.created_at,
|
|
208
|
+
updated_at: b.created_at,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function branchDetail(b) {
|
|
212
|
+
return {
|
|
213
|
+
ref: b.project_ref,
|
|
214
|
+
postgres_version: "17.4.1",
|
|
215
|
+
postgres_engine: "17",
|
|
216
|
+
release_channel: "ga",
|
|
217
|
+
status: Date.now() >= b.readyAt ? "ACTIVE_HEALTHY" : "COMING_UP",
|
|
218
|
+
db_host: `db.${b.project_ref}.supabase.co`,
|
|
219
|
+
db_port: 5432,
|
|
220
|
+
db_user: "postgres",
|
|
221
|
+
db_pass: b.db_pass,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/** The Auth config of a project ref: a parent project's, or a preview branch's own (assumption S9). */
|
|
225
|
+
function authOf(state, ref) {
|
|
226
|
+
return state.projects[ref]?.auth ?? branchByRef(state, ref)?.auth;
|
|
227
|
+
}
|
|
228
|
+
function authConfig(a) {
|
|
229
|
+
return { site_url: a.site_url, uri_allow_list: a.uri_allow_list, disable_signup: false, jwt_exp: 3600 };
|
|
230
|
+
}
|
|
231
|
+
function notFound(what) {
|
|
232
|
+
return new Reply(404, { message: `${what} not found` });
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=supabase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/routes/supabase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simulated Vercel: project env vars and deployments.
|
|
3
|
+
*
|
|
4
|
+
* Assumptions about the real API that this fake encodes, each marked with how far it is checked. "Verified" means
|
|
5
|
+
* against Vercel's published OpenAPI document (https://openapi.vercel.sh/, fetched 2026-10-10); see
|
|
6
|
+
* docs/api-verification.md for the per-call table. A local fake cannot prove the rest; scenarios/contract.test.ts
|
|
7
|
+
* pins the critical ones against live accounts (`pnpm test:live`):
|
|
8
|
+
* V1. Env writes are visible to the next deployment immediately (no propagation delay). Lists are
|
|
9
|
+
* read-your-writes here; the real list may lag a write, so adapters trust write responses instead.
|
|
10
|
+
* Unverified: needs a live account.
|
|
11
|
+
* V2. GET /v7/deployments?projectId=&sha= filters by commit and returns newest first. The `sha` filter is
|
|
12
|
+
* verified (a v7 query parameter; v6 is not in the spec); items carry `readyState` (required) and `state`
|
|
13
|
+
* (optional), and `url` may be null until the upload completes (verified). The order is unverified: the
|
|
14
|
+
* adapter sorts by createdAt anyway.
|
|
15
|
+
* V3. GET /v10/projects/:id/env?decrypt=true returns plaintext with `decrypted: true`; without `decrypt`,
|
|
16
|
+
* `encrypted` values are opaque. `decrypt` (deprecated), `decrypted` and GET /v1/projects/:id/env/:id
|
|
17
|
+
* ("Retrieve the decrypted value") are verified; whether the deprecated parameter still decrypts is
|
|
18
|
+
* unverified, so the adapter falls back to the per-variable GET. `sensitive` values are never returned
|
|
19
|
+
* (the GET /v1 variant without `value`), so those always diff as `update`.
|
|
20
|
+
* V4. POST /v10/projects/:id/env?upsert=true answers 201 with `{ created, failed }` (verified: `upsert`, the
|
|
21
|
+
* status, `created` as one object or a list, `failed[].error` with `code`, `message`, `key`/`envVarKey`).
|
|
22
|
+
* Unverified: that `created` lists every entry written (new or updated, `createdAt === updatedAt` only for
|
|
23
|
+
* new ones), and that an entry whose key+gitBranch exists with an overlapping but different target set
|
|
24
|
+
* fails the whole request with 400 `ENV_CONFLICT`. Entries named in chaos `env_upsert_fail` come back under
|
|
25
|
+
* `failed` and are not written. Without `upsert` a duplicate answers 403 (verified: documented 403 reason).
|
|
26
|
+
* V5. POST /v13/deployments: `project` overrides `name` and a GitHub `gitSource` needs `ref` plus `repoId` (or
|
|
27
|
+
* `org` + `repo`) — both verified, as is `forceNew`. Deployments go QUEUED → BUILDING → READY over chaos
|
|
28
|
+
* `deploy_ms` (default 0: READY at once; the real API also passes through INITIALIZING, which the adapter
|
|
29
|
+
* handles as in progress). Every deployment has its own URL (verified: "the unique URL of the deployment").
|
|
30
|
+
* `deploy: cancel` cancels a branch's in-progress builds when a new one starts (unverified).
|
|
31
|
+
* V6. Pagination (chaos `page_size`): `{ envs, pagination: { count, next, prev } }` (verified: the spec's
|
|
32
|
+
* Pagination schema). The `?until=` page parameter is unverified for the env list, which documents no page
|
|
33
|
+
* parameter; the adapter drops repeated records, so an API that ignores it costs one extra request.
|
|
34
|
+
* V7. GET /v9/projects/:id carries `link`, the connected repository (`type`, `repoId`, …); verified.
|
|
35
|
+
* V8. GET /v7/deployments accepts `target` (`production` | `preview`) and each item's `target` is `production`,
|
|
36
|
+
* a custom environment name such as `staging`, or null for a preview; verified against the spec's
|
|
37
|
+
* `/v7/deployments` parameters and item schema. The git integration builds previews; production builds
|
|
38
|
+
* of a commit exist separately.
|
|
39
|
+
*/
|
|
40
|
+
import { type CreatedBy, type ProviderSim, type SimCore } from "../provider.js";
|
|
41
|
+
/** One simulated Vercel environment variable. */
|
|
42
|
+
export interface VercelEnv {
|
|
43
|
+
id: string;
|
|
44
|
+
key: string;
|
|
45
|
+
value: string;
|
|
46
|
+
target: string[];
|
|
47
|
+
type: "encrypted" | "plain";
|
|
48
|
+
gitBranch?: string;
|
|
49
|
+
createdAt: number;
|
|
50
|
+
updatedAt: number;
|
|
51
|
+
createdBy: CreatedBy;
|
|
52
|
+
}
|
|
53
|
+
/** Vercel's deployment states, as its API reports them. */
|
|
54
|
+
export type DeploymentState = "QUEUED" | "BUILDING" | "READY" | "ERROR" | "CANCELED";
|
|
55
|
+
/** One simulated deployment. */
|
|
56
|
+
export interface VercelDeployment {
|
|
57
|
+
uid: string;
|
|
58
|
+
url: string;
|
|
59
|
+
state: DeploymentState;
|
|
60
|
+
createdAt: number;
|
|
61
|
+
/** While in progress: QUEUED until `buildingAt`, BUILDING until `readyAt`, then `finalState`. */
|
|
62
|
+
buildingAt?: number;
|
|
63
|
+
readyAt?: number;
|
|
64
|
+
finalState?: DeploymentState;
|
|
65
|
+
meta: {
|
|
66
|
+
githubCommitSha: string;
|
|
67
|
+
githubCommitRef?: string;
|
|
68
|
+
};
|
|
69
|
+
/** `production` for production deployments, null for previews. */
|
|
70
|
+
target: "production" | null;
|
|
71
|
+
createdBy: CreatedBy;
|
|
72
|
+
}
|
|
73
|
+
/** The Git repository a project is connected to (`link` in GET /v9/projects/:id); null when it has none. */
|
|
74
|
+
export interface VercelLink {
|
|
75
|
+
type: "github";
|
|
76
|
+
repoId: number;
|
|
77
|
+
org: string;
|
|
78
|
+
repo: string;
|
|
79
|
+
productionBranch: string;
|
|
80
|
+
}
|
|
81
|
+
/** One simulated Vercel project: its variables, deployments and Git connection. */
|
|
82
|
+
export interface VercelProject {
|
|
83
|
+
envs: VercelEnv[];
|
|
84
|
+
deployments: VercelDeployment[];
|
|
85
|
+
link: VercelLink | null;
|
|
86
|
+
}
|
|
87
|
+
/** Simulated Vercel: projects by id. */
|
|
88
|
+
export interface VercelState {
|
|
89
|
+
projects: Record<string, VercelProject>;
|
|
90
|
+
}
|
|
91
|
+
/** Initial Vercel state. */
|
|
92
|
+
export interface VercelSeed {
|
|
93
|
+
projects: Record<string, {
|
|
94
|
+
envs: Array<{
|
|
95
|
+
key: string;
|
|
96
|
+
value: string;
|
|
97
|
+
target: string;
|
|
98
|
+
gitBranch?: string;
|
|
99
|
+
}>;
|
|
100
|
+
}>;
|
|
101
|
+
}
|
|
102
|
+
/** Simulated Vercel (env vars, deployments); see the assumptions at the top of this file. */
|
|
103
|
+
export declare const vercelSim: ProviderSim<VercelState, VercelSeed>;
|
|
104
|
+
/**
|
|
105
|
+
* Every deployment gets its own URL: the first one of a sha is `<project>-<sha8>.vercel.app`, later ones
|
|
106
|
+
* (redeploys) `-2`, `-3`, … `buildMs` > 0 starts it QUEUED and makes it reach `state` over that time.
|
|
107
|
+
*/
|
|
108
|
+
export declare function createDeployment(core: SimCore, projectId: string, project: VercelProject, sha: string, state: DeploymentState, createdAt: number, opts?: {
|
|
109
|
+
ref?: string;
|
|
110
|
+
buildMs?: number;
|
|
111
|
+
target?: "production";
|
|
112
|
+
}): VercelDeployment;
|
|
113
|
+
/** Advance in-progress deployments to the state their timings say they are in now. */
|
|
114
|
+
export declare function refreshDeployments(list: VercelDeployment[], now?: number): void;
|