@theholocron/holocron-plugin-cloudflare 5.0.0-alpha.13 → 5.0.0-alpha.140
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 +27 -6
- package/dist/index.d.mts +19 -34
- package/dist/index.mjs +43 -78
- package/package.json +14 -11
package/README.md
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# `@theholocron/holocron-plugin-cloudflare`
|
|
4
4
|
|
|
5
|
-
Cloudflare plugin for [Holocron](../cli). Implements the `dns
|
|
6
|
-
capabilities against the
|
|
5
|
+
Cloudflare plugin for [Holocron](../cli). Implements the `dns`, `deployment`,
|
|
6
|
+
and `workers` capabilities against the
|
|
7
|
+
[Cloudflare v4 API](https://developers.cloudflare.com/api/).
|
|
7
8
|
|
|
8
9
|
## Install
|
|
9
10
|
|
|
@@ -40,12 +41,15 @@ Generate a scoped API token at **dash.cloudflare.com/profile/api-tokens**.
|
|
|
40
41
|
// Cloudflare Pages deployments (requires accountId)
|
|
41
42
|
// accountId falls back to CLOUDFLARE_ACCOUNT_ID env var when omitted
|
|
42
43
|
"deployment": "cloudflare",
|
|
44
|
+
|
|
45
|
+
// Workers deployment (also requires accountId)
|
|
46
|
+
"workers": "cloudflare",
|
|
43
47
|
},
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
```
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
Any combination of capabilities can be enabled together:
|
|
49
53
|
|
|
50
54
|
<!-- prettier-ignore -->
|
|
51
55
|
```jsonc
|
|
@@ -53,12 +57,15 @@ Both capabilities can be enabled together:
|
|
|
53
57
|
"providers": {
|
|
54
58
|
"dns": "cloudflare",
|
|
55
59
|
"deployment": "cloudflare",
|
|
60
|
+
"workers": "cloudflare",
|
|
56
61
|
},
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
```
|
|
60
65
|
|
|
61
|
-
The `deployment`
|
|
66
|
+
The `deployment` and `workers` capabilities are only exposed when `accountId`
|
|
67
|
+
is resolvable — either passed explicitly in options or set via the
|
|
68
|
+
`CLOUDFLARE_ACCOUNT_ID` env var.
|
|
62
69
|
|
|
63
70
|
## `dns` capability
|
|
64
71
|
|
|
@@ -72,7 +79,7 @@ Zone ids are cached per plugin instance for the lifetime of the process.
|
|
|
72
79
|
|
|
73
80
|
## `deployment` capability
|
|
74
81
|
|
|
75
|
-
Manages [Cloudflare Pages](https://developers.cloudflare.com/pages/) projects. Used by `holocron setup` to provision per-PR preview deployments.
|
|
82
|
+
Manages [Cloudflare Pages](https://developers.cloudflare.com/pages/) projects. Used by `holocron repo setup` to provision per-PR preview deployments.
|
|
76
83
|
|
|
77
84
|
| Method | What it does |
|
|
78
85
|
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -83,9 +90,23 @@ Manages [Cloudflare Pages](https://developers.cloudflare.com/pages/) projects. U
|
|
|
83
90
|
| `triggerDeployment` | Triggers a new Pages deployment from the latest production branch commit. |
|
|
84
91
|
| `updateProjectSettings` | Updates project-level settings (currently a no-op; CF Pages REST API has no direct settings endpoint for these fields). |
|
|
85
92
|
|
|
93
|
+
## `workers` capability
|
|
94
|
+
|
|
95
|
+
Deploys and manages [Workers](https://developers.cloudflare.com/workers/) scripts.
|
|
96
|
+
|
|
97
|
+
| Method | What it does |
|
|
98
|
+
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
99
|
+
| `upsertProxy` | Deploys a generated reverse-proxy Worker forwarding `hostname/*` to `config.target`, injecting `config.headers`. Used by `setup` to wire wiki custom-domain proxies when the wiki provider requires one in addition to the CNAME. |
|
|
100
|
+
| `deployScript` | Deploys (or updates) an arbitrary Worker script — the caller's own code, not a generated proxy — with optional secret bindings and route patterns. For a consumer that isn't a reverse-proxy, e.g. a webhook receiver. |
|
|
101
|
+
|
|
102
|
+
Both methods are idempotent: re-running with the same inputs makes no
|
|
103
|
+
route-write call when nothing changed. Zone ids are cached per plugin
|
|
104
|
+
instance for the lifetime of the process — the `workers` capability's own
|
|
105
|
+
cache, separate from `dns`'s.
|
|
106
|
+
|
|
86
107
|
### Preview deployment setup
|
|
87
108
|
|
|
88
|
-
When `preview: true` (or `preview: { project, domain }`) is set in a repo's deploy config, `holocron setup` calls:
|
|
109
|
+
When `preview: true` (or `preview: { project, domain }`) is set in a repo's deploy config, `holocron repo setup` calls:
|
|
89
110
|
|
|
90
111
|
1. `ensureProject` — creates `<org>-preview` if it doesn't exist
|
|
91
112
|
2. `ensureCustomDomain` — attaches `*.<domain>` to the project
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AuthError, Deployment, DeploymentProject, DeploymentProjectSettings, DeploymentRecord, DeploymentTarget, DeploymentTrigger, Dns, DnsRecord, ResolveTokenInput, WikiProxyConfig, Workers } from "@theholocron/cli";
|
|
2
|
-
import { CloudflareClient,
|
|
1
|
+
import { AuthError, DeployScriptConfig, DeployScriptResult, Deployment, DeploymentProject, DeploymentProjectSettings, DeploymentRecord, DeploymentTarget, DeploymentTrigger, Dns, DnsRecord, DnsRecordRequest, ResolveTokenInput, VerifyTokenFailure, VerifyTokenResult, VerifyTokenResult as VerifyTokenResult$1, VerifyTokenSuccess, WikiProxyConfig, Workers } from "@theholocron/cli";
|
|
2
|
+
import { CloudflareClient, CloudflareClient as CloudflareClient$1, CloudflareClientOptions, createCloudflareClient } from "@theholocron/cloudflare-client";
|
|
3
3
|
//#region src/auth.d.ts
|
|
4
4
|
declare const resolveToken: (input?: ResolveTokenInput) => string;
|
|
5
5
|
//#endregion
|
|
@@ -28,7 +28,7 @@ declare class CloudflareDeployment implements Deployment {
|
|
|
28
28
|
getDeployment(deploymentId: string): Promise<DeploymentRecord>;
|
|
29
29
|
listPreviewDeployments(projectId: string, branch: string): Promise<DeploymentRecord[]>;
|
|
30
30
|
deletePreviewDeployments(projectId: string, deploymentIds: string[]): Promise<number>;
|
|
31
|
-
ensureCustomDomain(projectId: string, hostname: string): Promise<
|
|
31
|
+
ensureCustomDomain(projectId: string, hostname: string): Promise<DnsRecordRequest | null>;
|
|
32
32
|
private getProjectByName;
|
|
33
33
|
}
|
|
34
34
|
//#endregion
|
|
@@ -42,6 +42,11 @@ declare class CloudflareDns implements Dns {
|
|
|
42
42
|
listRecords(domain: string): Promise<DnsRecord[]>;
|
|
43
43
|
upsertRecord(domain: string, record: DnsRecord): Promise<DnsRecord>;
|
|
44
44
|
deleteRecord(domain: string, id: string): Promise<void>;
|
|
45
|
+
/** `holocron doctor` has no specific domain to check — lists every zone the token can see instead. */
|
|
46
|
+
whoami(): Promise<{
|
|
47
|
+
ok: boolean;
|
|
48
|
+
zones: number;
|
|
49
|
+
}>;
|
|
45
50
|
/**
|
|
46
51
|
* Walk from full domain up to apex to find the Cloudflare zone.
|
|
47
52
|
* E.g. "api.staging.example.com" tries:
|
|
@@ -53,51 +58,31 @@ declare class CloudflareDns implements Dns {
|
|
|
53
58
|
}
|
|
54
59
|
//#endregion
|
|
55
60
|
//#region src/capabilities/workers.d.ts
|
|
56
|
-
interface ZonesClient {
|
|
57
|
-
list(query?: {
|
|
58
|
-
name?: string;
|
|
59
|
-
per_page?: number;
|
|
60
|
-
}): Promise<Array<{
|
|
61
|
-
id: string;
|
|
62
|
-
}>>;
|
|
63
|
-
}
|
|
64
61
|
declare class CloudflareWorkers implements Workers {
|
|
65
|
-
private readonly
|
|
62
|
+
private readonly client;
|
|
66
63
|
private readonly accountId;
|
|
67
64
|
readonly key: "workers";
|
|
68
65
|
readonly providerName = "cloudflare";
|
|
69
66
|
private readonly zoneCache;
|
|
70
|
-
|
|
71
|
-
private readonly fetchImpl;
|
|
72
|
-
/** Memoized token thunk — resolved on the first authenticated request. */
|
|
73
|
-
private readonly token;
|
|
74
|
-
constructor(zones: () => ZonesClient, accountId: string, opts: {
|
|
75
|
-
token: () => string;
|
|
76
|
-
} & Pick<CloudflareClientOptions$1, "baseUrl" | "fetch">);
|
|
67
|
+
constructor(client: () => Pick<CloudflareClient$1, "workers" | "zones">, accountId: string);
|
|
77
68
|
upsertProxy(hostname: string, config: WikiProxyConfig): Promise<void>;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
69
|
+
/** `holocron doctor` has no specific script to check — lists every script the token can see instead. */
|
|
70
|
+
whoami(): Promise<{
|
|
71
|
+
ok: boolean;
|
|
72
|
+
scripts: number;
|
|
73
|
+
}>;
|
|
74
|
+
deployScript(name: string, config: DeployScriptConfig): Promise<DeployScriptResult>;
|
|
75
|
+
/** Idempotent create-or-update for one route pattern — shared by both public methods. */
|
|
76
|
+
private upsertRoute;
|
|
83
77
|
private resolveZone;
|
|
84
78
|
}
|
|
85
79
|
//#endregion
|
|
86
80
|
//#region src/verify-token.d.ts
|
|
87
|
-
interface VerifyTokenSuccess {
|
|
88
|
-
ok: true;
|
|
89
|
-
subject: string;
|
|
90
|
-
}
|
|
91
|
-
interface VerifyTokenFailure {
|
|
92
|
-
ok: false;
|
|
93
|
-
message: string;
|
|
94
|
-
}
|
|
95
|
-
type VerifyTokenResult = VerifyTokenSuccess | VerifyTokenFailure;
|
|
96
81
|
interface VerifyTokenOptions {
|
|
97
82
|
baseUrl?: string;
|
|
98
83
|
fetch?: typeof fetch;
|
|
99
84
|
}
|
|
100
|
-
declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult>;
|
|
85
|
+
declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult$1>;
|
|
101
86
|
//#endregion
|
|
102
87
|
//#region src/index.d.ts
|
|
103
88
|
interface CloudflarePluginOptions extends ResolveTokenInput {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AuthError, ProviderApiError, createResolveToken } from "@theholocron/cli";
|
|
2
2
|
import { createCloudflareClient } from "@theholocron/cloudflare-client";
|
|
3
|
+
import { errorMessage } from "@theholocron/misc-utils";
|
|
3
4
|
//#region src/auth.ts
|
|
4
5
|
const resolveToken = createResolveToken({
|
|
5
6
|
envName: "HOLOCRON_CLOUDFLARE_TOKEN",
|
|
@@ -74,8 +75,9 @@ var CloudflareDeployment = class {
|
|
|
74
75
|
return deploymentIds.length;
|
|
75
76
|
}
|
|
76
77
|
async ensureCustomDomain(projectId, hostname) {
|
|
77
|
-
if ((await this.client().pages.listDomains(this.accountId, projectId)).some((d) => d.name === hostname)) return;
|
|
78
|
+
if ((await this.client().pages.listDomains(this.accountId, projectId)).some((d) => d.name === hostname)) return null;
|
|
78
79
|
await this.client().pages.addDomain(this.accountId, projectId, hostname);
|
|
80
|
+
return null;
|
|
79
81
|
}
|
|
80
82
|
async getProjectByName(name) {
|
|
81
83
|
try {
|
|
@@ -153,6 +155,13 @@ var CloudflareDns = class {
|
|
|
153
155
|
const zoneId = await this.resolveZone(domain);
|
|
154
156
|
await this.client().dns.delete(zoneId, id);
|
|
155
157
|
}
|
|
158
|
+
/** `holocron doctor` has no specific domain to check — lists every zone the token can see instead. */
|
|
159
|
+
async whoami() {
|
|
160
|
+
return {
|
|
161
|
+
ok: true,
|
|
162
|
+
zones: (await this.client().zones.list()).length
|
|
163
|
+
};
|
|
164
|
+
}
|
|
156
165
|
/**
|
|
157
166
|
* Walk from full domain up to apex to find the Cloudflare zone.
|
|
158
167
|
* E.g. "api.staging.example.com" tries:
|
|
@@ -187,87 +196,42 @@ function mapRecord(raw) {
|
|
|
187
196
|
//#endregion
|
|
188
197
|
//#region src/capabilities/workers.ts
|
|
189
198
|
var CloudflareWorkers = class {
|
|
190
|
-
|
|
199
|
+
client;
|
|
191
200
|
accountId;
|
|
192
201
|
key = "workers";
|
|
193
202
|
providerName = "cloudflare";
|
|
194
203
|
zoneCache = /* @__PURE__ */ new Map();
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
/** Memoized token thunk — resolved on the first authenticated request. */
|
|
198
|
-
token;
|
|
199
|
-
constructor(zones, accountId, opts) {
|
|
200
|
-
this.zones = zones;
|
|
204
|
+
constructor(client, accountId) {
|
|
205
|
+
this.client = client;
|
|
201
206
|
this.accountId = accountId;
|
|
202
|
-
this.token = opts.token;
|
|
203
|
-
this.baseUrl = opts.baseUrl ?? "https://api.cloudflare.com/client/v4";
|
|
204
|
-
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
205
207
|
}
|
|
206
208
|
async upsertProxy(hostname, config) {
|
|
207
209
|
const scriptName = hostnameToScriptName(hostname);
|
|
208
210
|
const script = generateProxyScript(config);
|
|
209
|
-
await this.putScript(scriptName, script);
|
|
210
|
-
|
|
211
|
-
const pattern = `${hostname}/*`;
|
|
212
|
-
const existing = (await this.listRoutes(zoneId)).find((r) => r.pattern === pattern);
|
|
213
|
-
if (existing) {
|
|
214
|
-
if (existing.script !== scriptName) await this.updateRoute(zoneId, existing.id, pattern, scriptName);
|
|
215
|
-
} else await this.createRoute(zoneId, pattern, scriptName);
|
|
211
|
+
await this.client().workers.putScript(this.accountId, scriptName, script);
|
|
212
|
+
await this.upsertRoute(`${hostname}/*`, scriptName);
|
|
216
213
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
form.append("index.js", new Blob([script], { type: "application/javascript+module" }), "index.js");
|
|
224
|
-
const path = `/accounts/${this.accountId}/workers/scripts/${encodeURIComponent(scriptName)}`;
|
|
225
|
-
const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
226
|
-
method: "PUT",
|
|
227
|
-
headers: { authorization: `Bearer ${this.token()}` },
|
|
228
|
-
body: form
|
|
229
|
-
});
|
|
230
|
-
if (!res.ok) {
|
|
231
|
-
const body = await res.text().catch(() => "");
|
|
232
|
-
throw new ProviderApiError(`Cloudflare PUT ${path} → ${res.status}`, res.status, body);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
listRoutes(zoneId) {
|
|
236
|
-
return this.cfRequest("GET", `/zones/${zoneId}/workers/routes`);
|
|
237
|
-
}
|
|
238
|
-
createRoute(zoneId, pattern, script) {
|
|
239
|
-
return this.cfRequest("POST", `/zones/${zoneId}/workers/routes`, {
|
|
240
|
-
pattern,
|
|
241
|
-
script
|
|
242
|
-
});
|
|
214
|
+
/** `holocron doctor` has no specific script to check — lists every script the token can see instead. */
|
|
215
|
+
async whoami() {
|
|
216
|
+
return {
|
|
217
|
+
ok: true,
|
|
218
|
+
scripts: (await this.client().workers.listScripts(this.accountId)).length
|
|
219
|
+
};
|
|
243
220
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
221
|
+
async deployScript(name, config) {
|
|
222
|
+
await this.client().workers.putScript(this.accountId, name, config.code);
|
|
223
|
+
for (const [secretName, value] of Object.entries(config.secrets ?? {})) await this.client().workers.putSecret(this.accountId, name, secretName, value);
|
|
224
|
+
for (const pattern of config.routes ?? []) await this.upsertRoute(pattern, name);
|
|
225
|
+
return { scriptName: name };
|
|
249
226
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
};
|
|
259
|
-
if (body !== void 0) {
|
|
260
|
-
headers["content-type"] = "application/json";
|
|
261
|
-
init.body = JSON.stringify(body);
|
|
262
|
-
}
|
|
263
|
-
const res = await this.fetchImpl(`${this.baseUrl}${path}`, init);
|
|
264
|
-
if (!res.ok) {
|
|
265
|
-
const text = await res.text().catch(() => "");
|
|
266
|
-
throw new ProviderApiError(`Cloudflare ${method} ${path} → ${res.status}`, res.status, text);
|
|
267
|
-
}
|
|
268
|
-
const envelope = await res.json();
|
|
269
|
-
if (!envelope.success) throw new ProviderApiError(`Cloudflare ${method} ${path} returned success:false`, 0, JSON.stringify(envelope.errors));
|
|
270
|
-
return envelope.result;
|
|
227
|
+
/** Idempotent create-or-update for one route pattern — shared by both public methods. */
|
|
228
|
+
async upsertRoute(pattern, scriptName) {
|
|
229
|
+
const hostname = pattern.split("/")[0];
|
|
230
|
+
const zoneId = await this.resolveZone(hostname);
|
|
231
|
+
const existing = (await this.client().workers.listRoutes(zoneId)).find((r) => r.pattern === pattern);
|
|
232
|
+
if (existing) {
|
|
233
|
+
if (existing.script !== scriptName) await this.client().workers.updateRoute(zoneId, existing.id, pattern, scriptName);
|
|
234
|
+
} else await this.client().workers.createRoute(zoneId, pattern, scriptName);
|
|
271
235
|
}
|
|
272
236
|
async resolveZone(domain) {
|
|
273
237
|
const cached = this.zoneCache.get(domain);
|
|
@@ -275,7 +239,7 @@ var CloudflareWorkers = class {
|
|
|
275
239
|
const parts = domain.split(".");
|
|
276
240
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
277
241
|
const candidate = parts.slice(i).join(".");
|
|
278
|
-
const zones = await this.
|
|
242
|
+
const zones = await this.client().zones.list({ name: candidate });
|
|
279
243
|
if (zones.length > 0) {
|
|
280
244
|
this.zoneCache.set(domain, zones[0].id);
|
|
281
245
|
return zones[0].id;
|
|
@@ -318,14 +282,19 @@ async function verifyToken(token, opts = {}) {
|
|
|
318
282
|
};
|
|
319
283
|
} catch {}
|
|
320
284
|
try {
|
|
285
|
+
const names = (await client.zones.list()).map((z) => z.name);
|
|
286
|
+
if (names.length === 0) return {
|
|
287
|
+
ok: true,
|
|
288
|
+
subject: "no zones visible"
|
|
289
|
+
};
|
|
321
290
|
return {
|
|
322
291
|
ok: true,
|
|
323
|
-
subject: `
|
|
292
|
+
subject: `zones: ${names.length <= 5 ? names.join(", ") : `${names.slice(0, 5).join(", ")} (+${names.length - 5} more)`}`
|
|
324
293
|
};
|
|
325
294
|
} catch (err) {
|
|
326
295
|
return {
|
|
327
296
|
ok: false,
|
|
328
|
-
message:
|
|
297
|
+
message: errorMessage(err)
|
|
329
298
|
};
|
|
330
299
|
}
|
|
331
300
|
}
|
|
@@ -359,11 +328,7 @@ function deployment(ctx) {
|
|
|
359
328
|
}
|
|
360
329
|
function workersCapability(ctx) {
|
|
361
330
|
if (!ctx.options.accountId) throw new Error("Cloudflare accountId is required for Workers — set accountId in the plugin options or CLOUDFLARE_ACCOUNT_ID env var");
|
|
362
|
-
return new CloudflareWorkers(
|
|
363
|
-
token: ctx.token,
|
|
364
|
-
baseUrl: ctx.options.baseUrl,
|
|
365
|
-
fetch: ctx.options.fetch
|
|
366
|
-
});
|
|
331
|
+
return new CloudflareWorkers(ctx.client, ctx.options.accountId);
|
|
367
332
|
}
|
|
368
333
|
function createPlugin(options = {}) {
|
|
369
334
|
const ctx = createContext(options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theholocron/holocron-plugin-cloudflare",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.140",
|
|
4
4
|
"description": "Holocron plugin for Cloudflare. Implements the dns capability against Cloudflare's REST API — zone resolution, DNS record management.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"holocron",
|
|
9
9
|
"plugin"
|
|
10
10
|
],
|
|
11
|
-
"homepage": "https://github.com/theholocron/holocron/tree/main/
|
|
11
|
+
"homepage": "https://github.com/theholocron/holocron/tree/main/plugins/holocron-plugin-cloudflare#readme",
|
|
12
12
|
"bugs": "https://github.com/theholocron/holocron/issues",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "git+https://github.com/theholocron/holocron.git",
|
|
16
|
-
"directory": "
|
|
16
|
+
"directory": "plugins/holocron-plugin-cloudflare"
|
|
17
17
|
},
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"author": "Newton Koumantzelis",
|
|
@@ -30,11 +30,13 @@
|
|
|
30
30
|
"dist"
|
|
31
31
|
],
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@theholocron/cloudflare-client": "^1.
|
|
34
|
-
"@theholocron/eslint-config": "^8.
|
|
35
|
-
"@theholocron/
|
|
36
|
-
"@theholocron/
|
|
37
|
-
"@theholocron/
|
|
33
|
+
"@theholocron/cloudflare-client": "^1.41.0",
|
|
34
|
+
"@theholocron/eslint-config": "^8.7.1",
|
|
35
|
+
"@theholocron/http-client": "^1.41.0",
|
|
36
|
+
"@theholocron/misc-utils": "^1.9.2",
|
|
37
|
+
"@theholocron/tsconfig": "^8.7.1",
|
|
38
|
+
"@theholocron/tsdown-config": "^8.7.1",
|
|
39
|
+
"@theholocron/vitest-config": "^8.7.0",
|
|
38
40
|
"@types/node": "^26",
|
|
39
41
|
"@vitest/coverage-v8": "^4.1.11",
|
|
40
42
|
"@vitest/eslint-plugin": "^1.6.27",
|
|
@@ -46,11 +48,12 @@
|
|
|
46
48
|
"tsx": "4.23.12",
|
|
47
49
|
"typescript": "^5.9.3",
|
|
48
50
|
"vitest": "^4.1.11",
|
|
49
|
-
"@theholocron/cli": "5.0.0-alpha.
|
|
51
|
+
"@theholocron/cli": "5.0.0-alpha.140"
|
|
50
52
|
},
|
|
51
53
|
"peerDependencies": {
|
|
52
|
-
"@theholocron/cloudflare-client": "^1.
|
|
53
|
-
"@theholocron/
|
|
54
|
+
"@theholocron/cloudflare-client": "^1.41.0",
|
|
55
|
+
"@theholocron/misc-utils": "^1.9.2",
|
|
56
|
+
"@theholocron/cli": "5.0.0-alpha.140"
|
|
54
57
|
},
|
|
55
58
|
"peerDependenciesMeta": {
|
|
56
59
|
"@theholocron/cloudflare-client": {}
|