@volter/twin-cloudflare 0.1.0 → 0.1.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.
@@ -3,7 +3,7 @@
3
3
  // cloudflare-twin.ts) and the provisioning slice (Workers/R2/Hyperdrive/Queues in
4
4
  // cloudflare-provisioning.ts). Pure helpers over the @volter/world-core kernel — no routes here.
5
5
  import { createHash } from 'node:crypto';
6
- import { applyTwinWrite, projectResources } from '@volter/world-core';
6
+ import { applyTwinWrite, projectResources, worldNow } from '@volter/world-core';
7
7
  export const SERVICE = 'cloudflare';
8
8
  export const CLOUDFLARE_RESOURCE_TYPES = [
9
9
  'account',
@@ -133,7 +133,7 @@ export function callerEmail(req) {
133
133
  }
134
134
  /** One entry in an account's audit log, attributed to the calling token's user. */
135
135
  export async function audit(req, accountID, entry) {
136
- const when = req.occurredAt ?? new Date().toISOString();
136
+ const when = req.occurredAt ?? worldNow();
137
137
  const id = deterministicHex(`audit:${accountID}:${when}:${entry.resource.type}:${entry.resource.id}:${rows('audit_log', req.root).length}`, 32);
138
138
  const email = callerEmail(req);
139
139
  await write('audit_log', id, 'audit_log.record', { account_id: accountID, when, action: { type: entry.type, result: true, info: '' },
@@ -17,6 +17,7 @@
17
17
  // pack's generic conventions (1004 validation, 1001 not found) everywhere else — see README
18
18
  // "Official grounding". No live probe was possible (no Cloudflare account); the OpenAPI + SDK
19
19
  // are the honest grounding ceiling for this slice.
20
+ import { worldNow } from '@volter/world-core';
20
21
  import { createHash } from 'node:crypto';
21
22
  import { deterministicHex, failure, headers as lowerHeaders, isResponse, mint, noRoute, paginate, parseBody, readOnly, row, rows, callerEmail, audit, scopeMissing, success, uuidFrom, write, } from "./cloudflare-common.js";
22
23
  import { catchUpR2CustomDomains, connectR2CustomDomain, createR2TempCredential, r2BearerToken, r2Credential, r2ParentCovers, removeR2CustomDomain, r2CustomDomains, TEMP_PERMISSIONS, updateR2CustomDomain } from "./cloudflare-r2.js";
@@ -768,7 +769,7 @@ function buildUpload(req, url, accountID, scriptName, mode) {
768
769
  * UUID (the shape wrangler prints as "Current Version ID"). */
769
770
  async function writeVersion(req, accountID, scriptName, scriptTag, number, content, annotations) {
770
771
  const id = mint('worker_version', `${accountID}:${scriptName}:${scriptTag}:${number}`, req.root);
771
- const at = req.occurredAt ?? new Date().toISOString();
772
+ const at = req.occurredAt ?? worldNow();
772
773
  await pwrite('worker_version', id, 'worker_version.upload', {
773
774
  account_id: accountID, script_name: scriptName, script_tag: scriptTag, number, ...content,
774
775
  source: deploySource(req), annotations, author_email: callerEmail(req) || null, created_on: at, modified_on: at, deleted: false,
@@ -779,7 +780,7 @@ function deploymentRecord(req, script, versions, annotations) {
779
780
  const count = Array.isArray(script.deployments) ? script.deployments.length : 0;
780
781
  return {
781
782
  id: uuidFrom(`${String(script.tag)}:deployment:${count}`),
782
- created_on: req.occurredAt ?? new Date().toISOString(),
783
+ created_on: req.occurredAt ?? worldNow(),
783
784
  source: deploySource(req),
784
785
  strategy: 'percentage',
785
786
  versions,
@@ -803,7 +804,7 @@ async function uploadScript(req, url, accountID, scriptName) {
803
804
  const { existing, content } = built;
804
805
  const tag = String(existing?.tag ?? mintScriptTag(accountID, scriptName, req.root));
805
806
  const number = Number(existing?.version_count ?? 0) + 1;
806
- const at = req.occurredAt ?? new Date().toISOString();
807
+ const at = req.occurredAt ?? worldNow();
807
808
  // All validation passed — now perform the writes (migrations, the version, then the script).
808
809
  await applyMigrationPlan(accountID, scriptName, built.migrationOps, req);
809
810
  const version = await writeVersion(req, accountID, scriptName, tag, number, content, built.annotations);
@@ -989,7 +990,7 @@ async function createDeployment(req, accountID, script) {
989
990
  modules: null,
990
991
  version_id: live.id,
991
992
  deployments: [...deployments, deployment],
992
- modified_on: req.occurredAt ?? new Date().toISOString(),
993
+ modified_on: req.occurredAt ?? worldNow(),
993
994
  }, req);
994
995
  return success(deployment);
995
996
  }
@@ -1025,7 +1026,7 @@ async function patchScriptSettings(req, accountID, script) {
1025
1026
  ...(body.tags !== undefined ? { tags: body.tags ?? [] } : {}),
1026
1027
  ...(body.tail_consumers !== undefined ? { tail_consumers: body.tail_consumers } : {}),
1027
1028
  ...(body.observability !== undefined ? { observability: body.observability } : {}),
1028
- modified_on: req.occurredAt ?? new Date().toISOString(),
1029
+ modified_on: req.occurredAt ?? worldNow(),
1029
1030
  }, req);
1030
1031
  return success(settingsView(scriptRow(accountID, String(script.name), req.root)));
1031
1032
  }
@@ -1237,7 +1238,7 @@ async function workersRoute(req, method, url, parts, accountID) {
1237
1238
  }
1238
1239
  if (!Array.isArray(body))
1239
1240
  return failure(400, 1004, 'Cron trigger update requires an array of {cron} objects');
1240
- const at = req.occurredAt ?? new Date().toISOString();
1241
+ const at = req.occurredAt ?? worldNow();
1241
1242
  const schedules = [];
1242
1243
  for (const value of body) {
1243
1244
  const item = value;
@@ -1546,7 +1547,7 @@ async function r2Route(req, method, url, parts, accountID) {
1546
1547
  if (accountBuckets().some((item) => item.name === body.name)) {
1547
1548
  return failure(409, 10004, 'The bucket you tried to create already exists, and you own it.');
1548
1549
  }
1549
- const at = req.occurredAt ?? new Date().toISOString();
1550
+ const at = req.occurredAt ?? worldNow();
1550
1551
  await pwrite('r2_bucket', `${accountID}:${body.name}`, 'r2_bucket.create', {
1551
1552
  account_id: accountID,
1552
1553
  name: body.name,
@@ -1582,7 +1583,7 @@ async function r2Route(req, method, url, parts, accountID) {
1582
1583
  await pwrite('r2_bucket', `${accountID}:${bucketName}`, 'r2_bucket.delete', { account_id: accountID, deleted: true }, req);
1583
1584
  // "The specified domain will also remain connected to R2 until you remove it or delete the bucket." (public buckets)
1584
1585
  for (const d of r2CustomDomains(req.root).filter((x) => x.account_id === accountID && x.bucket === bucketName))
1585
- await removeR2CustomDomain(d.id, req.root, req.occurredAt ?? new Date().toISOString());
1586
+ await removeR2CustomDomain(d.id, req.root, req.occurredAt ?? worldNow());
1586
1587
  return success({});
1587
1588
  }
1588
1589
  return noRoute();
@@ -1617,7 +1618,7 @@ async function r2TempCredentialsRoute(req, accountID) {
1617
1618
  const objects = list(body.objects);
1618
1619
  if (!prefixes || !objects)
1619
1620
  return failure(400, 1004, 'prefixes and objects must be lists of strings');
1620
- const c = await createR2TempCredential({ accountId: accountID, bucket: body.bucket, parent, permission, ttlSeconds: ttl, prefixes, objects }, req.root, req.occurredAt ?? new Date().toISOString());
1621
+ const c = await createR2TempCredential({ accountId: accountID, bucket: body.bucket, parent, permission, ttlSeconds: ttl, prefixes, objects }, req.root, req.occurredAt ?? worldNow());
1621
1622
  return success({ accessKeyId: c.access_key_id, secretAccessKey: c.secret_access_key, sessionToken: c.session_token });
1622
1623
  }
1623
1624
  // R2 custom domains (https://developers.cloudflare.com/api/resources/r2/subresources/buckets/subresources/domains/subresources/custom/):
@@ -1628,7 +1629,7 @@ async function r2TempCredentialsRoute(req, accountID) {
1628
1629
  // and 1001 not-found conventions.
1629
1630
  const TLS_VERSIONS = new Set(['1.0', '1.1', '1.2', '1.3']);
1630
1631
  async function r2CustomDomainRoute(req, method, parts, accountID, bucketName) {
1631
- const at = req.occurredAt ?? new Date().toISOString();
1632
+ const at = req.occurredAt ?? worldNow();
1632
1633
  await catchUpR2CustomDomains(req.root, at);
1633
1634
  const mine = () => r2CustomDomains(req.root).filter((d) => d.account_id === accountID && d.bucket === bucketName);
1634
1635
  const full = (d) => ({ domain: d.domain, enabled: d.enabled, status: { ownership: d.ownership, ssl: d.ssl }, minTLS: d.min_tls, ...(d.ciphers ? { ciphers: d.ciphers } : {}), zoneId: d.zone_id, zoneName: d.zone_name });
@@ -1844,7 +1845,7 @@ async function hyperdriveRoute(req, method, url, parts, accountID) {
1844
1845
  const checked = validateWrite(body);
1845
1846
  if (isResponse(checked))
1846
1847
  return checked;
1847
- const at = req.occurredAt ?? new Date().toISOString();
1848
+ const at = req.occurredAt ?? worldNow();
1848
1849
  const id = mint('hyperdrive_config', `${accountID}:${body.name}`, req.root);
1849
1850
  await pwrite('hyperdrive_config', id, 'hyperdrive_config.create', {
1850
1851
  account_id: accountID,
@@ -1884,7 +1885,7 @@ async function hyperdriveRoute(req, method, url, parts, accountID) {
1884
1885
  caching: body.caching ?? null,
1885
1886
  mtls: body.mtls ?? null,
1886
1887
  origin_connection_limit: typeof body.origin_connection_limit === 'number' ? body.origin_connection_limit : null,
1887
- modified_on: req.occurredAt ?? new Date().toISOString(),
1888
+ modified_on: req.occurredAt ?? worldNow(),
1888
1889
  }, req);
1889
1890
  return success(hyperdriveView(row('hyperdrive_config', hyperdriveID, req.root)));
1890
1891
  }
@@ -1926,7 +1927,7 @@ async function hyperdriveRoute(req, method, url, parts, accountID) {
1926
1927
  ...(body.caching !== undefined ? { caching: body.caching } : {}),
1927
1928
  ...(body.mtls !== undefined ? { mtls: body.mtls } : {}),
1928
1929
  ...(body.origin_connection_limit !== undefined ? { origin_connection_limit: body.origin_connection_limit } : {}),
1929
- modified_on: req.occurredAt ?? new Date().toISOString(),
1930
+ modified_on: req.occurredAt ?? worldNow(),
1930
1931
  }, req);
1931
1932
  return success(hyperdriveView(row('hyperdrive_config', hyperdriveID, req.root)));
1932
1933
  }
@@ -1984,7 +1985,7 @@ async function queuesRoute(req, method, parts, accountID) {
1984
1985
  if (accountQueues().some((item) => item.queue_name === body.queue_name)) {
1985
1986
  return failure(400, 1004, `A queue named "${body.queue_name}" already exists on this account`);
1986
1987
  }
1987
- const at = req.occurredAt ?? new Date().toISOString();
1988
+ const at = req.occurredAt ?? worldNow();
1988
1989
  const id = mint('queue', `${accountID}:${body.queue_name}`, req.root);
1989
1990
  await pwrite('queue', id, 'queue.create', {
1990
1991
  account_id: accountID, queue_name: body.queue_name, created_on: at, modified_on: at, deleted: false,
@@ -2037,7 +2038,7 @@ async function queuesRoute(req, method, parts, accountID) {
2037
2038
  // A Cloudflare queue has at most one consumer (worker and http_pull are mutually exclusive).
2038
2039
  if (queueConsumers().length > 0)
2039
2040
  return failure(400, 1004, 'This queue already has a consumer; delete it before adding another');
2040
- const at = req.occurredAt ?? new Date().toISOString();
2041
+ const at = req.occurredAt ?? worldNow();
2041
2042
  const id = mint('queue_consumer', `${queueID}:${String(body.script_name ?? 'http_pull')}`, req.root);
2042
2043
  await pwrite('queue_consumer', id, 'queue_consumer.create', {
2043
2044
  account_id: accountID,
@@ -9,7 +9,7 @@
9
9
  // api-schemas OpenAPI 4.0.0 (commit 2ac8369e9b63dccacee1a2284e95bb819f05b307) and official
10
10
  // cloudflare-typescript SDK (commit faaaf89ed8064a9fb54de538ec3e89487f1302b0; npm cloudflare@7.1.0).
11
11
  import { isIP } from 'node:net';
12
- import { resolveSubjectId } from '@volter/world-core';
12
+ import { resolveSubjectId, worldNow } from '@volter/world-core';
13
13
  import { CLOUDFLARE_RESOURCE_TYPES, deterministicHex, failure, headers, isResponse, mint, noRoute, paginate, parseBody, readOnly, row, rows, SERVICE, scopeMissing, success, write, callerEmail, audit, } from "./cloudflare-common.js";
14
14
  import { CLOUDFLARE_PROVISIONING_SURFACE, handleProvisioningRoute } from "./cloudflare-provisioning.js";
15
15
  export { CLOUDFLARE_RESOURCE_TYPES } from "./cloudflare-common.js";
@@ -138,7 +138,7 @@ async function bootstrap(req, body) {
138
138
  const blocked = readOnly(req);
139
139
  if (blocked)
140
140
  return blocked;
141
- const observedAt = req.occurredAt ?? new Date().toISOString();
141
+ const observedAt = req.occurredAt ?? worldNow();
142
142
  const accounts = Array.isArray(body.accounts) ? body.accounts : [];
143
143
  const zones = Array.isArray(body.zones) ? body.zones : [];
144
144
  for (const value of accounts) {
@@ -200,7 +200,7 @@ async function bootstrap(req, body) {
200
200
  const item = (value ?? {});
201
201
  if (typeof item.email !== 'string' || typeof item.token !== 'string' || !item.token)
202
202
  return failure(400, 1004, 'Bootstrap user_tokens require an email and a token');
203
- await write('user_token', item.token, 'user_token.observe', { token: item.token, email: item.email, created_on: req.occurredAt ?? new Date().toISOString() }, req);
203
+ await write('user_token', item.token, 'user_token.observe', { token: item.token, email: item.email, created_on: req.occurredAt ?? worldNow() }, req);
204
204
  }
205
205
  return success({ accounts: accounts.length, zones: zones.length, members: members.length, user_tokens: userTokens.length });
206
206
  }
@@ -350,7 +350,7 @@ async function zoneSettingRoute(req, method, parts) {
350
350
  if (typeof body.value !== 'string' || !def.values.includes(body.value))
351
351
  return failure(400, 1007, `Invalid value for zone setting ${parts[3]}`);
352
352
  const before = view().value;
353
- await write('zone_setting', id, 'zone_setting.update', { zone_id: parts[1], setting: parts[3], value: body.value, modified_on: req.occurredAt ?? new Date().toISOString() }, req);
353
+ await write('zone_setting', id, 'zone_setting.update', { zone_id: parts[1], setting: parts[3], value: body.value, modified_on: req.occurredAt ?? worldNow() }, req);
354
354
  await audit(req, String(zone.account_id), { type: 'update', resource: { type: 'zone_setting', id: parts[3] }, oldValue: before, newValue: body.value, metadata: { zone_id: parts[1], zone_name: zone.name, setting: parts[3] } });
355
355
  return success(view());
356
356
  }
@@ -384,7 +384,7 @@ export async function handleCloudflareTwinRequest(req) {
384
384
  if (!/^[^@\s]+@[^@\s]+$/.test(parts[2]))
385
385
  return failure(400, 1001, 'A valid email is required');
386
386
  const token = `cf-${deterministicHex(`token:${parts[2]}:${rows('user_token', req.root).length}`, 40)}`;
387
- await write('user_token', token, 'user_token.create', { token, email: parts[2], created_on: req.occurredAt ?? new Date().toISOString() }, req);
387
+ await write('user_token', token, 'user_token.create', { token, email: parts[2], created_on: req.occurredAt ?? worldNow() }, req);
388
388
  // A user's token is logged in each account the user is a member of.
389
389
  for (const m of rows('account_member', req.root).filter((x) => x.email === parts[2]))
390
390
  await audit({ ...req, headers: { authorization: `Bearer ${token}` } }, String(m.account_id), { type: 'create', resource: { type: 'token', id: token.slice(0, 12) }, newValue: { owner: parts[2] } });
@@ -490,7 +490,7 @@ export async function handleCloudflareTwinRequest(req) {
490
490
  return failure(400, 1004, 'tunnel_secret must be canonical base64 encoding of at least 32 bytes');
491
491
  }
492
492
  const id = mint('cloudflare_tunnel', `${accountID}:${body.name}`, req.root);
493
- const createdAt = req.occurredAt ?? new Date().toISOString();
493
+ const createdAt = req.occurredAt ?? worldNow();
494
494
  await write('cloudflare_tunnel', id, 'tunnel.create', {
495
495
  account_id: accountID,
496
496
  name: body.name,
@@ -537,7 +537,7 @@ export async function handleCloudflareTwinRequest(req) {
537
537
  const blocked = readOnly(req);
538
538
  if (blocked)
539
539
  return blocked;
540
- const deletedAt = req.occurredAt ?? new Date().toISOString();
540
+ const deletedAt = req.occurredAt ?? worldNow();
541
541
  await write('cloudflare_tunnel', tunnelID, 'tunnel.delete', { account_id: accountID, deleted: true, deleted_at: deletedAt }, req);
542
542
  return success(tunnelView(row('cloudflare_tunnel', tunnelID, req.root, true)));
543
543
  }
@@ -580,7 +580,7 @@ export async function handleCloudflareTwinRequest(req) {
580
580
  tunnel_id: tunnelID,
581
581
  source: 'cloudflare',
582
582
  version: Number(current?.version ?? 0) + 1,
583
- created_at: current?.created_at ?? (req.occurredAt ?? new Date().toISOString()),
583
+ created_at: current?.created_at ?? (req.occurredAt ?? worldNow()),
584
584
  config,
585
585
  }, req);
586
586
  return success(configurationView(row('tunnel_configuration', id, req.root)));
@@ -620,7 +620,7 @@ export async function handleCloudflareTwinRequest(req) {
620
620
  if (invalid)
621
621
  return invalid;
622
622
  const id = mint('dns_record', `${zoneID}:${body.type}:${body.name}:${JSON.stringify(body.content ?? body.data)}`, req.root);
623
- const at = req.occurredAt ?? new Date().toISOString();
623
+ const at = req.occurredAt ?? worldNow();
624
624
  await write('dns_record', id, 'dns_record.create', {
625
625
  zone_id: zoneID,
626
626
  zone_name: zone.name,
@@ -687,7 +687,7 @@ export async function handleCloudflareTwinRequest(req) {
687
687
  const invalid = dnsValidation(merged, zoneID, req.root, recordID);
688
688
  if (invalid)
689
689
  return invalid;
690
- const at = req.occurredAt ?? new Date().toISOString();
690
+ const at = req.occurredAt ?? worldNow();
691
691
  await write('dns_record', recordID, method === 'PUT' ? 'dns_record.replace' : 'dns_record.update', {
692
692
  zone_id: zoneID,
693
693
  name: merged.name,
@@ -24,6 +24,7 @@
24
24
  // (wrangler reads `wrangler_single_asset_uploads` from it; the twin never sets it, so the bulk
25
25
  // multipart path is the one driven) and the twin verifies the signature, purpose, account,
26
26
  // and expiry on redemption.
27
+ import { worldNow } from '@volter/world-core';
27
28
  import { createHmac, timingSafeEqual } from 'node:crypto';
28
29
  import { failure, headers as lowerHeaders, isResponse, mint, row, rows, success, write, } from "./cloudflare-common.js";
29
30
  const TOKEN_KEY = 'volter-cloudflare-twin:workers-assets';
@@ -60,7 +61,7 @@ function readToken(token) {
60
61
  }
61
62
  }
62
63
  function epochSeconds(req) {
63
- return Math.floor(Date.parse(req.occurredAt ?? new Date().toISOString()) / 1000);
64
+ return Math.floor(Date.parse(req.occurredAt ?? worldNow()) / 1000);
64
65
  }
65
66
  function assetID(accountID, hash) {
66
67
  return `${accountID}:${hash}`;
@@ -108,7 +109,7 @@ export async function createAssetsUploadSession(req, accountID, scriptName, body
108
109
  const buckets = [];
109
110
  for (let index = 0; index < pending.length; index += ASSET_BUCKET_SIZE)
110
111
  buckets.push(pending.slice(index, index + ASSET_BUCKET_SIZE));
111
- const at = req.occurredAt ?? new Date().toISOString();
112
+ const at = req.occurredAt ?? worldNow();
112
113
  const id = mint('worker_asset_upload_session', `${accountID}:${scriptName}:${JSON.stringify(entries)}`, req.root);
113
114
  await write('worker_asset_upload_session', id, 'worker_asset_upload_session.create', {
114
115
  account_id: accountID, script_name: scriptName, manifest: entries, pending, created_on: at, deleted: false,
@@ -162,7 +163,7 @@ export async function uploadAssets(req, accountID, url, parseParts) {
162
163
  const contentType = part.contentType && part.contentType !== 'application/null' ? part.contentType : null;
163
164
  accepted.push({ hash: part.name, size, contentType });
164
165
  }
165
- const at = req.occurredAt ?? new Date().toISOString();
166
+ const at = req.occurredAt ?? worldNow();
166
167
  for (const asset of accepted) {
167
168
  if (row('worker_asset', assetID(accountID, asset.hash), req.root))
168
169
  continue; // content-addressed: already held
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/twin-cloudflare",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Local Cloudflare API twin for accounts, zones, Cloudflare Tunnels, tunnel configurations and zone DNS records, built on @volter/world-core.",
5
5
  "author": "Volter (https://github.com/volter-ai)",
6
6
  "license": "Apache-2.0",
@@ -35,17 +35,17 @@
35
35
  "postpack": "node ../../../scripts/publish/prepare-publish.mjs postpack"
36
36
  },
37
37
  "dependencies": {
38
- "@volter/world-ui": "0.1.0",
38
+ "@volter/world-ui": "0.1.2",
39
39
  "react": "^19.2.7",
40
40
  "react-dom": "^19.2.7"
41
41
  },
42
42
  "peerDependencies": {
43
- "@volter/world-core": "2.0.0"
43
+ "@volter/world-core": "2.0.2"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/bun": "^1.2.20",
47
47
  "@types/node": "^24.0.0",
48
- "@volter/world-core": "2.0.0",
48
+ "@volter/world-core": "2.0.2",
49
49
  "@volter/world-tooling": "0.1.0",
50
50
  "cloudflare": "7.1.0",
51
51
  "typescript": "^5.9.0"
@@ -3,7 +3,7 @@
3
3
  // cloudflare-twin.ts) and the provisioning slice (Workers/R2/Hyperdrive/Queues in
4
4
  // cloudflare-provisioning.ts). Pure helpers over the @volter/world-core kernel — no routes here.
5
5
  import { createHash } from 'node:crypto';
6
- import { applyTwinWrite, projectResources } from '@volter/world-core';
6
+ import { applyTwinWrite, projectResources, worldNow } from '@volter/world-core';
7
7
 
8
8
  export const SERVICE = 'cloudflare';
9
9
 
@@ -174,7 +174,7 @@ export function callerEmail(req: CloudflareRequest): string {
174
174
 
175
175
  /** One entry in an account's audit log, attributed to the calling token's user. */
176
176
  export async function audit(req: CloudflareRequest, accountID: string, entry: { type: string; resource: { type: string; id: string }; oldValue?: unknown; newValue?: unknown; metadata?: Record<string, unknown> }): Promise<void> {
177
- const when = req.occurredAt ?? new Date().toISOString();
177
+ const when = req.occurredAt ?? worldNow();
178
178
  const id = deterministicHex(`audit:${accountID}:${when}:${entry.resource.type}:${entry.resource.id}:${rows('audit_log', req.root).length}`, 32);
179
179
  const email = callerEmail(req);
180
180
  await write('audit_log', id, 'audit_log.record', { account_id: accountID, when, action: { type: entry.type, result: true, info: '' },
@@ -17,6 +17,7 @@
17
17
  // pack's generic conventions (1004 validation, 1001 not found) everywhere else — see README
18
18
  // "Official grounding". No live probe was possible (no Cloudflare account); the OpenAPI + SDK
19
19
  // are the honest grounding ceiling for this slice.
20
+ import { worldNow } from '@volter/world-core';
20
21
  import { createHash } from 'node:crypto';
21
22
  import {
22
23
  deterministicHex,
@@ -807,7 +808,7 @@ function buildUpload(req: CloudflareRequest, url: URL, accountID: string, script
807
808
  * UUID (the shape wrangler prints as "Current Version ID"). */
808
809
  async function writeVersion(req: CloudflareRequest, accountID: string, scriptName: string, scriptTag: string, number: number, content: VersionContent, annotations: Body): Promise<Row> {
809
810
  const id = mint('worker_version', `${accountID}:${scriptName}:${scriptTag}:${number}`, req.root);
810
- const at = req.occurredAt ?? new Date().toISOString();
811
+ const at = req.occurredAt ?? worldNow();
811
812
  await pwrite('worker_version', id, 'worker_version.upload', {
812
813
  account_id: accountID, script_name: scriptName, script_tag: scriptTag, number, ...content,
813
814
  source: deploySource(req), annotations, author_email: callerEmail(req) || null, created_on: at, modified_on: at, deleted: false,
@@ -819,7 +820,7 @@ function deploymentRecord(req: CloudflareRequest, script: { tag: unknown; deploy
819
820
  const count = Array.isArray(script.deployments) ? script.deployments.length : 0;
820
821
  return {
821
822
  id: uuidFrom(`${String(script.tag)}:deployment:${count}`),
822
- created_on: req.occurredAt ?? new Date().toISOString(),
823
+ created_on: req.occurredAt ?? worldNow(),
823
824
  source: deploySource(req),
824
825
  strategy: 'percentage',
825
826
  versions,
@@ -841,7 +842,7 @@ async function uploadScript(req: CloudflareRequest, url: URL, accountID: string,
841
842
  const { existing, content } = built;
842
843
  const tag = String(existing?.tag ?? mintScriptTag(accountID, scriptName, req.root));
843
844
  const number = Number(existing?.version_count ?? 0) + 1;
844
- const at = req.occurredAt ?? new Date().toISOString();
845
+ const at = req.occurredAt ?? worldNow();
845
846
  // All validation passed — now perform the writes (migrations, the version, then the script).
846
847
  await applyMigrationPlan(accountID, scriptName, built.migrationOps, req);
847
848
  const version = await writeVersion(req, accountID, scriptName, tag, number, content, built.annotations);
@@ -1023,7 +1024,7 @@ async function createDeployment(req: CloudflareRequest, accountID: string, scrip
1023
1024
  modules: null,
1024
1025
  version_id: live.id,
1025
1026
  deployments: [...deployments, deployment],
1026
- modified_on: req.occurredAt ?? new Date().toISOString(),
1027
+ modified_on: req.occurredAt ?? worldNow(),
1027
1028
  }, req);
1028
1029
  return success(deployment);
1029
1030
  }
@@ -1057,7 +1058,7 @@ async function patchScriptSettings(req: CloudflareRequest, accountID: string, sc
1057
1058
  ...(body.tags !== undefined ? { tags: body.tags ?? [] } : {}),
1058
1059
  ...(body.tail_consumers !== undefined ? { tail_consumers: body.tail_consumers } : {}),
1059
1060
  ...(body.observability !== undefined ? { observability: body.observability } : {}),
1060
- modified_on: req.occurredAt ?? new Date().toISOString(),
1061
+ modified_on: req.occurredAt ?? worldNow(),
1061
1062
  }, req);
1062
1063
  return success(settingsView(scriptRow(accountID, String(script.name), req.root)!));
1063
1064
  }
@@ -1249,7 +1250,7 @@ async function workersRoute(req: CloudflareRequest, method: string, url: URL, pa
1249
1250
  let body: unknown;
1250
1251
  try { body = req.body ? JSON.parse(req.body) : undefined; } catch { return failure(400, 1004, 'Invalid request body'); }
1251
1252
  if (!Array.isArray(body)) return failure(400, 1004, 'Cron trigger update requires an array of {cron} objects');
1252
- const at = req.occurredAt ?? new Date().toISOString();
1253
+ const at = req.occurredAt ?? worldNow();
1253
1254
  const schedules: Body[] = [];
1254
1255
  for (const value of body) {
1255
1256
  const item = value as Body | null;
@@ -1517,7 +1518,7 @@ async function r2Route(req: CloudflareRequest, method: string, url: URL, parts:
1517
1518
  if (accountBuckets().some((item) => item.name === body.name)) {
1518
1519
  return failure(409, 10004, 'The bucket you tried to create already exists, and you own it.');
1519
1520
  }
1520
- const at = req.occurredAt ?? new Date().toISOString();
1521
+ const at = req.occurredAt ?? worldNow();
1521
1522
  await pwrite('r2_bucket', `${accountID}:${body.name}`, 'r2_bucket.create', {
1522
1523
  account_id: accountID,
1523
1524
  name: body.name,
@@ -1545,7 +1546,7 @@ async function r2Route(req: CloudflareRequest, method: string, url: URL, parts:
1545
1546
  if (rows('r2_object', req.root).some((o) => o.bucket_id === `${accountID}:${bucketName}`)) return failure(409, 10008, 'Cannot delete bucket that contains objects.');
1546
1547
  await pwrite('r2_bucket', `${accountID}:${bucketName}`, 'r2_bucket.delete', { account_id: accountID, deleted: true }, req);
1547
1548
  // "The specified domain will also remain connected to R2 until you remove it or delete the bucket." (public buckets)
1548
- for (const d of r2CustomDomains(req.root).filter((x) => x.account_id === accountID && x.bucket === bucketName)) await removeR2CustomDomain(d.id, req.root, req.occurredAt ?? new Date().toISOString());
1549
+ for (const d of r2CustomDomains(req.root).filter((x) => x.account_id === accountID && x.bucket === bucketName)) await removeR2CustomDomain(d.id, req.root, req.occurredAt ?? worldNow());
1549
1550
  return success({});
1550
1551
  }
1551
1552
  return noRoute();
@@ -1573,7 +1574,7 @@ async function r2TempCredentialsRoute(req: CloudflareRequest, accountID: string)
1573
1574
  const prefixes = list(body.prefixes);
1574
1575
  const objects = list(body.objects);
1575
1576
  if (!prefixes || !objects) return failure(400, 1004, 'prefixes and objects must be lists of strings');
1576
- const c = await createR2TempCredential({ accountId: accountID, bucket: body.bucket, parent, permission, ttlSeconds: ttl, prefixes, objects }, req.root, req.occurredAt ?? new Date().toISOString());
1577
+ const c = await createR2TempCredential({ accountId: accountID, bucket: body.bucket, parent, permission, ttlSeconds: ttl, prefixes, objects }, req.root, req.occurredAt ?? worldNow());
1577
1578
  return success({ accessKeyId: c.access_key_id, secretAccessKey: c.secret_access_key, sessionToken: c.session_token });
1578
1579
  }
1579
1580
 
@@ -1585,7 +1586,7 @@ async function r2TempCredentialsRoute(req: CloudflareRequest, accountID: string)
1585
1586
  // and 1001 not-found conventions.
1586
1587
  const TLS_VERSIONS = new Set(['1.0', '1.1', '1.2', '1.3']);
1587
1588
  async function r2CustomDomainRoute(req: CloudflareRequest, method: string, parts: string[], accountID: string, bucketName: string): Promise<CloudflareResponse> {
1588
- const at = req.occurredAt ?? new Date().toISOString();
1589
+ const at = req.occurredAt ?? worldNow();
1589
1590
  await catchUpR2CustomDomains(req.root, at);
1590
1591
  const mine = () => r2CustomDomains(req.root).filter((d) => d.account_id === accountID && d.bucket === bucketName);
1591
1592
  const full = (d: R2CustomDomain): Body => ({ domain: d.domain, enabled: d.enabled, status: { ownership: d.ownership, ssl: d.ssl }, minTLS: d.min_tls, ...(d.ciphers ? { ciphers: d.ciphers } : {}), zoneId: d.zone_id, zoneName: d.zone_name });
@@ -1755,7 +1756,7 @@ async function hyperdriveRoute(req: CloudflareRequest, method: string, url: URL,
1755
1756
  if (isResponse(body)) return body;
1756
1757
  const checked = validateWrite(body);
1757
1758
  if (isResponse(checked)) return checked;
1758
- const at = req.occurredAt ?? new Date().toISOString();
1759
+ const at = req.occurredAt ?? worldNow();
1759
1760
  const id = mint('hyperdrive_config', `${accountID}:${body.name}`, req.root);
1760
1761
  await pwrite('hyperdrive_config', id, 'hyperdrive_config.create', {
1761
1762
  account_id: accountID,
@@ -1789,7 +1790,7 @@ async function hyperdriveRoute(req: CloudflareRequest, method: string, url: URL,
1789
1790
  caching: body.caching ?? null,
1790
1791
  mtls: body.mtls ?? null,
1791
1792
  origin_connection_limit: typeof body.origin_connection_limit === 'number' ? body.origin_connection_limit : null,
1792
- modified_on: req.occurredAt ?? new Date().toISOString(),
1793
+ modified_on: req.occurredAt ?? worldNow(),
1793
1794
  }, req);
1794
1795
  return success(hyperdriveView(row('hyperdrive_config', hyperdriveID, req.root)!));
1795
1796
  }
@@ -1824,7 +1825,7 @@ async function hyperdriveRoute(req: CloudflareRequest, method: string, url: URL,
1824
1825
  ...(body.caching !== undefined ? { caching: body.caching } : {}),
1825
1826
  ...(body.mtls !== undefined ? { mtls: body.mtls } : {}),
1826
1827
  ...(body.origin_connection_limit !== undefined ? { origin_connection_limit: body.origin_connection_limit } : {}),
1827
- modified_on: req.occurredAt ?? new Date().toISOString(),
1828
+ modified_on: req.occurredAt ?? worldNow(),
1828
1829
  }, req);
1829
1830
  return success(hyperdriveView(row('hyperdrive_config', hyperdriveID, req.root)!));
1830
1831
  }
@@ -1873,7 +1874,7 @@ async function queuesRoute(req: CloudflareRequest, method: string, parts: string
1873
1874
  if (accountQueues().some((item) => item.queue_name === body.queue_name)) {
1874
1875
  return failure(400, 1004, `A queue named "${body.queue_name}" already exists on this account`);
1875
1876
  }
1876
- const at = req.occurredAt ?? new Date().toISOString();
1877
+ const at = req.occurredAt ?? worldNow();
1877
1878
  const id = mint('queue', `${accountID}:${body.queue_name}`, req.root);
1878
1879
  await pwrite('queue', id, 'queue.create', {
1879
1880
  account_id: accountID, queue_name: body.queue_name, created_on: at, modified_on: at, deleted: false,
@@ -1916,7 +1917,7 @@ async function queuesRoute(req: CloudflareRequest, method: string, parts: string
1916
1917
  }
1917
1918
  // A Cloudflare queue has at most one consumer (worker and http_pull are mutually exclusive).
1918
1919
  if (queueConsumers().length > 0) return failure(400, 1004, 'This queue already has a consumer; delete it before adding another');
1919
- const at = req.occurredAt ?? new Date().toISOString();
1920
+ const at = req.occurredAt ?? worldNow();
1920
1921
  const id = mint('queue_consumer', `${queueID}:${String(body.script_name ?? 'http_pull')}`, req.root);
1921
1922
  await pwrite('queue_consumer', id, 'queue_consumer.create', {
1922
1923
  account_id: accountID,
@@ -9,7 +9,7 @@
9
9
  // api-schemas OpenAPI 4.0.0 (commit 2ac8369e9b63dccacee1a2284e95bb819f05b307) and official
10
10
  // cloudflare-typescript SDK (commit faaaf89ed8064a9fb54de538ec3e89487f1302b0; npm cloudflare@7.1.0).
11
11
  import { isIP } from 'node:net';
12
- import { resolveSubjectId } from '@volter/world-core';
12
+ import { resolveSubjectId, worldNow } from '@volter/world-core';
13
13
  import {
14
14
  CLOUDFLARE_RESOURCE_TYPES,
15
15
  deterministicHex,
@@ -169,7 +169,7 @@ function auditLogRoute(req: CloudflareRequest, method: string, url: URL, parts:
169
169
  async function bootstrap(req: CloudflareRequest, body: Record<string, unknown>): Promise<CloudflareResponse> {
170
170
  const blocked = readOnly(req);
171
171
  if (blocked) return blocked;
172
- const observedAt = req.occurredAt ?? new Date().toISOString();
172
+ const observedAt = req.occurredAt ?? worldNow();
173
173
  const accounts = Array.isArray(body.accounts) ? body.accounts : [];
174
174
  const zones = Array.isArray(body.zones) ? body.zones : [];
175
175
  for (const value of accounts) {
@@ -224,7 +224,7 @@ async function bootstrap(req: CloudflareRequest, body: Record<string, unknown>):
224
224
  for (const value of userTokens) {
225
225
  const item = (value ?? {}) as Record<string, unknown>;
226
226
  if (typeof item.email !== 'string' || typeof item.token !== 'string' || !item.token) return failure(400, 1004, 'Bootstrap user_tokens require an email and a token');
227
- await write('user_token', item.token, 'user_token.observe', { token: item.token, email: item.email, created_on: req.occurredAt ?? new Date().toISOString() }, req);
227
+ await write('user_token', item.token, 'user_token.observe', { token: item.token, email: item.email, created_on: req.occurredAt ?? worldNow() }, req);
228
228
  }
229
229
  return success({ accounts: accounts.length, zones: zones.length, members: members.length, user_tokens: userTokens.length });
230
230
  }
@@ -343,7 +343,7 @@ async function zoneSettingRoute(req: CloudflareRequest, method: string, parts: s
343
343
  const body = parseBody(req); if (isResponse(body)) return body;
344
344
  if (typeof body.value !== 'string' || !def.values.includes(body.value)) return failure(400, 1007, `Invalid value for zone setting ${parts[3]}`);
345
345
  const before = view().value;
346
- await write('zone_setting', id, 'zone_setting.update', { zone_id: parts[1], setting: parts[3], value: body.value, modified_on: req.occurredAt ?? new Date().toISOString() }, req);
346
+ await write('zone_setting', id, 'zone_setting.update', { zone_id: parts[1], setting: parts[3], value: body.value, modified_on: req.occurredAt ?? worldNow() }, req);
347
347
  await audit(req, String(zone.account_id), { type: 'update', resource: { type: 'zone_setting', id: parts[3]! }, oldValue: before, newValue: body.value, metadata: { zone_id: parts[1], zone_name: zone.name, setting: parts[3] } });
348
348
  return success(view());
349
349
  }
@@ -372,7 +372,7 @@ export async function handleCloudflareTwinRequest(req: CloudflareRequest): Promi
372
372
  const blocked = readOnly(req); if (blocked) return blocked;
373
373
  if (!/^[^@\s]+@[^@\s]+$/.test(parts[2])) return failure(400, 1001, 'A valid email is required');
374
374
  const token = `cf-${deterministicHex(`token:${parts[2]}:${rows('user_token', req.root).length}`, 40)}`;
375
- await write('user_token', token, 'user_token.create', { token, email: parts[2], created_on: req.occurredAt ?? new Date().toISOString() }, req);
375
+ await write('user_token', token, 'user_token.create', { token, email: parts[2], created_on: req.occurredAt ?? worldNow() }, req);
376
376
  // A user's token is logged in each account the user is a member of.
377
377
  for (const m of rows('account_member', req.root).filter((x) => x.email === parts[2])) await audit({ ...req, headers: { authorization: `Bearer ${token}` } }, String(m.account_id), { type: 'create', resource: { type: 'token', id: token.slice(0, 12) }, newValue: { owner: parts[2] } });
378
378
  return success({ token, email: parts[2] });
@@ -464,7 +464,7 @@ export async function handleCloudflareTwinRequest(req: CloudflareRequest): Promi
464
464
  if (!validTunnelSecret(body.tunnel_secret)) return failure(400, 1004, 'tunnel_secret must be canonical base64 encoding of at least 32 bytes');
465
465
  }
466
466
  const id = mint('cloudflare_tunnel', `${accountID}:${body.name}`, req.root);
467
- const createdAt = req.occurredAt ?? new Date().toISOString();
467
+ const createdAt = req.occurredAt ?? worldNow();
468
468
  await write('cloudflare_tunnel', id, 'tunnel.create', {
469
469
  account_id: accountID,
470
470
  name: body.name,
@@ -507,7 +507,7 @@ export async function handleCloudflareTwinRequest(req: CloudflareRequest): Promi
507
507
  if (parts.length === 4 && method === 'DELETE') {
508
508
  const blocked = readOnly(req);
509
509
  if (blocked) return blocked;
510
- const deletedAt = req.occurredAt ?? new Date().toISOString();
510
+ const deletedAt = req.occurredAt ?? worldNow();
511
511
  await write('cloudflare_tunnel', tunnelID, 'tunnel.delete', { account_id: accountID, deleted: true, deleted_at: deletedAt }, req);
512
512
  return success(tunnelView(row('cloudflare_tunnel', tunnelID, req.root, true)!));
513
513
  }
@@ -544,7 +544,7 @@ export async function handleCloudflareTwinRequest(req: CloudflareRequest): Promi
544
544
  tunnel_id: tunnelID,
545
545
  source: 'cloudflare',
546
546
  version: Number(current?.version ?? 0) + 1,
547
- created_at: current?.created_at ?? (req.occurredAt ?? new Date().toISOString()),
547
+ created_at: current?.created_at ?? (req.occurredAt ?? worldNow()),
548
548
  config,
549
549
  }, req);
550
550
  return success(configurationView(row('tunnel_configuration', id, req.root)!));
@@ -577,7 +577,7 @@ export async function handleCloudflareTwinRequest(req: CloudflareRequest): Promi
577
577
  const invalid = dnsValidation(body, zoneID, req.root);
578
578
  if (invalid) return invalid;
579
579
  const id = mint('dns_record', `${zoneID}:${body.type}:${body.name}:${JSON.stringify(body.content ?? body.data)}`, req.root);
580
- const at = req.occurredAt ?? new Date().toISOString();
580
+ const at = req.occurredAt ?? worldNow();
581
581
  await write('dns_record', id, 'dns_record.create', {
582
582
  zone_id: zoneID,
583
583
  zone_name: zone.name,
@@ -636,7 +636,7 @@ export async function handleCloudflareTwinRequest(req: CloudflareRequest): Promi
636
636
  if (typeof merged.name === 'string') merged.name = merged.name.toLowerCase();
637
637
  const invalid = dnsValidation(merged, zoneID, req.root, recordID);
638
638
  if (invalid) return invalid;
639
- const at = req.occurredAt ?? new Date().toISOString();
639
+ const at = req.occurredAt ?? worldNow();
640
640
  await write('dns_record', recordID, method === 'PUT' ? 'dns_record.replace' : 'dns_record.update', {
641
641
  zone_id: zoneID,
642
642
  name: merged.name,
@@ -24,6 +24,7 @@
24
24
  // (wrangler reads `wrangler_single_asset_uploads` from it; the twin never sets it, so the bulk
25
25
  // multipart path is the one driven) and the twin verifies the signature, purpose, account,
26
26
  // and expiry on redemption.
27
+ import { worldNow } from '@volter/world-core';
27
28
  import { createHmac, timingSafeEqual } from 'node:crypto';
28
29
  import {
29
30
  failure,
@@ -79,7 +80,7 @@ function readToken(token: string): TokenClaims | null {
79
80
  }
80
81
 
81
82
  function epochSeconds(req: CloudflareRequest): number {
82
- return Math.floor(Date.parse(req.occurredAt ?? new Date().toISOString()) / 1000);
83
+ return Math.floor(Date.parse(req.occurredAt ?? worldNow()) / 1000);
83
84
  }
84
85
 
85
86
  function assetID(accountID: string, hash: string): string {
@@ -128,7 +129,7 @@ export async function createAssetsUploadSession(req: CloudflareRequest, accountI
128
129
  const pending = [...new Set(Object.values(entries).map((entry) => entry.hash))].filter((hash) => !held.has(hash)).sort();
129
130
  const buckets: string[][] = [];
130
131
  for (let index = 0; index < pending.length; index += ASSET_BUCKET_SIZE) buckets.push(pending.slice(index, index + ASSET_BUCKET_SIZE));
131
- const at = req.occurredAt ?? new Date().toISOString();
132
+ const at = req.occurredAt ?? worldNow();
132
133
  const id = mint('worker_asset_upload_session', `${accountID}:${scriptName}:${JSON.stringify(entries)}`, req.root);
133
134
  await write('worker_asset_upload_session', id, 'worker_asset_upload_session.create', {
134
135
  account_id: accountID, script_name: scriptName, manifest: entries, pending, created_on: at, deleted: false,
@@ -179,7 +180,7 @@ export async function uploadAssets(req: CloudflareRequest, accountID: string, ur
179
180
  const contentType = part.contentType && part.contentType !== 'application/null' ? part.contentType : null;
180
181
  accepted.push({ hash: part.name, size, contentType });
181
182
  }
182
- const at = req.occurredAt ?? new Date().toISOString();
183
+ const at = req.occurredAt ?? worldNow();
183
184
  for (const asset of accepted) {
184
185
  if (row('worker_asset', assetID(accountID, asset.hash), req.root)) continue; // content-addressed: already held
185
186
  await write('worker_asset', assetID(accountID, asset.hash), 'worker_asset.upload', {