@volter/twin-cloudflare 0.1.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 +223 -0
- package/dist/r2/src/endpoint.d.ts +14 -0
- package/dist/r2/src/endpoint.js +30 -0
- package/dist/r2/src/fetch.d.ts +7 -0
- package/dist/r2/src/fetch.js +230 -0
- package/dist/r2/src/generated/surface.gen.json +1 -0
- package/dist/r2/src/manifest.d.ts +22 -0
- package/dist/r2/src/manifest.js +69 -0
- package/dist/r2/src/semantics/buckets.d.ts +18 -0
- package/dist/r2/src/semantics/buckets.js +145 -0
- package/dist/r2/src/semantics/objects.d.ts +8 -0
- package/dist/r2/src/semantics/objects.js +252 -0
- package/dist/r2/src/wire.d.ts +54 -0
- package/dist/r2/src/wire.js +120 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +26 -0
- package/dist/src/cloudflare-budget.d.ts +22 -0
- package/dist/src/cloudflare-budget.js +40 -0
- package/dist/src/cloudflare-capabilities.d.ts +6 -0
- package/dist/src/cloudflare-capabilities.js +1161 -0
- package/dist/src/cloudflare-common.d.ts +59 -0
- package/dist/src/cloudflare-common.js +142 -0
- package/dist/src/cloudflare-conformance.d.ts +6 -0
- package/dist/src/cloudflare-conformance.js +251 -0
- package/dist/src/cloudflare-connector.d.ts +53 -0
- package/dist/src/cloudflare-connector.js +418 -0
- package/dist/src/cloudflare-openapi-operations.d.ts +10 -0
- package/dist/src/cloudflare-openapi-operations.js +3336 -0
- package/dist/src/cloudflare-provisioning.d.ts +5 -0
- package/dist/src/cloudflare-provisioning.js +2097 -0
- package/dist/src/cloudflare-r2.d.ts +121 -0
- package/dist/src/cloudflare-r2.js +138 -0
- package/dist/src/cloudflare-server.d.ts +17 -0
- package/dist/src/cloudflare-server.js +101 -0
- package/dist/src/cloudflare-twin.d.ts +14 -0
- package/dist/src/cloudflare-twin.js +762 -0
- package/dist/src/cloudflare-worker-assets.d.ts +25 -0
- package/dist/src/cloudflare-worker-assets.js +192 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.js +69 -0
- package/dist/src/screens/dashboard.d.ts +3 -0
- package/dist/src/screens/dashboard.js +265 -0
- package/package.json +56 -0
- package/src/cli.ts +25 -0
- package/src/cloudflare-budget.ts +61 -0
- package/src/cloudflare-capabilities.ts +1107 -0
- package/src/cloudflare-common.ts +183 -0
- package/src/cloudflare-conformance.ts +204 -0
- package/src/cloudflare-connector.ts +443 -0
- package/src/cloudflare-openapi-operations.ts +3344 -0
- package/src/cloudflare-provisioning.ts +1969 -0
- package/src/cloudflare-r2.ts +173 -0
- package/src/cloudflare-server.ts +109 -0
- package/src/cloudflare-twin.ts +714 -0
- package/src/cloudflare-worker-assets.ts +207 -0
- package/src/index.ts +112 -0
- package/src/screens/dashboard.tsx +297 -0
package/src/cli.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { keepProcessAlive } from '@volter/world-core/lifecycle';
|
|
3
|
+
// world-cloudflare CLI: serve the KERNEL-BACKED Cloudflare API twin, or run conformance. State
|
|
4
|
+
// lives in the @volter/world-core action log (no in-memory side-store). Conformance is dev-only +
|
|
5
|
+
// lazy-imported so the bin runs without @volter/world-tooling (E2).
|
|
6
|
+
import { hasFlag, optionValue } from '@volter/world-core/args';
|
|
7
|
+
import { createCloudflareTwinServer } from './cloudflare-server.ts';
|
|
8
|
+
|
|
9
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
10
|
+
const port = Number(optionValue(rest, '--port', String(process.env.PORT ?? '0'))) || undefined;
|
|
11
|
+
const root = optionValue(rest, '--root') || undefined;
|
|
12
|
+
const readOnly = hasFlag(rest, '--read-only'); // a twin accepts writes unless started read-only
|
|
13
|
+
|
|
14
|
+
if (cmd === 'serve' || cmd === undefined) {
|
|
15
|
+
const s = await createCloudflareTwinServer({ readOnly, ...(root ? { root } : {}), ...(port ? { port } : {}) });
|
|
16
|
+
process.stdout.write(`cloudflare twin (accounts, zones, Cloudflare Tunnels, DNS records, Workers, R2, Hyperdrive, Queues)${readOnly ? ' [read-only]' : ''} at ${s.url}\n`);
|
|
17
|
+
await keepProcessAlive();
|
|
18
|
+
} else if (cmd === 'conformance') {
|
|
19
|
+
const { checkCloudflareConformance } = await import('./cloudflare-conformance.ts');
|
|
20
|
+
const report = await checkCloudflareConformance();
|
|
21
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
22
|
+
if (!report.ok) process.exitCode = 1;
|
|
23
|
+
} else {
|
|
24
|
+
process.stdout.write('Usage: world-cloudflare serve|conformance [--port N] [--root DIR] [--read-only]\n');
|
|
25
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Cloudflare client-side rate budget. The mechanism is shared @volter/world-core RateBudget;
|
|
2
|
+
// only Cloudflare's documented limit and conservative weights live here.
|
|
3
|
+
//
|
|
4
|
+
// Official source, live-fetched 2026-08-21:
|
|
5
|
+
// https://developers.cloudflare.com/fundamentals/api/reference/limits/
|
|
6
|
+
// Cloudflare publishes a global 1,200 requests / five minutes per user/account token.
|
|
7
|
+
// This declaration stays at the kernel fallback's much tighter 60 weighted units/minute.
|
|
8
|
+
import {
|
|
9
|
+
declareRateBudget,
|
|
10
|
+
rateBudgetPath,
|
|
11
|
+
rateBudgetWeight,
|
|
12
|
+
RateBudget,
|
|
13
|
+
type RateBudgetDeclaration,
|
|
14
|
+
type RateBudgetOptions,
|
|
15
|
+
type RateBudgetReservation,
|
|
16
|
+
type RateBudgetSnapshot,
|
|
17
|
+
} from '@volter/world-core';
|
|
18
|
+
|
|
19
|
+
const VENDOR = 'cloudflare';
|
|
20
|
+
export const CLOUDFLARE_BUDGET_WINDOW_MS = 60_000;
|
|
21
|
+
export const CLOUDFLARE_BUDGET_CEILING = 60;
|
|
22
|
+
export const CLOUDFLARE_BUDGET_MAX_RETRY_AFTER_S = 300;
|
|
23
|
+
export const CLOUDFLARE_CALL_WEIGHTS = { mutation: 3, read: 2 } as const;
|
|
24
|
+
|
|
25
|
+
export const CLOUDFLARE_RATE_BUDGET: RateBudgetDeclaration = {
|
|
26
|
+
windowMs: CLOUDFLARE_BUDGET_WINDOW_MS,
|
|
27
|
+
ceiling: CLOUDFLARE_BUDGET_CEILING,
|
|
28
|
+
defaultWeight: CLOUDFLARE_CALL_WEIGHTS.read,
|
|
29
|
+
maxRetryAfterSeconds: CLOUDFLARE_BUDGET_MAX_RETRY_AFTER_S,
|
|
30
|
+
rules: [
|
|
31
|
+
{ match: '^(POST|PUT|PATCH|DELETE) ', weight: CLOUDFLARE_CALL_WEIGHTS.mutation },
|
|
32
|
+
],
|
|
33
|
+
reason:
|
|
34
|
+
'Cloudflare publishes a global Client API limit of 1,200 requests per five minutes per user/account token ' +
|
|
35
|
+
'(https://developers.cloudflare.com/fundamentals/api/reference/limits/, live-fetched 2026-08-21). ' +
|
|
36
|
+
'This declaration is deliberately tighter: 60 weighted units per minute; reads cost 2 (30/minute) and ' +
|
|
37
|
+
'mutations cost 3 (20/minute). It neither exceeds the documented sustained limit nor the kernel fallback burst.',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
declareRateBudget(VENDOR, CLOUDFLARE_RATE_BUDGET);
|
|
41
|
+
|
|
42
|
+
export function cloudflareCallWeight(method: string, path: string): number {
|
|
43
|
+
return rateBudgetWeight(VENDOR, `${method.toUpperCase()} ${path.split('?')[0] ?? path}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function cloudflareBudgetPath(opts: { root?: string; token?: string } | string = {}): string {
|
|
47
|
+
const value = typeof opts === 'string' ? { root: opts } : opts;
|
|
48
|
+
return rateBudgetPath({ ...value, vendor: VENDOR });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type CloudflareBudgetOptions = Omit<RateBudgetOptions, 'vendor'>;
|
|
52
|
+
export class CloudflareBudget extends RateBudget {
|
|
53
|
+
constructor(opts: CloudflareBudgetOptions = {}) {
|
|
54
|
+
super({ ...opts, vendor: VENDOR });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type { RateBudgetErrorKind as CloudflareBudgetErrorKind } from '@volter/world-core';
|
|
59
|
+
export { RateBudgetError as CloudflareBudgetError } from '@volter/world-core';
|
|
60
|
+
export type CloudflareBudgetReservation = RateBudgetReservation;
|
|
61
|
+
export type CloudflareBudgetSnapshot = RateBudgetSnapshot;
|