Skip to content

feat(state): stamp createdAt/updatedAt on state-store records#462

Open
Mkassabov wants to merge 1 commit into
mainfrom
claude/busy-taussig-ff189e
Open

feat(state): stamp createdAt/updatedAt on state-store records#462
Mkassabov wants to merge 1 commit into
mainfrom
claude/busy-taussig-ff189e

Conversation

@Mkassabov

Copy link
Copy Markdown
Contributor

Closes #427.

State-store HTTP API bumps to v6 and returns server-stamped createdAt / updatedAt ISO timestamps on every resource record. createdAt is preserved across writes, updatedAt is refreshed on every set. Intended for HTTP-API consumers that curl the deployed store directly (e.g. a CLI building gc --older-than 14d).

GET /state/stacks/:stack/stages/:stage/resources/:fqn
{
  "status": "created",
  "fqn": "Api",
  "...": "...",
  "createdAt": "2026-05-28T12:34:56.000Z",
  "updatedAt": "2026-05-28T12:40:01.000Z"
}

Scoped to the wire contract — the typed HttpStateStore client strips both fields before returning to the engine, so they never leak into ResourceState or downstream resource attr outputs:

// HttpStateStore.ts
const stripServerTimestamps = (s: unknown): unknown => {
  if (s == null || typeof s !== "object" || Array.isArray(s)) return s;
  const { createdAt: _c, updatedAt: _u, ...rest } = s as Record<string, unknown>;
  return rest;
};

Cloudflare DO persists them unencrypted alongside the existing encrypted payload, so a GC pass can read them without holding the key. Pre-v6 entries (bare encrypted string) decode transparently and get re-shaped on the next write.

// Cloudflare/StateStore/Store.ts
type StoredEntry = {
  v: string;          // AES-CTR ciphertext, base64-framed nonce||ct
  createdAt: string;  // ISO 8601, preserved across writes
  updatedAt: string;  // ISO 8601, refreshed on every set
};

Both STATE_STORE_VERSION constants (State/HttpStateApi.ts and Cloudflare/StateStore/Api.ts) move 5 → 6 so the bootstrap probe forces a worker redeploy.

State-store HTTP API (v6) now returns server-stamped `createdAt` /
`updatedAt` ISO timestamps on every resource record. The Cloudflare
Durable Object persists them unencrypted alongside the existing
encrypted payload — `createdAt` is preserved across writes, `updatedAt`
is refreshed on each `set`. Legacy entries written pre-v6 (bare
encrypted string) are read transparently and re-shaped on the next
write.

The fields are scoped to the wire contract: the typed `HttpStateStore`
client strips them before returning to the engine, so they never leak
into `ResourceState` or downstream resource `attr` outputs. They're
intended for HTTP-API consumers (e.g. CLI building `gc --older-than 14d`
over a deployed store) that curl `/state/...` directly.

Closes #427
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add createdAt and updatedAt to resource state

1 participant