@spacefast/wpcloud-sdk 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +38 -0
  2. package/dist/fake/index.d.ts +4 -0
  3. package/dist/fake/index.d.ts.map +1 -0
  4. package/dist/fake/index.js +3 -0
  5. package/dist/fake/router.d.ts +17 -0
  6. package/dist/fake/router.d.ts.map +1 -0
  7. package/dist/fake/router.js +188 -0
  8. package/dist/fake/server.d.ts +10 -0
  9. package/dist/fake/server.d.ts.map +1 -0
  10. package/dist/fake/server.js +62 -0
  11. package/dist/fake/store.d.ts +67 -0
  12. package/dist/fake/store.d.ts.map +1 -0
  13. package/dist/fake/store.js +174 -0
  14. package/dist/generated/client/client.gen.d.ts +3 -0
  15. package/dist/generated/client/client.gen.d.ts.map +1 -0
  16. package/dist/generated/client/client.gen.js +216 -0
  17. package/dist/generated/client/index.d.ts +8 -0
  18. package/dist/generated/client/index.d.ts.map +1 -0
  19. package/dist/generated/client/index.js +5 -0
  20. package/dist/generated/client/types.gen.d.ts +125 -0
  21. package/dist/generated/client/types.gen.d.ts.map +1 -0
  22. package/dist/generated/client/types.gen.js +2 -0
  23. package/dist/generated/client/utils.gen.d.ts +39 -0
  24. package/dist/generated/client/utils.gen.d.ts.map +1 -0
  25. package/dist/generated/client/utils.gen.js +228 -0
  26. package/dist/generated/client.gen.d.ts +13 -0
  27. package/dist/generated/client.gen.d.ts.map +1 -0
  28. package/dist/generated/client.gen.js +7 -0
  29. package/dist/generated/core/auth.gen.d.ts +19 -0
  30. package/dist/generated/core/auth.gen.d.ts.map +1 -0
  31. package/dist/generated/core/auth.gen.js +14 -0
  32. package/dist/generated/core/bodySerializer.gen.d.ts +18 -0
  33. package/dist/generated/core/bodySerializer.gen.d.ts.map +1 -0
  34. package/dist/generated/core/bodySerializer.gen.js +57 -0
  35. package/dist/generated/core/params.gen.d.ts +34 -0
  36. package/dist/generated/core/params.gen.d.ts.map +1 -0
  37. package/dist/generated/core/params.gen.js +88 -0
  38. package/dist/generated/core/pathSerializer.gen.d.ts +34 -0
  39. package/dist/generated/core/pathSerializer.gen.d.ts.map +1 -0
  40. package/dist/generated/core/pathSerializer.gen.js +106 -0
  41. package/dist/generated/core/serverSentEvents.gen.d.ts +72 -0
  42. package/dist/generated/core/serverSentEvents.gen.d.ts.map +1 -0
  43. package/dist/generated/core/serverSentEvents.gen.js +131 -0
  44. package/dist/generated/core/types.gen.d.ts +79 -0
  45. package/dist/generated/core/types.gen.d.ts.map +1 -0
  46. package/dist/generated/core/types.gen.js +2 -0
  47. package/dist/generated/core/utils.gen.d.ts +15 -0
  48. package/dist/generated/core/utils.gen.d.ts.map +1 -0
  49. package/dist/generated/core/utils.gen.js +69 -0
  50. package/dist/generated/sdk.gen.d.ts +840 -0
  51. package/dist/generated/sdk.gen.d.ts.map +1 -0
  52. package/dist/generated/sdk.gen.js +2198 -0
  53. package/dist/generated/types.gen.d.ts +7970 -0
  54. package/dist/generated/types.gen.d.ts.map +1 -0
  55. package/dist/generated/types.gen.js +2 -0
  56. package/dist/runtime.d.ts +24 -0
  57. package/dist/runtime.d.ts.map +1 -0
  58. package/dist/runtime.js +486 -0
  59. package/package.json +36 -0
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # `@spacefast/wpcloud-sdk`
2
+
3
+ Generated TypeScript client for the WP.Cloud API.
4
+
5
+ Use this package to call WP.Cloud from TypeScript services, automation, and
6
+ infrastructure tools without hand-writing request serialization or response
7
+ unwrapping code.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @spacefast/wpcloud-sdk
13
+ ```
14
+
15
+ ## Runtime Configuration
16
+
17
+ ```ts
18
+ import { createClientConfig } from "@spacefast/wpcloud-sdk/runtime";
19
+ import { createClient } from "@spacefast/wpcloud-sdk/generated/client.gen";
20
+
21
+ const client = createClient(
22
+ createClientConfig({
23
+ baseUrl: "https://wp.cloud/api",
24
+ headers: {
25
+ Authorization: `Bearer ${process.env.WPCLOUD_TOKEN}`,
26
+ },
27
+ }),
28
+ );
29
+ ```
30
+
31
+ `createClientConfig` configures the generated client for WP.Cloud request and
32
+ response conventions, including form-encoded request bodies, response envelope
33
+ unwrapping, and timeout-aware fetch errors.
34
+
35
+ ## Documentation
36
+
37
+ - [WP.Cloud](https://wp.cloud)
38
+ - [WP.Cloud API docs](https://wp.cloud/docs/api)
@@ -0,0 +1,4 @@
1
+ export { makeFakeAtomic, defaultFakeFetch } from "./server.js";
2
+ export { FakeAtomicStore, type FakeSite } from "./store.js";
3
+ export { routeFakeRequest, type FakeResult } from "./router.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fake/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { makeFakeAtomic, defaultFakeFetch } from "./server.js";
2
+ export { FakeAtomicStore } from "./store.js";
3
+ export { routeFakeRequest } from "./router.js";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Routes a parsed wp.cloud request to the in-memory store and returns the `{message, data}` envelope
3
+ * the real API uses. Errors are `{message, data: []}` + an HTTP status with NO machine code — exactly
4
+ * what the captured fixtures show (the control plane classifies on status + message text).
5
+ */
6
+ import { FakeAtomicStore } from "./store.js";
7
+ export type FakeResult = {
8
+ status: number;
9
+ body: unknown;
10
+ };
11
+ /**
12
+ * @param path the path after `/api/v1.0/`, e.g. `create-site/minipage` or `site-meta/151/_data/get`
13
+ * (segments still URL-encoded; this fn decodes the ones it needs)
14
+ * @param body the nested-decoded request body (form-urlencoded → object)
15
+ */
16
+ export declare function routeFakeRequest(store: FakeAtomicStore, method: string, path: string, body: Record<string, unknown>): FakeResult;
17
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/fake/router.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,MAAM,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AA0C3D;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,eAAe,EACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,UAAU,CAmJZ"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Routes a parsed wp.cloud request to the in-memory store and returns the `{message, data}` envelope
3
+ * the real API uses. Errors are `{message, data: []}` + an HTTP status with NO machine code — exactly
4
+ * what the captured fixtures show (the control plane classifies on status + message text).
5
+ */
6
+ import { FakeAtomicStore } from "./store.js";
7
+ const ok = (data) => ({ status: 200, body: { message: "OK", data } });
8
+ const fail = (status, message) => ({
9
+ status,
10
+ body: { message, data: [] },
11
+ });
12
+ const RESTRICTED_DOMAINS = new Set(["wordpress.com", "wp.com", "automattic.com"]);
13
+ function isRecord(value) {
14
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
15
+ }
16
+ function asStringMap(value) {
17
+ const out = {};
18
+ if (isRecord(value)) {
19
+ for (const [k, v] of Object.entries(value))
20
+ out[k] = String(v);
21
+ }
22
+ return out;
23
+ }
24
+ const READABLE_CLIENT_META_KEYS = new Set([
25
+ "webhook_url",
26
+ "client_ssh_default_from",
27
+ "client_ssh_force_from",
28
+ "client_ssh_firewall",
29
+ "default_privacy_model",
30
+ "max_space_quota",
31
+ "skip_force_backup_db",
32
+ ]);
33
+ const WRITABLE_CLIENT_META_KEYS = new Set([
34
+ "webhook_url",
35
+ "webhook_secret_key",
36
+ "client_ssh_default_from",
37
+ "client_ssh_force_from",
38
+ "client_ssh_firewall",
39
+ "default_privacy_model",
40
+ "webhook_hmac_key",
41
+ "skip_force_backup_db",
42
+ ]);
43
+ /**
44
+ * @param path the path after `/api/v1.0/`, e.g. `create-site/minipage` or `site-meta/151/_data/get`
45
+ * (segments still URL-encoded; this fn decodes the ones it needs)
46
+ * @param body the nested-decoded request body (form-urlencoded → object)
47
+ */
48
+ export function routeFakeRequest(store, method, path, body) {
49
+ const seg = path.split("/").filter(Boolean);
50
+ const head = seg[0] ?? "";
51
+ // --- static reads ---------------------------------------------------------------------------
52
+ if (method === "GET" && head === "get-available-datacenters")
53
+ return ok(store.datacenters());
54
+ if (method === "GET" && head === "get-php-versions")
55
+ return ok(store.phpVersions());
56
+ if (method === "GET" && head === "check-can-host-domain") {
57
+ const domain = decodeURIComponent(seg[2] ?? "");
58
+ if (RESTRICTED_DOMAINS.has(domain))
59
+ return fail(400, `Restricted domain [${domain}]`);
60
+ if (domain.endsWith("example.com")) {
61
+ return fail(400, `Domain name already used [${domain}]. TXT record verification is required to bypass this check.`);
62
+ }
63
+ return ok([]); // claimable
64
+ }
65
+ // --- sites lifecycle ------------------------------------------------------------------------
66
+ // GET /get-sites/{client}[/+_data]?limit=… — one page is enough (the client stops below pageSize)
67
+ if (method === "GET" && head === "get-sites") {
68
+ return ok(store.list().map((site) => store.listEntry(site)));
69
+ }
70
+ // POST /create-site/{client}
71
+ if (method === "POST" && head === "create-site") {
72
+ const meta = asStringMap(body.meta);
73
+ const domainName = String(body.domain_name ?? `fake-${store.nextJobId()}.wpcomstaging.com`);
74
+ return ok(store.createSite({ domainName, meta }));
75
+ }
76
+ // POST /delete-site/{service}/{identifier}
77
+ if (method === "POST" && head === "delete-site") {
78
+ return ok(store.delete(seg[2] ?? ""));
79
+ }
80
+ // GET /get-site/{site}[/extra]
81
+ if (method === "GET" && head === "get-site") {
82
+ const site = store.get(seg[1] ?? "");
83
+ return site ? ok(store.siteExtra(site)) : fail(404, "Site not found.");
84
+ }
85
+ // GET /job-completion/{id} , GET /job-status/{id} — jobs settle immediately in the fake
86
+ if (method === "GET" && head === "job-completion")
87
+ return ok("success");
88
+ if (method === "GET" && head === "job-status")
89
+ return ok({ status: "success" });
90
+ // POST /site-persist-data/{site}
91
+ if (method === "POST" && head === "site-persist-data") {
92
+ const data = isRecord(body.data) ? store.applyPersistentData(seg[1] ?? "", body.data) : null;
93
+ if (!data)
94
+ return fail(404, "Site not found.");
95
+ return ok({
96
+ response_ticket_id: "fake-persist-ticket",
97
+ job_id: store.nextJobId(),
98
+ data,
99
+ });
100
+ }
101
+ // /site-meta/{site}/{key}/{action}
102
+ if (head === "site-meta") {
103
+ const [, id, key, action] = seg;
104
+ if (method === "GET" && action === "get") {
105
+ // envelope `data` is the raw value string (or null) — faithful to the captured _data/get
106
+ return ok(store.getMeta(id ?? "", key ?? "") ?? null);
107
+ }
108
+ if (method === "POST" && (action === "update" || action === "add")) {
109
+ store.setMeta(id ?? "", key ?? "", String(body.value ?? ""));
110
+ return ok([]);
111
+ }
112
+ }
113
+ // /site-alias/{client}/{id}/{op}[/{domain}]
114
+ if (method === "GET" && head === "site-alias") {
115
+ const id = seg[2] ?? "";
116
+ const op = seg[3];
117
+ const domain = decodeURIComponent(seg[4] ?? "");
118
+ if (op === "list")
119
+ return ok({ domains: store.aliases(id) });
120
+ if (op === "add") {
121
+ store.addAlias(id, domain);
122
+ return ok({ domains: store.aliases(id) });
123
+ }
124
+ if (op === "remove") {
125
+ store.removeAlias(id, domain);
126
+ return ok([]);
127
+ }
128
+ }
129
+ // /edge-cache/{id}/{op}/{host} — lean: benign success so publish/serve never trips on it.
130
+ // Real edge-cache behavior is covered by the gated `direct/` suites, not the fake.
131
+ if (head === "edge-cache") {
132
+ const op = seg[2];
133
+ if (op === "on" || op === "off" || op === "purge")
134
+ return ok([]);
135
+ if (op === "get")
136
+ return ok({ state: "enabled", status_code: 200, ddos_until: null });
137
+ }
138
+ // /ssl-info/{host} — lean: not provisioned (loadWpCloudSslInfo tolerates null). SSL = direct suites.
139
+ if (head === "ssl-info")
140
+ return fail(404, "Site not found.");
141
+ // POST /site-logs/{site} — enough provider shape for the control plane's
142
+ // access-log normalization and hostname filtering to run in full-lane tests.
143
+ if (method === "POST" && head === "site-logs") {
144
+ const logs = store.accessLogs(seg[1] ?? "");
145
+ return logs ? ok({ logs }) : fail(404, "Site not found.");
146
+ }
147
+ // /client-authorized-keys/{client}/{op}[/{id}] — deploy-key registration with the
148
+ // platform. The full lane's local-atomic node already trusts the test deploy key via
149
+ // its authorized_keys, so ack add/list/remove and let real SSH carry the deploy.
150
+ if (head === "client-authorized-keys") {
151
+ const op = seg[2];
152
+ if (op === "list")
153
+ return ok({ keys: [] });
154
+ return ok([]); // add / remove
155
+ }
156
+ // /client-meta/{client}/{key}/{action}
157
+ if (head === "client-meta") {
158
+ const [, , key, action] = seg.map((part) => decodeURIComponent(part));
159
+ if (!key)
160
+ return fail(400, "Invalid key");
161
+ if (method === "GET" && action === "get") {
162
+ if (!READABLE_CLIENT_META_KEYS.has(key))
163
+ return fail(400, "Invalid key");
164
+ const value = store.getClientMeta(key);
165
+ return value === undefined ? fail(404, "Not Found") : ok(value);
166
+ }
167
+ if (method === "GET" && action === "remove") {
168
+ if (!WRITABLE_CLIENT_META_KEYS.has(key))
169
+ return fail(400, "Invalid key");
170
+ store.deleteClientMeta(key);
171
+ return ok([]);
172
+ }
173
+ if (method === "POST" && (action === "update" || action === "add")) {
174
+ if (!WRITABLE_CLIENT_META_KEYS.has(key))
175
+ return fail(400, "Invalid key");
176
+ if (body.value === undefined || body.value === null || body.value === "") {
177
+ return fail(400, "A value must be provided");
178
+ }
179
+ if (action === "update" && store.getClientMeta(key) === undefined) {
180
+ return fail(404, "Not Found");
181
+ }
182
+ store.setClientMeta(key, String(body.value));
183
+ return ok([]);
184
+ }
185
+ }
186
+ // Anything the control plane calls that we don't model: surface it loudly, don't silently pass.
187
+ return fail(404, `fake_endpoint_not_implemented: ${method} /${path}`);
188
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The lean wp.cloud fake exposed as a `fetch`-shaped function — the same seam `wpCloudRawFetch` uses.
3
+ * `makeFakeAtomic()` gives a fresh, isolated store (per-suite use via `setWpCloudFakeFetch`);
4
+ * `defaultFakeFetch` is a process-global instance for env-driven `WP_CLOUD_PROVIDER_MODE=fake`.
5
+ */
6
+ import type { WpCloudFakeFetch } from "../runtime.js";
7
+ export declare function makeFakeAtomic(): WpCloudFakeFetch;
8
+ /** Process-global fake for `WP_CLOUD_PROVIDER_MODE=fake` (no per-suite override installed). */
9
+ export declare const defaultFakeFetch: WpCloudFakeFetch;
10
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/fake/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AA6CtD,wBAAgB,cAAc,IAAI,gBAAgB,CAiBjD;AAED,+FAA+F;AAC/F,eAAO,MAAM,gBAAgB,EAAE,gBAAmC,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { routeFakeRequest } from "./router.js";
2
+ import { FakeAtomicStore } from "./store.js";
3
+ /** Decode an `application/x-www-form-urlencoded` body, un-nesting `key[child]` / `key[]` keys. */
4
+ function parseNestedForm(raw) {
5
+ const out = {};
6
+ for (const [rawKey, value] of new URLSearchParams(raw)) {
7
+ const segs = rawKey.replace(/\]/g, "").split("[");
8
+ let node = out;
9
+ for (let i = 0; i < segs.length; i++) {
10
+ const key = segs[i];
11
+ const last = i === segs.length - 1;
12
+ if (last) {
13
+ if (key === "" && Array.isArray(node))
14
+ node.push(value);
15
+ else
16
+ node[key] = value;
17
+ }
18
+ else {
19
+ const container = node;
20
+ const nextIsArray = segs[i + 1] === "";
21
+ container[key] ??= nextIsArray ? [] : {};
22
+ node = container[key];
23
+ }
24
+ }
25
+ }
26
+ return out;
27
+ }
28
+ async function readBody(input, init) {
29
+ let raw = "";
30
+ const body = init?.body;
31
+ if (typeof body === "string")
32
+ raw = body;
33
+ else if (body instanceof URLSearchParams)
34
+ raw = body.toString();
35
+ else if (input instanceof Request) {
36
+ try {
37
+ raw = await input.text();
38
+ }
39
+ catch {
40
+ raw = "";
41
+ }
42
+ }
43
+ return raw ? parseNestedForm(raw) : {};
44
+ }
45
+ export function makeFakeAtomic() {
46
+ const store = new FakeAtomicStore();
47
+ return async (input, init) => {
48
+ const rawUrl = input instanceof Request ? input.url : String(input);
49
+ const url = new URL(rawUrl);
50
+ // path after /api/v1.0/, trailing slash trimmed; segments stay encoded (router decodes its own)
51
+ const path = url.pathname.replace(/^.*\/api\/v1\.0\//, "").replace(/\/+$/, "");
52
+ const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
53
+ const body = await readBody(input, init);
54
+ const { status, body: payload } = routeFakeRequest(store, method, path, body);
55
+ return new Response(JSON.stringify(payload), {
56
+ status,
57
+ headers: { "content-type": "application/json" },
58
+ });
59
+ };
60
+ }
61
+ /** Process-global fake for `WP_CLOUD_PROVIDER_MODE=fake` (no per-suite override installed). */
62
+ export const defaultFakeFetch = makeFakeAtomic();
@@ -0,0 +1,67 @@
1
+ /**
2
+ * In-memory state for the lean wp.cloud fake. Models only the lifecycle we captured real shapes for
3
+ * (sites, jobs, aliases, meta) — see internal-docs/testing-system-plan.html §4. Edge-cache / SSL /
4
+ * domain-claim are answered leniently by the router but not modelled here; their real behavior lives
5
+ * in the gated `direct/` suites.
6
+ */
7
+ export type FakeSite = {
8
+ atomicSiteId: string;
9
+ domainName: string;
10
+ meta: Record<string, string>;
11
+ persistentData: Record<string, string>;
12
+ aliases: Set<string>;
13
+ };
14
+ export type FakeSiteSnapshot = {
15
+ atomicSiteId: string;
16
+ domainName: string;
17
+ meta: Record<string, string>;
18
+ persistentData: Record<string, string>;
19
+ aliases: string[];
20
+ };
21
+ export declare class FakeAtomicStore {
22
+ private readonly sites;
23
+ private readonly clientMeta;
24
+ private siteSeq;
25
+ private jobSeq;
26
+ datacenters(): string[];
27
+ phpVersions(): string[];
28
+ nextJobId(): number;
29
+ createSite(input: {
30
+ domainName: string;
31
+ meta: Record<string, string>;
32
+ }): {
33
+ job_id: number;
34
+ atomic_site_id: number;
35
+ domain_name: string;
36
+ };
37
+ ensureSite(input: {
38
+ atomicSiteId: string;
39
+ domainName: string;
40
+ meta?: Record<string, string>;
41
+ persistentData?: Record<string, string>;
42
+ aliases?: Iterable<string>;
43
+ }): FakeSite;
44
+ snapshot(): FakeSiteSnapshot[];
45
+ get(id: string): FakeSite | undefined;
46
+ delete(id: string): {
47
+ job_id: number;
48
+ };
49
+ list(): FakeSite[];
50
+ setMeta(id: string, key: string, value: string): void;
51
+ getMeta(id: string, key: string): string | undefined;
52
+ addAlias(id: string, domain: string): void;
53
+ removeAlias(id: string, domain: string): void;
54
+ aliases(id: string): string[];
55
+ accessLogs(id: string): Array<Record<string, unknown>> | null;
56
+ setClientMeta(key: string, value: string): void;
57
+ getClientMeta(key: string): string | undefined;
58
+ deleteClientMeta(key: string): boolean;
59
+ applyPersistentData(id: string, operations: Record<string, unknown>): Record<string, string> | null;
60
+ persistentData(id: string): Record<string, string> | null;
61
+ /** `GET /get-site/{id}/extra` shape — note `_data` is intentionally ABSENT (faithful to the real
62
+ * endpoint, which omits it; the marker lives only on the list + site-meta endpoints). */
63
+ siteExtra(site: FakeSite): Record<string, unknown>;
64
+ /** `GET /get-sites/{client}?meta=_data` entry shape — carries `_data` so findWpCloudSiteByTargetId works. */
65
+ listEntry(site: FakeSite): Record<string, unknown>;
66
+ }
67
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/fake/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * In-memory state for the lean wp.cloud fake. Models only the lifecycle we captured real shapes for
3
+ * (sites, jobs, aliases, meta) — see internal-docs/testing-system-plan.html §4. Edge-cache / SSL /
4
+ * domain-claim are answered leniently by the router but not modelled here; their real behavior lives
5
+ * in the gated `direct/` suites.
6
+ */
7
+ const DATACENTERS = ["ams", "bur", "dca", "dfw"];
8
+ const PHP_VERSIONS = ["8.2", "8.3", "8.4", "8.5"];
9
+ function formFlag(value) {
10
+ return value === true || value === 1 || value === "1" || value === "true" || value === "on";
11
+ }
12
+ export class FakeAtomicStore {
13
+ sites = new Map();
14
+ clientMeta = new Map();
15
+ siteSeq = 151_000_000;
16
+ jobSeq = 154_000_000;
17
+ datacenters() {
18
+ return [...DATACENTERS];
19
+ }
20
+ phpVersions() {
21
+ return [...PHP_VERSIONS];
22
+ }
23
+ nextJobId() {
24
+ return ++this.jobSeq;
25
+ }
26
+ createSite(input) {
27
+ const atomicSiteId = String(++this.siteSeq);
28
+ this.sites.set(atomicSiteId, {
29
+ atomicSiteId,
30
+ domainName: input.domainName,
31
+ meta: { ...input.meta },
32
+ persistentData: {},
33
+ aliases: new Set(),
34
+ });
35
+ return {
36
+ job_id: this.nextJobId(),
37
+ atomic_site_id: Number(atomicSiteId),
38
+ domain_name: input.domainName,
39
+ };
40
+ }
41
+ ensureSite(input) {
42
+ const existing = this.sites.get(input.atomicSiteId);
43
+ if (existing)
44
+ return existing;
45
+ this.siteSeq = Math.max(this.siteSeq, Number(input.atomicSiteId) || this.siteSeq);
46
+ const site = {
47
+ atomicSiteId: input.atomicSiteId,
48
+ domainName: input.domainName,
49
+ meta: input.meta ? { ...input.meta } : {},
50
+ persistentData: input.persistentData ? { ...input.persistentData } : {},
51
+ aliases: new Set(input.aliases ?? []),
52
+ };
53
+ this.sites.set(input.atomicSiteId, site);
54
+ return site;
55
+ }
56
+ snapshot() {
57
+ return [...this.sites.values()].map((site) => ({
58
+ atomicSiteId: site.atomicSiteId,
59
+ domainName: site.domainName,
60
+ meta: { ...site.meta },
61
+ persistentData: { ...site.persistentData },
62
+ aliases: [...site.aliases],
63
+ }));
64
+ }
65
+ get(id) {
66
+ return this.sites.get(id);
67
+ }
68
+ delete(id) {
69
+ this.sites.delete(id);
70
+ return { job_id: this.nextJobId() };
71
+ }
72
+ list() {
73
+ return [...this.sites.values()];
74
+ }
75
+ setMeta(id, key, value) {
76
+ const site = this.sites.get(id);
77
+ if (site)
78
+ site.meta[key] = value;
79
+ }
80
+ getMeta(id, key) {
81
+ return this.sites.get(id)?.meta[key];
82
+ }
83
+ addAlias(id, domain) {
84
+ this.sites.get(id)?.aliases.add(domain);
85
+ }
86
+ removeAlias(id, domain) {
87
+ this.sites.get(id)?.aliases.delete(domain);
88
+ }
89
+ aliases(id) {
90
+ return [...(this.sites.get(id)?.aliases ?? [])];
91
+ }
92
+ accessLogs(id) {
93
+ const site = this.sites.get(id);
94
+ if (!site)
95
+ return null;
96
+ const host = [...site.aliases][0] ?? site.domainName;
97
+ return [
98
+ {
99
+ timestamp: Math.floor(Date.now() / 1000),
100
+ http_host: host,
101
+ request_type: "GET",
102
+ request_url: "/",
103
+ status: 200,
104
+ response_bytes: 1024,
105
+ },
106
+ ];
107
+ }
108
+ setClientMeta(key, value) {
109
+ this.clientMeta.set(key, value);
110
+ }
111
+ getClientMeta(key) {
112
+ return this.clientMeta.get(key);
113
+ }
114
+ deleteClientMeta(key) {
115
+ return this.clientMeta.delete(key);
116
+ }
117
+ applyPersistentData(id, operations) {
118
+ const site = this.sites.get(id);
119
+ if (!site)
120
+ return null;
121
+ for (const [key, operation] of Object.entries(operations)) {
122
+ if (!operation || typeof operation !== "object" || Array.isArray(operation))
123
+ continue;
124
+ const record = operation;
125
+ if (formFlag(record.delete)) {
126
+ delete site.persistentData[key];
127
+ continue;
128
+ }
129
+ site.persistentData[key] = String(record.value ?? "");
130
+ }
131
+ return this.persistentData(id);
132
+ }
133
+ persistentData(id) {
134
+ const site = this.sites.get(id);
135
+ if (!site)
136
+ return null;
137
+ return { ...site.persistentData };
138
+ }
139
+ /** `GET /get-site/{id}/extra` shape — note `_data` is intentionally ABSENT (faithful to the real
140
+ * endpoint, which omits it; the marker lives only on the list + site-meta endpoints). */
141
+ siteExtra(site) {
142
+ return {
143
+ atomic_site_id: site.atomicSiteId,
144
+ wpcom_blog_id: null,
145
+ domain_name: site.domainName,
146
+ server_pool_id: "146",
147
+ atomic_client_id: "168",
148
+ chroot_path: "/client-chroot/generic/web",
149
+ chroot_ssh_path: "/client-chroot/generic/ssh",
150
+ burst_php_conns: Number(site.meta.burst_php_conns ?? 0),
151
+ cache_prefix: "fake00000000000000000000000000000",
152
+ canonicalize_aliases: site.meta.canonicalize_aliases ?? "false",
153
+ db_charset: "utf8mb4",
154
+ db_collate: "utf8mb4_general_ci",
155
+ db_pass: "[REDACTED]",
156
+ default_php_conns: Number(site.meta.default_php_conns ?? 10),
157
+ php_fs_permissions: site.meta.php_fs_permissions ?? "RW",
158
+ php_memory_limit: Number(site.meta.php_memory_limit ?? 512),
159
+ php_version: site.meta.php_version ?? "8.4",
160
+ site_api_key: "[REDACTED]",
161
+ static_file_404: site.meta.static_file_404 ?? "wordpress",
162
+ wp_admin_user: `stattic-${site.atomicSiteId}`.slice(0, 32),
163
+ wp_version: "latest",
164
+ };
165
+ }
166
+ /** `GET /get-sites/{client}?meta=_data` entry shape — carries `_data` so findWpCloudSiteByTargetId works. */
167
+ listEntry(site) {
168
+ return {
169
+ atomic_site_id: Number(site.atomicSiteId),
170
+ domain_name: site.domainName,
171
+ _data: site.meta._data ?? null,
172
+ };
173
+ }
174
+ }
@@ -0,0 +1,3 @@
1
+ import type { Client, Config } from "./types.gen";
2
+ export declare const createClient: (config?: Config) => Client;
3
+ //# sourceMappingURL=client.gen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.gen.d.ts","sourceRoot":"","sources":["../../../src/generated/client/client.gen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAA0C,MAAM,aAAa,CAAC;AAgB1F,eAAO,MAAM,YAAY,GAAI,SAAQ,MAAW,KAAG,MA2PlD,CAAC"}