Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/generic-sandbox-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cloudflare/sandbox': patch
---

Fix type error when extending Sandbox class by making getSandbox and SandboxEnv generic
12 changes: 6 additions & 6 deletions packages/sandbox/src/request-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { createLogger, type LogContext, TraceContext } from '@repo/shared';
import { getSandbox, type Sandbox } from './sandbox';
import { sanitizeSandboxId, validatePort } from './security';

export interface SandboxEnv {
Sandbox: DurableObjectNamespace<Sandbox>;
export interface SandboxEnv<T extends Sandbox<any> = Sandbox<any>> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the same explanatory comment here about the any usage to align with the codebase's "never use any" standard.

Sandbox: DurableObjectNamespace<T>;
}

export interface RouteInfo {
Expand All @@ -14,10 +14,10 @@ export interface RouteInfo {
token: string;
}

export async function proxyToSandbox<E extends SandboxEnv>(
request: Request,
env: E
): Promise<Response | null> {
export async function proxyToSandbox<
T extends Sandbox<any>,
E extends SandboxEnv<T>
>(request: Request, env: E): Promise<Response | null> {
// Create logger context for this request
const traceId =
TraceContext.fromHeaders(request.headers) || TraceContext.generate();
Expand Down
10 changes: 5 additions & 5 deletions packages/sandbox/src/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ import {
import type { MountInfo } from './storage-mount/types';
import { SDK_VERSION } from './version';

export function getSandbox(
ns: DurableObjectNamespace<Sandbox>,
export function getSandbox<T extends Sandbox<any>>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment explaining why any is justified here:

// Use 'any' for Env parameter to allow covariance - we need to accept
// Sandbox subclasses with any environment type (Sandbox<E> for all E)
export function getSandbox<T extends Sandbox<any>>(

This is one of the rare valid uses of any - it enables type variance that unknown can't provide, and the Env parameter doesn't affect runtime behavior.

ns: DurableObjectNamespace<T>,
id: string,
options?: SandboxOptions
): Sandbox {
): T {
const sanitizedId = sanitizeSandboxId(id);
const effectiveId = options?.normalizeId
? sanitizedId.toLowerCase()
Expand All @@ -65,7 +65,7 @@ export function getSandbox(
);
}

const stub = getContainer(ns, effectiveId) as unknown as Sandbox;
const stub = getContainer(ns, effectiveId);

stub.setSandboxName?.(effectiveId, options?.normalizeId);

Expand All @@ -87,7 +87,7 @@ export function getSandbox(

return Object.assign(stub, {
wsConnect: connect(stub)
});
}) as T;
}

export function connect(stub: {
Expand Down
Loading