From b21168589bfd036479e55bc96320c781b764a7bc Mon Sep 17 00:00:00 2001
From: bradleyshep <148254416+bradleyshep@users.noreply.github.com>
Date: Mon, 26 Jan 2026 15:13:25 -0500
Subject: [PATCH 1/3] Add Node.js quickstart template and documentation
---
.../00200-quickstarts/00300-nodejs.md | 235 ++++++++++++++++++
templates/nodejs-ts/.template.json | 5 +
templates/nodejs-ts/LICENSE | 1 +
templates/nodejs-ts/package.json | 21 ++
templates/nodejs-ts/spacetimedb/package.json | 15 ++
templates/nodejs-ts/spacetimedb/src/index.ts | 33 +++
templates/nodejs-ts/spacetimedb/tsconfig.json | 24 ++
templates/nodejs-ts/src/main.ts | 177 +++++++++++++
.../src/module_bindings/add_reducer.ts | 15 ++
.../nodejs-ts/src/module_bindings/add_type.ts | 15 ++
.../nodejs-ts/src/module_bindings/index.ts | 151 +++++++++++
.../src/module_bindings/init_type.ts | 13 +
.../src/module_bindings/on_connect_reducer.ts | 13 +
.../src/module_bindings/on_connect_type.ts | 13 +
.../module_bindings/on_disconnect_reducer.ts | 13 +
.../src/module_bindings/on_disconnect_type.ts | 13 +
.../src/module_bindings/person_table.ts | 15 ++
.../src/module_bindings/person_type.ts | 15 ++
.../src/module_bindings/say_hello_reducer.ts | 13 +
.../src/module_bindings/say_hello_type.ts | 13 +
templates/nodejs-ts/tsconfig.json | 22 ++
21 files changed, 835 insertions(+)
create mode 100644 docs/docs/00100-intro/00200-quickstarts/00300-nodejs.md
create mode 100644 templates/nodejs-ts/.template.json
create mode 100644 templates/nodejs-ts/LICENSE
create mode 100644 templates/nodejs-ts/package.json
create mode 100644 templates/nodejs-ts/spacetimedb/package.json
create mode 100644 templates/nodejs-ts/spacetimedb/src/index.ts
create mode 100644 templates/nodejs-ts/spacetimedb/tsconfig.json
create mode 100644 templates/nodejs-ts/src/main.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/add_reducer.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/add_type.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/index.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/init_type.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/on_connect_reducer.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/on_connect_type.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/on_disconnect_reducer.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/on_disconnect_type.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/person_table.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/person_type.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/say_hello_reducer.ts
create mode 100644 templates/nodejs-ts/src/module_bindings/say_hello_type.ts
create mode 100644 templates/nodejs-ts/tsconfig.json
diff --git a/docs/docs/00100-intro/00200-quickstarts/00300-nodejs.md b/docs/docs/00100-intro/00200-quickstarts/00300-nodejs.md
new file mode 100644
index 00000000000..83c7b54b9ac
--- /dev/null
+++ b/docs/docs/00100-intro/00200-quickstarts/00300-nodejs.md
@@ -0,0 +1,235 @@
+---
+title: Node.js Quickstart
+sidebar_label: Node.js
+slug: /quickstarts/nodejs
+hide_table_of_contents: true
+---
+
+import { InstallCardLink } from "@site/src/components/InstallCardLink";
+import { StepByStep, Step, StepText, StepCode } from "@site/src/components/Steps";
+
+
+Get a SpacetimeDB Node.js app running in under 5 minutes.
+
+## Prerequisites
+
+- [Node.js](https://nodejs.org/) 18+ installed
+- [SpacetimeDB CLI](https://spacetimedb.com/install) installed
+
+
+
+---
+
+
+
+
+ Run the `spacetime dev` command to create a new project with a SpacetimeDB module and Node.js client.
+
+ This will start the local SpacetimeDB server, publish your module, and generate TypeScript bindings.
+
+
+```bash
+spacetime dev --template nodejs-ts
+```
+
+
+
+
+
+ Your project contains both server and client code.
+
+ Edit `spacetimedb/src/index.ts` to add tables and reducers. Edit `src/main.ts` to build your Node.js client.
+
+
+```
+my-spacetime-app/
+├── spacetimedb/ # Your SpacetimeDB module
+│ └── src/
+│ └── index.ts # Server-side logic
+├── src/
+│ ├── main.ts # Node.js client script
+│ └── module_bindings/ # Auto-generated types
+└── package.json
+```
+
+
+
+
+
+ Open `spacetimedb/src/index.ts` to see the module code. The template includes a `person` table and two reducers: `add` to insert a person, and `say_hello` to greet everyone.
+
+ Tables store your data. Reducers are functions that modify data — they're the only way to write to the database.
+
+
+```typescript
+import { schema, table, t } from 'spacetimedb/server';
+
+export const spacetimedb = schema(
+ table(
+ { name: 'person', public: true },
+ {
+ name: t.string(),
+ }
+ )
+);
+
+spacetimedb.reducer('add', { name: t.string() }, (ctx, { name }) => {
+ ctx.db.person.insert({ name });
+});
+
+spacetimedb.reducer('say_hello', (ctx) => {
+ for (const person of ctx.db.person.iter()) {
+ console.info(`Hello, ${person.name}!`);
+ }
+ console.info('Hello, World!');
+});
+```
+
+
+
+
+
+ In a new terminal, run the Node.js client. It will connect to SpacetimeDB and start an interactive CLI where you can add people and query the database.
+
+
+```bash
+# Run with auto-reload during development
+npm run dev
+
+# Or run once
+npm run start
+```
+
+
+
+
+
+ The client provides a command-line interface to interact with your SpacetimeDB module. Type a name to add a person, or use the built-in commands.
+
+
+```
+Connecting to SpacetimeDB...
+ URI: ws://localhost:3000
+ Module: nodejs-ts
+
+Connected to SpacetimeDB!
+Identity: abc123def456...
+
+Current people (0):
+ (none yet)
+
+Commands:
+ - Add a person with that name
+ list - Show all people
+ hello - Greet everyone (check server logs)
+ Ctrl+C - Quit
+
+> Alice
+[Added] Alice
+
+> Bob
+[Added] Bob
+
+> list
+People in database:
+ - Alice
+ - Bob
+
+> hello
+Called say_hello reducer (check server logs)
+```
+
+
+
+
+
+ Open `src/main.ts` to see the Node.js client. It uses `DbConnection.builder()` to connect to SpacetimeDB, subscribes to tables, and sets up the interactive CLI using Node's `readline` module.
+
+ Unlike browser apps, Node.js stores the authentication token in a file instead of localStorage.
+
+
+```typescript
+import { DbConnection } from './module_bindings/index.js';
+
+// Build and establish connection
+const conn = DbConnection.builder()
+ .withUri(HOST)
+ .withModuleName(DB_NAME)
+ .withToken(loadToken()) // Load saved token from file
+ .onConnect((conn, identity, token) => {
+ console.log('Connected! Identity:', identity.toHexString());
+ saveToken(token); // Save token for future connections
+
+ // Subscribe to all tables
+ conn.subscriptionBuilder()
+ .onApplied((ctx) => {
+ // Show current data, start CLI
+ setupCLI();
+ })
+ .subscribeToAllTables();
+
+ // Listen for table changes
+ conn.db.person.onInsert((ctx, person) => {
+ console.log(`[Added] ${person.name}`);
+ });
+ })
+ .build();
+```
+
+
+
+
+
+ You can also use the SpacetimeDB CLI to call reducers and query your data directly. Changes made via the CLI will appear in your Node.js client in real-time.
+
+
+```bash
+# Call the add reducer to insert a person
+spacetime call add Charlie
+
+# Query the person table
+spacetime sql "SELECT * FROM person"
+ name
+---------
+ "Alice"
+ "Bob"
+ "Charlie"
+
+# Call say_hello to greet everyone
+spacetime call say_hello
+
+# View the module logs
+spacetime logs
+2025-01-13T12:00:00.000000Z INFO: Hello, Alice!
+2025-01-13T12:00:00.000000Z INFO: Hello, Bob!
+2025-01-13T12:00:00.000000Z INFO: Hello, Charlie!
+2025-01-13T12:00:00.000000Z INFO: Hello, World!
+```
+
+
+
+
+
+ **WebSocket support:** Node.js 22+ has native WebSocket support. For Node.js 18-21, the SDK automatically uses the `undici` package (included in devDependencies).
+
+ **Environment variables:** Configure the connection using `SPACETIMEDB_HOST` and `SPACETIMEDB_DB_NAME` environment variables.
+
+ **Graceful shutdown:** The template includes signal handlers for `SIGINT` and `SIGTERM` to cleanly disconnect when stopping the process.
+
+
+```bash
+# Configure via environment variables
+SPACETIMEDB_HOST=ws://localhost:3000 \
+SPACETIMEDB_DB_NAME=my-app \
+npm run start
+
+# Or use a .env file with dotenv
+```
+
+
+
+
+## Next steps
+
+- See the [Chat App Tutorial](/tutorials/chat-app) for a complete example
+- Read the [TypeScript SDK Reference](/sdks/typescript) for detailed API docs
diff --git a/templates/nodejs-ts/.template.json b/templates/nodejs-ts/.template.json
new file mode 100644
index 00000000000..af38af2c866
--- /dev/null
+++ b/templates/nodejs-ts/.template.json
@@ -0,0 +1,5 @@
+{
+ "description": "Node.js TypeScript client and server template",
+ "client_lang": "typescript",
+ "server_lang": "typescript"
+}
diff --git a/templates/nodejs-ts/LICENSE b/templates/nodejs-ts/LICENSE
new file mode 100644
index 00000000000..039e117dde2
--- /dev/null
+++ b/templates/nodejs-ts/LICENSE
@@ -0,0 +1 @@
+../../licenses/apache2.txt
\ No newline at end of file
diff --git a/templates/nodejs-ts/package.json b/templates/nodejs-ts/package.json
new file mode 100644
index 00000000000..9b87a1c7750
--- /dev/null
+++ b/templates/nodejs-ts/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "@clockworklabs/nodejs-ts",
+ "private": true,
+ "version": "0.0.1",
+ "type": "module",
+ "scripts": {
+ "dev": "tsx watch src/main.ts",
+ "start": "tsx src/main.ts",
+ "build": "tsc",
+ "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb"
+ },
+ "dependencies": {
+ "spacetimedb": "workspace:*"
+ },
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "tsx": "^4.19.0",
+ "typescript": "~5.6.2",
+ "undici": "^6.19.2"
+ }
+}
diff --git a/templates/nodejs-ts/spacetimedb/package.json b/templates/nodejs-ts/spacetimedb/package.json
new file mode 100644
index 00000000000..214ccc569bf
--- /dev/null
+++ b/templates/nodejs-ts/spacetimedb/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "spacetime-module",
+ "version": "1.0.0",
+ "description": "",
+ "scripts": {
+ "build": "spacetime build",
+ "publish": "spacetime publish"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "spacetimedb": "1.*"
+ }
+}
diff --git a/templates/nodejs-ts/spacetimedb/src/index.ts b/templates/nodejs-ts/spacetimedb/src/index.ts
new file mode 100644
index 00000000000..3a5ddbc8257
--- /dev/null
+++ b/templates/nodejs-ts/spacetimedb/src/index.ts
@@ -0,0 +1,33 @@
+import { schema, table, t } from 'spacetimedb/server';
+
+export const spacetimedb = schema(
+ table(
+ { name: 'person', public: true },
+ {
+ name: t.string(),
+ }
+ )
+);
+
+spacetimedb.init(_ctx => {
+ // Called when the module is initially published
+});
+
+spacetimedb.clientConnected(_ctx => {
+ // Called every time a new client connects
+});
+
+spacetimedb.clientDisconnected(_ctx => {
+ // Called every time a client disconnects
+});
+
+spacetimedb.reducer('add', { name: t.string() }, (ctx, { name }) => {
+ ctx.db.person.insert({ name });
+});
+
+spacetimedb.reducer('say_hello', ctx => {
+ for (const person of ctx.db.person.iter()) {
+ console.info(`Hello, ${person.name}!`);
+ }
+ console.info('Hello, World!');
+});
diff --git a/templates/nodejs-ts/spacetimedb/tsconfig.json b/templates/nodejs-ts/spacetimedb/tsconfig.json
new file mode 100644
index 00000000000..6283107337e
--- /dev/null
+++ b/templates/nodejs-ts/spacetimedb/tsconfig.json
@@ -0,0 +1,24 @@
+
+/*
+ * This tsconfig is used for TypeScript projects created with `spacetimedb init
+ * --lang typescript`. You can modify it as needed for your project, although
+ * some options are required by SpacetimeDB.
+ */
+{
+ "compilerOptions": {
+ "strict": true,
+ "skipLibCheck": true,
+ "moduleResolution": "bundler",
+ "jsx": "react-jsx",
+
+ /* The following options are required by SpacetimeDB
+ * and should not be modified
+ */
+ "target": "ESNext",
+ "lib": ["ES2021", "dom"],
+ "module": "ESNext",
+ "isolatedModules": true,
+ "noEmit": true
+ },
+ "include": ["./**/*"]
+}
diff --git a/templates/nodejs-ts/src/main.ts b/templates/nodejs-ts/src/main.ts
new file mode 100644
index 00000000000..f9939e073a5
--- /dev/null
+++ b/templates/nodejs-ts/src/main.ts
@@ -0,0 +1,177 @@
+import * as fs from 'fs';
+import * as path from 'path';
+import * as readline from 'readline';
+import { fileURLToPath } from 'url';
+import { Identity } from 'spacetimedb';
+import {
+ DbConnection,
+ ErrorContext,
+ EventContext,
+} from './module_bindings/index.js';
+
+// Configuration
+const HOST = process.env.SPACETIMEDB_HOST ?? 'ws://localhost:3000';
+const DB_NAME = process.env.SPACETIMEDB_DB_NAME ?? 'nodejs-ts';
+
+// Token persistence (file-based for Node.js instead of localStorage)
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const TOKEN_FILE = path.join(__dirname, '..', '.spacetimedb-token');
+
+function loadToken(): string | undefined {
+ try {
+ if (fs.existsSync(TOKEN_FILE)) {
+ return fs.readFileSync(TOKEN_FILE, 'utf-8').trim();
+ }
+ } catch (err) {
+ console.warn('Could not load token:', err);
+ }
+ return undefined;
+}
+
+function saveToken(token: string): void {
+ try {
+ fs.writeFileSync(TOKEN_FILE, token, 'utf-8');
+ } catch (err) {
+ console.warn('Could not save token:', err);
+ }
+}
+
+// Connection state
+let conn: DbConnection | null = null;
+let isReady = false;
+
+// Setup interactive CLI
+function setupCLI(): void {
+ const rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ });
+
+ console.log('\nCommands:');
+ console.log(' - Add a person with that name');
+ console.log(' list - Show all people');
+ console.log(' hello - Greet everyone (check server logs)');
+ console.log(' Ctrl+C - Quit\n');
+
+ rl.on('line', input => {
+ const text = input.trim();
+ if (!text || !conn || !isReady) return;
+
+ if (text.toLowerCase() === 'list') {
+ console.log('\nPeople in database:');
+ let count = 0;
+ for (const person of conn.db.person.iter()) {
+ console.log(` - ${person.name}`);
+ count++;
+ }
+ if (count === 0) {
+ console.log(' (none)');
+ }
+ console.log();
+ } else if (text.toLowerCase() === 'hello') {
+ conn.reducers.sayHello({});
+ console.log('Called say_hello reducer (check server logs)\n');
+ } else {
+ conn.reducers.add({ name: text });
+ }
+ });
+
+ rl.on('close', shutdown);
+}
+
+// Connection callbacks
+function onConnect(
+ _conn: DbConnection,
+ identity: Identity,
+ token: string
+): void {
+ console.log('\nConnected to SpacetimeDB!');
+ console.log(`Identity: ${identity.toHexString().slice(0, 16)}...`);
+
+ // Save token for future connections
+ saveToken(token);
+
+ // Subscribe to all tables
+ _conn
+ .subscriptionBuilder()
+ .onApplied(ctx => {
+ isReady = true;
+
+ // Show current people
+ const people = [...ctx.db.person.iter()];
+ console.log(`\nCurrent people (${people.length}):`);
+ if (people.length === 0) {
+ console.log(' (none yet)');
+ } else {
+ for (const person of people) {
+ console.log(` - ${person.name}`);
+ }
+ }
+
+ setupCLI();
+ })
+ .onError((_ctx, err) => {
+ console.error('Subscription error:', err);
+ })
+ .subscribeToAllTables();
+
+ // Register callbacks for table changes
+ _conn.db.person.onInsert((_ctx: EventContext, person) => {
+ console.log(`[Added] ${person.name}`);
+ });
+
+ _conn.db.person.onDelete((_ctx: EventContext, person) => {
+ console.log(`[Removed] ${person.name}`);
+ });
+}
+
+function onDisconnect(_ctx: ErrorContext, error?: Error): void {
+ isReady = false;
+ if (error) {
+ console.error('Disconnected with error:', error);
+ } else {
+ console.log('Disconnected from SpacetimeDB');
+ }
+}
+
+function onConnectError(_ctx: ErrorContext, error: Error): void {
+ console.error('Connection error:', error);
+ process.exit(1);
+}
+
+// Main entry point
+async function main(): Promise {
+ console.log(`Connecting to SpacetimeDB...`);
+ console.log(` URI: ${HOST}`);
+ console.log(` Module: ${DB_NAME}`);
+
+ const token = loadToken();
+
+ // Build and establish connection
+ conn = DbConnection.builder()
+ .withUri(HOST)
+ .withModuleName(DB_NAME)
+ .withToken(token)
+ .onConnect(onConnect)
+ .onDisconnect(onDisconnect)
+ .onConnectError(onConnectError)
+ .build();
+}
+
+// Graceful shutdown
+function shutdown(): void {
+ console.log('\nShutting down...');
+ if (conn) {
+ conn.disconnect();
+ }
+ process.exit(0);
+}
+
+process.on('SIGINT', shutdown);
+process.on('SIGTERM', shutdown);
+
+// Run the main function
+main().catch(err => {
+ console.error('Fatal error:', err);
+ process.exit(1);
+});
diff --git a/templates/nodejs-ts/src/module_bindings/add_reducer.ts b/templates/nodejs-ts/src/module_bindings/add_reducer.ts
new file mode 100644
index 00000000000..85081559c7d
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/add_reducer.ts
@@ -0,0 +1,15 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default {
+ name: __t.string(),
+};
diff --git a/templates/nodejs-ts/src/module_bindings/add_type.ts b/templates/nodejs-ts/src/module_bindings/add_type.ts
new file mode 100644
index 00000000000..638f62cea39
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/add_type.ts
@@ -0,0 +1,15 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default __t.object('Add', {
+ name: __t.string(),
+});
diff --git a/templates/nodejs-ts/src/module_bindings/index.ts b/templates/nodejs-ts/src/module_bindings/index.ts
new file mode 100644
index 00000000000..5e83bc75b20
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/index.ts
@@ -0,0 +1,151 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+// This was generated using spacetimedb cli version 1.11.3 (commit f9bca6a8df856d950360b40cbce744fcbffc9a63).
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ DbConnectionBuilder as __DbConnectionBuilder,
+ DbConnectionImpl as __DbConnectionImpl,
+ SubscriptionBuilderImpl as __SubscriptionBuilderImpl,
+ TypeBuilder as __TypeBuilder,
+ Uuid as __Uuid,
+ convertToAccessorMap as __convertToAccessorMap,
+ makeQueryBuilder as __makeQueryBuilder,
+ procedureSchema as __procedureSchema,
+ procedures as __procedures,
+ reducerSchema as __reducerSchema,
+ reducers as __reducers,
+ schema as __schema,
+ t as __t,
+ table as __table,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type DbConnectionConfig as __DbConnectionConfig,
+ type ErrorContextInterface as __ErrorContextInterface,
+ type Event as __Event,
+ type EventContextInterface as __EventContextInterface,
+ type Infer as __Infer,
+ type QueryBuilder as __QueryBuilder,
+ type ReducerEventContextInterface as __ReducerEventContextInterface,
+ type RemoteModule as __RemoteModule,
+ type SubscriptionEventContextInterface as __SubscriptionEventContextInterface,
+ type SubscriptionHandleImpl as __SubscriptionHandleImpl,
+} from 'spacetimedb';
+
+// Import and reexport all reducer arg types
+import OnConnectReducer from './on_connect_reducer.js';
+export { OnConnectReducer };
+import OnDisconnectReducer from './on_disconnect_reducer.js';
+export { OnDisconnectReducer };
+import AddReducer from './add_reducer.js';
+export { AddReducer };
+import SayHelloReducer from './say_hello_reducer.js';
+export { SayHelloReducer };
+
+// Import and reexport all procedure arg types
+
+// Import and reexport all table handle types
+import PersonRow from './person_table.js';
+export { PersonRow };
+
+// Import and reexport all types
+import Add from './add_type.js';
+export { Add };
+import Init from './init_type.js';
+export { Init };
+import OnConnect from './on_connect_type.js';
+export { OnConnect };
+import OnDisconnect from './on_disconnect_type.js';
+export { OnDisconnect };
+import Person from './person_type.js';
+export { Person };
+import SayHello from './say_hello_type.js';
+export { SayHello };
+
+/** The schema information for all tables in this module. This is defined the same was as the tables would have been defined in the server. */
+const tablesSchema = __schema(
+ __table(
+ {
+ name: 'person',
+ indexes: [],
+ constraints: [],
+ },
+ PersonRow
+ )
+);
+
+/** The schema information for all reducers in this module. This is defined the same way as the reducers would have been defined in the server, except the body of the reducer is omitted in code generation. */
+const reducersSchema = __reducers(
+ __reducerSchema('add', AddReducer),
+ __reducerSchema('say_hello', SayHelloReducer)
+);
+
+/** The schema information for all procedures in this module. This is defined the same way as the procedures would have been defined in the server. */
+const proceduresSchema = __procedures();
+
+/** The remote SpacetimeDB module schema, both runtime and type information. */
+const REMOTE_MODULE = {
+ versionInfo: {
+ cliVersion: '1.11.3' as const,
+ },
+ tables: tablesSchema.schemaType.tables,
+ reducers: reducersSchema.reducersType.reducers,
+ ...proceduresSchema,
+} satisfies __RemoteModule<
+ typeof tablesSchema.schemaType,
+ typeof reducersSchema.reducersType,
+ typeof proceduresSchema
+>;
+
+/** The tables available in this remote SpacetimeDB module. */
+export const tables = __convertToAccessorMap(tablesSchema.schemaType.tables);
+
+/** A typed query builder for this remote SpacetimeDB module. */
+export const query: __QueryBuilder =
+ __makeQueryBuilder(tablesSchema.schemaType);
+
+/** The reducers available in this remote SpacetimeDB module. */
+export const reducers = __convertToAccessorMap(
+ reducersSchema.reducersType.reducers
+);
+
+/** The context type returned in callbacks for all possible events. */
+export type EventContext = __EventContextInterface;
+/** The context type returned in callbacks for reducer events. */
+export type ReducerEventContext = __ReducerEventContextInterface<
+ typeof REMOTE_MODULE
+>;
+/** The context type returned in callbacks for subscription events. */
+export type SubscriptionEventContext = __SubscriptionEventContextInterface<
+ typeof REMOTE_MODULE
+>;
+/** The context type returned in callbacks for error events. */
+export type ErrorContext = __ErrorContextInterface;
+/** The subscription handle type to manage active subscriptions created from a {@link SubscriptionBuilder}. */
+export type SubscriptionHandle = __SubscriptionHandleImpl;
+
+/** Builder class to configure a new subscription to the remote SpacetimeDB instance. */
+export class SubscriptionBuilder extends __SubscriptionBuilderImpl<
+ typeof REMOTE_MODULE
+> {}
+
+/** Builder class to configure a new database connection to the remote SpacetimeDB instance. */
+export class DbConnectionBuilder extends __DbConnectionBuilder {}
+
+/** 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 {
+ /** Creates a new {@link DbConnectionBuilder} to configure and connect to the remote SpacetimeDB instance. */
+ static builder = (): DbConnectionBuilder => {
+ return new DbConnectionBuilder(
+ REMOTE_MODULE,
+ (config: __DbConnectionConfig) =>
+ new DbConnection(config)
+ );
+ };
+
+ /** Creates a new {@link SubscriptionBuilder} to configure a subscription to the remote SpacetimeDB instance. */
+ override subscriptionBuilder = (): SubscriptionBuilder => {
+ return new SubscriptionBuilder(this);
+ };
+}
diff --git a/templates/nodejs-ts/src/module_bindings/init_type.ts b/templates/nodejs-ts/src/module_bindings/init_type.ts
new file mode 100644
index 00000000000..52ed691ed94
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/init_type.ts
@@ -0,0 +1,13 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default __t.object('Init', {});
diff --git a/templates/nodejs-ts/src/module_bindings/on_connect_reducer.ts b/templates/nodejs-ts/src/module_bindings/on_connect_reducer.ts
new file mode 100644
index 00000000000..2ca99c88fea
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/on_connect_reducer.ts
@@ -0,0 +1,13 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default {};
diff --git a/templates/nodejs-ts/src/module_bindings/on_connect_type.ts b/templates/nodejs-ts/src/module_bindings/on_connect_type.ts
new file mode 100644
index 00000000000..d36362515de
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/on_connect_type.ts
@@ -0,0 +1,13 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default __t.object('OnConnect', {});
diff --git a/templates/nodejs-ts/src/module_bindings/on_disconnect_reducer.ts b/templates/nodejs-ts/src/module_bindings/on_disconnect_reducer.ts
new file mode 100644
index 00000000000..2ca99c88fea
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/on_disconnect_reducer.ts
@@ -0,0 +1,13 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default {};
diff --git a/templates/nodejs-ts/src/module_bindings/on_disconnect_type.ts b/templates/nodejs-ts/src/module_bindings/on_disconnect_type.ts
new file mode 100644
index 00000000000..efda71ebcfd
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/on_disconnect_type.ts
@@ -0,0 +1,13 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default __t.object('OnDisconnect', {});
diff --git a/templates/nodejs-ts/src/module_bindings/person_table.ts b/templates/nodejs-ts/src/module_bindings/person_table.ts
new file mode 100644
index 00000000000..0f70f74f617
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/person_table.ts
@@ -0,0 +1,15 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default __t.row({
+ name: __t.string(),
+});
diff --git a/templates/nodejs-ts/src/module_bindings/person_type.ts b/templates/nodejs-ts/src/module_bindings/person_type.ts
new file mode 100644
index 00000000000..1156775a3cf
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/person_type.ts
@@ -0,0 +1,15 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default __t.object('Person', {
+ name: __t.string(),
+});
diff --git a/templates/nodejs-ts/src/module_bindings/say_hello_reducer.ts b/templates/nodejs-ts/src/module_bindings/say_hello_reducer.ts
new file mode 100644
index 00000000000..2ca99c88fea
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/say_hello_reducer.ts
@@ -0,0 +1,13 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default {};
diff --git a/templates/nodejs-ts/src/module_bindings/say_hello_type.ts b/templates/nodejs-ts/src/module_bindings/say_hello_type.ts
new file mode 100644
index 00000000000..6293ca6bd09
--- /dev/null
+++ b/templates/nodejs-ts/src/module_bindings/say_hello_type.ts
@@ -0,0 +1,13 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
+
+/* eslint-disable */
+/* tslint:disable */
+import {
+ TypeBuilder as __TypeBuilder,
+ t as __t,
+ type AlgebraicTypeType as __AlgebraicTypeType,
+ type Infer as __Infer,
+} from 'spacetimedb';
+
+export default __t.object('SayHello', {});
diff --git a/templates/nodejs-ts/tsconfig.json b/templates/nodejs-ts/tsconfig.json
new file mode 100644
index 00000000000..2992457d9d5
--- /dev/null
+++ b/templates/nodejs-ts/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext",
+ "lib": ["ES2022"],
+ "outDir": "dist",
+ "rootDir": "src",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "declaration": true,
+ "declarationMap": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"],
+ "exclude": ["node_modules", "dist"]
+}
From 5c174f0cd0d0142c4455777e24eb606141993d32 Mon Sep 17 00:00:00 2001
From: bradleyshep <148254416+bradleyshep@users.noreply.github.com>
Date: Mon, 2 Feb 2026 16:44:58 -0500
Subject: [PATCH 2/3] cleanup (simplifications, code reorg)
---
.../00200-quickstarts/00300-nodejs.md | 85 +++++---
templates/nodejs-ts/src/main.ts | 184 ++++++++----------
2 files changed, 138 insertions(+), 131 deletions(-)
diff --git a/docs/docs/00100-intro/00200-quickstarts/00300-nodejs.md b/docs/docs/00100-intro/00200-quickstarts/00300-nodejs.md
index 83c7b54b9ac..e26004d861b 100644
--- a/docs/docs/00100-intro/00200-quickstarts/00300-nodejs.md
+++ b/docs/docs/00100-intro/00200-quickstarts/00300-nodejs.md
@@ -8,7 +8,6 @@ hide_table_of_contents: true
import { InstallCardLink } from "@site/src/components/InstallCardLink";
import { StepByStep, Step, StepText, StepCode } from "@site/src/components/Steps";
-
Get a SpacetimeDB Node.js app running in under 5 minutes.
## Prerequisites
@@ -28,10 +27,13 @@ Get a SpacetimeDB Node.js app running in under 5 minutes.
This will start the local SpacetimeDB server, publish your module, and generate TypeScript bindings.
+
```bash
spacetime dev --template nodejs-ts
```
+
+
@@ -41,6 +43,7 @@ spacetime dev --template nodejs-ts
Edit `spacetimedb/src/index.ts` to add tables and reducers. Edit `src/main.ts` to build your Node.js client.
+
```
my-spacetime-app/
├── spacetimedb/ # Your SpacetimeDB module
@@ -51,7 +54,9 @@ my-spacetime-app/
│ └── module_bindings/ # Auto-generated types
└── package.json
```
+
+
@@ -61,6 +66,7 @@ my-spacetime-app/
Tables store your data. Reducers are functions that modify data — they're the only way to write to the database.
+
```typescript
import { schema, table, t } from 'spacetimedb/server';
@@ -77,14 +83,16 @@ spacetimedb.reducer('add', { name: t.string() }, (ctx, { name }) => {
ctx.db.person.insert({ name });
});
-spacetimedb.reducer('say_hello', (ctx) => {
+spacetimedb.reducer('say_hello', ctx => {
for (const person of ctx.db.person.iter()) {
console.info(`Hello, ${person.name}!`);
}
console.info('Hello, World!');
});
```
+
+
@@ -97,7 +105,9 @@ spacetimedb.reducer('say_hello', (ctx) => {
npm run dev
# Or run once
+
npm run start
+
```
@@ -108,36 +118,39 @@ npm run start
```
+
Connecting to SpacetimeDB...
- URI: ws://localhost:3000
- Module: nodejs-ts
+URI: ws://localhost:3000
+Module: nodejs-ts
Connected to SpacetimeDB!
Identity: abc123def456...
Current people (0):
- (none yet)
+(none yet)
Commands:
- - Add a person with that name
- list - Show all people
- hello - Greet everyone (check server logs)
- Ctrl+C - Quit
+ - Add a person with that name
+list - Show all people
+hello - Greet everyone (check server logs)
+Ctrl+C - Quit
> Alice
-[Added] Alice
+> [Added] Alice
> Bob
-[Added] Bob
+> [Added] Bob
> list
-People in database:
- - Alice
- - Bob
+> People in database:
+
+- Alice
+- Bob
> hello
-Called say_hello reducer (check server logs)
-```
+> Called say_hello reducer (check server logs)
+
+````
@@ -152,7 +165,7 @@ Called say_hello reducer (check server logs)
import { DbConnection } from './module_bindings/index.js';
// Build and establish connection
-const conn = DbConnection.builder()
+DbConnection.builder()
.withUri(HOST)
.withModuleName(DB_NAME)
.withToken(loadToken()) // Load saved token from file
@@ -164,7 +177,7 @@ const conn = DbConnection.builder()
conn.subscriptionBuilder()
.onApplied((ctx) => {
// Show current data, start CLI
- setupCLI();
+ setupCLI(conn);
})
.subscribeToAllTables();
@@ -174,8 +187,10 @@ const conn = DbConnection.builder()
});
})
.build();
-```
+````
+
+
@@ -188,23 +203,29 @@ const conn = DbConnection.builder()
spacetime call add Charlie
# Query the person table
-spacetime sql "SELECT * FROM person"
- name
----------
- "Alice"
- "Bob"
- "Charlie"
+
+spacetime sql "SELECT \* FROM person"
+name
+
+---
+
+"Alice"
+"Bob"
+"Charlie"
# Call say_hello to greet everyone
+
spacetime call say_hello
# View the module logs
+
spacetime logs
-2025-01-13T12:00:00.000000Z INFO: Hello, Alice!
-2025-01-13T12:00:00.000000Z INFO: Hello, Bob!
-2025-01-13T12:00:00.000000Z INFO: Hello, Charlie!
-2025-01-13T12:00:00.000000Z INFO: Hello, World!
-```
+2025-01-13T12:00:00.000000Z INFO: Hello, Alice!
+2025-01-13T12:00:00.000000Z INFO: Hello, Bob!
+2025-01-13T12:00:00.000000Z INFO: Hello, Charlie!
+2025-01-13T12:00:00.000000Z INFO: Hello, World!
+
+````
@@ -224,8 +245,10 @@ SPACETIMEDB_DB_NAME=my-app \
npm run start
# Or use a .env file with dotenv
-```
+````
+
+
diff --git a/templates/nodejs-ts/src/main.ts b/templates/nodejs-ts/src/main.ts
index f9939e073a5..a25757ca752 100644
--- a/templates/nodejs-ts/src/main.ts
+++ b/templates/nodejs-ts/src/main.ts
@@ -13,75 +13,30 @@ import {
const HOST = process.env.SPACETIMEDB_HOST ?? 'ws://localhost:3000';
const DB_NAME = process.env.SPACETIMEDB_DB_NAME ?? 'nodejs-ts';
-// Token persistence (file-based for Node.js instead of localStorage)
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-const TOKEN_FILE = path.join(__dirname, '..', '.spacetimedb-token');
-
-function loadToken(): string | undefined {
- try {
- if (fs.existsSync(TOKEN_FILE)) {
- return fs.readFileSync(TOKEN_FILE, 'utf-8').trim();
- }
- } catch (err) {
- console.warn('Could not load token:', err);
- }
- return undefined;
-}
+// Main entry point
+async function main(): Promise {
+ console.log(`Connecting to SpacetimeDB...`);
+ console.log(` URI: ${HOST}`);
+ console.log(` Module: ${DB_NAME}`);
-function saveToken(token: string): void {
- try {
- fs.writeFileSync(TOKEN_FILE, token, 'utf-8');
- } catch (err) {
- console.warn('Could not save token:', err);
- }
+ // Build and establish connection
+ DbConnection.builder()
+ .withUri(HOST)
+ .withModuleName(DB_NAME)
+ .withToken(loadToken())
+ .onConnect(onConnect)
+ .onDisconnect(onDisconnect)
+ .onConnectError(onConnectError)
+ .build();
}
-// Connection state
-let conn: DbConnection | null = null;
-let isReady = false;
-
-// Setup interactive CLI
-function setupCLI(): void {
- const rl = readline.createInterface({
- input: process.stdin,
- output: process.stdout,
- });
-
- console.log('\nCommands:');
- console.log(' - Add a person with that name');
- console.log(' list - Show all people');
- console.log(' hello - Greet everyone (check server logs)');
- console.log(' Ctrl+C - Quit\n');
-
- rl.on('line', input => {
- const text = input.trim();
- if (!text || !conn || !isReady) return;
-
- if (text.toLowerCase() === 'list') {
- console.log('\nPeople in database:');
- let count = 0;
- for (const person of conn.db.person.iter()) {
- console.log(` - ${person.name}`);
- count++;
- }
- if (count === 0) {
- console.log(' (none)');
- }
- console.log();
- } else if (text.toLowerCase() === 'hello') {
- conn.reducers.sayHello({});
- console.log('Called say_hello reducer (check server logs)\n');
- } else {
- conn.reducers.add({ name: text });
- }
- });
-
- rl.on('close', shutdown);
-}
+main().catch(err => {
+ console.error('Fatal error:', err);
+ process.exit(1);
+});
-// Connection callbacks
function onConnect(
- _conn: DbConnection,
+ conn: DbConnection,
identity: Identity,
token: string
): void {
@@ -92,11 +47,9 @@ function onConnect(
saveToken(token);
// Subscribe to all tables
- _conn
+ conn
.subscriptionBuilder()
.onApplied(ctx => {
- isReady = true;
-
// Show current people
const people = [...ctx.db.person.iter()];
console.log(`\nCurrent people (${people.length}):`);
@@ -108,7 +61,7 @@ function onConnect(
}
}
- setupCLI();
+ setupCLI(conn);
})
.onError((_ctx, err) => {
console.error('Subscription error:', err);
@@ -116,17 +69,16 @@ function onConnect(
.subscribeToAllTables();
// Register callbacks for table changes
- _conn.db.person.onInsert((_ctx: EventContext, person) => {
+ conn.db.person.onInsert((_ctx: EventContext, person) => {
console.log(`[Added] ${person.name}`);
});
- _conn.db.person.onDelete((_ctx: EventContext, person) => {
+ conn.db.person.onDelete((_ctx: EventContext, person) => {
console.log(`[Removed] ${person.name}`);
});
}
function onDisconnect(_ctx: ErrorContext, error?: Error): void {
- isReady = false;
if (error) {
console.error('Disconnected with error:', error);
} else {
@@ -139,39 +91,71 @@ function onConnectError(_ctx: ErrorContext, error: Error): void {
process.exit(1);
}
-// Main entry point
-async function main(): Promise {
- console.log(`Connecting to SpacetimeDB...`);
- console.log(` URI: ${HOST}`);
- console.log(` Module: ${DB_NAME}`);
+function setupCLI(conn: DbConnection): void {
+ const rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ });
- const token = loadToken();
+ console.log('\nCommands:');
+ console.log(' - Add a person with that name');
+ console.log(' list - Show all people');
+ console.log(' hello - Greet everyone (check server logs)');
+ console.log(' Ctrl+C - Quit\n');
- // Build and establish connection
- conn = DbConnection.builder()
- .withUri(HOST)
- .withModuleName(DB_NAME)
- .withToken(token)
- .onConnect(onConnect)
- .onDisconnect(onDisconnect)
- .onConnectError(onConnectError)
- .build();
-}
+ rl.on('line', input => {
+ const text = input.trim();
+ if (!text) return;
+
+ if (text.toLowerCase() === 'list') {
+ console.log('\nPeople in database:');
+ let count = 0;
+ for (const person of conn.db.person.iter()) {
+ console.log(` - ${person.name}`);
+ count++;
+ }
+ if (count === 0) {
+ console.log(' (none)');
+ }
+ console.log();
+ } else if (text.toLowerCase() === 'hello') {
+ conn.reducers.sayHello({});
+ console.log('Called say_hello reducer (check server logs)\n');
+ } else {
+ conn.reducers.add({ name: text });
+ }
+ });
-// Graceful shutdown
-function shutdown(): void {
- console.log('\nShutting down...');
- if (conn) {
+ const shutdown = (): void => {
+ console.log('\nShutting down...');
conn.disconnect();
- }
- process.exit(0);
+ process.exit(0);
+ };
+
+ rl.on('close', shutdown);
+ process.on('SIGINT', shutdown);
+ process.on('SIGTERM', shutdown);
}
-process.on('SIGINT', shutdown);
-process.on('SIGTERM', shutdown);
+// Token persistence (file-based for Node.js instead of localStorage)
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const TOKEN_FILE = path.join(__dirname, '..', '.spacetimedb-token');
-// Run the main function
-main().catch(err => {
- console.error('Fatal error:', err);
- process.exit(1);
-});
+function loadToken(): string | undefined {
+ try {
+ if (fs.existsSync(TOKEN_FILE)) {
+ return fs.readFileSync(TOKEN_FILE, 'utf-8').trim();
+ }
+ } catch (err) {
+ console.warn('Could not load token:', err);
+ }
+ return undefined;
+}
+
+function saveToken(token: string): void {
+ try {
+ fs.writeFileSync(TOKEN_FILE, token, 'utf-8');
+ } catch (err) {
+ console.warn('Could not save token:', err);
+ }
+}
From 42d0af817e45bb052d767b79993d1f1259b96f6b Mon Sep 17 00:00:00 2001
From: bradleyshep <148254416+bradleyshep@users.noreply.github.com>
Date: Mon, 2 Feb 2026 16:52:38 -0500
Subject: [PATCH 3/3] fix
---
templates/nodejs-ts/src/main.ts | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/templates/nodejs-ts/src/main.ts b/templates/nodejs-ts/src/main.ts
index a25757ca752..89f04e49260 100644
--- a/templates/nodejs-ts/src/main.ts
+++ b/templates/nodejs-ts/src/main.ts
@@ -30,11 +30,6 @@ async function main(): Promise {
.build();
}
-main().catch(err => {
- console.error('Fatal error:', err);
- process.exit(1);
-});
-
function onConnect(
conn: DbConnection,
identity: Identity,
@@ -159,3 +154,8 @@ function saveToken(token: string): void {
console.warn('Could not save token:', err);
}
}
+
+main().catch(err => {
+ console.error('Fatal error:', err);
+ process.exit(1);
+});