Skip to content

Commit 83851fe

Browse files
JulienLavocatclockwork-tienclockwork-labs-bot
authored
Add Angular integration (#4139)
# Description of Changes - Add Angular integration - Add Angular quickstart chat template # API and ABI breaking changes None. # Expected complexity level and risk 2 # Testing Ran the template --------- Co-authored-by: Tien Pham <tien@clockworklabs.io> Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
1 parent 4c962b9 commit 83851fe

54 files changed

Lines changed: 5209 additions & 377 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Editor configuration, see https://editorconfig.org
2+
root = true
3+
4+
[*]
5+
charset = utf-8
6+
indent_style = space
7+
indent_size = 2
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.ts]
12+
quote_type = single
13+
ij_typescript_use_double_quotes = false
14+
15+
[*.md]
16+
max_line_length = off
17+
trim_trailing_whitespace = false

crates/bindings-typescript/package.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@
8989
"import": "./dist/svelte/index.mjs",
9090
"require": "./dist/svelte/index.cjs",
9191
"default": "./dist/svelte/index.mjs"
92+
},
93+
"./angular": {
94+
"types": "./dist/angular/index.d.ts",
95+
"import": "./dist/angular/index.mjs",
96+
"require": "./dist/angular/index.cjs",
97+
"default": "./dist/angular/index.mjs"
9298
}
9399
},
94100
"size-limit": [
@@ -183,7 +189,8 @@
183189
"react": "^18.0.0 || ^19.0.0-0 || ^19.0.0",
184190
"svelte": "^4.0.0 || ^5.0.0",
185191
"undici": "^6.19.2",
186-
"vue": "^3.3.0"
192+
"vue": "^3.3.0",
193+
"@angular/core": ">=17.0.0"
187194
},
188195
"peerDependenciesMeta": {
189196
"@tanstack/react-query": {
@@ -200,6 +207,9 @@
200207
},
201208
"vue": {
202209
"optional": true
210+
},
211+
"@angular/core": {
212+
"optional": true
203213
}
204214
},
205215
"devDependencies": {
@@ -224,6 +234,8 @@
224234
"typescript": "^5.9.3",
225235
"typescript-eslint": "^8.18.2",
226236
"vite": "^7.1.5",
227-
"vitest": "^3.2.4"
237+
"vitest": "^3.2.4",
238+
"@angular/core": "^21.1.0",
239+
"@angular/compiler": "^21.1.0"
228240
}
229241
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { InjectionToken, type WritableSignal } from '@angular/core';
2+
import type { ConnectionId } from '../lib/connection_id';
3+
import type { Identity } from '../lib/identity';
4+
import type { DbConnectionImpl } from '../sdk/db_connection_impl';
5+
6+
export interface ConnectionState {
7+
isActive: boolean;
8+
identity?: Identity;
9+
token?: string;
10+
connectionId: ConnectionId;
11+
connectionError?: Error;
12+
getConnection<
13+
DbConnection extends DbConnectionImpl<any>,
14+
>(): DbConnection | null;
15+
}
16+
17+
export const SPACETIMEDB_CONNECTION = new InjectionToken<
18+
WritableSignal<ConnectionState>
19+
>('SpacetimeDB Connection State');
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type { ConnectionState } from './connection_state.ts';
2+
export * from './injectors/index.ts';
3+
export * from './providers/index.ts';
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { injectSpacetimeDB } from './inject-spacetimedb.ts';
2+
export { injectTable, type TableRows } from './inject-table.ts';
3+
export { injectSpacetimeDBConnected } from './inject-spacetimedb-connected.ts';
4+
export { injectReducer } from './inject-reducer.ts';
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { assertInInjectionContext, inject, effect } from '@angular/core';
2+
import { SPACETIMEDB_CONNECTION } from '../connection_state';
3+
import type { ParamsType } from '../../sdk';
4+
import type { UntypedReducerDef } from '../../sdk/reducers';
5+
6+
export function injectReducer<ReducerDef extends UntypedReducerDef>(
7+
reducerDef: ReducerDef
8+
): (...params: ParamsType<ReducerDef>) => void {
9+
assertInInjectionContext(injectReducer);
10+
11+
const connState = inject(SPACETIMEDB_CONNECTION);
12+
const queue: ParamsType<ReducerDef>[] = [];
13+
const reducerName = reducerDef.accessorName;
14+
15+
// flush queued calls when connection becomes active
16+
effect((onCleanup: (fn: () => void) => void) => {
17+
const state = connState();
18+
if (!state.isActive) {
19+
return;
20+
}
21+
22+
const connection = state.getConnection();
23+
if (!connection) {
24+
return;
25+
}
26+
27+
const callReducer = (connection.reducers as any)[reducerName] as (
28+
...p: ParamsType<ReducerDef>
29+
) => void;
30+
31+
if (queue.length) {
32+
const pending = queue.splice(0);
33+
for (const params of pending) {
34+
callReducer(...params);
35+
}
36+
}
37+
38+
onCleanup(() => {
39+
queue.splice(0);
40+
});
41+
});
42+
43+
return (...params: ParamsType<ReducerDef>) => {
44+
const state = connState();
45+
if (!state.isActive) {
46+
queue.push(params);
47+
return;
48+
}
49+
50+
const connection = state.getConnection();
51+
if (!connection) {
52+
queue.push(params);
53+
return;
54+
}
55+
56+
const callReducer = (connection.reducers as any)[reducerName] as (
57+
...p: ParamsType<ReducerDef>
58+
) => void;
59+
60+
return callReducer(...params);
61+
};
62+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {
2+
assertInInjectionContext,
3+
inject,
4+
computed,
5+
type Signal,
6+
} from '@angular/core';
7+
import { SPACETIMEDB_CONNECTION } from '../connection_state';
8+
9+
export function injectSpacetimeDBConnected(): Signal<boolean> {
10+
assertInInjectionContext(injectSpacetimeDBConnected);
11+
const state = inject(SPACETIMEDB_CONNECTION);
12+
return computed(() => state().isActive);
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { assertInInjectionContext, inject, type Signal } from '@angular/core';
2+
import {
3+
SPACETIMEDB_CONNECTION,
4+
type ConnectionState,
5+
} from '../connection_state';
6+
7+
export function injectSpacetimeDB(): Signal<ConnectionState> {
8+
assertInInjectionContext(injectSpacetimeDB);
9+
return inject(SPACETIMEDB_CONNECTION).asReadonly();
10+
}

0 commit comments

Comments
 (0)