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:
-
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.
-
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
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.
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
SandboxRefcarries no creation timestamp.sandboxRef()insdk/typescript/src/client.tsmapsid,name,workspace,phase,labels,resourceVersion, and lifecycle status, but silently dropsmetadata.created_time.The field is on the wire and is populated by the gateway:
ObjectMeta.created_timeis agoogle.protobuf.Timestampat field 103 (proto/datamodel.proto:46).current_time_ms()when a sandbox record is created (crates/openshell-server/src/grpc/sandbox.rs:1020).Every other OpenShell surface already reports it:
sandbox list(table)CREATEDcolumn (crates/openshell-cli/src/run.rs:2917)sandbox list -o json"created_at": "YYYY-MM-DD HH:MM:SS"(crates/openshell-cli/src/run.rs:3094)types.Sandbox.CreatedAt time.Time(sdk/go/openshell/v1/types/sandbox.go:14, wired atinternal/converter/sandbox.go:29)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 jsonand parsing a string — or drop to theclient.rawescape hatch and re-implement protobuf decoding for every list page. Both defeat the point of the curated surface, whose README billsclient.sandboxesas 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 bareYYYY-MM-DD HH:MM:SSUTC 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:
ObjectMetais exported from@nvidia/openshell-sdk/raw, but reaching it means giving up the curatedSandboxRefand hand-rollingTimestampdecoding.Proposed change
Add the creation time to the curated
SandboxRefand populate it insandboxRef()frommeta.createdTime. Two calls to make:Field name and type.
createdAt?: Dateis the idiomatic TypeScript choice and matches what the name implies. For consistency with the neighbouringnextRestartAtMs?: numberandmainProcessStartedAtMs?: numberfields,createdAtMs?: numberis the alternative. Maintainers should pick one; the mapping is identical either way.Absence must stay absence.
created_timeis an optional proto message, and older runtimes or hand-built fixtures may omit it. Leave the fieldundefinedrather 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
SandboxRefexposes the sandbox creation time andsandboxRef()populates it frommetadata.created_time.undefinedwhen the gateway omitscreated_time; no epoch default.create,get,list,listAll, andwaitReady— all of which route throughsandboxRef().sdk/typescript/src/client.test.tscover a populated timestamp and the absent case.sdk/typescript/README.mddocuments the field alongside the rest of theSandboxRefshape.mise run sdk:ts:cipasses.Related
The Python
SandboxRefhas the same gap —_sandbox_ref(python/openshell/sandbox.py:1767) never readsmetadata.created_timeeither, 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.