@spacefast/wpcloud-sdk 0.0.23 → 0.0.24
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/generated/sdk.gen.d.ts +2 -2
- package/dist/generated/sdk.gen.js +2 -2
- package/dist/generated/types.gen.d.ts +13 -5
- package/dist/generated/types.gen.d.ts.map +1 -1
- package/dist/runtime.d.ts +1 -7
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +24 -315
- package/package.json +1 -6
- package/dist/fake/index.d.ts +0 -2
- package/dist/fake/index.d.ts.map +0 -1
- package/dist/fake/index.js +0 -1
- package/dist/fake/router.d.ts +0 -13
- package/dist/fake/router.d.ts.map +0 -1
- package/dist/fake/router.js +0 -329
- package/dist/fake/server.d.ts +0 -28
- package/dist/fake/server.d.ts.map +0 -1
- package/dist/fake/server.js +0 -108
- package/dist/fake/store.d.ts +0 -157
- package/dist/fake/store.d.ts.map +0 -1
- package/dist/fake/store.js +0 -306
- package/dist/fake/test-fixtures/isolation-target.d.ts +0 -2
- package/dist/fake/test-fixtures/isolation-target.d.ts.map +0 -1
- package/dist/fake/test-fixtures/isolation-target.js +0 -1
package/dist/fake/store.js
DELETED
|
@@ -1,306 +0,0 @@
|
|
|
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, crontab) — see internal-docs/testing-system-plan.html §4. Edge-cache /
|
|
4
|
-
* SSL / domain-claim are answered leniently by the router but not modelled here; their real behavior
|
|
5
|
-
* lives in the gated `direct/` suites.
|
|
6
|
-
*/
|
|
7
|
-
import { createHash } from "node:crypto";
|
|
8
|
-
const DEFAULT_PERSIST_DATA_BEHAVIOR = {
|
|
9
|
-
ticketPolls: ["success"],
|
|
10
|
-
omitResponseTicket: false,
|
|
11
|
-
lockRefusals: 0,
|
|
12
|
-
retryAfterSeconds: 10,
|
|
13
|
-
};
|
|
14
|
-
const DATACENTERS = ["ams", "bur", "dca", "dfw"];
|
|
15
|
-
const PHP_VERSIONS = ["8.2", "8.3", "8.4", "8.5"];
|
|
16
|
-
function formFlag(value) {
|
|
17
|
-
return value === true || value === 1 || value === "1" || value === "true" || value === "on";
|
|
18
|
-
}
|
|
19
|
-
export class FakeAtomicStore {
|
|
20
|
-
sites = new Map();
|
|
21
|
-
clientMeta = new Map();
|
|
22
|
-
metricsResponses = new Map();
|
|
23
|
-
metricRequestLog = [];
|
|
24
|
-
responseTickets = new Map();
|
|
25
|
-
persistDataBehavior = { ...DEFAULT_PERSIST_DATA_BEHAVIOR };
|
|
26
|
-
siteSeq;
|
|
27
|
-
jobSeq = 154_000_000;
|
|
28
|
-
cronSeq = 900_000;
|
|
29
|
-
ticketSeq = 0;
|
|
30
|
-
constructor(options = {}) {
|
|
31
|
-
this.siteSeq = options.siteSequenceStart ?? 151_000_000;
|
|
32
|
-
}
|
|
33
|
-
datacenters() {
|
|
34
|
-
return [...DATACENTERS];
|
|
35
|
-
}
|
|
36
|
-
phpVersions() {
|
|
37
|
-
return [...PHP_VERSIONS];
|
|
38
|
-
}
|
|
39
|
-
nextJobId() {
|
|
40
|
-
return ++this.jobSeq;
|
|
41
|
-
}
|
|
42
|
-
createSite(input) {
|
|
43
|
-
const atomicSiteId = String(++this.siteSeq);
|
|
44
|
-
this.sites.set(atomicSiteId, {
|
|
45
|
-
atomicSiteId,
|
|
46
|
-
domainName: input.domainName,
|
|
47
|
-
meta: { ...input.meta },
|
|
48
|
-
persistentData: {},
|
|
49
|
-
persistentDataEnv: {},
|
|
50
|
-
aliases: new Set(),
|
|
51
|
-
crons: [],
|
|
52
|
-
});
|
|
53
|
-
return {
|
|
54
|
-
job_id: this.nextJobId(),
|
|
55
|
-
atomic_site_id: Number(atomicSiteId),
|
|
56
|
-
domain_name: input.domainName,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
ensureSite(input) {
|
|
60
|
-
const existing = this.sites.get(input.atomicSiteId);
|
|
61
|
-
if (existing)
|
|
62
|
-
return existing;
|
|
63
|
-
this.siteSeq = Math.max(this.siteSeq, Number(input.atomicSiteId) || this.siteSeq);
|
|
64
|
-
const site = {
|
|
65
|
-
atomicSiteId: input.atomicSiteId,
|
|
66
|
-
domainName: input.domainName,
|
|
67
|
-
meta: input.meta ? { ...input.meta } : {},
|
|
68
|
-
persistentData: input.persistentData ? { ...input.persistentData } : {},
|
|
69
|
-
persistentDataEnv: input.persistentDataEnv ? { ...input.persistentDataEnv } : {},
|
|
70
|
-
aliases: new Set(input.aliases ?? []),
|
|
71
|
-
crons: [],
|
|
72
|
-
};
|
|
73
|
-
this.sites.set(input.atomicSiteId, site);
|
|
74
|
-
return site;
|
|
75
|
-
}
|
|
76
|
-
snapshot() {
|
|
77
|
-
return [...this.sites.values()].map((site) => ({
|
|
78
|
-
atomicSiteId: site.atomicSiteId,
|
|
79
|
-
domainName: site.domainName,
|
|
80
|
-
meta: { ...site.meta },
|
|
81
|
-
persistentData: { ...site.persistentData },
|
|
82
|
-
persistentDataEnv: { ...site.persistentDataEnv },
|
|
83
|
-
aliases: [...site.aliases],
|
|
84
|
-
}));
|
|
85
|
-
}
|
|
86
|
-
get(id) {
|
|
87
|
-
return this.sites.get(id);
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Atomic's `get_site_by_site_id_or_domain`: an argument containing a dot is
|
|
91
|
-
* matched against `atomic_site.domain_name` first, then against the alias
|
|
92
|
-
* table (`atomic_domain` joined onto `atomic_site`); anything else is a site
|
|
93
|
-
* id. This is what lets one `get-site` call answer "who holds this hostname?".
|
|
94
|
-
*/
|
|
95
|
-
resolve(idOrDomain) {
|
|
96
|
-
if (!idOrDomain.includes(".")) {
|
|
97
|
-
return this.sites.get(idOrDomain);
|
|
98
|
-
}
|
|
99
|
-
const sites = [...this.sites.values()];
|
|
100
|
-
return (sites.find((site) => site.domainName === idOrDomain) ??
|
|
101
|
-
sites.find((site) => site.aliases.has(idOrDomain)));
|
|
102
|
-
}
|
|
103
|
-
delete(id) {
|
|
104
|
-
this.sites.delete(id);
|
|
105
|
-
return { job_id: this.nextJobId() };
|
|
106
|
-
}
|
|
107
|
-
list() {
|
|
108
|
-
return [...this.sites.values()];
|
|
109
|
-
}
|
|
110
|
-
setMeta(id, key, value) {
|
|
111
|
-
const site = this.sites.get(id);
|
|
112
|
-
if (site)
|
|
113
|
-
site.meta[key] = value;
|
|
114
|
-
}
|
|
115
|
-
getMeta(id, key) {
|
|
116
|
-
return this.sites.get(id)?.meta[key];
|
|
117
|
-
}
|
|
118
|
-
removeMeta(id, key) {
|
|
119
|
-
const site = this.sites.get(id);
|
|
120
|
-
if (site)
|
|
121
|
-
delete site.meta[key];
|
|
122
|
-
}
|
|
123
|
-
addAlias(id, domain) {
|
|
124
|
-
this.sites.get(id)?.aliases.add(domain);
|
|
125
|
-
}
|
|
126
|
-
removeAlias(id, domain) {
|
|
127
|
-
this.sites.get(id)?.aliases.delete(domain);
|
|
128
|
-
}
|
|
129
|
-
aliases(id) {
|
|
130
|
-
return [...(this.sites.get(id)?.aliases ?? [])];
|
|
131
|
-
}
|
|
132
|
-
addCron(id, input) {
|
|
133
|
-
const site = this.sites.get(id);
|
|
134
|
-
if (!site)
|
|
135
|
-
return null;
|
|
136
|
-
const cron = {
|
|
137
|
-
cronId: ++this.cronSeq,
|
|
138
|
-
schedule: input.schedule,
|
|
139
|
-
requestedSchedule: input.schedule,
|
|
140
|
-
command: input.command,
|
|
141
|
-
};
|
|
142
|
-
site.crons.push(cron);
|
|
143
|
-
return cron;
|
|
144
|
-
}
|
|
145
|
-
listCrons(id) {
|
|
146
|
-
return [...(this.sites.get(id)?.crons ?? [])];
|
|
147
|
-
}
|
|
148
|
-
updateCron(id, cronId, command) {
|
|
149
|
-
const cron = this.sites.get(id)?.crons.find((entry) => entry.cronId === cronId);
|
|
150
|
-
if (!cron)
|
|
151
|
-
return false;
|
|
152
|
-
cron.command = command;
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
removeCron(id, cronId) {
|
|
156
|
-
const site = this.sites.get(id);
|
|
157
|
-
if (!site)
|
|
158
|
-
return false;
|
|
159
|
-
const before = site.crons.length;
|
|
160
|
-
site.crons = site.crons.filter((entry) => entry.cronId !== cronId);
|
|
161
|
-
return site.crons.length < before;
|
|
162
|
-
}
|
|
163
|
-
accessLogs(id) {
|
|
164
|
-
const site = this.sites.get(id);
|
|
165
|
-
if (!site)
|
|
166
|
-
return null;
|
|
167
|
-
const host = [...site.aliases][0] ?? site.domainName;
|
|
168
|
-
return [
|
|
169
|
-
{
|
|
170
|
-
timestamp: Math.floor(Date.now() / 1000),
|
|
171
|
-
http_host: host,
|
|
172
|
-
request_type: "GET",
|
|
173
|
-
request_url: "/",
|
|
174
|
-
status: 200,
|
|
175
|
-
response_bytes: 1024,
|
|
176
|
-
},
|
|
177
|
-
];
|
|
178
|
-
}
|
|
179
|
-
setClientMeta(key, value) {
|
|
180
|
-
this.clientMeta.set(key, value);
|
|
181
|
-
}
|
|
182
|
-
getClientMeta(key) {
|
|
183
|
-
return this.clientMeta.get(key);
|
|
184
|
-
}
|
|
185
|
-
deleteClientMeta(key) {
|
|
186
|
-
return this.clientMeta.delete(key);
|
|
187
|
-
}
|
|
188
|
-
setMetricsResponse(type, key, response) {
|
|
189
|
-
this.metricsResponses.set(`${type}:${key}`, response);
|
|
190
|
-
}
|
|
191
|
-
metricsResponse(type, key) {
|
|
192
|
-
return this.metricsResponses.get(`${type}:${key}`) ?? { periods: [] };
|
|
193
|
-
}
|
|
194
|
-
recordMetricsRequest(request) {
|
|
195
|
-
this.metricRequestLog.push(request);
|
|
196
|
-
}
|
|
197
|
-
metricsRequests() {
|
|
198
|
-
return [...this.metricRequestLog];
|
|
199
|
-
}
|
|
200
|
-
applyPersistentData(id, operations) {
|
|
201
|
-
const site = this.sites.get(id);
|
|
202
|
-
if (!site)
|
|
203
|
-
return null;
|
|
204
|
-
for (const [key, operation] of Object.entries(operations)) {
|
|
205
|
-
if (!operation || typeof operation !== "object" || Array.isArray(operation))
|
|
206
|
-
continue;
|
|
207
|
-
const record = operation;
|
|
208
|
-
if (formFlag(record.delete)) {
|
|
209
|
-
delete site.persistentData[key];
|
|
210
|
-
delete site.persistentDataEnv[key];
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
// The wire form is `application/x-www-form-urlencoded`, so a scalar value
|
|
214
|
-
// always decodes to a string; anything else was never a persistable value.
|
|
215
|
-
site.persistentData[key] = typeof record.value === "string" ? record.value : "";
|
|
216
|
-
site.persistentDataEnv[key] = formFlag(record.env);
|
|
217
|
-
}
|
|
218
|
-
return this.persistentData(id);
|
|
219
|
-
}
|
|
220
|
-
/** Shape the next `POST /site-persist-data/{site}` answers a test needs. */
|
|
221
|
-
setPersistDataBehavior(input) {
|
|
222
|
-
this.persistDataBehavior = { ...this.persistDataBehavior, ...input };
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Consumes one pending lock refusal. Returns the `Retry-After` seconds to
|
|
226
|
-
* send with the documented 429, or null when the write should be accepted.
|
|
227
|
-
* Docs, `POST /site-persist-data/{site}` 429: "Site data lock could not be
|
|
228
|
-
* acquired; retry after the Retry-After header value (10 seconds)."
|
|
229
|
-
*/
|
|
230
|
-
takePersistDataLockRefusal() {
|
|
231
|
-
if (this.persistDataBehavior.lockRefusals <= 0)
|
|
232
|
-
return null;
|
|
233
|
-
this.persistDataBehavior.lockRefusals -= 1;
|
|
234
|
-
return this.persistDataBehavior.retryAfterSeconds;
|
|
235
|
-
}
|
|
236
|
-
persistDataOmitsResponseTicket() {
|
|
237
|
-
return this.persistDataBehavior.omitResponseTicket;
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Mints a ticket id in the shape of the real capture at
|
|
241
|
-
* `e2e-tests/fixtures/wpcloud-snapshots/site-lifecycle/4a94e336931c035047b5c3b39e2832c5258c0095623100933c5345a812c4b9a8.json`,
|
|
242
|
-
* whose persist-data response carried
|
|
243
|
-
* `"response_ticket_id": "6a3aeb00aec214efed259911342.54f874b098adb09f.1"` —
|
|
244
|
-
* three dot-separated segments, not the two-segment `67a3f000.abc123` the
|
|
245
|
-
* OpenAPI example shows.
|
|
246
|
-
*/
|
|
247
|
-
openResponseTicket() {
|
|
248
|
-
const seq = ++this.ticketSeq;
|
|
249
|
-
const digest = createHash("sha256").update(`fake-response-ticket:${seq}`).digest("hex");
|
|
250
|
-
const id = `${digest.slice(0, 27)}.${digest.slice(27, 43)}.${seq}`;
|
|
251
|
-
this.responseTickets.set(id, [...this.persistDataBehavior.ticketPolls]);
|
|
252
|
-
return id;
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* One `POST /response-ticket/get/summary` poll: consumes the head outcome,
|
|
256
|
-
* the last one repeating forever. null means the provider has no such ticket
|
|
257
|
-
* (the documented 404).
|
|
258
|
-
*/
|
|
259
|
-
pollResponseTicket(id) {
|
|
260
|
-
const polls = this.responseTickets.get(id);
|
|
261
|
-
if (!polls || polls.length === 0)
|
|
262
|
-
return null;
|
|
263
|
-
return polls.length === 1 ? polls[0] : polls.shift();
|
|
264
|
-
}
|
|
265
|
-
persistentData(id) {
|
|
266
|
-
const site = this.sites.get(id);
|
|
267
|
-
if (!site)
|
|
268
|
-
return null;
|
|
269
|
-
return { ...site.persistentData };
|
|
270
|
-
}
|
|
271
|
-
/** `GET /get-site/{id}/extra` shape — note `_data` is intentionally ABSENT (faithful to the real
|
|
272
|
-
* endpoint, which omits it; the marker lives only on the list + site-meta endpoints). */
|
|
273
|
-
siteExtra(site) {
|
|
274
|
-
return {
|
|
275
|
-
atomic_site_id: site.atomicSiteId,
|
|
276
|
-
wpcom_blog_id: null,
|
|
277
|
-
domain_name: site.domainName,
|
|
278
|
-
server_pool_id: "146",
|
|
279
|
-
atomic_client_id: "168",
|
|
280
|
-
chroot_path: "/client-chroot/generic/web",
|
|
281
|
-
chroot_ssh_path: "/client-chroot/generic/ssh",
|
|
282
|
-
burst_php_conns: Number(site.meta.burst_php_conns ?? 0),
|
|
283
|
-
cache_prefix: "fake00000000000000000000000000000",
|
|
284
|
-
canonicalize_aliases: site.meta.canonicalize_aliases ?? "false",
|
|
285
|
-
db_charset: "utf8mb4",
|
|
286
|
-
db_collate: "utf8mb4_general_ci",
|
|
287
|
-
db_pass: "[REDACTED]",
|
|
288
|
-
default_php_conns: Number(site.meta.default_php_conns ?? 10),
|
|
289
|
-
php_fs_permissions: site.meta.php_fs_permissions ?? "RW",
|
|
290
|
-
php_memory_limit: Number(site.meta.php_memory_limit ?? 512),
|
|
291
|
-
php_version: site.meta.php_version ?? "8.4",
|
|
292
|
-
site_api_key: "[REDACTED]",
|
|
293
|
-
static_file_404: site.meta.static_file_404 ?? "wordpress",
|
|
294
|
-
wp_admin_user: `stattic-${site.atomicSiteId}`.slice(0, 32),
|
|
295
|
-
wp_version: "latest",
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
/** `GET /get-sites/{client}/_data/` entry shape. */
|
|
299
|
-
listEntry(site, options) {
|
|
300
|
-
return {
|
|
301
|
-
atomic_site_id: Number(site.atomicSiteId),
|
|
302
|
-
domain_name: site.domainName,
|
|
303
|
-
...(options.includeData ? { _data: site.meta._data ?? null } : {}),
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"isolation-target.d.ts","sourceRoot":"","sources":["../../../src/fake/test-fixtures/isolation-target.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,SAAS,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const value = "real";
|