Skip to content

feat(sdk/ts): SandboxRef omits the sandbox creation time #4332

Description

@fbricon

User story

As a TypeScript SDK user listing sandboxes — building a dashboard, a sweeper for stale sandboxes, or an age-based retention policy — I want each sandbox's creation time on the curated SandboxRef, so I can order and filter by age without dropping to generated protobuf types.

Problem statement

SandboxRef carries no creation timestamp. sandboxRef() in sdk/typescript/src/client.ts maps id, name, workspace, phase, labels, resourceVersion, and lifecycle status, but silently drops metadata.created_time.

The field is on the wire and is populated by the gateway:

  • ObjectMeta.created_time is a google.protobuf.Timestamp at field 103 (proto/datamodel.proto:46).
  • The gateway sets it from current_time_ms() when a sandbox record is created (crates/openshell-server/src/grpc/sandbox.rs:1020).

Every other OpenShell surface already reports it:

Surface Creation time on sandbox list
CLI sandbox list (table) CREATED column (crates/openshell-cli/src/run.rs:2917)
CLI sandbox list -o json "created_at": "YYYY-MM-DD HH:MM:SS" (crates/openshell-cli/src/run.rs:3094)
Go SDK types.Sandbox.CreatedAt time.Time (sdk/go/openshell/v1/types/sandbox.go:14, wired at internal/converter/sandbox.go:29)
TypeScript SDK missing

So this is a TypeScript-specific parity gap, not a protocol limitation.

Impact

A TypeScript consumer must either reconstruct the age out of band — by shelling out to openshell sandbox list -o json and parsing a string — or drop to the client.raw escape hatch and re-implement protobuf decoding for every list page. Both defeat the point of the curated surface, whose README bills client.sandboxes as the idiomatic path.

The CLI's JSON form is also not a usable substitute for programmatic work: format_epoch_ms (crates/openshell-cli/src/commands/common.rs:74) emits a bare YYYY-MM-DD HH:MM:SS UTC string with no timezone designator and second precision, so consumers cannot round-trip it or preserve sub-second ordering.

Note the escape hatch is the only current workaround: ObjectMeta is exported from @nvidia/openshell-sdk/raw, but reaching it means giving up the curated SandboxRef and hand-rolling Timestamp decoding.

Proposed change

Add the creation time to the curated SandboxRef and populate it in sandboxRef() from meta.createdTime. Two calls to make:

  1. Field name and type. createdAt?: Date is the idiomatic TypeScript choice and matches what the name implies. For consistency with the neighbouring nextRestartAtMs?: number and mainProcessStartedAtMs?: number fields, createdAtMs?: number is the alternative. Maintainers should pick one; the mapping is identical either way.

  2. Absence must stay absence. created_time is an optional proto message, and older runtimes or hand-built fixtures may omit it. Leave the field undefined rather than defaulting to the epoch — a zero timestamp would read as "created in 1970" and silently sort to the top of any age sort.

Acceptance criteria

  • SandboxRef exposes the sandbox creation time and sandboxRef() populates it from metadata.created_time.
  • Absence is preserved as undefined when the gateway omits created_time; no epoch default.
  • The field is populated for create, get, list, listAll, and waitReady — all of which route through sandboxRef().
  • Unit tests in sdk/typescript/src/client.test.ts cover a populated timestamp and the absent case.
  • sdk/typescript/README.md documents the field alongside the rest of the SandboxRef shape.
  • mise run sdk:ts:ci passes.

Related

The Python SandboxRef has the same gap — _sandbox_ref (python/openshell/sandbox.py:1767) never reads metadata.created_time either, even though the raw proto object is in hand. Same one-line fix, but filed separately so this issue stays scoped to TypeScript.

#3646 tracks curated-SDK completeness for the Rust surface and does not cover the TypeScript client or timestamps.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:acceptedA maintainer decided OpenShell should pursue this issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions