From c29a3c929c77eba01b2a219139571b82aae47ec6 Mon Sep 17 00:00:00 2001 From: bradleyshep Date: Thu, 24 Sep 2026 10:19:38 -0400 Subject: [PATCH 1/8] Make the TypeScript SDK's types work for NodeNext and exactOptionalPropertyTypes consumers The published .d.ts files re-export with extensionless relative paths (`export * from './lib/connection_id'`). The package is `"type": "module"`, so TypeScript projects using `moduleResolution: node16/nodenext` cannot resolve them and see no exports from `spacetimedb` at all. Separately, `ConstraintOpts` and `IndexOpts` declare `name?: string` while the SDK derives `{ name: string | undefined }` for them. Under `exactOptionalPropertyTypes` every generated schema then fails `UntypedSchemaDef`, and `conn.reducers` collapses to `never`. - Give every relative import in the SDK source an explicit extension; tsc copies specifiers into the emitted .d.ts files verbatim. The moduledef and client-api generators now emit the extension too. - Widen the optional `name` fields to `string | undefined`. - Lint rejects extensionless relative imports in the SDK source, and a test typechecks generated bindings against the built package with `exactOptionalPropertyTypes` on. --- .../src/angular/connection_state.ts | 6 +- .../src/angular/injectors/inject-reducer.ts | 6 +- .../injectors/inject-spacetimedb-connected.ts | 2 +- .../angular/injectors/inject-spacetimedb.ts | 2 +- .../src/angular/injectors/inject-table.ts | 12 ++-- .../angular/providers/provide-spacetimedb.ts | 6 +- crates/bindings-typescript/src/index.ts | 32 +++++------ .../src/lib/algebraic_type.ts | 18 +++--- .../src/lib/algebraic_type_variants.ts | 2 +- .../src/lib/algebraic_value.ts | 2 +- .../src/lib/autogen/types.ts | 2 +- .../src/lib/connection_id.ts | 4 +- .../src/lib/constraints.ts | 6 +- .../src/lib/environment.ts | 2 +- crates/bindings-typescript/src/lib/filter.ts | 6 +- .../bindings-typescript/src/lib/identity.ts | 4 +- crates/bindings-typescript/src/lib/indexes.ts | 12 ++-- crates/bindings-typescript/src/lib/option.ts | 2 +- crates/bindings-typescript/src/lib/query.ts | 22 ++++---- .../src/lib/reducer_schema.ts | 10 ++-- .../bindings-typescript/src/lib/reducers.ts | 16 +++--- crates/bindings-typescript/src/lib/result.ts | 2 +- .../src/lib/schedule_at.ts | 9 ++- crates/bindings-typescript/src/lib/schema.ts | 14 ++--- crates/bindings-typescript/src/lib/table.ts | 22 ++++---- .../src/lib/table_schema.ts | 14 ++--- .../src/lib/time_duration.ts | 4 +- .../bindings-typescript/src/lib/timestamp.ts | 6 +- .../src/lib/type_builders.test-d.ts | 6 +- .../src/lib/type_builders.ts | 34 ++++++----- .../bindings-typescript/src/lib/type_util.ts | 10 ++-- crates/bindings-typescript/src/lib/util.ts | 14 ++--- crates/bindings-typescript/src/lib/uuid.ts | 4 +- .../src/react/SpacetimeDBProvider.ts | 10 ++-- .../src/react/connection_state.ts | 4 +- .../src/react/useProcedure.ts | 6 +- .../src/react/useReducer.ts | 6 +- .../src/react/useSpacetimeDB.ts | 2 +- .../bindings-typescript/src/react/useTable.ts | 14 ++--- .../src/sdk/client_api/index.ts | 2 +- .../src/sdk/client_api/types.ts | 2 +- .../src/sdk/client_api/types/procedures.ts | 2 +- .../src/sdk/client_api/types/reducers.ts | 2 +- .../src/sdk/client_table.ts | 16 +++--- .../src/sdk/connection_manager.ts | 6 +- .../src/sdk/db_connection_builder.ts | 15 +++-- .../src/sdk/db_connection_impl.ts | 14 ++--- .../bindings-typescript/src/sdk/db_context.ts | 8 +-- crates/bindings-typescript/src/sdk/db_view.ts | 6 +- crates/bindings-typescript/src/sdk/event.ts | 4 +- .../src/sdk/event_context.ts | 2 +- crates/bindings-typescript/src/sdk/logger.ts | 2 +- .../src/sdk/message_types.ts | 2 +- .../bindings-typescript/src/sdk/procedures.ts | 10 ++-- .../src/sdk/reducer_event.ts | 4 +- .../bindings-typescript/src/sdk/reducers.ts | 14 ++--- crates/bindings-typescript/src/sdk/schema.ts | 4 +- .../src/sdk/spacetime_module.ts | 6 +- .../src/sdk/subscription_builder_impl.ts | 14 ++--- .../src/sdk/table_cache.ts | 2 +- .../bindings-typescript/src/sdk/type_utils.ts | 8 +-- .../src/sdk/websocket_decompress_adapter.ts | 8 ++- .../src/sdk/websocket_test_adapter.ts | 9 ++- .../src/sdk/websocket_v3_frames.ts | 2 +- crates/bindings-typescript/src/sdk/ws.ts | 2 +- .../bindings-typescript/src/server/console.ts | 2 +- .../bindings-typescript/src/server/db_view.ts | 6 +- .../src/server/environment.ts | 8 +-- .../bindings-typescript/src/server/errors.ts | 2 +- .../src/server/http.test-d.ts | 6 +- crates/bindings-typescript/src/server/http.ts | 2 +- .../src/server/http_handlers.ts | 22 ++++---- .../src/server/http_internal.ts | 14 ++--- .../src/server/http_shared.ts | 2 +- .../bindings-typescript/src/server/index.ts | 45 ++++++++------- .../src/server/polyfills.ts | 2 +- .../src/server/procedures.ts | 38 ++++++------- .../bindings-typescript/src/server/query.ts | 2 +- .../src/server/reducers.ts | 16 +++--- crates/bindings-typescript/src/server/rng.ts | 2 +- .../bindings-typescript/src/server/runtime.ts | 56 +++++++++---------- .../src/server/schema.test-d.ts | 8 +-- .../bindings-typescript/src/server/schema.ts | 29 +++++----- .../src/server/view.test-d.ts | 6 +- .../bindings-typescript/src/server/views.ts | 24 ++++---- .../src/solid/SpacetimeDBProvider.ts | 10 ++-- .../src/solid/connection_state.ts | 4 +- .../src/solid/useProcedure.ts | 6 +- .../src/solid/useReducer.ts | 6 +- .../src/solid/useSpacetimeDB.ts | 2 +- .../bindings-typescript/src/solid/useTable.ts | 14 ++--- .../src/svelte/SpacetimeDBProvider.ts | 8 +-- .../src/svelte/connection_state.ts | 4 +- .../src/svelte/useReducer.ts | 8 +-- .../src/svelte/useSpacetimeDB.ts | 2 +- .../src/svelte/useTable.ts | 12 ++-- .../src/tanstack/SpacetimeDBQueryClient.ts | 2 +- .../bindings-typescript/src/tanstack/hooks.ts | 6 +- .../bindings-typescript/src/tanstack/index.ts | 12 ++-- .../src/vue/SpacetimeDBProvider.ts | 6 +- .../src/vue/connection_state.ts | 6 +- .../src/vue/useProcedure.ts | 6 +- .../bindings-typescript/src/vue/useReducer.ts | 6 +- .../src/vue/useSpacetimeDB.ts | 2 +- .../bindings-typescript/src/vue/useTable.ts | 12 ++-- .../bindings-typescript/tests/consumer/app.ts | 15 +++++ .../tests/consumer/tsconfig.json | 13 +++++ .../tests/consumer_types.test.ts | 16 ++++++ .../examples/regen-typescript-moduledef.rs | 2 +- eslint.config.js | 25 +++++++++ tools/generate-client-api/src/main.rs | 5 +- 111 files changed, 560 insertions(+), 463 deletions(-) create mode 100644 crates/bindings-typescript/tests/consumer/app.ts create mode 100644 crates/bindings-typescript/tests/consumer/tsconfig.json create mode 100644 crates/bindings-typescript/tests/consumer_types.test.ts diff --git a/crates/bindings-typescript/src/angular/connection_state.ts b/crates/bindings-typescript/src/angular/connection_state.ts index e57f2524e72..3b9aa624ffd 100644 --- a/crates/bindings-typescript/src/angular/connection_state.ts +++ b/crates/bindings-typescript/src/angular/connection_state.ts @@ -1,7 +1,7 @@ import { InjectionToken, type WritableSignal } from '@angular/core'; -import type { ConnectionId } from '../lib/connection_id'; -import type { Identity } from '../lib/identity'; -import type { DbConnectionImpl } from '../sdk/db_connection_impl'; +import type { ConnectionId } from '../lib/connection_id.ts'; +import type { Identity } from '../lib/identity.ts'; +import type { DbConnectionImpl } from '../sdk/db_connection_impl.ts'; export interface ConnectionState { isActive: boolean; diff --git a/crates/bindings-typescript/src/angular/injectors/inject-reducer.ts b/crates/bindings-typescript/src/angular/injectors/inject-reducer.ts index 7afa0f9367e..ffb5961b287 100644 --- a/crates/bindings-typescript/src/angular/injectors/inject-reducer.ts +++ b/crates/bindings-typescript/src/angular/injectors/inject-reducer.ts @@ -1,7 +1,7 @@ import { assertInInjectionContext, inject, effect } from '@angular/core'; -import { SPACETIMEDB_CONNECTION } from '../connection_state'; -import type { ParamsType } from '../../sdk'; -import type { UntypedReducerDef } from '../../sdk/reducers'; +import { SPACETIMEDB_CONNECTION } from '../connection_state.ts'; +import type { ParamsType } from '../../sdk/index.ts'; +import type { UntypedReducerDef } from '../../sdk/reducers.ts'; export function injectReducer( reducerDef: ReducerDef diff --git a/crates/bindings-typescript/src/angular/injectors/inject-spacetimedb-connected.ts b/crates/bindings-typescript/src/angular/injectors/inject-spacetimedb-connected.ts index 6cbfa53f80d..f41a0c1ea15 100644 --- a/crates/bindings-typescript/src/angular/injectors/inject-spacetimedb-connected.ts +++ b/crates/bindings-typescript/src/angular/injectors/inject-spacetimedb-connected.ts @@ -4,7 +4,7 @@ import { computed, type Signal, } from '@angular/core'; -import { SPACETIMEDB_CONNECTION } from '../connection_state'; +import { SPACETIMEDB_CONNECTION } from '../connection_state.ts'; export function injectSpacetimeDBConnected(): Signal { assertInInjectionContext(injectSpacetimeDBConnected); diff --git a/crates/bindings-typescript/src/angular/injectors/inject-spacetimedb.ts b/crates/bindings-typescript/src/angular/injectors/inject-spacetimedb.ts index c8dfa689cef..ba5a4b821ce 100644 --- a/crates/bindings-typescript/src/angular/injectors/inject-spacetimedb.ts +++ b/crates/bindings-typescript/src/angular/injectors/inject-spacetimedb.ts @@ -2,7 +2,7 @@ import { assertInInjectionContext, inject, type Signal } from '@angular/core'; import { SPACETIMEDB_CONNECTION, type ConnectionState, -} from '../connection_state'; +} from '../connection_state.ts'; export function injectSpacetimeDB(): Signal { assertInInjectionContext(injectSpacetimeDB); diff --git a/crates/bindings-typescript/src/angular/injectors/inject-table.ts b/crates/bindings-typescript/src/angular/injectors/inject-table.ts index ea46cde33fc..652a3422b9b 100644 --- a/crates/bindings-typescript/src/angular/injectors/inject-table.ts +++ b/crates/bindings-typescript/src/angular/injectors/inject-table.ts @@ -5,9 +5,9 @@ import { effect, type Signal, } from '@angular/core'; -import type { RowType, UntypedTableDef } from '../../lib/table'; -import type { Prettify } from '../../lib/type_util'; -import { SPACETIMEDB_CONNECTION } from '../connection_state'; +import type { RowType, UntypedTableDef } from '../../lib/table.ts'; +import type { Prettify } from '../../lib/type_util.ts'; +import { SPACETIMEDB_CONNECTION } from '../connection_state.ts'; import { type Query, type BooleanExpr, @@ -15,9 +15,9 @@ import { evaluateBooleanExpr, getQueryAccessorName, getQueryWhereClause, -} from '../../lib/query'; -import type { EventContextInterface } from '../../sdk'; -import type { UntypedRemoteModule } from '../../sdk/spacetime_module'; +} from '../../lib/query.ts'; +import type { EventContextInterface } from '../../sdk/index.ts'; +import type { UntypedRemoteModule } from '../../sdk/spacetime_module.ts'; export type RowTypeDef = Prettify< RowType diff --git a/crates/bindings-typescript/src/angular/providers/provide-spacetimedb.ts b/crates/bindings-typescript/src/angular/providers/provide-spacetimedb.ts index c847a44d4d7..40a61971fec 100644 --- a/crates/bindings-typescript/src/angular/providers/provide-spacetimedb.ts +++ b/crates/bindings-typescript/src/angular/providers/provide-spacetimedb.ts @@ -9,12 +9,12 @@ import type { DbConnectionImpl, ErrorContextInterface, RemoteModuleOf, -} from '../../sdk/db_connection_impl'; +} from '../../sdk/db_connection_impl.ts'; import { SPACETIMEDB_CONNECTION, type ConnectionState, -} from '../connection_state'; -import { ConnectionId } from '../../lib/connection_id'; +} from '../connection_state.ts'; +import { ConnectionId } from '../../lib/connection_id.ts'; let connRef: DbConnectionImpl | null = null; diff --git a/crates/bindings-typescript/src/index.ts b/crates/bindings-typescript/src/index.ts index 41674612e40..a83646301b1 100644 --- a/crates/bindings-typescript/src/index.ts +++ b/crates/bindings-typescript/src/index.ts @@ -1,16 +1,16 @@ -export * from './lib/connection_id'; -export * from './lib/errors'; -export * from './lib/algebraic_type'; -export * from './lib/algebraic_value'; -export { default as BinaryReader } from './lib/binary_reader'; -export { default as BinaryWriter } from './lib/binary_writer'; -export * from './lib/schedule_at'; -export * from './lib/time_duration'; -export * from './lib/timestamp'; -export * from './lib/uuid'; -export * from './lib/util'; -export * from './lib/identity'; -export * from './lib/option'; -export * from './lib/result'; -export * from './lib/query'; -export * from './sdk'; +export * from './lib/connection_id.ts'; +export * from './lib/errors.ts'; +export * from './lib/algebraic_type.ts'; +export * from './lib/algebraic_value.ts'; +export { default as BinaryReader } from './lib/binary_reader.ts'; +export { default as BinaryWriter } from './lib/binary_writer.ts'; +export * from './lib/schedule_at.ts'; +export * from './lib/time_duration.ts'; +export * from './lib/timestamp.ts'; +export * from './lib/uuid.ts'; +export * from './lib/util.ts'; +export * from './lib/identity.ts'; +export * from './lib/option.ts'; +export * from './lib/result.ts'; +export * from './lib/query.ts'; +export * from './sdk/index.ts'; diff --git a/crates/bindings-typescript/src/lib/algebraic_type.ts b/crates/bindings-typescript/src/lib/algebraic_type.ts index c325797af75..57098961fb3 100644 --- a/crates/bindings-typescript/src/lib/algebraic_type.ts +++ b/crates/bindings-typescript/src/lib/algebraic_type.ts @@ -1,12 +1,12 @@ -import { TimeDuration } from './time_duration'; -import { Timestamp } from './timestamp'; -import { Uuid } from './uuid'; -import { ConnectionId } from './connection_id'; -import BinaryReader from './binary_reader'; -import BinaryWriter from './binary_writer'; -import { Identity } from './identity'; -import * as AlgebraicTypeVariants from './algebraic_type_variants'; -import { hasOwn } from './util'; +import { TimeDuration } from './time_duration.ts'; +import { Timestamp } from './timestamp.ts'; +import { Uuid } from './uuid.ts'; +import { ConnectionId } from './connection_id.ts'; +import BinaryReader from './binary_reader.ts'; +import BinaryWriter from './binary_writer.ts'; +import { Identity } from './identity.ts'; +import * as AlgebraicTypeVariants from './algebraic_type_variants.ts'; +import { hasOwn } from './util.ts'; type TypespaceType = { types: AlgebraicTypeType[]; diff --git a/crates/bindings-typescript/src/lib/algebraic_type_variants.ts b/crates/bindings-typescript/src/lib/algebraic_type_variants.ts index 5890d53c148..d68c883d2c1 100644 --- a/crates/bindings-typescript/src/lib/algebraic_type_variants.ts +++ b/crates/bindings-typescript/src/lib/algebraic_type_variants.ts @@ -2,7 +2,7 @@ import type { AlgebraicTypeType, ProductTypeType, SumTypeType, -} from './algebraic_type'; +} from './algebraic_type.ts'; export type Ref = { tag: 'Ref'; value: number }; export type Sum = { tag: 'Sum'; value: SumTypeType }; diff --git a/crates/bindings-typescript/src/lib/algebraic_value.ts b/crates/bindings-typescript/src/lib/algebraic_value.ts index 558f48a2a01..e2122d00587 100644 --- a/crates/bindings-typescript/src/lib/algebraic_value.ts +++ b/crates/bindings-typescript/src/lib/algebraic_value.ts @@ -1,4 +1,4 @@ -import BinaryReader from './binary_reader'; +import BinaryReader from './binary_reader.ts'; export interface ParseableType { deserialize: (reader: BinaryReader) => T; diff --git a/crates/bindings-typescript/src/lib/autogen/types.ts b/crates/bindings-typescript/src/lib/autogen/types.ts index ef51c0682ed..c4bfc7b4fe8 100644 --- a/crates/bindings-typescript/src/lib/autogen/types.ts +++ b/crates/bindings-typescript/src/lib/autogen/types.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../lib/type_builders'; +} from '../../lib/type_builders.ts'; // The tagged union or sum type for the algebraic type `AlgebraicType`. export const AlgebraicType: __TypeBuilder< diff --git a/crates/bindings-typescript/src/lib/connection_id.ts b/crates/bindings-typescript/src/lib/connection_id.ts index a57e6bba1a6..862f87465de 100644 --- a/crates/bindings-typescript/src/lib/connection_id.ts +++ b/crates/bindings-typescript/src/lib/connection_id.ts @@ -1,10 +1,10 @@ -import { AlgebraicType } from './algebraic_type'; +import { AlgebraicType } from './algebraic_type.ts'; import { coerceToBigInt, hexStringToU128, u128ToHexString, u128ToUint8Array, -} from './util'; +} from './util.ts'; export type ConnectionIdAlgebraicType = { tag: 'Product'; diff --git a/crates/bindings-typescript/src/lib/constraints.ts b/crates/bindings-typescript/src/lib/constraints.ts index f779b49d309..eccace200f2 100644 --- a/crates/bindings-typescript/src/lib/constraints.ts +++ b/crates/bindings-typescript/src/lib/constraints.ts @@ -1,5 +1,5 @@ -import type { table, UntypedTableDef } from './table'; -import type { ColumnMetadata } from './type_builders'; +import type { table, UntypedTableDef } from './table.ts'; +import type { ColumnMetadata } from './type_builders.ts'; /** * A helper type to determine if all columns in an index are unique. @@ -44,5 +44,5 @@ export type ColumnIsUnique> = M extends * of constraint definitions. */ export type ConstraintOpts = { - name?: string; + name?: string | undefined; } & { constraint: 'unique'; columns: [AllowedCol] }; diff --git a/crates/bindings-typescript/src/lib/environment.ts b/crates/bindings-typescript/src/lib/environment.ts index d065d5bb0aa..c246c3a1a8b 100644 --- a/crates/bindings-typescript/src/lib/environment.ts +++ b/crates/bindings-typescript/src/lib/environment.ts @@ -3,7 +3,7 @@ import type { StringBuilder, TypeBuilder, t, -} from './type_builders'; +} from './type_builders.ts'; /** Only strings and simple, payload-free enums constrain environment strings. */ export type EnvironmentString = diff --git a/crates/bindings-typescript/src/lib/filter.ts b/crates/bindings-typescript/src/lib/filter.ts index 869f36d239d..d9dde9de43f 100644 --- a/crates/bindings-typescript/src/lib/filter.ts +++ b/crates/bindings-typescript/src/lib/filter.ts @@ -1,6 +1,6 @@ -import type { RowType, UntypedTableDef } from './table'; -import { Timestamp } from './timestamp'; -import { Uuid } from './uuid'; +import type { RowType, UntypedTableDef } from './table.ts'; +import { Timestamp } from './timestamp.ts'; +import { Uuid } from './uuid.ts'; export type Value = string | number | boolean | Uuid | Timestamp; diff --git a/crates/bindings-typescript/src/lib/identity.ts b/crates/bindings-typescript/src/lib/identity.ts index a1ada196fd9..640bee22f39 100644 --- a/crates/bindings-typescript/src/lib/identity.ts +++ b/crates/bindings-typescript/src/lib/identity.ts @@ -1,10 +1,10 @@ -import { AlgebraicType } from './algebraic_type'; +import { AlgebraicType } from './algebraic_type.ts'; import { coerceToBigInt, hexStringToU256, u256ToHexString, u256ToUint8Array, -} from './util'; +} from './util.ts'; export type IdentityAlgebraicType = { tag: 'Product'; diff --git a/crates/bindings-typescript/src/lib/indexes.ts b/crates/bindings-typescript/src/lib/indexes.ts index 0b507ff3bae..5bd1a164025 100644 --- a/crates/bindings-typescript/src/lib/indexes.ts +++ b/crates/bindings-typescript/src/lib/indexes.ts @@ -1,8 +1,8 @@ -import type { RowType, table, UntypedTableDef } from './table'; -import type { ColumnMetadata, IndexTypes } from './type_builders'; -import type { CollapseTuple, Prettify } from './type_util'; -import { Range } from '../server/range'; -import type { ColumnIsUnique } from './constraints'; +import type { RowType, table, UntypedTableDef } from './table.ts'; +import type { ColumnMetadata, IndexTypes } from './type_builders.ts'; +import type { CollapseTuple, Prettify } from './type_util.ts'; +import { Range } from '../server/range.ts'; +import type { ColumnIsUnique } from './constraints.ts'; /** * Index helper type used *inside* {@link table} to enforce that only @@ -10,7 +10,7 @@ import type { ColumnIsUnique } from './constraints'; */ export type IndexOpts = { accessor: string; - name?: string; + name?: string | undefined; } & ( | { algorithm: 'btree'; columns: readonly AllowedCol[] } | { algorithm: 'hash'; columns: readonly AllowedCol[] } diff --git a/crates/bindings-typescript/src/lib/option.ts b/crates/bindings-typescript/src/lib/option.ts index 40e11d2a9b2..bae7def2949 100644 --- a/crates/bindings-typescript/src/lib/option.ts +++ b/crates/bindings-typescript/src/lib/option.ts @@ -1,4 +1,4 @@ -import { AlgebraicType } from './algebraic_type'; +import { AlgebraicType } from './algebraic_type.ts'; export type OptionAlgebraicType = { tag: 'Sum'; diff --git a/crates/bindings-typescript/src/lib/query.ts b/crates/bindings-typescript/src/lib/query.ts index bb93b0e6ce3..2ddaa8a702e 100644 --- a/crates/bindings-typescript/src/lib/query.ts +++ b/crates/bindings-typescript/src/lib/query.ts @@ -1,19 +1,19 @@ -import { ConnectionId } from './connection_id'; -import { Identity } from './identity'; -import type { ColumnIndex, IndexColumns, IndexOpts } from './indexes'; -import type { UntypedSchemaDef } from './schema'; -import type { UntypedTableDef } from './table'; -import type { UntypedTableSchema } from './table_schema'; -import { Timestamp } from './timestamp'; +import { ConnectionId } from './connection_id.ts'; +import { Identity } from './identity.ts'; +import type { ColumnIndex, IndexColumns, IndexOpts } from './indexes.ts'; +import type { UntypedSchemaDef } from './schema.ts'; +import type { UntypedTableDef } from './table.ts'; +import type { UntypedTableSchema } from './table_schema.ts'; +import { Timestamp } from './timestamp.ts'; import type { ColumnBuilder, ColumnMetadata, RowBuilder, TypeBuilder, -} from './type_builders'; -import type { Values } from './type_util'; -import type { Bool as SatsBool } from './algebraic_type_variants'; -import { Uuid } from './uuid'; +} from './type_builders.ts'; +import type { Values } from './type_util.ts'; +import type { Bool as SatsBool } from './algebraic_type_variants.ts'; +import { Uuid } from './uuid.ts'; /** * Helper to get the set of table names. diff --git a/crates/bindings-typescript/src/lib/reducer_schema.ts b/crates/bindings-typescript/src/lib/reducer_schema.ts index df5bce88f0c..90ae6a19fe5 100644 --- a/crates/bindings-typescript/src/lib/reducer_schema.ts +++ b/crates/bindings-typescript/src/lib/reducer_schema.ts @@ -1,8 +1,8 @@ -import type { ProductType } from './algebraic_type'; -import type { RawReducerDefV9 } from './autogen/types'; -import type { ParamsObj } from './reducers'; -import type { RowBuilder, RowObj } from './type_builders'; -import type { CamelCase } from './type_util'; +import type { ProductType } from './algebraic_type.ts'; +import type { RawReducerDefV9 } from './autogen/types.ts'; +import type { ParamsObj } from './reducers.ts'; +import type { RowBuilder, RowObj } from './type_builders.ts'; +import type { CamelCase } from './type_util.ts'; /** * Represents a handle to a database reducer, including its name and argument type. diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index f2d470152ec..e7068c166a0 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -1,15 +1,15 @@ -import type { EnvironmentFor } from './environment'; -import type { DbView } from '../server/db_view'; -import type { Random } from '../server/rng'; -import type { ConnectionId } from './connection_id'; -import type { Identity } from './identity'; -import { type UntypedSchemaDef } from './schema'; -import { type Timestamp } from './timestamp'; +import type { EnvironmentFor } from './environment.ts'; +import type { DbView } from '../server/db_view.ts'; +import type { Random } from '../server/rng.ts'; +import type { ConnectionId } from './connection_id.ts'; +import type { Identity } from './identity.ts'; +import { type UntypedSchemaDef } from './schema.ts'; +import { type Timestamp } from './timestamp.ts'; import { ColumnBuilder, type InferTypeOfRow, type TypeBuilder, -} from './type_builders'; +} from './type_builders.ts'; import { Uuid } from './uuid.ts'; /** diff --git a/crates/bindings-typescript/src/lib/result.ts b/crates/bindings-typescript/src/lib/result.ts index 5ea0d682048..366a72e2962 100644 --- a/crates/bindings-typescript/src/lib/result.ts +++ b/crates/bindings-typescript/src/lib/result.ts @@ -1,4 +1,4 @@ -import { AlgebraicType } from './algebraic_type'; +import { AlgebraicType } from './algebraic_type.ts'; export type ResultAlgebraicType< T extends AlgebraicType = AlgebraicType, diff --git a/crates/bindings-typescript/src/lib/schedule_at.ts b/crates/bindings-typescript/src/lib/schedule_at.ts index 61d263b8a35..03bdd87ae6f 100644 --- a/crates/bindings-typescript/src/lib/schedule_at.ts +++ b/crates/bindings-typescript/src/lib/schedule_at.ts @@ -1,6 +1,9 @@ -import { AlgebraicType } from './algebraic_type'; -import { TimeDuration, type TimeDurationAlgebraicType } from './time_duration'; -import { Timestamp, type TimestampAlgebraicType } from './timestamp'; +import { AlgebraicType } from './algebraic_type.ts'; +import { + TimeDuration, + type TimeDurationAlgebraicType, +} from './time_duration.ts'; +import { Timestamp, type TimestampAlgebraicType } from './timestamp.ts'; export type ScheduleAtAlgebraicType = { tag: 'Sum'; diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index 67b263d8397..4ed45bc7f48 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -4,7 +4,7 @@ import { SumType, type AlgebraicTypeType, type AlgebraicTypeVariants, -} from './algebraic_type'; +} from './algebraic_type.ts'; import type { CaseConversionPolicy, RawSubmoduleV10, @@ -12,10 +12,10 @@ import type { RawModuleDefV10Section, RawScopedTypeNameV10, RawTableDefV10, -} from './autogen/types'; -import type { UntypedIndex } from './indexes'; -import type { UntypedTableDef } from './table'; -import type { UntypedTableSchema } from './table_schema'; +} from './autogen/types.ts'; +import type { UntypedIndex } from './indexes.ts'; +import type { UntypedTableDef } from './table.ts'; +import type { UntypedTableSchema } from './table_schema.ts'; import { ArrayBuilder, OptionBuilder, @@ -31,8 +31,8 @@ import { type InferSpacetimeTypeOfTypeBuilder, type RowObj, type VariantsObj, -} from './type_builders'; -import type { Values } from './type_util'; +} from './type_builders.ts'; +import type { Values } from './type_util.ts'; export type TableNamesOf = Values< S['tables'] diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index cb15705989f..e153114a7d1 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -1,5 +1,5 @@ -import type { ProcedureExport, ReducerExport, t } from '../server'; -import type { errors } from '../server/errors'; +import type { ProcedureExport, ReducerExport, t } from '../server/index.ts'; +import type { errors } from '../server/errors.ts'; import { ExplicitNameEntry, RawColumnDefaultValueV10, @@ -8,9 +8,9 @@ import { RawIndexDefV10, RawSequenceDefV10, RawTableDefV10, -} from './autogen/types'; -import BinaryWriter from './binary_writer'; -import type { AllUnique, ConstraintOpts } from './constraints'; +} from './autogen/types.ts'; +import BinaryWriter from './binary_writer.ts'; +import type { AllUnique, ConstraintOpts } from './constraints.ts'; import type { ColumnIndex, IndexColumns, @@ -18,9 +18,9 @@ import type { IndexOpts, ReadonlyIndexes, UntypedIndex, -} from './indexes'; -import ScheduleAt from './schedule_at'; -import type { TableSchema, TableSchedule } from './table_schema'; +} from './indexes.ts'; +import ScheduleAt from './schedule_at.ts'; +import type { TableSchema, TableSchedule } from './table_schema.ts'; import { RowBuilder, type ColumnBuilder, @@ -28,13 +28,13 @@ import { type InferTypeOfRow, type RowObj, type TypeBuilder, -} from './type_builders'; +} from './type_builders.ts'; import type { InvalidColumnMetadata, Prettify, ValidateColumnMetadata, -} from './type_util'; -import { toPascalCase } from './util'; +} from './type_util.ts'; +import { toPascalCase } from './util.ts'; export type AlgebraicTypeRef = number; type ColId = number; diff --git a/crates/bindings-typescript/src/lib/table_schema.ts b/crates/bindings-typescript/src/lib/table_schema.ts index f66a3eba226..85cd2f1eb85 100644 --- a/crates/bindings-typescript/src/lib/table_schema.ts +++ b/crates/bindings-typescript/src/lib/table_schema.ts @@ -1,10 +1,10 @@ -import type { ProductType } from './algebraic_type'; -import type { RawScheduleDefV10, RawTableDefV10 } from './autogen/types'; -import type { IndexOpts } from './indexes'; -import type { ModuleContext } from './schema'; -import type { ColumnBuilder, RowBuilder } from './type_builders'; -import type { HasExactlyOneKnownKey } from './type_util'; -import type { ProcedureExport, ReducerExport } from '../server'; +import type { ProductType } from './algebraic_type.ts'; +import type { RawScheduleDefV10, RawTableDefV10 } from './autogen/types.ts'; +import type { IndexOpts } from './indexes.ts'; +import type { ModuleContext } from './schema.ts'; +import type { ColumnBuilder, RowBuilder } from './type_builders.ts'; +import type { HasExactlyOneKnownKey } from './type_util.ts'; +import type { ProcedureExport, ReducerExport } from '../server/index.ts'; /** * Internal erased form of a scheduled reducer/procedure export. diff --git a/crates/bindings-typescript/src/lib/time_duration.ts b/crates/bindings-typescript/src/lib/time_duration.ts index 26830e7b830..eef182ab5c1 100644 --- a/crates/bindings-typescript/src/lib/time_duration.ts +++ b/crates/bindings-typescript/src/lib/time_duration.ts @@ -1,5 +1,5 @@ -import { AlgebraicType } from './algebraic_type'; -import { coerceToBigInt } from './util'; +import { AlgebraicType } from './algebraic_type.ts'; +import { coerceToBigInt } from './util.ts'; export type TimeDurationAlgebraicType = { tag: 'Product'; diff --git a/crates/bindings-typescript/src/lib/timestamp.ts b/crates/bindings-typescript/src/lib/timestamp.ts index 918f03b3d6b..d3fcac304b2 100644 --- a/crates/bindings-typescript/src/lib/timestamp.ts +++ b/crates/bindings-typescript/src/lib/timestamp.ts @@ -1,6 +1,6 @@ -import { AlgebraicType } from './algebraic_type'; -import { TimeDuration } from './time_duration'; -import { coerceToBigInt } from './util'; +import { AlgebraicType } from './algebraic_type.ts'; +import { TimeDuration } from './time_duration.ts'; +import { coerceToBigInt } from './util.ts'; export type TimestampAlgebraicType = { tag: 'Product'; diff --git a/crates/bindings-typescript/src/lib/type_builders.test-d.ts b/crates/bindings-typescript/src/lib/type_builders.test-d.ts index bae3089e145..3e59256b2f9 100644 --- a/crates/bindings-typescript/src/lib/type_builders.test-d.ts +++ b/crates/bindings-typescript/src/lib/type_builders.test-d.ts @@ -1,5 +1,5 @@ -import { t } from '../server'; -import { type AlgebraicTypeVariants } from '..'; +import { t } from '../server/index.ts'; +import { type AlgebraicTypeVariants } from '../index.ts'; import type { I32ColumnBuilder, I64ColumnBuilder, @@ -7,7 +7,7 @@ import type { InferTypeOfTypeBuilder, TypeBuilder, U8ColumnBuilder, -} from './type_builders'; +} from './type_builders.ts'; type MustBeNever = [T] extends [never] ? true diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 41d2da11015..26572a9b040 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -1,19 +1,25 @@ -import { AlgebraicType, type AlgebraicTypeVariants } from './algebraic_type'; -import type BinaryReader from './binary_reader'; -import type BinaryWriter from './binary_writer'; -import { ConnectionId, type ConnectionIdAlgebraicType } from './connection_id'; -import { Identity, type IdentityAlgebraicType } from './identity'; -import { Option, type OptionAlgebraicType } from './option'; -import { Result, type ResultAlgebraicType } from './result'; -import ScheduleAt, { type ScheduleAtAlgebraicType } from './schedule_at'; -import type { CoerceRow } from './table'; -import { TimeDuration, type TimeDurationAlgebraicType } from './time_duration'; -import { Timestamp, type TimestampAlgebraicType } from './timestamp'; -import { set, type Prettify, type SetField } from './type_util'; -import { Uuid, type UuidAlgebraicType } from './uuid'; +import { AlgebraicType, type AlgebraicTypeVariants } from './algebraic_type.ts'; +import type BinaryReader from './binary_reader.ts'; +import type BinaryWriter from './binary_writer.ts'; +import { + ConnectionId, + type ConnectionIdAlgebraicType, +} from './connection_id.ts'; +import { Identity, type IdentityAlgebraicType } from './identity.ts'; +import { Option, type OptionAlgebraicType } from './option.ts'; +import { Result, type ResultAlgebraicType } from './result.ts'; +import ScheduleAt, { type ScheduleAtAlgebraicType } from './schedule_at.ts'; +import type { CoerceRow } from './table.ts'; +import { + TimeDuration, + type TimeDurationAlgebraicType, +} from './time_duration.ts'; +import { Timestamp, type TimestampAlgebraicType } from './timestamp.ts'; +import { set, type Prettify, type SetField } from './type_util.ts'; +import { Uuid, type UuidAlgebraicType } from './uuid.ts'; // Used in codegen files -export { type AlgebraicTypeType } from './algebraic_type'; +export { type AlgebraicTypeType } from './algebraic_type.ts'; /** * Helper type to extract the TypeScript type from a TypeBuilder diff --git a/crates/bindings-typescript/src/lib/type_util.ts b/crates/bindings-typescript/src/lib/type_util.ts index 942b76a1424..337317f1134 100644 --- a/crates/bindings-typescript/src/lib/type_util.ts +++ b/crates/bindings-typescript/src/lib/type_util.ts @@ -1,8 +1,8 @@ -import type { ConnectionId } from './connection_id'; -import type { Identity } from './identity'; -import type { ScheduleAt } from './schedule_at'; -import type { TimeDuration } from './time_duration'; -import type { Timestamp } from './timestamp'; +import type { ConnectionId } from './connection_id.ts'; +import type { Identity } from './identity.ts'; +import type { ScheduleAt } from './schedule_at.ts'; +import type { TimeDuration } from './time_duration.ts'; +import type { Timestamp } from './timestamp.ts'; type DoNotPrettify = | Identity diff --git a/crates/bindings-typescript/src/lib/util.ts b/crates/bindings-typescript/src/lib/util.ts index 143d54bdfe0..489a64d5379 100644 --- a/crates/bindings-typescript/src/lib/util.ts +++ b/crates/bindings-typescript/src/lib/util.ts @@ -1,10 +1,10 @@ -import type { AlgebraicType } from './algebraic_type'; -import type { Typespace } from './autogen/types'; -import BinaryReader from './binary_reader'; -import BinaryWriter from './binary_writer'; -import type { ParamsObj } from './reducers'; -import type { ColumnBuilder, TypeBuilder } from './type_builders'; -import type { CamelCase, SnakeCase } from './type_util'; +import type { AlgebraicType } from './algebraic_type.ts'; +import type { Typespace } from './autogen/types.ts'; +import BinaryReader from './binary_reader.ts'; +import BinaryWriter from './binary_writer.ts'; +import type { ParamsObj } from './reducers.ts'; +import type { ColumnBuilder, TypeBuilder } from './type_builders.ts'; +import type { CamelCase, SnakeCase } from './type_util.ts'; export function deepEqual(obj1: any, obj2: any): boolean { // If both are strictly equal (covers primitives and reference equality), return true diff --git a/crates/bindings-typescript/src/lib/uuid.ts b/crates/bindings-typescript/src/lib/uuid.ts index 0d5d2fe0967..5dd2a22817e 100644 --- a/crates/bindings-typescript/src/lib/uuid.ts +++ b/crates/bindings-typescript/src/lib/uuid.ts @@ -1,6 +1,6 @@ -import { Timestamp } from './timestamp'; +import { Timestamp } from './timestamp.ts'; import { AlgebraicType } from './algebraic_type.ts'; -import { coerceToBigInt, u128ToHexString } from './util'; +import { coerceToBigInt, u128ToHexString } from './util.ts'; export type UuidAlgebraicType = { tag: 'Product'; diff --git a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts index a574e21d4a8..22afccf0b15 100644 --- a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts @@ -1,15 +1,15 @@ import { DbConnectionBuilder, type DbConnectionImpl, -} from '../sdk/db_connection_impl'; +} from '../sdk/db_connection_impl.ts'; import * as React from 'react'; -import { SpacetimeDBContext } from './useSpacetimeDB'; -import type { ConnectionState } from './connection_state'; -import { ConnectionId } from '../lib/connection_id'; +import { SpacetimeDBContext } from './useSpacetimeDB.ts'; +import type { ConnectionState } from './connection_state.ts'; +import { ConnectionId } from '../lib/connection_id.ts'; import { ConnectionManager, type ConnectionState as ManagerConnectionState, -} from '../sdk/connection_manager'; +} from '../sdk/connection_manager.ts'; export interface SpacetimeDBProviderProps< DbConnection extends DbConnectionImpl, diff --git a/crates/bindings-typescript/src/react/connection_state.ts b/crates/bindings-typescript/src/react/connection_state.ts index 5ad565f9be6..f1df5fe9dbb 100644 --- a/crates/bindings-typescript/src/react/connection_state.ts +++ b/crates/bindings-typescript/src/react/connection_state.ts @@ -1,5 +1,5 @@ -import type { DbConnectionImpl } from '../sdk/db_connection_impl'; -import type { ConnectionState as ManagerConnectionState } from '../sdk/connection_manager'; +import type { DbConnectionImpl } from '../sdk/db_connection_impl.ts'; +import type { ConnectionState as ManagerConnectionState } from '../sdk/connection_manager.ts'; export type ConnectionState = ManagerConnectionState & { getConnection(): DbConnectionImpl | null; diff --git a/crates/bindings-typescript/src/react/useProcedure.ts b/crates/bindings-typescript/src/react/useProcedure.ts index 1f688335f34..906fd0fce3c 100644 --- a/crates/bindings-typescript/src/react/useProcedure.ts +++ b/crates/bindings-typescript/src/react/useProcedure.ts @@ -1,10 +1,10 @@ import { useCallback, useEffect, useRef } from 'react'; -import type { UntypedProcedureDef } from '../sdk/procedures'; -import { useSpacetimeDB } from './useSpacetimeDB'; +import type { UntypedProcedureDef } from '../sdk/procedures.ts'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; import type { ProcedureParamsType, ProcedureReturnType, -} from '../sdk/type_utils'; +} from '../sdk/type_utils.ts'; export function useProcedure( procedureDef: ProcedureDef diff --git a/crates/bindings-typescript/src/react/useReducer.ts b/crates/bindings-typescript/src/react/useReducer.ts index 8e0ab3177c2..37762107d16 100644 --- a/crates/bindings-typescript/src/react/useReducer.ts +++ b/crates/bindings-typescript/src/react/useReducer.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef } from 'react'; -import type { UntypedReducerDef } from '../sdk/reducers'; -import { useSpacetimeDB } from './useSpacetimeDB'; -import type { ParamsType } from '../sdk'; +import type { UntypedReducerDef } from '../sdk/reducers.ts'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; +import type { ParamsType } from '../sdk/index.ts'; export function useReducer( reducerDef: ReducerDef diff --git a/crates/bindings-typescript/src/react/useSpacetimeDB.ts b/crates/bindings-typescript/src/react/useSpacetimeDB.ts index 2a7cbfc828a..db7183a21fd 100644 --- a/crates/bindings-typescript/src/react/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/react/useSpacetimeDB.ts @@ -1,5 +1,5 @@ import { createContext, useContext } from 'react'; -import type { ConnectionState } from './connection_state'; +import type { ConnectionState } from './connection_state.ts'; export const SpacetimeDBContext = createContext( undefined diff --git a/crates/bindings-typescript/src/react/useTable.ts b/crates/bindings-typescript/src/react/useTable.ts index 313627cead4..e6248582eaf 100644 --- a/crates/bindings-typescript/src/react/useTable.ts +++ b/crates/bindings-typescript/src/react/useTable.ts @@ -5,12 +5,12 @@ import { useState, useSyncExternalStore, } from 'react'; -import { useSpacetimeDB } from './useSpacetimeDB'; -import { type EventContextInterface } from '../sdk/db_connection_impl'; -import type { ConnectionState } from './connection_state'; -import type { UntypedRemoteModule } from '../sdk/spacetime_module'; -import type { RowType, UntypedTableDef } from '../lib/table'; -import type { Prettify } from '../lib/type_util'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; +import { type EventContextInterface } from '../sdk/db_connection_impl.ts'; +import type { ConnectionState } from './connection_state.ts'; +import type { UntypedRemoteModule } from '../sdk/spacetime_module.ts'; +import type { RowType, UntypedTableDef } from '../lib/table.ts'; +import type { Prettify } from '../lib/type_util.ts'; import { type Query, toSql, @@ -18,7 +18,7 @@ import { evaluateBooleanExpr, getQueryAccessorName, getQueryWhereClause, -} from '../lib/query'; +} from '../lib/query.ts'; export interface UseTableCallbacks { onInsert?: (row: RowType) => void; diff --git a/crates/bindings-typescript/src/sdk/client_api/index.ts b/crates/bindings-typescript/src/sdk/client_api/index.ts index 85be7b0c365..234a6dd5676 100644 --- a/crates/bindings-typescript/src/sdk/client_api/index.ts +++ b/crates/bindings-typescript/src/sdk/client_api/index.ts @@ -31,7 +31,7 @@ import { type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, type SubscriptionHandleImpl as __SubscriptionHandleImpl, -} from '../../index'; +} from '../../index.ts'; // Import all reducer arg schemas diff --git a/crates/bindings-typescript/src/sdk/client_api/types.ts b/crates/bindings-typescript/src/sdk/client_api/types.ts index 709a114da28..57c29127e3c 100644 --- a/crates/bindings-typescript/src/sdk/client_api/types.ts +++ b/crates/bindings-typescript/src/sdk/client_api/types.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../lib/type_builders'; +} from '../../lib/type_builders.ts'; export const BsatnRowList = __t.object('BsatnRowList', { get sizeHint() { diff --git a/crates/bindings-typescript/src/sdk/client_api/types/procedures.ts b/crates/bindings-typescript/src/sdk/client_api/types/procedures.ts index 8726cd8baf0..2f27124fb99 100644 --- a/crates/bindings-typescript/src/sdk/client_api/types/procedures.ts +++ b/crates/bindings-typescript/src/sdk/client_api/types/procedures.ts @@ -3,6 +3,6 @@ /* eslint-disable */ /* tslint:disable */ -import { type Infer as __Infer } from '../../../lib/type_builders'; +import { type Infer as __Infer } from '../../../lib/type_builders.ts'; // Import all procedure arg schemas diff --git a/crates/bindings-typescript/src/sdk/client_api/types/reducers.ts b/crates/bindings-typescript/src/sdk/client_api/types/reducers.ts index 183aff65fa7..02064193157 100644 --- a/crates/bindings-typescript/src/sdk/client_api/types/reducers.ts +++ b/crates/bindings-typescript/src/sdk/client_api/types/reducers.ts @@ -3,6 +3,6 @@ /* eslint-disable */ /* tslint:disable */ -import { type Infer as __Infer } from '../../../lib/type_builders'; +import { type Infer as __Infer } from '../../../lib/type_builders.ts'; // Import all reducer arg schemas diff --git a/crates/bindings-typescript/src/sdk/client_table.ts b/crates/bindings-typescript/src/sdk/client_table.ts index b6cd2c1a56d..4cd643179b4 100644 --- a/crates/bindings-typescript/src/sdk/client_table.ts +++ b/crates/bindings-typescript/src/sdk/client_table.ts @@ -1,16 +1,16 @@ -import type { ReadonlyIndexes } from '../lib/indexes'; -import type { TableNamesOf } from '../lib/schema'; +import type { ReadonlyIndexes } from '../lib/indexes.ts'; +import type { TableNamesOf } from '../lib/schema.ts'; import type { ReadonlyTableMethods, RowType, TableIndexes, UntypedTableDef, -} from '../lib/table'; -import type { ColumnBuilder } from '../lib/type_builders'; -import type { Prettify } from '../lib/type_util'; -import type { TableDefForTableName } from './client_cache'; -import type { EventContextInterface } from './event_context'; -import type { UntypedRemoteModule } from './spacetime_module'; +} from '../lib/table.ts'; +import type { ColumnBuilder } from '../lib/type_builders.ts'; +import type { Prettify } from '../lib/type_util.ts'; +import type { TableDefForTableName } from './client_cache.ts'; +import type { EventContextInterface } from './event_context.ts'; +import type { UntypedRemoteModule } from './spacetime_module.ts'; export type ClientTablePrimaryKeyMethods< RemoteModule extends UntypedRemoteModule, diff --git a/crates/bindings-typescript/src/sdk/connection_manager.ts b/crates/bindings-typescript/src/sdk/connection_manager.ts index 2cf34ea2c36..88d7922d090 100644 --- a/crates/bindings-typescript/src/sdk/connection_manager.ts +++ b/crates/bindings-typescript/src/sdk/connection_manager.ts @@ -31,9 +31,9 @@ import type { DbConnectionBuilder, DbConnectionImpl, ErrorContextInterface, -} from './db_connection_impl'; -import type { Identity } from '../lib/identity'; -import { ConnectionId } from '../lib/connection_id'; +} from './db_connection_impl.ts'; +import type { Identity } from '../lib/identity.ts'; +import { ConnectionId } from '../lib/connection_id.ts'; /** Represents the current state of a managed connection. */ export type ConnectionState = { diff --git a/crates/bindings-typescript/src/sdk/db_connection_builder.ts b/crates/bindings-typescript/src/sdk/db_connection_builder.ts index 282cab02d37..610b9f40d92 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_builder.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_builder.ts @@ -1,14 +1,17 @@ -import { DbConnectionImpl, type ConnectionEvent } from './db_connection_impl'; -import { EventEmitter } from './event_emitter'; +import { + DbConnectionImpl, + type ConnectionEvent, +} from './db_connection_impl.ts'; +import { EventEmitter } from './event_emitter.ts'; import type { DbConnectionConfig, ErrorContextInterface, Identity, RemoteModuleOf, -} from '../'; -import { ensureMinimumVersionOrThrow } from './version'; -import { WebsocketDecompressAdapter } from './websocket_decompress_adapter'; -import type { WebSocketFactory } from './ws'; +} from '../index.ts'; +import { ensureMinimumVersionOrThrow } from './version.ts'; +import { WebsocketDecompressAdapter } from './websocket_decompress_adapter.ts'; +import type { WebSocketFactory } from './ws.ts'; /** * The database client connection to a SpacetimeDB server. diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index 12dfca7afbf..fe90776ba0d 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -1,5 +1,5 @@ -import { ConnectionId, ProductBuilder, ProductType } from '../'; -import { AlgebraicType, type ComparablePrimitive } from '../'; +import { ConnectionId, ProductBuilder, ProductType } from '../index.ts'; +import { AlgebraicType, type ComparablePrimitive } from '../index.ts'; import BinaryReader from '../lib/binary_reader.ts'; import BinaryWriter from '../lib/binary_writer.ts'; import { @@ -10,7 +10,7 @@ import { ServerMessage, TableUpdateRows, UnsubscribeFlags, -} from './client_api/types'; +} from './client_api/types.ts'; import { ClientCache } from './client_cache.ts'; import { DbConnectionBuilder } from './db_connection_builder.ts'; import { INTERNAL_REMOTE_MODULE } from './internal.ts'; @@ -28,14 +28,14 @@ import type { Identity, InferTypeOfParams, Serializer, -} from '../'; +} from '../index.ts'; import type { ProcedureResultMessage, ReducerResultMessage, } from './message_types.ts'; import type { ReducerEvent } from './reducer_event.ts'; import { type UntypedRemoteModule } from './spacetime_module.ts'; -import { makeFromBuilder, type NamespacedQueryBuilder } from '../lib/query'; +import { makeFromBuilder, type NamespacedQueryBuilder } from '../lib/query.ts'; import { type TableCache, type Operation, @@ -57,7 +57,7 @@ import type { } from './reducers.ts'; import type { ClientDbView } from './db_view.ts'; import type { RowType, UntypedTableDef } from '../lib/table.ts'; -import type { UntypedSchemaDef } from '../lib/schema'; +import type { UntypedSchemaDef } from '../lib/schema.ts'; import type { ProceduresView } from './procedures.ts'; import type { Values } from '../lib/type_util.ts'; import type { TransactionUpdate } from './client_api/types.ts'; @@ -69,7 +69,7 @@ import { V2_WS_PROTOCOL, V3_WS_PROTOCOL, type NegotiatedWsProtocol, -} from './websocket_protocols'; +} from './websocket_protocols.ts'; import { countClientMessagesForV3Frame, encodeClientMessagesV3, diff --git a/crates/bindings-typescript/src/sdk/db_context.ts b/crates/bindings-typescript/src/sdk/db_context.ts index 3ac91225fd2..1e1ed2d5d68 100644 --- a/crates/bindings-typescript/src/sdk/db_context.ts +++ b/crates/bindings-typescript/src/sdk/db_context.ts @@ -1,7 +1,7 @@ -import type { ClientDbView } from './db_view'; -import type { ReducersView } from './reducers'; -import type { UntypedRemoteModule } from './spacetime_module'; -import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; +import type { ClientDbView } from './db_view.ts'; +import type { ReducersView } from './reducers.ts'; +import type { UntypedRemoteModule } from './spacetime_module.ts'; +import type { SubscriptionBuilderImpl } from './subscription_builder_impl.ts'; /** * Interface representing a database context. diff --git a/crates/bindings-typescript/src/sdk/db_view.ts b/crates/bindings-typescript/src/sdk/db_view.ts index baedb4dbe2d..cfa93e827b8 100644 --- a/crates/bindings-typescript/src/sdk/db_view.ts +++ b/crates/bindings-typescript/src/sdk/db_view.ts @@ -1,6 +1,6 @@ -import type { UntypedRemoteModule } from './spacetime_module'; -import type { ClientTable } from './client_table'; -import type { Values } from '../lib/type_util'; +import type { UntypedRemoteModule } from './spacetime_module.ts'; +import type { ClientTable } from './client_table.ts'; +import type { Values } from '../lib/type_util.ts'; /** * A type representing a client-side database view, mapping table names to their corresponding client Table handles. diff --git a/crates/bindings-typescript/src/sdk/event.ts b/crates/bindings-typescript/src/sdk/event.ts index a22c3873608..17a606eff8d 100644 --- a/crates/bindings-typescript/src/sdk/event.ts +++ b/crates/bindings-typescript/src/sdk/event.ts @@ -1,5 +1,5 @@ -import type { ReducerEvent } from './reducer_event'; -import type { ReducerEventInfo } from './reducers'; +import type { ReducerEvent } from './reducer_event.ts'; +import type { ReducerEventInfo } from './reducers.ts'; type WithId = { /** diff --git a/crates/bindings-typescript/src/sdk/event_context.ts b/crates/bindings-typescript/src/sdk/event_context.ts index 9efc0100166..fc0d1570beb 100644 --- a/crates/bindings-typescript/src/sdk/event_context.ts +++ b/crates/bindings-typescript/src/sdk/event_context.ts @@ -1,5 +1,5 @@ import type { InferTypeOfParams } from '../lib/type_builders.ts'; -import type { DbContext } from './db_context'; +import type { DbContext } from './db_context.ts'; import type { Event } from './event.ts'; import type { ReducerEvent } from './reducer_event.ts'; import type { ReducerEventInfo } from './reducers.ts'; diff --git a/crates/bindings-typescript/src/sdk/logger.ts b/crates/bindings-typescript/src/sdk/logger.ts index 7374e8b3510..9179a19b623 100644 --- a/crates/bindings-typescript/src/sdk/logger.ts +++ b/crates/bindings-typescript/src/sdk/logger.ts @@ -1,5 +1,5 @@ import { stringify as ssStringify } from 'safe-stable-stringify'; -import { u128ToHexString, u256ToHexString } from '../lib/util'; +import { u128ToHexString, u256ToHexString } from '../lib/util.ts'; export type LogLevel = 'info' | 'warn' | 'error' | 'debug' | 'trace'; const LogLevelIdentifierIcon = { diff --git a/crates/bindings-typescript/src/sdk/message_types.ts b/crates/bindings-typescript/src/sdk/message_types.ts index 319f8ac605a..5304b937320 100644 --- a/crates/bindings-typescript/src/sdk/message_types.ts +++ b/crates/bindings-typescript/src/sdk/message_types.ts @@ -1,6 +1,6 @@ import type { TableUpdate } from './table_cache.ts'; import type { UntypedTableDef } from '../lib/table.ts'; -import type { ReducerOutcome } from './client_api/types'; +import type { ReducerOutcome } from './client_api/types.ts'; export type TransactionUpdateMessage = { tag: 'TransactionUpdate'; diff --git a/crates/bindings-typescript/src/sdk/procedures.ts b/crates/bindings-typescript/src/sdk/procedures.ts index e8ac3a70b88..0672d963feb 100644 --- a/crates/bindings-typescript/src/sdk/procedures.ts +++ b/crates/bindings-typescript/src/sdk/procedures.ts @@ -1,12 +1,12 @@ -import type { ParamsObj } from '../lib/reducers'; +import type { ParamsObj } from '../lib/reducers.ts'; import type { Infer, InferTypeOfParams, TypeBuilder, -} from '../lib/type_builders'; -import type { CamelCase } from '../lib/type_util'; -import { coerceParams, toCamelCase, type CoerceParams } from '../lib/util'; -import type { UntypedRemoteModule } from './spacetime_module'; +} from '../lib/type_builders.ts'; +import type { CamelCase } from '../lib/type_util.ts'; +import { coerceParams, toCamelCase, type CoerceParams } from '../lib/util.ts'; +import type { UntypedRemoteModule } from './spacetime_module.ts'; // Utility: detect 'any' type IfAny = 0 extends 1 & T ? Y : N; diff --git a/crates/bindings-typescript/src/sdk/reducer_event.ts b/crates/bindings-typescript/src/sdk/reducer_event.ts index 18a39077410..eb138c0befc 100644 --- a/crates/bindings-typescript/src/sdk/reducer_event.ts +++ b/crates/bindings-typescript/src/sdk/reducer_event.ts @@ -1,5 +1,5 @@ -import { Timestamp } from '../'; -import type { ReducerOutcome } from './client_api/types'; +import { Timestamp } from '../index.ts'; +import type { ReducerOutcome } from './client_api/types.ts'; import type { ReducerEventInfo } from './reducers.ts'; export type ReducerEvent = { diff --git a/crates/bindings-typescript/src/sdk/reducers.ts b/crates/bindings-typescript/src/sdk/reducers.ts index 566df5c3076..f7005918cef 100644 --- a/crates/bindings-typescript/src/sdk/reducers.ts +++ b/crates/bindings-typescript/src/sdk/reducers.ts @@ -1,10 +1,10 @@ -import type { ProductType } from '../lib/algebraic_type'; -import type { ReducerSchema } from '../lib/reducer_schema'; -import type { ParamsObj } from '../lib/reducers'; -import { RowBuilder, type InferTypeOfParams } from '../lib/type_builders'; -import { toCamelCase } from '../lib/util'; -import type { SubscriptionEventContextInterface } from './event_context'; -import type { UntypedRemoteModule } from './spacetime_module'; +import type { ProductType } from '../lib/algebraic_type.ts'; +import type { ReducerSchema } from '../lib/reducer_schema.ts'; +import type { ParamsObj } from '../lib/reducers.ts'; +import { RowBuilder, type InferTypeOfParams } from '../lib/type_builders.ts'; +import { toCamelCase } from '../lib/util.ts'; +import type { SubscriptionEventContextInterface } from './event_context.ts'; +import type { UntypedRemoteModule } from './spacetime_module.ts'; export type SubscriptionEventCallback< RemoteModule extends UntypedRemoteModule, diff --git a/crates/bindings-typescript/src/sdk/schema.ts b/crates/bindings-typescript/src/sdk/schema.ts index d561076ebec..9747a8e4ff5 100644 --- a/crates/bindings-typescript/src/sdk/schema.ts +++ b/crates/bindings-typescript/src/sdk/schema.ts @@ -3,8 +3,8 @@ import { tablesToSchema, type TablesToSchema, type UntypedSchemaDef, -} from '../lib/schema'; -import type { UntypedTableSchema } from '../lib/table_schema'; +} from '../lib/schema.ts'; +import type { UntypedTableSchema } from '../lib/table_schema.ts'; class Tables { constructor(readonly schemaType: S) {} diff --git a/crates/bindings-typescript/src/sdk/spacetime_module.ts b/crates/bindings-typescript/src/sdk/spacetime_module.ts index aa19b38cd32..fbf00217add 100644 --- a/crates/bindings-typescript/src/sdk/spacetime_module.ts +++ b/crates/bindings-typescript/src/sdk/spacetime_module.ts @@ -1,6 +1,6 @@ -import type { UntypedProceduresDef } from './procedures'; -import type { UntypedSchemaDef } from '../lib/schema'; -import type { UntypedReducersDef } from './reducers'; +import type { UntypedProceduresDef } from './procedures.ts'; +import type { UntypedSchemaDef } from '../lib/schema.ts'; +import type { UntypedReducersDef } from './reducers.ts'; export type RemoteModule< SchemaDef extends UntypedSchemaDef, diff --git a/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts b/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts index f7e271b4e85..e8b62135ca2 100644 --- a/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts +++ b/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts @@ -1,18 +1,18 @@ -import type { DbConnectionImpl } from './db_connection_impl'; -import { INTERNAL_REMOTE_MODULE } from './internal'; +import type { DbConnectionImpl } from './db_connection_impl.ts'; +import { INTERNAL_REMOTE_MODULE } from './internal.ts'; import type { ErrorContextInterface, SubscriptionEventContextInterface, -} from './event_context'; -import { EventEmitter } from './event_emitter'; -import type { UntypedRemoteModule } from './spacetime_module'; +} from './event_context.ts'; +import { EventEmitter } from './event_emitter.ts'; +import type { UntypedRemoteModule } from './spacetime_module.ts'; import { isRowTypedQuery, toSql, type NamespacedQueryBuilder, type RowTypedQuery, -} from '../lib/query'; -import type { UntypedSchemaDef } from '../lib/schema'; +} from '../lib/query.ts'; +import type { UntypedSchemaDef } from '../lib/schema.ts'; export class SubscriptionBuilderImpl { #onApplied?: (ctx: SubscriptionEventContextInterface) => void = diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index 543d3fb78ed..c7099715555 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -1,7 +1,7 @@ import { EventEmitter } from './event_emitter.ts'; import { stdbLogger } from './logger.ts'; -import { deepEqual, type ComparablePrimitive } from '../'; +import { deepEqual, type ComparablePrimitive } from '../index.ts'; import type { EventContextInterface, TableDefForTableName } from './index.ts'; import type { RowType, TableIndexes, UntypedTableDef } from '../lib/table.ts'; import type { ClientTableCoreImplementable } from './client_table.ts'; diff --git a/crates/bindings-typescript/src/sdk/type_utils.ts b/crates/bindings-typescript/src/sdk/type_utils.ts index 99ae49ca3b1..f4353206e39 100644 --- a/crates/bindings-typescript/src/sdk/type_utils.ts +++ b/crates/bindings-typescript/src/sdk/type_utils.ts @@ -1,7 +1,7 @@ -import type { Infer, InferTypeOfParams } from '.'; -import type { Prettify } from '../lib/type_util'; -import type { UntypedProcedureDef } from './procedures'; -import type { UntypedReducerDef } from './reducers'; +import type { Infer, InferTypeOfParams } from './index.ts'; +import type { Prettify } from '../lib/type_util.ts'; +import type { UntypedProcedureDef } from './procedures.ts'; +import type { UntypedReducerDef } from './reducers.ts'; export type IsEmptyObject = [keyof T] extends [never] ? true : false; export type MaybeParams = IsEmptyObject extends true ? [] : [params: T]; diff --git a/crates/bindings-typescript/src/sdk/websocket_decompress_adapter.ts b/crates/bindings-typescript/src/sdk/websocket_decompress_adapter.ts index c3c474b960a..c31086283fd 100644 --- a/crates/bindings-typescript/src/sdk/websocket_decompress_adapter.ts +++ b/crates/bindings-typescript/src/sdk/websocket_decompress_adapter.ts @@ -1,5 +1,9 @@ -import { decompress } from './decompress'; -import { openWebSocket, type WebSocketAdapter, type WebSocketArgs } from './ws'; +import { decompress } from './decompress.ts'; +import { + openWebSocket, + type WebSocketAdapter, + type WebSocketArgs, +} from './ws.ts'; export class WebsocketDecompressAdapter implements WebSocketAdapter { get protocol(): string { diff --git a/crates/bindings-typescript/src/sdk/websocket_test_adapter.ts b/crates/bindings-typescript/src/sdk/websocket_test_adapter.ts index 257f9cb2806..899318a1d0f 100644 --- a/crates/bindings-typescript/src/sdk/websocket_test_adapter.ts +++ b/crates/bindings-typescript/src/sdk/websocket_test_adapter.ts @@ -1,8 +1,11 @@ import BinaryReader from '../lib/binary_reader.ts'; import BinaryWriter from '../lib/binary_writer.ts'; -import { ClientMessage, ServerMessage } from './client_api/types'; -import type { WebSocketAdapter, WebSocketFactory } from './ws'; -import { PREFERRED_WS_PROTOCOLS, V3_WS_PROTOCOL } from './websocket_protocols'; +import { ClientMessage, ServerMessage } from './client_api/types.ts'; +import type { WebSocketAdapter, WebSocketFactory } from './ws.ts'; +import { + PREFERRED_WS_PROTOCOLS, + V3_WS_PROTOCOL, +} from './websocket_protocols.ts'; import { decodeClientMessagesV3, encodeServerMessagesV3, diff --git a/crates/bindings-typescript/src/sdk/websocket_v3_frames.ts b/crates/bindings-typescript/src/sdk/websocket_v3_frames.ts index e6613101ceb..17c8e20267b 100644 --- a/crates/bindings-typescript/src/sdk/websocket_v3_frames.ts +++ b/crates/bindings-typescript/src/sdk/websocket_v3_frames.ts @@ -1,6 +1,6 @@ import BinaryReader from '../lib/binary_reader.ts'; import BinaryWriter from '../lib/binary_writer.ts'; -import { ClientMessage, ServerMessage } from './client_api/types'; +import { ClientMessage, ServerMessage } from './client_api/types.ts'; // v3 is only a transport framing convention. The payload is one or more // already-encoded v2 websocket messages concatenated back-to-back, so these diff --git a/crates/bindings-typescript/src/sdk/ws.ts b/crates/bindings-typescript/src/sdk/ws.ts index 99d1b688ece..166edb03e04 100644 --- a/crates/bindings-typescript/src/sdk/ws.ts +++ b/crates/bindings-typescript/src/sdk/ws.ts @@ -1,4 +1,4 @@ -import { stdbLogger } from './logger'; +import { stdbLogger } from './logger.ts'; async function resolveWS(): Promise { // Browser or Node >= 22 (or any env that exposes global WebSocket) diff --git a/crates/bindings-typescript/src/server/console.ts b/crates/bindings-typescript/src/server/console.ts index 5094030ce33..fc1a11e10ec 100644 --- a/crates/bindings-typescript/src/server/console.ts +++ b/crates/bindings-typescript/src/server/console.ts @@ -1,5 +1,5 @@ import type { u32 } from 'spacetime:sys@2.0'; -import { sys } from './runtime'; +import { sys } from './runtime.ts'; import inspect from 'object-inspect'; const fmtLog = (...data: any[]) => diff --git a/crates/bindings-typescript/src/server/db_view.ts b/crates/bindings-typescript/src/server/db_view.ts index 847a74f957b..e6cf9cb3897 100644 --- a/crates/bindings-typescript/src/server/db_view.ts +++ b/crates/bindings-typescript/src/server/db_view.ts @@ -1,6 +1,6 @@ -import type { UntypedSchemaDef } from '../lib/schema'; -import type { ReadonlyTable, Table } from '../lib/table'; -import type { Values } from '../lib/type_util'; +import type { UntypedSchemaDef } from '../lib/schema.ts'; +import type { ReadonlyTable, Table } from '../lib/table.ts'; +import type { Values } from '../lib/type_util.ts'; /** * A type representing a read-only database view, mapping table names to their corresponding read-only Table handles. diff --git a/crates/bindings-typescript/src/server/environment.ts b/crates/bindings-typescript/src/server/environment.ts index 93daa9ce767..4dc6185e825 100644 --- a/crates/bindings-typescript/src/server/environment.ts +++ b/crates/bindings-typescript/src/server/environment.ts @@ -1,11 +1,11 @@ import { env_get } from 'spacetime:sys@2.2'; -import type { Environment, EnvironmentSchema } from '../lib/environment'; +import type { Environment, EnvironmentSchema } from '../lib/environment.ts'; import type { EnvironmentDeclaration, EnvVarType, AlgebraicType, -} from '../lib/autogen/types'; -import { OptionBuilder, StringBuilder } from '../lib/type_builders'; +} from '../lib/autogen/types.ts'; +import { OptionBuilder, StringBuilder } from '../lib/type_builders.ts'; // These UTF-8 byte/count limits match spacetimedb_lib::environment. const MAX_ENV_KEY_BYTES = 256; @@ -31,7 +31,7 @@ export type { Environment, EnvironmentFor, EnvironmentSchema, -} from '../lib/environment'; +} from '../lib/environment.ts'; /** Produce metadata only. No environment value is embedded in the artifact. */ export function environmentDeclarations( diff --git a/crates/bindings-typescript/src/server/errors.ts b/crates/bindings-typescript/src/server/errors.ts index 397512e50ce..0f153cffad1 100644 --- a/crates/bindings-typescript/src/server/errors.ts +++ b/crates/bindings-typescript/src/server/errors.ts @@ -1,4 +1,4 @@ -import { SenderError } from '../lib/errors'; +import { SenderError } from '../lib/errors.ts'; /** * Base class for all Spacetime host errors (i.e. errors that may be thrown diff --git a/crates/bindings-typescript/src/server/http.test-d.ts b/crates/bindings-typescript/src/server/http.test-d.ts index 80299ef6a85..9d45a36b7e5 100644 --- a/crates/bindings-typescript/src/server/http.test-d.ts +++ b/crates/bindings-typescript/src/server/http.test-d.ts @@ -1,12 +1,12 @@ -import { table } from '../lib/table'; -import t from '../lib/type_builders'; +import { table } from '../lib/table.ts'; +import t from '../lib/type_builders.ts'; import { type HandlerContext, Request, SyncResponse, Router, schema, -} from './index'; +} from './index.ts'; const person = table( {}, diff --git a/crates/bindings-typescript/src/server/http.ts b/crates/bindings-typescript/src/server/http.ts index 62f68906f1b..2fafb1982c0 100644 --- a/crates/bindings-typescript/src/server/http.ts +++ b/crates/bindings-typescript/src/server/http.ts @@ -11,4 +11,4 @@ export { type HandlerFn, type HttpHandlerExport, type HttpHandlerOpts, -} from './http_handlers'; +} from './http_handlers.ts'; diff --git a/crates/bindings-typescript/src/server/http_handlers.ts b/crates/bindings-typescript/src/server/http_handlers.ts index b8823577f4e..ad6311d0b2f 100644 --- a/crates/bindings-typescript/src/server/http_handlers.ts +++ b/crates/bindings-typescript/src/server/http_handlers.ts @@ -1,22 +1,22 @@ -import type { EnvironmentFor } from '../lib/environment'; -import type { Identity } from '../lib/identity'; +import type { EnvironmentFor } from '../lib/environment.ts'; +import type { Identity } from '../lib/identity.ts'; import type { HttpMethod, HttpVersion, MethodOrAny, -} from '../lib/autogen/types'; -import type { UntypedSchemaDef } from '../lib/schema'; -import type { Timestamp } from '../lib/timestamp'; -import type { Uuid } from '../lib/uuid'; -import type { TransactionCtx } from './procedures'; -import type { HttpClient } from './http_internal'; -import type { Random } from './rng'; +} from '../lib/autogen/types.ts'; +import type { UntypedSchemaDef } from '../lib/schema.ts'; +import type { Timestamp } from '../lib/timestamp.ts'; +import type { Uuid } from '../lib/uuid.ts'; +import type { TransactionCtx } from './procedures.ts'; +import type { HttpClient } from './http_internal.ts'; +import type { Random } from './rng.ts'; import { exportContext, registerExport, type ModuleExport, type SchemaInner, -} from './schema'; +} from './schema.ts'; import { Headers, makeResponse, @@ -26,7 +26,7 @@ import { type BodyInit, type HeadersInit, type ResponseInit, -} from './http_shared'; +} from './http_shared.ts'; export { Headers }; export { SyncResponse }; diff --git a/crates/bindings-typescript/src/server/http_internal.ts b/crates/bindings-typescript/src/server/http_internal.ts index 1ba1f31a5bf..141f8ae0df7 100644 --- a/crates/bindings-typescript/src/server/http_internal.ts +++ b/crates/bindings-typescript/src/server/http_internal.ts @@ -1,9 +1,9 @@ -import BinaryReader from '../lib/binary_reader'; -import BinaryWriter from '../lib/binary_writer'; +import BinaryReader from '../lib/binary_reader.ts'; +import BinaryWriter from '../lib/binary_writer.ts'; import status from 'statuses'; -import { HttpRequest, HttpResponse } from '../lib/autogen/types'; -import type { TimeDuration } from '../lib/time_duration'; -import { bsatnBaseSize } from '../lib/util'; +import { HttpRequest, HttpResponse } from '../lib/autogen/types.ts'; +import type { TimeDuration } from '../lib/time_duration.ts'; +import { bsatnBaseSize } from '../lib/util.ts'; import { type BodyInit, type HeadersInit, @@ -13,8 +13,8 @@ import { serializeHeaders, serializeMethod, SyncResponse, -} from './http_shared'; -import { sys } from './runtime'; +} from './http_shared.ts'; +import { sys } from './runtime.ts'; export { Headers }; diff --git a/crates/bindings-typescript/src/server/http_shared.ts b/crates/bindings-typescript/src/server/http_shared.ts index ea422b7ecd1..f85e2b85dca 100644 --- a/crates/bindings-typescript/src/server/http_shared.ts +++ b/crates/bindings-typescript/src/server/http_shared.ts @@ -3,7 +3,7 @@ import type { HttpHeaders, HttpMethod, HttpVersion, -} from '../lib/autogen/types'; +} from '../lib/autogen/types.ts'; export { Headers }; diff --git a/crates/bindings-typescript/src/server/index.ts b/crates/bindings-typescript/src/server/index.ts index 3ac3e8f0fbb..5557f235250 100644 --- a/crates/bindings-typescript/src/server/index.ts +++ b/crates/bindings-typescript/src/server/index.ts @@ -1,27 +1,32 @@ -export * from '../lib/type_builders'; +export * from '../lib/type_builders.ts'; export { schema, type InferSchema, type ModuleExport, type ModuleSettings, -} from './schema'; -export { CaseConversionPolicy } from '../lib/autogen/types'; -export { table } from '../lib/table'; -export { SenderError, SpacetimeHostError, errors } from './errors'; -export type { Reducer, ReducerCtx, JwtClaims, AuthCtx } from '../lib/reducers'; -export type { ReducerExport } from './reducers'; -export { type DbView } from './db_view'; -export * from './query'; +} from './schema.ts'; +export { CaseConversionPolicy } from '../lib/autogen/types.ts'; +export { table } from '../lib/table.ts'; +export { SenderError, SpacetimeHostError, errors } from './errors.ts'; +export type { + Reducer, + ReducerCtx, + JwtClaims, + AuthCtx, +} from '../lib/reducers.ts'; +export type { ReducerExport } from './reducers.ts'; +export { type DbView } from './db_view.ts'; +export * from './query.ts'; export type { ProcedureCtx, TransactionCtx, ProcedureExport, -} from './procedures'; -export { toCamelCase } from '../lib/util'; -export type { Uuid } from '../lib/uuid'; -export type { Random } from './rng'; -export type { ViewExport, ViewCtx, AnonymousViewCtx } from './views'; -export { Range, type Bound } from './range'; +} from './procedures.ts'; +export { toCamelCase } from '../lib/util.ts'; +export type { Uuid } from '../lib/uuid.ts'; +export type { Random } from './rng.ts'; +export type { ViewExport, ViewCtx, AnonymousViewCtx } from './views.ts'; +export { Range, type Bound } from './range.ts'; export { Headers, Request, @@ -31,10 +36,10 @@ export { type HeadersInit, type RequestInit, type ResponseInit, -} from './http'; -export type { HandlerContext, HttpHandlerExport } from './http'; -export { ScheduleAt } from '../lib/schedule_at'; +} from './http.ts'; +export type { HandlerContext, HttpHandlerExport } from './http.ts'; +export { ScheduleAt } from '../lib/schedule_at.ts'; -export type { Environment } from './environment'; +export type { Environment } from './environment.ts'; -import './polyfills'; // Ensure polyfills are loaded +import './polyfills.ts'; // Ensure polyfills are loaded diff --git a/crates/bindings-typescript/src/server/polyfills.ts b/crates/bindings-typescript/src/server/polyfills.ts index 3e88b119de4..d02579fd088 100644 --- a/crates/bindings-typescript/src/server/polyfills.ts +++ b/crates/bindings-typescript/src/server/polyfills.ts @@ -1,4 +1,4 @@ import 'url-polyfill'; -import { console } from './console'; +import { console } from './console.ts'; globalThis.console = console; diff --git a/crates/bindings-typescript/src/server/procedures.ts b/crates/bindings-typescript/src/server/procedures.ts index f5b8e2aa1e2..8bfe6a6fc02 100644 --- a/crates/bindings-typescript/src/server/procedures.ts +++ b/crates/bindings-typescript/src/server/procedures.ts @@ -1,30 +1,30 @@ -import { environment, type EnvironmentFor } from './environment'; +import { environment, type EnvironmentFor } from './environment.ts'; import { AlgebraicType, ProductType, type Deserializer, type Serializer, -} from '../lib/algebraic_type'; -import { FunctionVisibility } from '../lib/autogen/types'; -import BinaryReader from '../lib/binary_reader'; -import BinaryWriter from '../lib/binary_writer'; -import type { ConnectionId } from '../lib/connection_id'; -import { Identity } from '../lib/identity'; -import type { ParamsObj, ReducerCtx } from '../lib/reducers'; -import { type UntypedSchemaDef } from '../lib/schema'; -import type { ScheduleTableForParams } from '../lib/table_schema'; -import { Timestamp } from '../lib/timestamp'; +} from '../lib/algebraic_type.ts'; +import { FunctionVisibility } from '../lib/autogen/types.ts'; +import BinaryReader from '../lib/binary_reader.ts'; +import BinaryWriter from '../lib/binary_writer.ts'; +import type { ConnectionId } from '../lib/connection_id.ts'; +import { Identity } from '../lib/identity.ts'; +import type { ParamsObj, ReducerCtx } from '../lib/reducers.ts'; +import { type UntypedSchemaDef } from '../lib/schema.ts'; +import type { ScheduleTableForParams } from '../lib/table_schema.ts'; +import { Timestamp } from '../lib/timestamp.ts'; import { type Infer, type InferTypeOfRow, type t, type TypeBuilder, -} from '../lib/type_builders'; -import { bsatnBaseSize } from '../lib/util'; -import { Uuid } from '../lib/uuid'; -import { httpClient, type HttpClient } from './http_internal'; -import type { DbView } from './db_view'; -import { makeRandom, type Random } from './rng'; +} from '../lib/type_builders.ts'; +import { bsatnBaseSize } from '../lib/util.ts'; +import { Uuid } from '../lib/uuid.ts'; +import { httpClient, type HttpClient } from './http_internal.ts'; +import type { DbView } from './db_view.ts'; +import { makeRandom, type Random } from './rng.ts'; import { assignTxAliasViews, buildProcedureAliasCtxMap, @@ -32,14 +32,14 @@ import { ReducerCtxImpl, runWithTx, sys, -} from './runtime'; +} from './runtime.ts'; import { exportContext, registerExport, type SubmoduleDispatchInfo, type ModuleExport, type SchemaInner, -} from './schema'; +} from './schema.ts'; export type ProcedureExport< S extends UntypedSchemaDef, diff --git a/crates/bindings-typescript/src/server/query.ts b/crates/bindings-typescript/src/server/query.ts index afeafcdfe03..71487a58b88 100644 --- a/crates/bindings-typescript/src/server/query.ts +++ b/crates/bindings-typescript/src/server/query.ts @@ -1 +1 @@ -export * from '../lib/query'; +export * from '../lib/query.ts'; diff --git a/crates/bindings-typescript/src/server/reducers.ts b/crates/bindings-typescript/src/server/reducers.ts index ea5f770faf8..3a981901d41 100644 --- a/crates/bindings-typescript/src/server/reducers.ts +++ b/crates/bindings-typescript/src/server/reducers.ts @@ -1,16 +1,16 @@ -import { AlgebraicType } from '../lib/algebraic_type'; -import { FunctionVisibility, type Lifecycle } from '../lib/autogen/types'; -import type { ParamsObj, Reducer } from '../lib/reducers'; -import { type UntypedSchemaDef } from '../lib/schema'; -import type { ScheduleTableForParams } from '../lib/table_schema'; -import { RowBuilder, type RowObj } from '../lib/type_builders'; -import { toPascalCase } from '../lib/util'; +import { AlgebraicType } from '../lib/algebraic_type.ts'; +import { FunctionVisibility, type Lifecycle } from '../lib/autogen/types.ts'; +import type { ParamsObj, Reducer } from '../lib/reducers.ts'; +import { type UntypedSchemaDef } from '../lib/schema.ts'; +import type { ScheduleTableForParams } from '../lib/table_schema.ts'; +import { RowBuilder, type RowObj } from '../lib/type_builders.ts'; +import { toPascalCase } from '../lib/util.ts'; import { exportContext, registerExport, type ModuleExport, type SchemaInner, -} from './schema'; +} from './schema.ts'; export interface ReducerExport< S extends UntypedSchemaDef, diff --git a/crates/bindings-typescript/src/server/rng.ts b/crates/bindings-typescript/src/server/rng.ts index 2bde81d64ad..0b619112620 100644 --- a/crates/bindings-typescript/src/server/rng.ts +++ b/crates/bindings-typescript/src/server/rng.ts @@ -2,7 +2,7 @@ import type { RandomGenerator } from 'pure-rand'; import { unsafeUniformBigIntDistribution } from 'pure-rand/distribution/UnsafeUniformBigIntDistribution'; import { unsafeUniformIntDistribution } from 'pure-rand/distribution/UnsafeUniformIntDistribution'; import { xoroshiro128plus } from 'pure-rand/generator/XoroShiro'; -import type { Timestamp } from '../lib/timestamp'; +import type { Timestamp } from '../lib/timestamp.ts'; type IntArray = | Int8Array diff --git a/crates/bindings-typescript/src/server/runtime.ts b/crates/bindings-typescript/src/server/runtime.ts index 70c6eb81401..be0ded8c500 100644 --- a/crates/bindings-typescript/src/server/runtime.ts +++ b/crates/bindings-typescript/src/server/runtime.ts @@ -1,4 +1,4 @@ -import { environment, type EnvironmentFor } from './environment'; +import { environment, type EnvironmentFor } from './environment.ts'; import * as _syscalls2_0 from 'spacetime:sys@2.0'; import * as _syscalls2_1 from 'spacetime:sys@2.1'; @@ -7,7 +7,7 @@ import { AlgebraicType, ProductType, type Deserializer, -} from '../lib/algebraic_type'; +} from '../lib/algebraic_type.ts'; import { RawModuleDef, ViewResultHeader, @@ -15,68 +15,68 @@ import { type RawReducerDefV10, type RawTableDefV10, type Typespace, -} from '../lib/autogen/types'; -import { ConnectionId } from '../lib/connection_id'; -import { Identity } from '../lib/identity'; -import { Timestamp } from '../lib/timestamp'; -import { Uuid } from '../lib/uuid'; -import BinaryReader from '../lib/binary_reader'; -import BinaryWriter, { ResizableBuffer } from '../lib/binary_writer'; +} from '../lib/autogen/types.ts'; +import { ConnectionId } from '../lib/connection_id.ts'; +import { Identity } from '../lib/identity.ts'; +import { Timestamp } from '../lib/timestamp.ts'; +import { Uuid } from '../lib/uuid.ts'; +import BinaryReader from '../lib/binary_reader.ts'; +import BinaryWriter, { ResizableBuffer } from '../lib/binary_writer.ts'; import { type Index, type IndexVal, type PointIndex, type RangedIndex, type UniqueIndex, -} from '../lib/indexes'; -import { callProcedure } from './procedures'; -import type { Procedures } from './procedures'; -import type { Reducers } from './reducers'; +} from '../lib/indexes.ts'; +import { callProcedure } from './procedures.ts'; +import type { Procedures } from './procedures.ts'; +import type { Reducers } from './reducers.ts'; import { type HandlerContext, Request, SyncResponse, makeRequest, -} from './http_handlers'; -import { httpClient } from './http_internal'; +} from './http_handlers.ts'; +import { httpClient } from './http_internal.ts'; import { deserializeHeaders, deserializeMethod, serializeHeaders, -} from './http_shared'; +} from './http_shared.ts'; import { type AliasViews, type AuthCtx, type JsonObject, type JwtClaims, type ReducerCtx as IReducerCtx, -} from '../lib/reducers'; -import { type UntypedSchemaDef } from '../lib/schema'; +} from '../lib/reducers.ts'; +import { type UntypedSchemaDef } from '../lib/schema.ts'; import { type RowType, type Table, type TableMethods, type UntypedTableDef, -} from '../lib/table'; -import { bsatnBaseSize, hasOwn } from '../lib/util'; +} from '../lib/table.ts'; +import { bsatnBaseSize, hasOwn } from '../lib/util.ts'; import { type AnonymousViewCtx, type AnonViews, type ViewCtx, type Views, -} from './views'; +} from './views.ts'; import { isRowTypedQuery, makeQueryBuilder, toSql, type QueryBuilder, -} from './query'; -import type { DbView, ReadonlyDbView } from './db_view'; -import { getErrorConstructor, SenderError } from './errors'; -import { Range, type Bound } from './range'; -import { makeRandom, type Random } from './rng'; -import type { SubmoduleDispatchInfo, SchemaInner } from './schema'; -import { HttpRequest, HttpResponse } from '../lib/autogen/types'; +} from './query.ts'; +import type { DbView, ReadonlyDbView } from './db_view.ts'; +import { getErrorConstructor, SenderError } from './errors.ts'; +import { Range, type Bound } from './range.ts'; +import { makeRandom, type Random } from './rng.ts'; +import type { SubmoduleDispatchInfo, SchemaInner } from './schema.ts'; +import { HttpRequest, HttpResponse } from '../lib/autogen/types.ts'; const { freeze } = Object; diff --git a/crates/bindings-typescript/src/server/schema.test-d.ts b/crates/bindings-typescript/src/server/schema.test-d.ts index 6d142fe2741..7f21a2acb29 100644 --- a/crates/bindings-typescript/src/server/schema.test-d.ts +++ b/crates/bindings-typescript/src/server/schema.test-d.ts @@ -1,7 +1,7 @@ -import { registerExport, schema } from './schema'; -import type { ProcedureExport } from './procedures'; -import { table } from '../lib/table'; -import t from '../lib/type_builders'; +import { registerExport, schema } from './schema.ts'; +import type { ProcedureExport } from './procedures.ts'; +import { table } from '../lib/table.ts'; +import t from '../lib/type_builders.ts'; const person = table( { diff --git a/crates/bindings-typescript/src/server/schema.ts b/crates/bindings-typescript/src/server/schema.ts index 95688b7f3cd..08f4f95de4a 100644 --- a/crates/bindings-typescript/src/server/schema.ts +++ b/crates/bindings-typescript/src/server/schema.ts @@ -1,4 +1,7 @@ -import { environmentDeclarations, type EnvironmentSchema } from './environment'; +import { + environmentDeclarations, + type EnvironmentSchema, +} from './environment.ts'; import { moduleHooks, type ModuleDefaultExport } from 'spacetime:sys@2.0'; import { CaseConversionPolicy, @@ -9,22 +12,22 @@ import { type RawReducerDefV10, type RawTableDefV10, type Typespace, -} from '../lib/autogen/types'; +} from '../lib/autogen/types.ts'; import { type ParamsAsObject, type ParamsObj, type Reducer, type ReducerCtx, -} from '../lib/reducers'; +} from '../lib/reducers.ts'; import { ModuleContext, tableToSchema, type TablesToSchema, type UntypedSchemaDef, -} from '../lib/schema'; -import type { UntypedTableSchema } from '../lib/table_schema'; -import { TypeBuilder, type ColumnBuilder } from '../lib/type_builders'; -import { hasOwn } from '../lib/util'; +} from '../lib/schema.ts'; +import type { UntypedTableSchema } from '../lib/table_schema.ts'; +import { TypeBuilder, type ColumnBuilder } from '../lib/type_builders.ts'; +import { hasOwn } from '../lib/util.ts'; import { Router, type HandlerFn, @@ -32,7 +35,7 @@ import { type HttpHandlerOpts, makeHttpHandlerExport, makeHttpRouterExport, -} from './http_handlers'; +} from './http_handlers.ts'; import { makeProcedureExport, type ProcedureExport, @@ -40,15 +43,15 @@ import { type ProcedureOpts, type ProcedureOptsWithOptionalName, type Procedures, -} from './procedures'; +} from './procedures.ts'; import { makeReducerExport, type ReducerExport, type ReducerOpts, type ReducerOptsWithOptionalName, type Reducers, -} from './reducers'; -import { makeHooks } from './runtime'; +} from './reducers.ts'; +import { makeHooks } from './runtime.ts'; import { makeAnonViewExport, @@ -61,8 +64,8 @@ import { type ViewReturnTypeBuilder, type ValidateViewPrimaryKey, type Views, -} from './views'; -import type { UntypedTableDef } from '../lib/table'; +} from './views.ts'; +import type { UntypedTableDef } from '../lib/table.ts'; /** * Internal erased form of a scheduled reducer/procedure export. diff --git a/crates/bindings-typescript/src/server/view.test-d.ts b/crates/bindings-typescript/src/server/view.test-d.ts index de91adfcb83..d99a6e50c66 100644 --- a/crates/bindings-typescript/src/server/view.test-d.ts +++ b/crates/bindings-typescript/src/server/view.test-d.ts @@ -1,6 +1,6 @@ -import { schema } from './schema'; -import { table } from '../lib/table'; -import t from '../lib/type_builders'; +import { schema } from './schema.ts'; +import { table } from '../lib/table.ts'; +import t from '../lib/type_builders.ts'; const person = table( { diff --git a/crates/bindings-typescript/src/server/views.ts b/crates/bindings-typescript/src/server/views.ts index f089de2f0c1..03120e88828 100644 --- a/crates/bindings-typescript/src/server/views.ts +++ b/crates/bindings-typescript/src/server/views.ts @@ -1,15 +1,15 @@ -import type { EnvironmentFor } from '../lib/environment'; +import type { EnvironmentFor } from '../lib/environment.ts'; import { AlgebraicType, ProductType, type AlgebraicTypeVariants, type Deserializer, type Serializer, -} from '../lib/algebraic_type'; -import type { Identity } from '../lib/identity'; -import type { OptionAlgebraicType } from '../lib/option'; -import type { ParamsObj } from '../lib/reducers'; -import { type UntypedSchemaDef } from '../lib/schema'; +} from '../lib/algebraic_type.ts'; +import type { Identity } from '../lib/identity.ts'; +import type { OptionAlgebraicType } from '../lib/option.ts'; +import type { ParamsObj } from '../lib/reducers.ts'; +import { type UntypedSchemaDef } from '../lib/schema.ts'; import { ArrayBuilder, OptionBuilder, @@ -21,17 +21,17 @@ import { type InferTypeOfRow, type RowObj, type TypeBuilder, -} from '../lib/type_builders'; -import type { IsUnion } from '../lib/type_util'; -import { bsatnBaseSize, toPascalCase } from '../lib/util'; -import type { ReadonlyDbView } from './db_view'; -import { type QueryBuilder, type RowTypedQuery } from './query'; +} from '../lib/type_builders.ts'; +import type { IsUnion } from '../lib/type_util.ts'; +import { bsatnBaseSize, toPascalCase } from '../lib/util.ts'; +import type { ReadonlyDbView } from './db_view.ts'; +import { type QueryBuilder, type RowTypedQuery } from './query.ts'; import { exportContext, registerExport, type ModuleExport, type SchemaInner, -} from './schema'; +} from './schema.ts'; export type ViewExport = ViewFn & ModuleExport; diff --git a/crates/bindings-typescript/src/solid/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/solid/SpacetimeDBProvider.ts index 84752691d5a..346edce5cef 100644 --- a/crates/bindings-typescript/src/solid/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/solid/SpacetimeDBProvider.ts @@ -1,16 +1,16 @@ import { DbConnectionBuilder, type DbConnectionImpl, -} from '../sdk/db_connection_impl'; +} from '../sdk/db_connection_impl.ts'; import { onCleanup, createMemo, createComputed } from 'solid-js'; import { createStore } from 'solid-js/store'; -import { SpacetimeDBContext } from './useSpacetimeDB'; -import type { ConnectionState } from './connection_state'; -import { ConnectionId } from '../lib/connection_id'; +import { SpacetimeDBContext } from './useSpacetimeDB.ts'; +import type { ConnectionState } from './connection_state.ts'; +import { ConnectionId } from '../lib/connection_id.ts'; import { ConnectionManager, type ConnectionState as ManagerConnectionState, -} from '../sdk/connection_manager'; +} from '../sdk/connection_manager.ts'; export interface SpacetimeDBProviderProps< DbConnection extends DbConnectionImpl, diff --git a/crates/bindings-typescript/src/solid/connection_state.ts b/crates/bindings-typescript/src/solid/connection_state.ts index 5ad565f9be6..f1df5fe9dbb 100644 --- a/crates/bindings-typescript/src/solid/connection_state.ts +++ b/crates/bindings-typescript/src/solid/connection_state.ts @@ -1,5 +1,5 @@ -import type { DbConnectionImpl } from '../sdk/db_connection_impl'; -import type { ConnectionState as ManagerConnectionState } from '../sdk/connection_manager'; +import type { DbConnectionImpl } from '../sdk/db_connection_impl.ts'; +import type { ConnectionState as ManagerConnectionState } from '../sdk/connection_manager.ts'; export type ConnectionState = ManagerConnectionState & { getConnection(): DbConnectionImpl | null; diff --git a/crates/bindings-typescript/src/solid/useProcedure.ts b/crates/bindings-typescript/src/solid/useProcedure.ts index a5db86dc434..ebfe4f38090 100644 --- a/crates/bindings-typescript/src/solid/useProcedure.ts +++ b/crates/bindings-typescript/src/solid/useProcedure.ts @@ -1,10 +1,10 @@ import { createEffect } from 'solid-js'; -import type { UntypedProcedureDef } from '../sdk/procedures'; -import { useSpacetimeDB } from './useSpacetimeDB'; +import type { UntypedProcedureDef } from '../sdk/procedures.ts'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; import type { ProcedureParamsType, ProcedureReturnType, -} from '../sdk/type_utils'; +} from '../sdk/type_utils.ts'; export function useProcedure( procedureDef: ProcedureDef diff --git a/crates/bindings-typescript/src/solid/useReducer.ts b/crates/bindings-typescript/src/solid/useReducer.ts index c9a6968f4b1..c74333387c4 100644 --- a/crates/bindings-typescript/src/solid/useReducer.ts +++ b/crates/bindings-typescript/src/solid/useReducer.ts @@ -1,7 +1,7 @@ import { createEffect } from 'solid-js'; -import type { UntypedReducerDef } from '../sdk/reducers'; -import { useSpacetimeDB } from './useSpacetimeDB'; -import type { ParamsType } from '../sdk'; +import type { UntypedReducerDef } from '../sdk/reducers.ts'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; +import type { ParamsType } from '../sdk/index.ts'; export function useReducer( reducerDef: ReducerDef diff --git a/crates/bindings-typescript/src/solid/useSpacetimeDB.ts b/crates/bindings-typescript/src/solid/useSpacetimeDB.ts index 4eed7c2d41c..d9665de159e 100644 --- a/crates/bindings-typescript/src/solid/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/solid/useSpacetimeDB.ts @@ -1,5 +1,5 @@ import { createContext, useContext } from 'solid-js'; -import type { ConnectionState } from './connection_state'; +import type { ConnectionState } from './connection_state.ts'; export const SpacetimeDBContext = createContext( undefined diff --git a/crates/bindings-typescript/src/solid/useTable.ts b/crates/bindings-typescript/src/solid/useTable.ts index 70e4064b971..b0fa5274fc0 100644 --- a/crates/bindings-typescript/src/solid/useTable.ts +++ b/crates/bindings-typescript/src/solid/useTable.ts @@ -1,9 +1,9 @@ import { createSignal, onCleanup, createMemo, createComputed } from 'solid-js'; -import { useSpacetimeDB } from './useSpacetimeDB'; -import { type EventContextInterface } from '../sdk/db_connection_impl'; -import type { UntypedRemoteModule } from '../sdk/spacetime_module'; -import type { RowType, UntypedTableDef } from '../lib/table'; -import type { Prettify } from '../lib/type_util'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; +import { type EventContextInterface } from '../sdk/db_connection_impl.ts'; +import type { UntypedRemoteModule } from '../sdk/spacetime_module.ts'; +import type { RowType, UntypedTableDef } from '../lib/table.ts'; +import type { Prettify } from '../lib/type_util.ts'; import { type Query, type BooleanExpr, @@ -11,7 +11,7 @@ import { evaluateBooleanExpr, getQueryAccessorName, getQueryWhereClause, -} from '../lib/query'; +} from '../lib/query.ts'; import { createStore, reconcile } from 'solid-js/store'; export interface UseTableCallbacks { @@ -69,7 +69,7 @@ export function useTable( const whereExpr = createMemo(() => getQueryWhereClause(q())); const querySql = createMemo(() => toSql(q())); - let connectionState: import('./connection_state').ConnectionState; + let connectionState: import('./connection_state.ts').ConnectionState; try { connectionState = useSpacetimeDB(); } catch { diff --git a/crates/bindings-typescript/src/svelte/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/svelte/SpacetimeDBProvider.ts index ea7521384c9..20480c500ef 100644 --- a/crates/bindings-typescript/src/svelte/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/svelte/SpacetimeDBProvider.ts @@ -3,16 +3,16 @@ import { writable, type Writable } from 'svelte/store'; import { DbConnectionBuilder, type DbConnectionImpl, -} from '../sdk/db_connection_impl'; -import { ConnectionId } from '../lib/connection_id'; +} from '../sdk/db_connection_impl.ts'; +import { ConnectionId } from '../lib/connection_id.ts'; import { ConnectionManager, type ConnectionState as ManagerConnectionState, -} from '../sdk/connection_manager'; +} from '../sdk/connection_manager.ts'; import { SPACETIMEDB_CONTEXT_KEY, type ConnectionState, -} from './connection_state'; +} from './connection_state.ts'; /** * Establish a SpacetimeDB connection for the current component subtree and make diff --git a/crates/bindings-typescript/src/svelte/connection_state.ts b/crates/bindings-typescript/src/svelte/connection_state.ts index 502ec666d4b..03a81ecd862 100644 --- a/crates/bindings-typescript/src/svelte/connection_state.ts +++ b/crates/bindings-typescript/src/svelte/connection_state.ts @@ -1,8 +1,8 @@ import type { DbConnectionBuilder, DbConnectionImpl, -} from '../sdk/db_connection_impl'; -import type { ConnectionState as ManagerConnectionState } from '../sdk/connection_manager'; +} from '../sdk/db_connection_impl.ts'; +import type { ConnectionState as ManagerConnectionState } from '../sdk/connection_manager.ts'; export const SPACETIMEDB_CONTEXT_KEY = Symbol('spacetimedb'); diff --git a/crates/bindings-typescript/src/svelte/useReducer.ts b/crates/bindings-typescript/src/svelte/useReducer.ts index 236cc8c5faa..81f7e9516fd 100644 --- a/crates/bindings-typescript/src/svelte/useReducer.ts +++ b/crates/bindings-typescript/src/svelte/useReducer.ts @@ -1,9 +1,9 @@ import { onDestroy } from 'svelte'; import { get } from 'svelte/store'; -import type { InferTypeOfParams } from '../lib/type_builders'; -import type { UntypedReducerDef } from '../sdk/reducers'; -import { useSpacetimeDB } from './useSpacetimeDB'; -import type { Prettify } from '../lib/type_util'; +import type { InferTypeOfParams } from '../lib/type_builders.ts'; +import type { UntypedReducerDef } from '../sdk/reducers.ts'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; +import type { Prettify } from '../lib/type_util.ts'; type IsEmptyObject = [keyof T] extends [never] ? true : false; type MaybeParams = IsEmptyObject extends true ? [] : [params: T]; diff --git a/crates/bindings-typescript/src/svelte/useSpacetimeDB.ts b/crates/bindings-typescript/src/svelte/useSpacetimeDB.ts index 899c23c4f5f..af74990e85c 100644 --- a/crates/bindings-typescript/src/svelte/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/svelte/useSpacetimeDB.ts @@ -3,7 +3,7 @@ import type { Writable } from 'svelte/store'; import { SPACETIMEDB_CONTEXT_KEY, type ConnectionState, -} from './connection_state'; +} from './connection_state.ts'; // Throws an error if used outside of a SpacetimeDBProvider export function useSpacetimeDB(): Writable { diff --git a/crates/bindings-typescript/src/svelte/useTable.ts b/crates/bindings-typescript/src/svelte/useTable.ts index c2e15602e9b..4394e6bd2a8 100644 --- a/crates/bindings-typescript/src/svelte/useTable.ts +++ b/crates/bindings-typescript/src/svelte/useTable.ts @@ -1,10 +1,10 @@ import { onDestroy } from 'svelte'; import { writable, get, type Readable } from 'svelte/store'; -import { useSpacetimeDB } from './useSpacetimeDB'; -import type { EventContextInterface } from '../sdk/db_connection_impl'; -import type { UntypedRemoteModule } from '../sdk/spacetime_module'; -import type { RowType, UntypedTableDef } from '../lib/table'; -import type { Prettify } from '../lib/type_util'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; +import type { EventContextInterface } from '../sdk/db_connection_impl.ts'; +import type { UntypedRemoteModule } from '../sdk/spacetime_module.ts'; +import type { RowType, UntypedTableDef } from '../lib/table.ts'; +import type { Prettify } from '../lib/type_util.ts'; import { type BooleanExpr, evaluateBooleanExpr, @@ -12,7 +12,7 @@ import { getQueryWhereClause, type Query, toSql, -} from '../lib/query'; +} from '../lib/query.ts'; export interface UseTableCallbacks { onInsert?: (row: RowType) => void; diff --git a/crates/bindings-typescript/src/tanstack/SpacetimeDBQueryClient.ts b/crates/bindings-typescript/src/tanstack/SpacetimeDBQueryClient.ts index 4bce2812e52..e5303aad41d 100644 --- a/crates/bindings-typescript/src/tanstack/SpacetimeDBQueryClient.ts +++ b/crates/bindings-typescript/src/tanstack/SpacetimeDBQueryClient.ts @@ -10,7 +10,7 @@ import { evaluateBooleanExpr, getQueryAccessorName, getQueryWhereClause, -} from '../lib/query'; +} from '../lib/query.ts'; type QueryInput = Query; diff --git a/crates/bindings-typescript/src/tanstack/hooks.ts b/crates/bindings-typescript/src/tanstack/hooks.ts index f8eb2c8decd..e31d4aedcf9 100644 --- a/crates/bindings-typescript/src/tanstack/hooks.ts +++ b/crates/bindings-typescript/src/tanstack/hooks.ts @@ -5,9 +5,9 @@ import type { UseSuspenseQueryOptions, UseSuspenseQueryResult, } from '@tanstack/react-query'; -import type { UntypedTableDef, RowType } from '../lib/table'; -import type { Query } from '../lib/query'; -import { spacetimeDBQuery } from './SpacetimeDBQueryClient'; +import type { UntypedTableDef, RowType } from '../lib/table.ts'; +import type { Query } from '../lib/query.ts'; +import { spacetimeDBQuery } from './SpacetimeDBQueryClient.ts'; export type UseSpacetimeDBQueryResult = [ T[], diff --git a/crates/bindings-typescript/src/tanstack/index.ts b/crates/bindings-typescript/src/tanstack/index.ts index e74fcf71cfb..f90660992d9 100644 --- a/crates/bindings-typescript/src/tanstack/index.ts +++ b/crates/bindings-typescript/src/tanstack/index.ts @@ -3,14 +3,14 @@ export { spacetimeDBQuery, type SpacetimeDBQueryOptions, type SpacetimeDBQueryOptionsSkipped, -} from './SpacetimeDBQueryClient'; +} from './SpacetimeDBQueryClient.ts'; export { useSpacetimeDBQuery, useSpacetimeDBSuspenseQuery, type UseSpacetimeDBQueryResult, type UseSpacetimeDBSuspenseQueryResult, -} from './hooks'; -export * from '../react/SpacetimeDBProvider'; -export { useSpacetimeDB } from '../react/useSpacetimeDB'; -export { useReducer } from '../react/useReducer'; -export { useProcedure } from '../react/useProcedure'; +} from './hooks.ts'; +export * from '../react/SpacetimeDBProvider.ts'; +export { useSpacetimeDB } from '../react/useSpacetimeDB.ts'; +export { useReducer } from '../react/useReducer.ts'; +export { useProcedure } from '../react/useProcedure.ts'; diff --git a/crates/bindings-typescript/src/vue/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/vue/SpacetimeDBProvider.ts index fffd3091d43..979f1a48f85 100644 --- a/crates/bindings-typescript/src/vue/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/vue/SpacetimeDBProvider.ts @@ -12,12 +12,12 @@ import { type DbConnectionImpl, type ErrorContextInterface, type RemoteModuleOf, -} from '../sdk/db_connection_impl'; -import { ConnectionId } from '../lib/connection_id'; +} from '../sdk/db_connection_impl.ts'; +import { ConnectionId } from '../lib/connection_id.ts'; import { SPACETIMEDB_INJECTION_KEY, type ConnectionState, -} from './connection_state'; +} from './connection_state.ts'; export interface SpacetimeDBProviderProps< DbConnection extends DbConnectionImpl, diff --git a/crates/bindings-typescript/src/vue/connection_state.ts b/crates/bindings-typescript/src/vue/connection_state.ts index aded21a0c52..05b10c2a1d3 100644 --- a/crates/bindings-typescript/src/vue/connection_state.ts +++ b/crates/bindings-typescript/src/vue/connection_state.ts @@ -1,7 +1,7 @@ import type { InjectionKey } from 'vue'; -import type { ConnectionId } from '../lib/connection_id'; -import type { Identity } from '../lib/identity'; -import type { DbConnectionImpl } from '../sdk/db_connection_impl'; +import type { ConnectionId } from '../lib/connection_id.ts'; +import type { Identity } from '../lib/identity.ts'; +import type { DbConnectionImpl } from '../sdk/db_connection_impl.ts'; export interface ConnectionState { isActive: boolean; diff --git a/crates/bindings-typescript/src/vue/useProcedure.ts b/crates/bindings-typescript/src/vue/useProcedure.ts index 385b0c96ae8..f4025d3735f 100644 --- a/crates/bindings-typescript/src/vue/useProcedure.ts +++ b/crates/bindings-typescript/src/vue/useProcedure.ts @@ -1,10 +1,10 @@ import { shallowRef, watch, onUnmounted } from 'vue'; -import { useSpacetimeDB } from './useSpacetimeDB'; -import type { UntypedProcedureDef } from '../sdk/procedures'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; +import type { UntypedProcedureDef } from '../sdk/procedures.ts'; import type { ProcedureParamsType, ProcedureReturnType, -} from '../sdk/type_utils'; +} from '../sdk/type_utils.ts'; export function useProcedure( procedureDef: ProcedureDef diff --git a/crates/bindings-typescript/src/vue/useReducer.ts b/crates/bindings-typescript/src/vue/useReducer.ts index b64ef2324ed..0c4a814da47 100644 --- a/crates/bindings-typescript/src/vue/useReducer.ts +++ b/crates/bindings-typescript/src/vue/useReducer.ts @@ -1,7 +1,7 @@ import { shallowRef, watch, onUnmounted } from 'vue'; -import { useSpacetimeDB } from './useSpacetimeDB'; -import type { UntypedReducerDef } from '../sdk/reducers'; -import type { ParamsType } from '../sdk'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; +import type { UntypedReducerDef } from '../sdk/reducers.ts'; +import type { ParamsType } from '../sdk/index.ts'; export function useReducer( reducerDef: ReducerDef diff --git a/crates/bindings-typescript/src/vue/useSpacetimeDB.ts b/crates/bindings-typescript/src/vue/useSpacetimeDB.ts index 1d80fa8f3a3..01e0ea69b6e 100644 --- a/crates/bindings-typescript/src/vue/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/vue/useSpacetimeDB.ts @@ -2,7 +2,7 @@ import { inject } from 'vue'; import { SPACETIMEDB_INJECTION_KEY, type ConnectionState, -} from './connection_state'; +} from './connection_state.ts'; export function useSpacetimeDB(): ConnectionState { const context = inject(SPACETIMEDB_INJECTION_KEY); diff --git a/crates/bindings-typescript/src/vue/useTable.ts b/crates/bindings-typescript/src/vue/useTable.ts index c0f6fa63848..cd52f3d38cb 100644 --- a/crates/bindings-typescript/src/vue/useTable.ts +++ b/crates/bindings-typescript/src/vue/useTable.ts @@ -7,12 +7,12 @@ import { type DeepReadonly, type Ref, } from 'vue'; -import { useSpacetimeDB } from './useSpacetimeDB'; +import { useSpacetimeDB } from './useSpacetimeDB.ts'; -import type { EventContextInterface } from '../sdk/db_connection_impl'; -import type { UntypedRemoteModule } from '../sdk/spacetime_module'; -import type { RowType, UntypedTableDef } from '../lib/table'; -import type { Prettify } from '../lib/type_util'; +import type { EventContextInterface } from '../sdk/db_connection_impl.ts'; +import type { UntypedRemoteModule } from '../sdk/spacetime_module.ts'; +import type { RowType, UntypedTableDef } from '../lib/table.ts'; +import type { Prettify } from '../lib/type_util.ts'; import { type Query, type BooleanExpr, @@ -20,7 +20,7 @@ import { evaluateBooleanExpr, getQueryAccessorName, getQueryWhereClause, -} from '../lib/query'; +} from '../lib/query.ts'; export interface UseTableCallbacks { onInsert?: (row: RowType) => void; diff --git a/crates/bindings-typescript/tests/consumer/app.ts b/crates/bindings-typescript/tests/consumer/app.ts new file mode 100644 index 00000000000..fb7362d3e2f --- /dev/null +++ b/crates/bindings-typescript/tests/consumer/app.ts @@ -0,0 +1,15 @@ +// A strict app on generated bindings that import the built package, typechecked +// by tests/consumer_types.test.ts. Generated schemas must keep satisfying the +// SDK's own constraints under exactOptionalPropertyTypes. +import { DbConnection } from '../../case-conversion-test-client/src/module_bindings'; + +const conn = DbConnection.builder() + .withUri('ws://localhost:3000') + .withDatabaseName('test') + .build(); + +export const created: Promise = conn.reducers.createPlayer1({ + player1Name: 'player', + start2Level: 1, +}); +export const players = [...conn.db.player1.iter()]; diff --git a/crates/bindings-typescript/tests/consumer/tsconfig.json b/crates/bindings-typescript/tests/consumer/tsconfig.json new file mode 100644 index 00000000000..dc47f1ddf4d --- /dev/null +++ b/crates/bindings-typescript/tests/consumer/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "strict": true, + "exactOptionalPropertyTypes": true, + "skipLibCheck": true, + "noEmit": true, + "target": "ES2022", + "lib": ["ES2022", "DOM"], + "module": "ESNext", + "moduleResolution": "Bundler" + }, + "files": ["app.ts"] +} diff --git a/crates/bindings-typescript/tests/consumer_types.test.ts b/crates/bindings-typescript/tests/consumer_types.test.ts new file mode 100644 index 00000000000..db0d708d217 --- /dev/null +++ b/crates/bindings-typescript/tests/consumer_types.test.ts @@ -0,0 +1,16 @@ +import { spawnSync } from 'node:child_process'; +import { createRequire } from 'node:module'; +import { fileURLToPath } from 'node:url'; +import { expect, test } from 'vitest'; + +// Checks the built `dist` typings, so run `pnpm build` first (CI does). +test('generated bindings typecheck in a strict consumer', () => { + const tsc = createRequire(import.meta.url).resolve('typescript/bin/tsc'); + const project = fileURLToPath( + new URL('./consumer/tsconfig.json', import.meta.url) + ); + const result = spawnSync(process.execPath, [tsc, '-p', project], { + encoding: 'utf8', + }); + expect(result.stdout + result.stderr).toBe(''); +}, 60_000); diff --git a/crates/codegen/examples/regen-typescript-moduledef.rs b/crates/codegen/examples/regen-typescript-moduledef.rs index a3fb1b30f76..faa800365d6 100644 --- a/crates/codegen/examples/regen-typescript-moduledef.rs +++ b/crates/codegen/examples/regen-typescript-moduledef.rs @@ -49,7 +49,7 @@ fn main() -> anyhow::Result<()> { if filename.starts_with("types/") { return Ok(()); } - let code = regex_replace!(&code, r#"from "spacetimedb";"#, r#"from "../../lib/type_builders";"#); + let code = regex_replace!(&code, r#"from "spacetimedb";"#, r#"from "../../lib/type_builders.ts";"#); // Elide types which are related to client-side only things let code = regex_replace!(&code, r"type CallReducerFlags as __CallReducerFlags,", r""); diff --git a/eslint.config.js b/eslint.config.js index ffe5c709e54..da1735a01ee 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -118,6 +118,31 @@ export default tseslint.config( ], }, }, + { + files: ['crates/bindings-typescript/src/**/*.{ts,tsx}'], + rules: { + 'no-restricted-syntax': [ + 'error', + { + selector: 'TSEnumDeclaration', + message: 'Do not use enums; stick to JS-compatible types.', + }, + { + selector: 'TSEnumDeclaration[const=true]', + message: 'Do not use const enum; use unions or objects.', + }, + { selector: 'Decorator', message: 'Do not use decorators.' }, + { + // tsc copies specifiers into the published .d.ts files verbatim, and + // NodeNext consumers cannot resolve extensionless relative imports. + selector: + ':matches(ImportDeclaration, ExportAllDeclaration, ExportNamedDeclaration, ImportExpression)[source.value=/^\\.(?!.*\\.(ts|tsx|js)$)/]', + message: + "Relative imports need an explicit extension (e.g. './foo.ts') so the published types resolve under NodeNext.", + }, + ], + }, + }, { files: ['templates/angular-ts/src/**/*.ts'], rules: { diff --git a/tools/generate-client-api/src/main.rs b/tools/generate-client-api/src/main.rs index 440e06cf6b9..e97c42f1760 100644 --- a/tools/generate-client-api/src/main.rs +++ b/tools/generate-client-api/src/main.rs @@ -48,8 +48,9 @@ fn run_capture(cmd: &str, args: &[&str]) -> Result { fn main() -> Result<()> { let out_dir = "src/sdk/client_api"; - let index_replacement = "../../index"; - let other_replacement = "../../lib/type_builders"; + // Explicit extensions keep the emitted .d.ts files resolvable under NodeNext. + let index_replacement = "../../index.ts"; + let other_replacement = "../../lib/type_builders.ts"; let workspace_dir = Path::new(env!("CARGO_MANIFEST_DIR")) .parent() From b2e4ae6306fbd81f7f2bfe6dca64a37cf796969c Mon Sep 17 00:00:00 2001 From: bradleyshep Date: Thu, 24 Sep 2026 12:40:37 -0400 Subject: [PATCH 2/8] Ship CommonJS type declarations for the TypeScript SDK's require entry points The package is `"type": "module"`, so its .d.ts files are ES module types, yet `require` resolves to the .cjs builds. Under node16 resolution CommonJS consumers were told they were importing an ES module ("Masquerading as ESM" in arethetypeswrong) and could not require it. build:types now mirrors dist/**/*.d.ts as .d.cts, and each entry that ships a .cjs build points its `require` types condition at them. The consumer types test also typechecks a Node ESM and a CommonJS consumer. --- crates/bindings-typescript/package.json | 42 +++++++++++++++---- .../scripts/emit-cjs-types.mjs | 22 ++++++++++ .../tests/consumer/node.cts | 6 +++ .../tests/consumer/node.mts | 8 ++++ .../tests/consumer/tsconfig.node.json | 11 +++++ .../tests/consumer_types.test.ts | 27 +++++++----- 6 files changed, 97 insertions(+), 19 deletions(-) create mode 100644 crates/bindings-typescript/scripts/emit-cjs-types.mjs create mode 100644 crates/bindings-typescript/tests/consumer/node.cts create mode 100644 crates/bindings-typescript/tests/consumer/node.mts create mode 100644 crates/bindings-typescript/tests/consumer/tsconfig.node.json diff --git a/crates/bindings-typescript/package.json b/crates/bindings-typescript/package.json index 7d25339a03e..d8b63eeebda 100644 --- a/crates/bindings-typescript/package.json +++ b/crates/bindings-typescript/package.json @@ -24,7 +24,7 @@ ], "scripts": { "build:js": "tsup", - "build:types": "tsc -p tsconfig.build.json", + "build:types": "tsc -p tsconfig.build.json && node scripts/emit-cjs-types.mjs", "build": "pnpm -s build:js && pnpm -s build:types", "format": "prettier . --write --ignore-path ../../.prettierignore", "lint": "eslint . && prettier . --check --ignore-path ../../.prettierignore", @@ -47,21 +47,30 @@ "types": "dist/index.d.ts", "exports": { ".": { - "types": "./dist/index.d.ts", + "types": { + "require": "./dist/index.d.cts", + "default": "./dist/index.d.ts" + }, "browser": "./dist/index.browser.mjs", "import": "./dist/index.mjs", "require": "./dist/index.cjs", "default": "./dist/index.mjs" }, "./sdk": { - "types": "./dist/index.d.ts", + "types": { + "require": "./dist/index.d.cts", + "default": "./dist/index.d.ts" + }, "browser": "./dist/sdk/index.browser.mjs", "import": "./dist/sdk/index.mjs", "require": "./dist/sdk/index.cjs", "default": "./dist/sdk/index.mjs" }, "./react": { - "types": "./dist/react/index.d.ts", + "types": { + "require": "./dist/react/index.d.cts", + "default": "./dist/react/index.d.ts" + }, "import": "./dist/react/index.mjs", "require": "./dist/react/index.cjs", "default": "./dist/react/index.mjs" @@ -73,31 +82,46 @@ "default": "./dist/server/index.mjs" }, "./vue": { - "types": "./dist/vue/index.d.ts", + "types": { + "require": "./dist/vue/index.d.cts", + "default": "./dist/vue/index.d.ts" + }, "import": "./dist/vue/index.mjs", "require": "./dist/vue/index.cjs", "default": "./dist/vue/index.mjs" }, "./tanstack": { - "types": "./dist/tanstack/index.d.ts", + "types": { + "require": "./dist/tanstack/index.d.cts", + "default": "./dist/tanstack/index.d.ts" + }, "import": "./dist/tanstack/index.mjs", "require": "./dist/tanstack/index.cjs", "default": "./dist/tanstack/index.mjs" }, "./svelte": { - "types": "./dist/svelte/index.d.ts", + "types": { + "require": "./dist/svelte/index.d.cts", + "default": "./dist/svelte/index.d.ts" + }, "import": "./dist/svelte/index.mjs", "require": "./dist/svelte/index.cjs", "default": "./dist/svelte/index.mjs" }, "./angular": { - "types": "./dist/angular/index.d.ts", + "types": { + "require": "./dist/angular/index.d.cts", + "default": "./dist/angular/index.d.ts" + }, "import": "./dist/angular/index.mjs", "require": "./dist/angular/index.cjs", "default": "./dist/angular/index.mjs" }, "./solid": { - "types": "./dist/solid/index.d.ts", + "types": { + "require": "./dist/solid/index.d.cts", + "default": "./dist/solid/index.d.ts" + }, "import": "./dist/solid/index.mjs", "require": "./dist/solid/index.cjs", "default": "./dist/solid/index.mjs" diff --git a/crates/bindings-typescript/scripts/emit-cjs-types.mjs b/crates/bindings-typescript/scripts/emit-cjs-types.mjs new file mode 100644 index 00000000000..8e922299c02 --- /dev/null +++ b/crates/bindings-typescript/scripts/emit-cjs-types.mjs @@ -0,0 +1,22 @@ +// Mirrors dist/**/*.d.ts as .d.cts so `require` consumers get CommonJS type +// declarations. The package is `"type": "module"`, so its .d.ts files are ESM +// types and would otherwise describe the .cjs builds as ES modules. +import { readdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const dist = fileURLToPath(new URL('../dist', import.meta.url)); +const relativeTs = /((?:from\s+|import\()['"]\.{1,2}\/[^'"]+)\.ts(['"])/g; + +for (const entry of readdirSync(dist, { + recursive: true, + withFileTypes: true, +})) { + if (!entry.isFile() || !entry.name.endsWith('.d.ts')) continue; + const file = join(entry.parentPath, entry.name); + const source = readFileSync(file, 'utf8'); + writeFileSync( + file.replace(/\.d\.ts$/, '.d.cts'), + source.replace(relativeTs, '$1.cjs$2') + ); +} diff --git a/crates/bindings-typescript/tests/consumer/node.cts b/crates/bindings-typescript/tests/consumer/node.cts new file mode 100644 index 00000000000..c914a4f2d34 --- /dev/null +++ b/crates/bindings-typescript/tests/consumer/node.cts @@ -0,0 +1,6 @@ +// The CommonJS half of node.mts: `require` resolves the .d.cts types. +import { Identity } from 'spacetimedb'; +import { useTable } from 'spacetimedb/react'; + +export const zero: Identity = Identity.zero(); +export const hook: typeof useTable = useTable; diff --git a/crates/bindings-typescript/tests/consumer/node.mts b/crates/bindings-typescript/tests/consumer/node.mts new file mode 100644 index 00000000000..a293e30cca3 --- /dev/null +++ b/crates/bindings-typescript/tests/consumer/node.mts @@ -0,0 +1,8 @@ +// Node consumers resolve the package from an ES module here and from CommonJS +// in node.cts. The config uses node16, which unlike nodenext rejects CommonJS +// types that are really ES modules. +import { Identity } from 'spacetimedb'; +import { useTable } from 'spacetimedb/react'; + +export const zero: Identity = Identity.zero(); +export const hook: typeof useTable = useTable; diff --git a/crates/bindings-typescript/tests/consumer/tsconfig.node.json b/crates/bindings-typescript/tests/consumer/tsconfig.node.json new file mode 100644 index 00000000000..e79ef21795b --- /dev/null +++ b/crates/bindings-typescript/tests/consumer/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16" + }, + "files": ["node.mts", "node.cts"] +} diff --git a/crates/bindings-typescript/tests/consumer_types.test.ts b/crates/bindings-typescript/tests/consumer_types.test.ts index db0d708d217..1396a105026 100644 --- a/crates/bindings-typescript/tests/consumer_types.test.ts +++ b/crates/bindings-typescript/tests/consumer_types.test.ts @@ -4,13 +4,20 @@ import { fileURLToPath } from 'node:url'; import { expect, test } from 'vitest'; // Checks the built `dist` typings, so run `pnpm build` first (CI does). -test('generated bindings typecheck in a strict consumer', () => { - const tsc = createRequire(import.meta.url).resolve('typescript/bin/tsc'); - const project = fileURLToPath( - new URL('./consumer/tsconfig.json', import.meta.url) - ); - const result = spawnSync(process.execPath, [tsc, '-p', project], { - encoding: 'utf8', - }); - expect(result.stdout + result.stderr).toBe(''); -}, 60_000); +test.each([ + ['generated bindings in a strict consumer', 'tsconfig.json'], + ['Node ESM and CommonJS consumers', 'tsconfig.node.json'], +])( + '%s typecheck', + (_name, config) => { + const tsc = createRequire(import.meta.url).resolve('typescript/bin/tsc'); + const project = fileURLToPath( + new URL(`./consumer/${config}`, import.meta.url) + ); + const result = spawnSync(process.execPath, [tsc, '-p', project], { + encoding: 'utf8', + }); + expect(result.stdout + result.stderr).toBe(''); + }, + 60_000 +); From 4eb78fc1bee8a684c44033a6b251803f9eaf508b Mon Sep 17 00:00:00 2001 From: bradleyshep Date: Thu, 24 Sep 2026 13:49:23 -0400 Subject: [PATCH 3/8] Fail the connection instead of crashing Node when a server message cannot be applied Errors while processing an inbound message, whether an undecodable row (e.g. client bindings out of step with the module's schema) or a user callback that throws, escaped the WebSocket message listener. Browsers only report such errors, but Node rethrows them on the next tick, which killed the host process. The inbound drain now catches them, logs, drops the queued messages, and closes the socket, so `onDisconnect` receives the error the same way it does for a websocket error on an established connection. --- .../src/sdk/db_connection_impl.ts | 10 ++++++ .../tests/db_connection.test.ts | 34 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index fe90776ba0d..4b43d2fc0b3 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -1160,6 +1160,16 @@ export class DbConnectionImpl this.#processMessage(data); } } + } catch (e) { + // A message that fails to apply (undecodable, or a callback threw) + // leaves the client cache inconsistent, and rethrowing from a WebSocket + // listener crashes Node hosts. Fail the connection instead: drop what is + // queued and close, so `onDisconnect` receives the error. + stdbLogger('error', 'Failed to process a server message', e); + this.#connectionError = toError(e); + this.#inboundQueueOffset = this.#inboundQueue.length; + this.isActive = false; + this.ws?.close(); } finally { if (this.#inboundQueueOffset >= this.#inboundQueue.length) { this.#inboundQueue.length = 0; diff --git a/crates/bindings-typescript/tests/db_connection.test.ts b/crates/bindings-typescript/tests/db_connection.test.ts index 9e340637eb8..4bae98fe494 100644 --- a/crates/bindings-typescript/tests/db_connection.test.ts +++ b/crates/bindings-typescript/tests/db_connection.test.ts @@ -213,6 +213,40 @@ describe('DbConnection', () => { expect(client.isActive).toBe(false); }); + test('reports a server message it cannot apply through onDisconnect instead of throwing', async () => { + const onDisconnectPromise = new Deferred(); + const wsAdapter = new WebsocketTestAdapter(); + + const client = DbConnection.builder() + .withUri('ws://127.0.0.1:1234') + .withDatabaseName('db') + .withWSFn(wsAdapter.openWebSocket) + .onConnect(() => { + throw new Error('callback failed'); + }) + .onDisconnect((_ctx, error) => onDisconnectPromise.resolve(error)) + .build(); + + await client['wsPromise']; + wsAdapter.acceptConnection(); + // Node rethrows errors from WebSocket listeners on the next tick, which + // crashes the host process. + expect(() => + wsAdapter.sendToClient( + ServerMessage.InitialConnection({ + identity: anIdentity, + token: 'a-token', + connectionId: ConnectionId.random(), + }) + ) + ).not.toThrow(); + + expect((await onDisconnectPromise.promise)?.message).toBe( + 'callback failed' + ); + expect(client.isActive).toBe(false); + }); + test('marks disconnect as requested when disconnect() is called', async () => { const onDisconnectPromise = new Deferred(); const wsAdapter = new WebsocketTestAdapter(); From 6237c0ea36b39a065b010952b8577cb380726c62 Mon Sep 17 00:00:00 2001 From: bradleyshep Date: Thu, 24 Sep 2026 16:45:35 -0400 Subject: [PATCH 4/8] Type DbConnection.db with a merged interface instead of a declare field Generated TypeScript bindings narrowed `db` with `declare db: DbView;`. Babel rejects `declare` class fields unless `allowDeclareFields` is set, and babel-preset-expo does not set it, so React Native and Expo apps could not bundle generated bindings for any module with snake_case table accessor aliases. Declare the narrowed type on an interface merged into the class instead. It is type-only like before and emits nothing in any transpiler. Updated the codegen snapshot and the checked-in bindings to match. --- .../src/module_bindings/index.ts | 6 ++++-- .../test-app/src/module_bindings/index.ts | 6 ++++-- .../src/module_bindings/index.ts | 6 ++++-- .../test-solid-router/src/module_bindings/index.ts | 6 ++++-- crates/codegen/src/typescript.rs | 13 ++++++++++--- .../snapshots/codegen__codegen_typescript.snap | 6 ++++-- .../client-ts/src/module_bindings/index.ts | 6 ++++-- .../hangman-react-ts/src/module_bindings/index.ts | 6 ++++-- .../src/module_bindings/index.ts | 6 ++++-- 9 files changed, 42 insertions(+), 19 deletions(-) diff --git a/crates/bindings-typescript/case-conversion-test-client/src/module_bindings/index.ts b/crates/bindings-typescript/case-conversion-test-client/src/module_bindings/index.ts index 8fbf73d58d4..82ddf0cb52f 100644 --- a/crates/bindings-typescript/case-conversion-test-client/src/module_bindings/index.ts +++ b/crates/bindings-typescript/case-conversion-test-client/src/module_bindings/index.ts @@ -229,10 +229,12 @@ export class SubscriptionBuilder extends __SubscriptionBuilderImpl< /** Builder class to configure a new database connection to the remote SpacetimeDB instance. */ export class DbConnectionBuilder extends __DbConnectionBuilder {} +export interface DbConnection { + db: DbView; +} + /** The typed database connection to manage connections to the remote SpacetimeDB instance. This class has type information specific to the generated module. */ export class DbConnection extends __DbConnectionImpl { - declare db: DbView; - constructor(config: __DbConnectionConfig) { super(config); this.db = __withTableAccessorAliases(this.db) as DbView; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 5a5cc759b17..cf33870746c 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -249,10 +249,12 @@ export class SubscriptionBuilder extends __SubscriptionBuilderImpl< /** Builder class to configure a new database connection to the remote SpacetimeDB instance. */ export class DbConnectionBuilder extends __DbConnectionBuilder {} +export interface DbConnection { + db: DbView; +} + /** The typed database connection to manage connections to the remote SpacetimeDB instance. This class has type information specific to the generated module. */ export class DbConnection extends __DbConnectionImpl { - declare db: DbView; - constructor(config: __DbConnectionConfig) { super(config); this.db = __withTableAccessorAliases(this.db) as DbView; diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/index.ts index 5a7a64d1e2b..dae611869c6 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/index.ts @@ -227,10 +227,12 @@ export class SubscriptionBuilder extends __SubscriptionBuilderImpl< /** Builder class to configure a new database connection to the remote SpacetimeDB instance. */ export class DbConnectionBuilder extends __DbConnectionBuilder {} +export interface DbConnection { + db: DbView; +} + /** The typed database connection to manage connections to the remote SpacetimeDB instance. This class has type information specific to the generated module. */ export class DbConnection extends __DbConnectionImpl { - declare db: DbView; - constructor(config: __DbConnectionConfig) { super(config); this.db = __withTableAccessorAliases(this.db) as DbView; diff --git a/crates/bindings-typescript/test-solid-router/src/module_bindings/index.ts b/crates/bindings-typescript/test-solid-router/src/module_bindings/index.ts index 5a7a64d1e2b..dae611869c6 100644 --- a/crates/bindings-typescript/test-solid-router/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-solid-router/src/module_bindings/index.ts @@ -227,10 +227,12 @@ export class SubscriptionBuilder extends __SubscriptionBuilderImpl< /** Builder class to configure a new database connection to the remote SpacetimeDB instance. */ export class DbConnectionBuilder extends __DbConnectionBuilder {} +export interface DbConnection { + db: DbView; +} + /** The typed database connection to manage connections to the remote SpacetimeDB instance. This class has type information specific to the generated module. */ export class DbConnection extends __DbConnectionImpl { - declare db: DbView; - constructor(config: __DbConnectionConfig) { super(config); this.db = __withTableAccessorAliases(this.db) as DbView; diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index e2ee468eba4..78247aa03c2 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -754,6 +754,16 @@ impl Lang for TypeScript { ); writeln!(out); + if has_table_accessor_aliases { + // Narrow `db` by merging an interface into the class rather than with a + // `declare` field, which Babel (React Native, Expo) rejects by default. + writeln!(out, "export interface DbConnection {{"); + out.indent(1); + writeln!(out, "db: DbView;"); + out.dedent(1); + writeln!(out, "}}"); + writeln!(out); + } writeln!(out, "/** The typed database connection to manage connections to the remote SpacetimeDB instance. This class has type information specific to the generated module. */"); writeln!( out, @@ -761,9 +771,6 @@ impl Lang for TypeScript { ); out.indent(1); if has_table_accessor_aliases { - writeln!(out, "declare db: DbView;"); - - writeln!(out); writeln!( out, "constructor(config: __DbConnectionConfig) {{" diff --git a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap index 80b88f79b73..e32448cbd40 100644 --- a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap +++ b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap @@ -409,10 +409,12 @@ export class SubscriptionBuilder extends __SubscriptionBuilderImpl {} +export interface DbConnection { + db: DbView; +} + /** The typed database connection to manage connections to the remote SpacetimeDB instance. This class has type information specific to the generated module. */ export class DbConnection extends __DbConnectionImpl { - declare db: DbView; - constructor(config: __DbConnectionConfig) { super(config); this.db = __withTableAccessorAliases(this.db) as DbView; diff --git a/demo/Blackholio/client-ts/src/module_bindings/index.ts b/demo/Blackholio/client-ts/src/module_bindings/index.ts index 81afe450da0..0e7f3e8df74 100644 --- a/demo/Blackholio/client-ts/src/module_bindings/index.ts +++ b/demo/Blackholio/client-ts/src/module_bindings/index.ts @@ -219,10 +219,12 @@ export class SubscriptionBuilder extends __SubscriptionBuilderImpl {} +export interface DbConnection { + db: DbView; +} + /** The typed database connection to manage connections to the remote SpacetimeDB instance. This class has type information specific to the generated module. */ export class DbConnection extends __DbConnectionImpl { - declare db: DbView; - constructor(config: __DbConnectionConfig) { super(config); this.db = __withTableAccessorAliases(this.db) as DbView; diff --git a/templates/hangman-react-ts/src/module_bindings/index.ts b/templates/hangman-react-ts/src/module_bindings/index.ts index 6852d40b6fe..625f44b14a7 100644 --- a/templates/hangman-react-ts/src/module_bindings/index.ts +++ b/templates/hangman-react-ts/src/module_bindings/index.ts @@ -259,10 +259,12 @@ export class SubscriptionBuilder extends __SubscriptionBuilderImpl< /** Builder class to configure a new database connection to the remote SpacetimeDB instance. */ export class DbConnectionBuilder extends __DbConnectionBuilder {} +export interface DbConnection { + db: DbView; +} + /** The typed database connection to manage connections to the remote SpacetimeDB instance. This class has type information specific to the generated module. */ export class DbConnection extends __DbConnectionImpl { - declare db: DbView; - constructor(config: __DbConnectionConfig) { super(config); this.db = __withTableAccessorAliases(this.db) as DbView; diff --git a/templates/money-exchange-react-ts/src/module_bindings/index.ts b/templates/money-exchange-react-ts/src/module_bindings/index.ts index c4bf96e2c56..ee0cd17aa2f 100644 --- a/templates/money-exchange-react-ts/src/module_bindings/index.ts +++ b/templates/money-exchange-react-ts/src/module_bindings/index.ts @@ -229,10 +229,12 @@ export class SubscriptionBuilder extends __SubscriptionBuilderImpl< /** Builder class to configure a new database connection to the remote SpacetimeDB instance. */ export class DbConnectionBuilder extends __DbConnectionBuilder {} +export interface DbConnection { + db: DbView; +} + /** The typed database connection to manage connections to the remote SpacetimeDB instance. This class has type information specific to the generated module. */ export class DbConnection extends __DbConnectionImpl { - declare db: DbView; - constructor(config: __DbConnectionConfig) { super(config); this.db = __withTableAccessorAliases(this.db) as DbView; From e978d068fe085a25ff798b5a487078a5d115ce6d Mon Sep 17 00:00:00 2001 From: bradleyshep Date: Thu, 24 Sep 2026 17:14:55 -0400 Subject: [PATCH 5/8] Let short-lived auth tokens survive reconnects in the TypeScript SDK `withToken` only took a string, and the ConnectionManager re-applies the session's token on every automatic rebuild. For third-party OIDC tokens such as Clerk session JWTs (about a minute of lifetime) that token is the original JWT, so once it expired every reconnect failed with 401 and retried forever. React apps also had no way to switch identity while mounted: `retain()` ignores a new builder once a connection is live. `withToken` now also accepts a `TokenProvider`, a sync or async function that is called on every connection attempt: the initial build, automatic reconnects, resume and zombie revival, and `rebuild()`. Its value is that attempt's token (`undefined` connects anonymously) and `conn.token` reflects it. A throw or rejection reaches `onConnectError`, so the manager retries it with backoff. The manager no longer resumes the session token over a builder with a provider; string tokens resume as before. `TokenProvider` is exported from the package root. The React context gains `reconnect(builder)`, calling `ConnectionManager.rebuild()` like the Svelte provider does. The Clerk guide now passes a provider instead of a token fetched once. --- .../src/react/SpacetimeDBProvider.ts | 11 ++- .../src/react/connection_state.ts | 12 ++- .../src/sdk/connection_manager.ts | 6 +- .../src/sdk/db_connection_builder.ts | 20 ++++- .../src/sdk/db_connection_impl.ts | 40 ++++++--- .../tests/connection_manager_liveness.test.ts | 4 + .../connection_manager_reconnect.test.ts | 90 ++++++++++++++++++- .../bindings-typescript/tests/consumer/app.ts | 1 + .../tests/consumer/node.cts | 3 +- .../tests/consumer/node.mts | 3 +- .../tests/db_connection.test.ts | 46 ++++++++++ .../00500-authentication/00300-Clerk.md | 16 ++-- 12 files changed, 224 insertions(+), 28 deletions(-) diff --git a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts index 22afccf0b15..96c1c61dd5f 100644 --- a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts @@ -64,9 +64,16 @@ export function SpacetimeDBProvider< [key] ); + const reconnect = React.useCallback( + (builder: DbConnectionBuilder) => { + ConnectionManager.rebuild(key, builder); + }, + [key] + ); + const contextValue = React.useMemo( - () => ({ ...state, getConnection }), - [state, getConnection] + () => ({ ...state, getConnection, reconnect }), + [state, getConnection, reconnect] ); React.useEffect(() => { diff --git a/crates/bindings-typescript/src/react/connection_state.ts b/crates/bindings-typescript/src/react/connection_state.ts index f1df5fe9dbb..e2900be5071 100644 --- a/crates/bindings-typescript/src/react/connection_state.ts +++ b/crates/bindings-typescript/src/react/connection_state.ts @@ -1,6 +1,16 @@ -import type { DbConnectionImpl } from '../sdk/db_connection_impl.ts'; +import type { + DbConnectionBuilder, + DbConnectionImpl, +} from '../sdk/db_connection_impl.ts'; import type { ConnectionState as ManagerConnectionState } from '../sdk/connection_manager.ts'; export type ConnectionState = ManagerConnectionState & { getConnection(): DbConnectionImpl | null; + /** + * Tear down the current connection and reconnect using a fresh builder, for + * example to switch identity after sign-in or sign-out. The builder should + * carry the new token and the same uri + database name. Hooks re-bind to the + * new connection automatically. + */ + reconnect(builder: DbConnectionBuilder): void; }; diff --git a/crates/bindings-typescript/src/sdk/connection_manager.ts b/crates/bindings-typescript/src/sdk/connection_manager.ts index 88d7922d090..afbd5f57bd2 100644 --- a/crates/bindings-typescript/src/sdk/connection_manager.ts +++ b/crates/bindings-typescript/src/sdk/connection_manager.ts @@ -315,6 +315,10 @@ class ConnectionManagerImpl { * * Pass `resumeSession: false` when the caller is deliberately changing * identity — see {@link rebuild} — so the builder's own token wins. + * + * A builder with a token provider is never overwritten: the provider is + * called for every attempt and already decides the identity, and resuming + * its last token would reuse a short-lived credential after it expired. */ #buildManagedConnection>( managed: ManagedConnection, @@ -322,7 +326,7 @@ class ConnectionManagerImpl { { resumeSession = true }: { resumeSession?: boolean } = {} ): T { managed.builder = builder; - if (resumeSession && managed.state.token) { + if (resumeSession && managed.state.token && !builder.hasTokenProvider()) { builder.withToken(managed.state.token); } const connection = builder.build(); diff --git a/crates/bindings-typescript/src/sdk/db_connection_builder.ts b/crates/bindings-typescript/src/sdk/db_connection_builder.ts index 610b9f40d92..c03dfdc77e3 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_builder.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_builder.ts @@ -1,6 +1,7 @@ import { DbConnectionImpl, type ConnectionEvent, + type TokenProvider, } from './db_connection_impl.ts'; import { EventEmitter } from './event_emitter.ts'; import type { @@ -25,7 +26,7 @@ export class DbConnectionBuilder> { #uri?: URL; #nameOrAddress?: string; #identity?: Identity; - #token?: string; + #token?: string | TokenProvider; #emitter: EventEmitter = new EventEmitter(); #compression: 'gzip' | 'brotli' | 'none' = 'gzip'; #lightMode: boolean = false; @@ -79,13 +80,28 @@ export class DbConnectionBuilder> { * is optional. You can store the token returned by the `onConnect` callback * to use in future connections. * + * Pass a function instead of a string for short-lived tokens, such as OIDC + * session JWTs. It is called, and may return a promise, on every connection + * attempt, including automatic reconnects by the framework providers, so + * each attempt authenticates with a fresh token. Returning `undefined` + * connects anonymously. + * * @returns The `DbConnectionBuilder` instance. */ - withToken(token?: string): this { + withToken(token?: string | TokenProvider): this { this.#token = token; return this; } + /** + * Whether the token was set as a {@link TokenProvider}. The + * `ConnectionManager` does not resume a session's token over a provider, + * which already decides the identity for each attempt. + */ + hasTokenProvider(): boolean { + return typeof this.#token === 'function'; + } + withWSFn(createWSFn: WebSocketFactory): this { this.#createWSFn = createWSFn; return this; diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index 4b43d2fc0b3..b8121206822 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -98,11 +98,20 @@ export type { export type ConnectionEvent = 'connect' | 'disconnect' | 'connectError'; +/** + * Supplies the auth token for one connection attempt. See + * {@link DbConnectionBuilder.withToken}. + */ +export type TokenProvider = () => + | string + | undefined + | Promise; + export type DbConnectionConfig = { uri: URL; nameOrAddress: string; identity?: Identity; - token?: string; + token?: string | TokenProvider; emitter: EventEmitter; createWSFn: WebSocketFactory; compression: 'gzip' | 'brotli' | 'none'; @@ -327,7 +336,6 @@ export class DbConnectionImpl } this.identity = identity; - this.token = token; this.#remoteModule = remoteModule; this.#emitter = emitter; @@ -388,15 +396,23 @@ export class DbConnectionImpl this.reducers = this.#makeReducers(remoteModule); this.procedures = this.#makeProcedures(remoteModule); - this.wsPromise = createWSFn({ - url, - nameOrAddress, - wsProtocol: [...PREFERRED_WS_PROTOCOLS], - authToken: token, - compression: compression, - lightMode: lightMode, - confirmedReads: confirmedReads, - }) + // A token provider is asked for a fresh token on every attempt, so + // short-lived credentials such as OIDC session JWTs survive reconnects. + // Resolving it inside the chain routes a throw or rejection to + // `onConnectError` rather than out of `build()`. A plain string token is + // assigned synchronously, as before. + this.wsPromise = (async () => { + this.token = typeof token === 'function' ? await token() : token; + return createWSFn({ + url, + nameOrAddress, + wsProtocol: [...PREFERRED_WS_PROTOCOLS], + authToken: this.token, + compression: compression, + lightMode: lightMode, + confirmedReads: confirmedReads, + }); + })() .then(v => { this.ws = v; @@ -423,7 +439,7 @@ export class DbConnectionImpl }) .catch(e => { stdbLogger('error', 'Error connecting to SpacetimeDB WS'); - this.#emitter.emit('connectError', this, e); + this.#emitter.emit('connectError', this, toError(e)); return undefined; }); diff --git a/crates/bindings-typescript/tests/connection_manager_liveness.test.ts b/crates/bindings-typescript/tests/connection_manager_liveness.test.ts index 5c2e1e75c98..fabb9436824 100644 --- a/crates/bindings-typescript/tests/connection_manager_liveness.test.ts +++ b/crates/bindings-typescript/tests/connection_manager_liveness.test.ts @@ -99,6 +99,10 @@ class MockBuilder { return this; } + hasTokenProvider(): boolean { + return false; + } + build(): MockConnection { const connection = new MockConnection(); connection.token = this.token; diff --git a/crates/bindings-typescript/tests/connection_manager_reconnect.test.ts b/crates/bindings-typescript/tests/connection_manager_reconnect.test.ts index ee981ccf2f9..806119974eb 100644 --- a/crates/bindings-typescript/tests/connection_manager_reconnect.test.ts +++ b/crates/bindings-typescript/tests/connection_manager_reconnect.test.ts @@ -1,10 +1,14 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; -import { ConnectionId } from '../src'; +import { ConnectionId, type TokenProvider } from '../src'; +import { ServerMessage } from '../src/sdk/client_api/types.ts'; import { CONNECTION_MANAGER_RECONNECT_MAX_DELAY_MS, connectionManagerReconnectDelayMs, ConnectionManager, } from '../src/sdk/connection_manager.ts'; +import WebsocketTestAdapter from '../src/sdk/websocket_test_adapter.ts'; +import { DbConnection } from '../test-app/src/module_bindings/index.ts'; +import { anIdentity } from './utils.ts'; type ErrorContextInterface = { isActive: boolean; @@ -144,6 +148,10 @@ class MockBuilder { return this; } + hasTokenProvider(): boolean { + return false; + } + build(): MockConnection { const connection = new MockConnection(this.token); this.buildCount += 1; @@ -809,3 +817,83 @@ describe('ConnectionManager session continuity across rebuilds', () => { ConnectionManager.release(key); }); }); + +// These use a real `DbConnection` because the provider is resolved inside it, +// per connection attempt. +describe('ConnectionManager with a token provider', () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.runOnlyPendingTimers(); + vi.useRealTimers(); + }); + + function providerBuilder(provider: TokenProvider) { + const sockets: WebsocketTestAdapter[] = []; + const authTokens: (string | undefined)[] = []; + const builder = DbConnection.builder() + .withUri('ws://127.0.0.1:1234') + .withDatabaseName('db') + .withToken(provider) + .withWSFn(args => { + authTokens.push(args.authToken); + const socket = new WebsocketTestAdapter(); + sockets.push(socket); + return socket.openWebSocket(args); + }); + return { builder, sockets, authTokens }; + } + + test('asks the provider again on reconnect instead of resuming its last token', async () => { + const key = nextKey(); + let issued = 0; + const { builder, sockets, authTokens } = providerBuilder( + async () => `jwt-${++issued}` + ); + + ConnectionManager.retain(key, builder); + await vi.advanceTimersByTimeAsync(0); + sockets[0].acceptConnection(); + sockets[0].sendToClient( + ServerMessage.InitialConnection({ + identity: anIdentity, + token: 'jwt-1', + connectionId: ConnectionId.random(), + }) + ); + expect(ConnectionManager.getSnapshot(key)?.token).toBe('jwt-1'); + + // By now the short-lived token may have expired; the rebuild must not + // resume it. + sockets[0].close(); + await vi.advanceTimersByTimeAsync(connectionManagerReconnectDelayMs(0)); + + expect(authTokens).toEqual(['jwt-1', 'jwt-2']); + + ConnectionManager.release(key); + }); + + test('retries after the provider rejects', async () => { + const key = nextKey(); + const provider = vi + .fn() + .mockRejectedValueOnce(new Error('token fetch failed')) + .mockResolvedValue('jwt'); + const { builder, authTokens } = providerBuilder(provider); + + ConnectionManager.retain(key, builder); + await vi.advanceTimersByTimeAsync(0); + expect(ConnectionManager.getSnapshot(key)?.connectionError?.message).toBe( + 'token fetch failed' + ); + expect(authTokens).toEqual([]); + + await vi.advanceTimersByTimeAsync(connectionManagerReconnectDelayMs(0)); + expect(provider).toHaveBeenCalledTimes(2); + expect(authTokens).toEqual(['jwt']); + + ConnectionManager.release(key); + }); +}); diff --git a/crates/bindings-typescript/tests/consumer/app.ts b/crates/bindings-typescript/tests/consumer/app.ts index fb7362d3e2f..fcae15fc0d6 100644 --- a/crates/bindings-typescript/tests/consumer/app.ts +++ b/crates/bindings-typescript/tests/consumer/app.ts @@ -6,6 +6,7 @@ import { DbConnection } from '../../case-conversion-test-client/src/module_bindi const conn = DbConnection.builder() .withUri('ws://localhost:3000') .withDatabaseName('test') + .withToken(async () => 'token') .build(); export const created: Promise = conn.reducers.createPlayer1({ diff --git a/crates/bindings-typescript/tests/consumer/node.cts b/crates/bindings-typescript/tests/consumer/node.cts index c914a4f2d34..fa2467781ee 100644 --- a/crates/bindings-typescript/tests/consumer/node.cts +++ b/crates/bindings-typescript/tests/consumer/node.cts @@ -1,6 +1,7 @@ // The CommonJS half of node.mts: `require` resolves the .d.cts types. -import { Identity } from 'spacetimedb'; +import { Identity, type TokenProvider } from 'spacetimedb'; import { useTable } from 'spacetimedb/react'; export const zero: Identity = Identity.zero(); export const hook: typeof useTable = useTable; +export const provider: TokenProvider = async () => undefined; diff --git a/crates/bindings-typescript/tests/consumer/node.mts b/crates/bindings-typescript/tests/consumer/node.mts index a293e30cca3..17b2bfade26 100644 --- a/crates/bindings-typescript/tests/consumer/node.mts +++ b/crates/bindings-typescript/tests/consumer/node.mts @@ -1,8 +1,9 @@ // Node consumers resolve the package from an ES module here and from CommonJS // in node.cts. The config uses node16, which unlike nodenext rejects CommonJS // types that are really ES modules. -import { Identity } from 'spacetimedb'; +import { Identity, type TokenProvider } from 'spacetimedb'; import { useTable } from 'spacetimedb/react'; export const zero: Identity = Identity.zero(); export const hook: typeof useTable = useTable; +export const provider: TokenProvider = async () => undefined; diff --git a/crates/bindings-typescript/tests/db_connection.test.ts b/crates/bindings-typescript/tests/db_connection.test.ts index 4bae98fe494..6971525f4b8 100644 --- a/crates/bindings-typescript/tests/db_connection.test.ts +++ b/crates/bindings-typescript/tests/db_connection.test.ts @@ -372,6 +372,52 @@ describe('DbConnection', () => { expect(called).toBeTruthy(); }); + test.each([ + ['sync', (token: string) => token], + ['async', async (token: string) => token], + ])( + 'asks a %s token provider for a fresh token on every build', + async (_kind, provide) => { + let issued = 0; + const authTokens: (string | undefined)[] = []; + const builder = DbConnection.builder() + .withUri('ws://127.0.0.1:1234') + .withDatabaseName('db') + .withToken(() => provide(`token-${++issued}`)) + .withWSFn(args => { + authTokens.push(args.authToken); + return new WebsocketTestAdapter().openWebSocket(args); + }); + + const first = builder.build(); + await first['wsPromise']; + const second = builder.build(); + await second['wsPromise']; + + expect(authTokens).toEqual(['token-1', 'token-2']); + expect(first.token).toBe('token-1'); + expect(second.token).toBe('token-2'); + } + ); + + test('reports a throwing token provider through onConnectError', async () => { + let connectError: Error | undefined; + const client = DbConnection.builder() + .withUri('ws://127.0.0.1:1234') + .withDatabaseName('db') + .withToken(() => { + throw new Error('token fetch failed'); + }) + .withWSFn(new WebsocketTestAdapter().openWebSocket) + .onConnectError((_ctx, error) => { + connectError = error; + }) + .build(); + + await client['wsPromise']; + expect(connectError?.message).toBe('token fetch failed'); + }); + test('batches same-tick reducer calls when v3 is negotiated', async () => { const wsAdapter = new WebsocketTestAdapter(); const client = DbConnection.builder() diff --git a/docs/docs/00200-core-concepts/00500-authentication/00300-Clerk.md b/docs/docs/00200-core-concepts/00500-authentication/00300-Clerk.md index 13df43bf929..f75228cedc3 100644 --- a/docs/docs/00200-core-concepts/00500-authentication/00300-Clerk.md +++ b/docs/docs/00200-core-concepts/00500-authentication/00300-Clerk.md @@ -211,8 +211,10 @@ createRoot(document.getElementById('root')!).render( Update your `App.tsx` file to: -1. Read the Clerk token via `useClerkToken`. -2. Pass it to the `DbConnection` builder using `.withToken(...)`. +1. Get Clerk's `getToken` function via `useAuth`. +2. Pass the `DbConnection` builder a function that calls it, using `.withToken(...)`. + +Clerk session tokens expire after about a minute, so pass a function rather than a token string: the SDK calls it on every connection attempt, including automatic reconnects, and so always authenticates with a fresh token. This mirrors the Auth0 flow: SpacetimeDB receives a bearer token (JWT) and can validate it server-side. @@ -220,10 +222,10 @@ This mirrors the Auth0 flow: SpacetimeDB receives a bearer token (JWT) and can v ```tsx import { useMemo } from 'react'; +import { useAuth } from '@clerk/clerk-react'; import { Identity } from 'spacetimedb'; import { SpacetimeDBProvider } from 'spacetimedb/react'; import { DbConnection, ErrorContext } from './module_bindings'; -import { useClerkToken } from './ClerkTokenProvider'; const onConnect = (_conn: DbConnection, identity: Identity) => { console.log( @@ -241,17 +243,17 @@ const onConnectError = (_ctx: ErrorContext, err: Error) => { }; export default function App() { - const token = useClerkToken(); + const { getToken } = useAuth(); const connectionBuilder = useMemo(() => { return DbConnection.builder() .withUri('') .withDatabaseName('') - .withToken(token) + .withToken(async () => (await getToken()) ?? undefined) .onConnect(onConnect) .onDisconnect(onDisconnect) .onConnectError(onConnectError); - }, [token]); + }, [getToken]); return ( @@ -296,7 +298,7 @@ export function Header() { You are now set up to use **Clerk** authentication in your React application. When users access your app, they will be redirected to Clerk for sign-in, a session token (JWT) will be retrieved in the browser, and that token will be used to authenticate your SpacetimeDB connection. -If you are using **Clerk JWT templates** (recommended for controlling claims/audience/issuer), update the token retrieval line to: +If you are using **Clerk JWT templates** (recommended for controlling claims/audience/issuer), update both `getToken()` calls to: ```ts await getToken({ template: '' }); From 7fe31dfcef46f1e1e8c6260c25adfd3b6a4b62d4 Mon Sep 17 00:00:00 2001 From: bradleyshep Date: Thu, 24 Sep 2026 20:45:16 -0400 Subject: [PATCH 6/8] Negotiate HTTP/2 for procedure HTTPS requests Enable reqwest's `native-tls-alpn` feature so the native-tls connector offers ALPN `h2`. Without it every outbound `ctx.http.fetch` over HTTPS was pinned to HTTP/1.1, and HTTP/2-only APIs such as Apple's APNs (iOS push notifications) could not be reached from modules. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e679f9d8c4a..7db7d3a965d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -285,7 +285,7 @@ rand = "0.9" rayon = "1.8" rayon-core = "1.11.0" regex = "1" -reqwest = { version = "0.12", features = ["stream", "json", "gzip", "brotli"] } +reqwest = { version = "0.12", features = ["stream", "json", "gzip", "brotli", "native-tls-alpn"] } rolldown = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-rc.3" } rolldown_common = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-rc.3" } rolldown_error = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-rc.3" } From ba65b2914957acab45fc6da9c8820c93f22afe14 Mon Sep 17 00:00:00 2001 From: bradleyshep Date: Sat, 26 Sep 2026 11:43:33 -0400 Subject: [PATCH 7/8] Stop re-signed websocket tokens from outliving the original /v1/identity/websocket-token re-signed any token it accepted, its own included, with a fresh iat and an exp 60 s out. Re-signing each copy before it expired renewed a token forever, and modules could never tell when a session token was issued. The copy now keeps the original iat and expires within 60 s but never after the original. --- crates/client-api/src/auth.rs | 43 ++++++++++++++++++++++-- crates/client-api/src/routes/identity.rs | 3 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/crates/client-api/src/auth.rs b/crates/client-api/src/auth.rs index 729d001e2c3..9f40fd4f2ae 100644 --- a/crates/client-api/src/auth.rs +++ b/crates/client-api/src/auth.rs @@ -206,15 +206,23 @@ impl SpacetimeAuth { ) } - // Sign a new token with the same claims and a new expiry. + // Sign a short-lived copy of this token that we will be able to verify. // Note that this will not change the issuer, so the private_key might not match. - // We do this to create short-lived tokens that we will be able to verify. + // The copy keeps the original `iat` and expires within `expiry`, but never after the + // original: re-signing a copy can't renew a token forever, and modules can still tell + // when it was issued. pub fn re_sign_with_expiry( &self, signer: &impl TokenSigner, expiry: Duration, ) -> Result<(SpacetimeIdentityClaims, String), JwtError> { - TokenClaims::from(self.clone()).encode_and_sign_with_expiry(signer, Some(expiry)) + let cap = SystemTime::now() + expiry; + let claims = SpacetimeIdentityClaims { + exp: Some(self.claims.exp.map_or(cap, |exp| exp.min(cap))), + ..self.claims.clone() + }; + let token = signer.sign(&claims)?; + Ok((claims, token)) } } @@ -376,6 +384,35 @@ mod tests { Ok(()) } + // A re-signed copy keeps the original `iat` and never outlives the original token. + #[tokio::test] + async fn re_sign_never_extends_a_token() -> Result<(), anyhow::Error> { + let kp = JwtKeys::generate()?; + let claims = TokenClaims::new("localhost".into(), "test-subject".into()); + let re_sign = |token: String, claims| { + crate::auth::SpacetimeAuth::new(SpacetimeCreds::from_signed_token(token), claims)? + .re_sign_with_expiry(&kp.private, std::time::Duration::from_secs(60)) + .map_err(|e| anyhow!("{e}")) + }; + + let (_, token) = claims.encode_and_sign_with_expiry(&kp.private, Some(std::time::Duration::from_secs(30)))?; + let original = kp.public.validate_token(&token).await?; + let (_, copy) = re_sign(token, original.clone())?; + let copy = kp.public.validate_token(©).await?; + assert_eq!(copy.iat, original.iat); + assert_eq!(copy.exp, original.exp); + + // A token without an expiry gets one, 60 seconds out. + let (_, token) = claims.encode_and_sign(&kp.private)?; + let original = kp.public.validate_token(&token).await?; + let (_, copy) = re_sign(token, original.clone())?; + let copy = kp.public.validate_token(©).await?; + assert_eq!(copy.iat, original.iat); + let exp = copy.exp.ok_or_else(|| anyhow!("no exp"))?; + assert!(exp > std::time::SystemTime::now() + std::time::Duration::from_secs(50)); + Ok(()) + } + #[tokio::test] async fn authorization_rejection_custom_uses_display_message() -> Result<(), anyhow::Error> { let response = diff --git a/crates/client-api/src/routes/identity.rs b/crates/client-api/src/routes/identity.rs index fa42b460561..dfaf73ff779 100644 --- a/crates/client-api/src/routes/identity.rs +++ b/crates/client-api/src/routes/identity.rs @@ -96,7 +96,8 @@ pub struct WebsocketTokenResponse { pub token: String, } -// This endpoint takes a token from a client and sends a newly signed token with a 60s expiry. +// This endpoint takes a token from a client and sends a newly signed copy that expires within +// 60s, never after the original. // Note that even if the token has a different issuer, we will sign it with our key. // This is ok because `FullTokenValidator` checks if we signed the token before worrying about the issuer. pub async fn create_websocket_token( From 925c66de062a2b0a86f33fc45bd2d762c641c9db Mon Sep 17 00:00:00 2001 From: bradleyshep Date: Sat, 26 Sep 2026 18:49:52 -0400 Subject: [PATCH 8/8] Revert "Ship CommonJS type declarations for the TypeScript SDK's require entry points" This reverts commit b2e4ae6306. T3 Code, the consumer these SDK changes were made for, only imports the SDK as an ES module, and typechecks without the .d.cts declarations. The TokenProvider check a later commit added to the removed Node consumer tests moves to the strict consumer app. --- crates/bindings-typescript/package.json | 42 ++++--------------- .../scripts/emit-cjs-types.mjs | 22 ---------- .../bindings-typescript/tests/consumer/app.ts | 2 + .../tests/consumer/node.cts | 7 ---- .../tests/consumer/node.mts | 9 ---- .../tests/consumer/tsconfig.node.json | 11 ----- .../tests/consumer_types.test.ts | 27 +++++------- 7 files changed, 21 insertions(+), 99 deletions(-) delete mode 100644 crates/bindings-typescript/scripts/emit-cjs-types.mjs delete mode 100644 crates/bindings-typescript/tests/consumer/node.cts delete mode 100644 crates/bindings-typescript/tests/consumer/node.mts delete mode 100644 crates/bindings-typescript/tests/consumer/tsconfig.node.json diff --git a/crates/bindings-typescript/package.json b/crates/bindings-typescript/package.json index d8b63eeebda..7d25339a03e 100644 --- a/crates/bindings-typescript/package.json +++ b/crates/bindings-typescript/package.json @@ -24,7 +24,7 @@ ], "scripts": { "build:js": "tsup", - "build:types": "tsc -p tsconfig.build.json && node scripts/emit-cjs-types.mjs", + "build:types": "tsc -p tsconfig.build.json", "build": "pnpm -s build:js && pnpm -s build:types", "format": "prettier . --write --ignore-path ../../.prettierignore", "lint": "eslint . && prettier . --check --ignore-path ../../.prettierignore", @@ -47,30 +47,21 @@ "types": "dist/index.d.ts", "exports": { ".": { - "types": { - "require": "./dist/index.d.cts", - "default": "./dist/index.d.ts" - }, + "types": "./dist/index.d.ts", "browser": "./dist/index.browser.mjs", "import": "./dist/index.mjs", "require": "./dist/index.cjs", "default": "./dist/index.mjs" }, "./sdk": { - "types": { - "require": "./dist/index.d.cts", - "default": "./dist/index.d.ts" - }, + "types": "./dist/index.d.ts", "browser": "./dist/sdk/index.browser.mjs", "import": "./dist/sdk/index.mjs", "require": "./dist/sdk/index.cjs", "default": "./dist/sdk/index.mjs" }, "./react": { - "types": { - "require": "./dist/react/index.d.cts", - "default": "./dist/react/index.d.ts" - }, + "types": "./dist/react/index.d.ts", "import": "./dist/react/index.mjs", "require": "./dist/react/index.cjs", "default": "./dist/react/index.mjs" @@ -82,46 +73,31 @@ "default": "./dist/server/index.mjs" }, "./vue": { - "types": { - "require": "./dist/vue/index.d.cts", - "default": "./dist/vue/index.d.ts" - }, + "types": "./dist/vue/index.d.ts", "import": "./dist/vue/index.mjs", "require": "./dist/vue/index.cjs", "default": "./dist/vue/index.mjs" }, "./tanstack": { - "types": { - "require": "./dist/tanstack/index.d.cts", - "default": "./dist/tanstack/index.d.ts" - }, + "types": "./dist/tanstack/index.d.ts", "import": "./dist/tanstack/index.mjs", "require": "./dist/tanstack/index.cjs", "default": "./dist/tanstack/index.mjs" }, "./svelte": { - "types": { - "require": "./dist/svelte/index.d.cts", - "default": "./dist/svelte/index.d.ts" - }, + "types": "./dist/svelte/index.d.ts", "import": "./dist/svelte/index.mjs", "require": "./dist/svelte/index.cjs", "default": "./dist/svelte/index.mjs" }, "./angular": { - "types": { - "require": "./dist/angular/index.d.cts", - "default": "./dist/angular/index.d.ts" - }, + "types": "./dist/angular/index.d.ts", "import": "./dist/angular/index.mjs", "require": "./dist/angular/index.cjs", "default": "./dist/angular/index.mjs" }, "./solid": { - "types": { - "require": "./dist/solid/index.d.cts", - "default": "./dist/solid/index.d.ts" - }, + "types": "./dist/solid/index.d.ts", "import": "./dist/solid/index.mjs", "require": "./dist/solid/index.cjs", "default": "./dist/solid/index.mjs" diff --git a/crates/bindings-typescript/scripts/emit-cjs-types.mjs b/crates/bindings-typescript/scripts/emit-cjs-types.mjs deleted file mode 100644 index 8e922299c02..00000000000 --- a/crates/bindings-typescript/scripts/emit-cjs-types.mjs +++ /dev/null @@ -1,22 +0,0 @@ -// Mirrors dist/**/*.d.ts as .d.cts so `require` consumers get CommonJS type -// declarations. The package is `"type": "module"`, so its .d.ts files are ESM -// types and would otherwise describe the .cjs builds as ES modules. -import { readdirSync, readFileSync, writeFileSync } from 'node:fs'; -import { join } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const dist = fileURLToPath(new URL('../dist', import.meta.url)); -const relativeTs = /((?:from\s+|import\()['"]\.{1,2}\/[^'"]+)\.ts(['"])/g; - -for (const entry of readdirSync(dist, { - recursive: true, - withFileTypes: true, -})) { - if (!entry.isFile() || !entry.name.endsWith('.d.ts')) continue; - const file = join(entry.parentPath, entry.name); - const source = readFileSync(file, 'utf8'); - writeFileSync( - file.replace(/\.d\.ts$/, '.d.cts'), - source.replace(relativeTs, '$1.cjs$2') - ); -} diff --git a/crates/bindings-typescript/tests/consumer/app.ts b/crates/bindings-typescript/tests/consumer/app.ts index fcae15fc0d6..3eba0ddff36 100644 --- a/crates/bindings-typescript/tests/consumer/app.ts +++ b/crates/bindings-typescript/tests/consumer/app.ts @@ -1,6 +1,7 @@ // A strict app on generated bindings that import the built package, typechecked // by tests/consumer_types.test.ts. Generated schemas must keep satisfying the // SDK's own constraints under exactOptionalPropertyTypes. +import type { TokenProvider } from 'spacetimedb'; import { DbConnection } from '../../case-conversion-test-client/src/module_bindings'; const conn = DbConnection.builder() @@ -14,3 +15,4 @@ export const created: Promise = conn.reducers.createPlayer1({ start2Level: 1, }); export const players = [...conn.db.player1.iter()]; +export const provider: TokenProvider = async () => undefined; diff --git a/crates/bindings-typescript/tests/consumer/node.cts b/crates/bindings-typescript/tests/consumer/node.cts deleted file mode 100644 index fa2467781ee..00000000000 --- a/crates/bindings-typescript/tests/consumer/node.cts +++ /dev/null @@ -1,7 +0,0 @@ -// The CommonJS half of node.mts: `require` resolves the .d.cts types. -import { Identity, type TokenProvider } from 'spacetimedb'; -import { useTable } from 'spacetimedb/react'; - -export const zero: Identity = Identity.zero(); -export const hook: typeof useTable = useTable; -export const provider: TokenProvider = async () => undefined; diff --git a/crates/bindings-typescript/tests/consumer/node.mts b/crates/bindings-typescript/tests/consumer/node.mts deleted file mode 100644 index 17b2bfade26..00000000000 --- a/crates/bindings-typescript/tests/consumer/node.mts +++ /dev/null @@ -1,9 +0,0 @@ -// Node consumers resolve the package from an ES module here and from CommonJS -// in node.cts. The config uses node16, which unlike nodenext rejects CommonJS -// types that are really ES modules. -import { Identity, type TokenProvider } from 'spacetimedb'; -import { useTable } from 'spacetimedb/react'; - -export const zero: Identity = Identity.zero(); -export const hook: typeof useTable = useTable; -export const provider: TokenProvider = async () => undefined; diff --git a/crates/bindings-typescript/tests/consumer/tsconfig.node.json b/crates/bindings-typescript/tests/consumer/tsconfig.node.json deleted file mode 100644 index e79ef21795b..00000000000 --- a/crates/bindings-typescript/tests/consumer/tsconfig.node.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "skipLibCheck": true, - "noEmit": true, - "target": "ES2022", - "module": "Node16", - "moduleResolution": "Node16" - }, - "files": ["node.mts", "node.cts"] -} diff --git a/crates/bindings-typescript/tests/consumer_types.test.ts b/crates/bindings-typescript/tests/consumer_types.test.ts index 1396a105026..db0d708d217 100644 --- a/crates/bindings-typescript/tests/consumer_types.test.ts +++ b/crates/bindings-typescript/tests/consumer_types.test.ts @@ -4,20 +4,13 @@ import { fileURLToPath } from 'node:url'; import { expect, test } from 'vitest'; // Checks the built `dist` typings, so run `pnpm build` first (CI does). -test.each([ - ['generated bindings in a strict consumer', 'tsconfig.json'], - ['Node ESM and CommonJS consumers', 'tsconfig.node.json'], -])( - '%s typecheck', - (_name, config) => { - const tsc = createRequire(import.meta.url).resolve('typescript/bin/tsc'); - const project = fileURLToPath( - new URL(`./consumer/${config}`, import.meta.url) - ); - const result = spawnSync(process.execPath, [tsc, '-p', project], { - encoding: 'utf8', - }); - expect(result.stdout + result.stderr).toBe(''); - }, - 60_000 -); +test('generated bindings typecheck in a strict consumer', () => { + const tsc = createRequire(import.meta.url).resolve('typescript/bin/tsc'); + const project = fileURLToPath( + new URL('./consumer/tsconfig.json', import.meta.url) + ); + const result = spawnSync(process.execPath, [tsc, '-p', project], { + encoding: 'utf8', + }); + expect(result.stdout + result.stderr).toBe(''); +}, 60_000);