Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
297 commits
Select commit Hold shift + click to select a range
f17b908
Implement compat useBatch promise batching
az-001-zkdm Mar 10, 2026
c667e54
v0.4.0-alpha.18
az-001-zkdm Mar 10, 2026
45c46ed
Harden query subscriptions against subscribe/unsubscribe races
az-001-zkdm Mar 10, 2026
8233799
v0.4.0-alpha.19
az-001-zkdm Mar 10, 2026
76aba52
Use useSub lifecycle for compat batch hooks
az-001-zkdm Mar 10, 2026
ea7674a
v0.4.0-alpha.20
az-001-zkdm Mar 10, 2026
0f33a6b
fix compat batch query materialization and add regression tests
az-001-zkdm Mar 10, 2026
5b440dc
v0.4.0-alpha.21
az-001-zkdm Mar 10, 2026
ae80393
fix compat batch hooks to avoid deferred param races
az-001-zkdm Mar 10, 2026
c66a5b5
v0.4.0-alpha.22
az-001-zkdm Mar 10, 2026
735c593
fix compat start/stop via root fallback without method conflicts
az-001-zkdm Mar 10, 2026
bcf9b46
v0.4.0-alpha.23
az-001-zkdm Mar 10, 2026
010994b
fix compat start soft-handle suspended deps
az-001-zkdm Mar 12, 2026
17b7848
v0.4.0-alpha.24
az-001-zkdm Mar 12, 2026
6771674
fix compat set semantics to replace and add regressions
az-001-zkdm Mar 12, 2026
4f833dc
v0.4.0-alpha.25
az-001-zkdm Mar 12, 2026
87078cd
fix compat setEach to use per-key set semantics
az-001-zkdm Mar 12, 2026
6597912
v0.4.0-alpha.26
az-001-zkdm Mar 12, 2026
da8f119
fix setDiffDeep to fallback safely on proxy/react-like values
az-001-zkdm Mar 12, 2026
6254d72
docs compat mutator semantics and lock null/undefined matrix
az-001-zkdm Mar 12, 2026
f7a6412
v0.4.0-alpha.27
az-001-zkdm Mar 12, 2026
3485c76
fix compat setDiff alias semantics and update docs/tests
az-001-zkdm Mar 12, 2026
1c8386e
v0.4.0-alpha.28
az-001-zkdm Mar 12, 2026
4c6a3a0
implement racer-like compat setDiffDeep recursion
az-001-zkdm Mar 12, 2026
a29a65b
v0.4.0-alpha.29
az-001-zkdm Mar 12, 2026
2f91828
fix compat start to skip ticks on suspended deps
az-001-zkdm Mar 12, 2026
dc30b21
v0.4.0-alpha.30
az-001-zkdm Mar 12, 2026
3c53c9f
add runtime batch scheduler and atomic compat composite mutators
az-001-zkdm Mar 12, 2026
a0efde2
v0.4.0-alpha.31
az-001-zkdm Mar 12, 2026
aa41f6f
route compat ref sync through batch scheduler
az-001-zkdm Mar 12, 2026
384c143
v0.4.0-alpha.32
az-001-zkdm Mar 12, 2026
5c29d7e
add compat subscription GC grace delay for docs and queries
az-001-zkdm Mar 12, 2026
6e43990
v0.4.0-alpha.33
az-001-zkdm Mar 12, 2026
49102ec
fix(compat): add batch materialization readiness barrier
az-001-zkdm Mar 12, 2026
619024e
v0.4.0-alpha.34
az-001-zkdm Mar 12, 2026
15a167a
fix(compat): force strict sync hooks without deferred snapshots
az-001-zkdm Mar 12, 2026
92ba9ce
v0.4.0-alpha.35
az-001-zkdm Mar 12, 2026
5fda4ac
fix(compat): handle aggregate batch readiness without doc materializa…
az-001-zkdm Mar 12, 2026
245b7fe
fix(compat): tighten aggregate batch readiness checks
az-001-zkdm Mar 12, 2026
0f90958
v0.4.0-alpha.36
az-001-zkdm Mar 12, 2026
af3b555
fix(compat): keep query-materialized docs alive via doc retain/release
az-001-zkdm Mar 13, 2026
5ef9050
v0.4.0-alpha.37
az-001-zkdm Mar 13, 2026
98ad7d0
feat(teamplay): add orm compatibility associations API
az-001-zkdm Mar 13, 2026
fb010df
v0.4.0-alpha.38
az-001-zkdm Mar 13, 2026
799e51b
fix(teamplay): preserve constructor access in extremely late bindings
az-001-zkdm Mar 13, 2026
1d96313
v0.4.0-alpha.39
az-001-zkdm Mar 13, 2026
0d72c98
fix(orm): defer doc destroy until pending ops complete
az-001-zkdm Mar 13, 2026
24677e6
v0.4.0-alpha.40
az-001-zkdm Mar 13, 2026
d7e1482
feat(compat): add Signal.close() shim for legacy model.close()
az-001-zkdm Mar 13, 2026
834adf2
v0.4.0-alpha.41
az-001-zkdm Mar 13, 2026
f3de798
fix(compat): initialize missing array targets as arrays for mutators
az-001-zkdm Mar 13, 2026
0ab40ff
v0.4.0-alpha.42
az-001-zkdm Mar 13, 2026
394ff98
fix(compat): prefer static model collection in getCollection
az-001-zkdm Mar 13, 2026
208471a
v0.4.0-alpha.43
az-001-zkdm Mar 13, 2026
55c0911
fix(orm): hydrate local public doc after create
az-001-zkdm Mar 13, 2026
7428f01
v0.4.0-alpha.44
az-001-zkdm Mar 13, 2026
d482aae
fix(orm): sync share docs with local tree and stabilize gc unsubscribe
az-001-zkdm Mar 14, 2026
0eede86
v0.4.0-alpha.45
az-001-zkdm Mar 14, 2026
01d68c3
teamplay: make compat del on missing public doc a no-op
az-001-zkdm Mar 14, 2026
0ca9a29
v0.4.0-alpha.46
az-001-zkdm Mar 14, 2026
c76a8f7
fix(compat): support refExtra/refIds on aggregation signals
az-001-zkdm Mar 14, 2026
6e0aef0
v0.4.0-alpha.47
az-001-zkdm Mar 14, 2026
282b1fc
fix(compat): align useBatch update semantics with master
az-001-zkdm Mar 16, 2026
ca2653a
v0.4.0-alpha.48
az-001-zkdm Mar 16, 2026
21799a2
teamplay compat: add create() API without createNull
az-001-zkdm Mar 16, 2026
a0220c2
v0.4.0-alpha.49
az-001-zkdm Mar 16, 2026
aafbea0
compat: implement silent updates without reactive rerenders
az-001-zkdm Mar 16, 2026
f9d3a5f
v0.4.0-alpha.50
az-001-zkdm Mar 16, 2026
3d9fed2
fix(orm): use pluralize for association keys
az-001-zkdm Mar 17, 2026
5e790f7
v0.4.0-alpha.51
az-001-zkdm Mar 17, 2026
f56a725
fix(orm): create missing public arrays on insert
az-001-zkdm Mar 17, 2026
f51a53c
v0.4.0-alpha.52
az-001-zkdm Mar 17, 2026
10a8b31
fix(compat): align create() post-create behavior with add()
az-001-zkdm Mar 18, 2026
c8f88c1
v0.4.0-alpha.53
az-001-zkdm Mar 18, 2026
dd51a6d
fix(compat): make public subpath mutators resilient without subscribe
az-001-zkdm Mar 18, 2026
4e0872c
v0.4.0-alpha.54
az-001-zkdm Mar 18, 2026
d4e1195
fix(compat): recover public docs via fetch when snapshot is missing
az-001-zkdm Mar 18, 2026
da3ed74
v0.4.0-alpha.55
az-001-zkdm Mar 18, 2026
9198e20
fix(compat): normalize undefined query params like racer
az-001-zkdm Mar 18, 2026
50b36e9
v0.4.0-alpha.56
az-001-zkdm Mar 18, 2026
85d08e2
Defer compat suspense cleanup until promise resolution
az-001-zkdm Mar 18, 2026
701b093
v0.4.0-alpha.57
az-001-zkdm Mar 18, 2026
ae45ce9
Replay compat observer updates after execution context
az-001-zkdm Mar 18, 2026
8d3e2fc
v0.4.0-alpha.58
az-001-zkdm Mar 18, 2026
a38a219
compat: return query.extra for extra queries in useQuery hooks
az-001-zkdm Mar 19, 2026
c981ac8
v0.4.0-alpha.59
az-001-zkdm Mar 19, 2026
a6da041
fix compat session alias ref reactivity
az-001-zkdm Mar 20, 2026
331161d
v0.4.0-alpha.60
az-001-zkdm Mar 20, 2026
4350d5d
fix compat session ref ids for stage store lookups
az-001-zkdm Mar 22, 2026
eb24aea
v0.4.0-alpha.61
az-001-zkdm Mar 22, 2026
69234d9
fix compat nested local writes from primitive values
az-001-zkdm Mar 24, 2026
b1fb873
v0.4.0-alpha.62
az-001-zkdm Mar 24, 2026
5c8998d
fix compat custom event dispatch snapshot semantics
az-001-zkdm Mar 24, 2026
b3f1f0a
fix compat useDidUpdate callback stability
az-001-zkdm Mar 24, 2026
3efa8ff
v0.4.0-alpha.63
az-001-zkdm Mar 24, 2026
645b5fb
dedupe compat undefined doc warnings
az-001-zkdm Mar 24, 2026
7018f7a
v0.4.0-alpha.64
az-001-zkdm Mar 24, 2026
229c2e8
fix: detach compat start snapshots
az-001-zkdm Mar 24, 2026
0c78a4d
v0.4.0-alpha.65
az-001-zkdm Mar 24, 2026
d40ed3c
fix(compat): add Signal.once for racer model events
az-001-zkdm Mar 26, 2026
ad81d82
v0.4.0-alpha.66
az-001-zkdm Mar 26, 2026
edf9637
fix(compat): resolve refs for root set(path, value)
az-001-zkdm Mar 26, 2026
2b2e89a
v0.4.0-alpha.67
az-001-zkdm Mar 26, 2026
bad3cb5
fix(compat): unify relative path resolution for path methods
az-001-zkdm Mar 26, 2026
063234a
v0.4.0-alpha.68
az-001-zkdm Mar 26, 2026
77bdf87
fix(compat): make start react to deep object mutations
az-001-zkdm Mar 26, 2026
8018721
v0.4.0-alpha.69
az-001-zkdm Mar 26, 2026
62993ba
fix(compat): align ref-aware path resolution across helpers
az-001-zkdm Mar 27, 2026
161b9b6
v0.4.0-alpha.70
az-001-zkdm Mar 27, 2026
7a903eb
align compat batch semantics with racer-style materialization and gc …
artypixel-tech Mar 27, 2026
b110c0b
v0.4.0-alpha.71
artypixel-tech Mar 27, 2026
26ceaab
compat: add mirror-only refs for query/aggregation targets
artypixel-tech Mar 30, 2026
f9f8674
tests: mark compat-only useValue materialization case as compat
artypixel-tech Mar 30, 2026
204b5dd
v0.4.0-alpha.72
artypixel-tech Mar 30, 2026
873d8bb
test: cover push materialization on missing public array path
artypixel-tech Mar 30, 2026
ce7e31c
compat: make at/scope on aggregation rows synchronous
artypixel-tech Mar 30, 2026
0043213
test: expand at/dot invariants for compat signals
artypixel-tech Mar 30, 2026
d17c223
v0.4.0-alpha.73
artypixel-tech Mar 30, 2026
f2e67f7
Align missing ShareDB docs with Racer compat
artypixel-tech Mar 30, 2026
52e6aaf
v0.4.0-alpha.74
artypixel-tech Mar 30, 2026
0859be7
Fix compat start child signal reactivity
artypixel-tech Apr 1, 2026
e1b1ccf
v0.4.0-alpha.75
artypixel-tech Apr 1, 2026
8393e72
Align increment on missing public numeric paths
artypixel-tech Apr 1, 2026
954f435
v0.4.0-alpha.76
artypixel-tech Apr 1, 2026
0acc38e
Add usePage external update coverage
artypixel-tech Apr 2, 2026
7bf321d
Add strict compat query materialization barrier
artypixel-tech Apr 2, 2026
53f8b82
v0.4.0-alpha.77
artypixel-tech Apr 2, 2026
5d62d7c
Limit id field protection to doc identity paths
artypixel-tech Apr 6, 2026
954b43a
Refactor and cover local add id handling
artypixel-tech Apr 6, 2026
cecff20
Split usePage external update coverage by mode
artypixel-tech Apr 6, 2026
6ced13d
v0.4.0-alpha.78
artypixel-tech Apr 6, 2026
39c4d23
Preserve nested ids on public subpath writes
artypixel-tech Apr 6, 2026
d01896f
v0.4.0-alpha.79
artypixel-tech Apr 6, 2026
a980da8
Restore missing-doc placeholders after delete
artypixel-tech Apr 6, 2026
8e3f46b
v0.4.0-alpha.80
artypixel-tech Apr 6, 2026
116a4c8
Scope query runtime by root while keeping transport shared
artypixel-tech Apr 7, 2026
b35daa3
Scope private storage by root
artypixel-tech Apr 7, 2026
d29b21b
Scope refs and model events by root
artypixel-tech Apr 7, 2026
1bb6e65
Add root-scoped public signal coverage
artypixel-tech Apr 7, 2026
753fa65
Centralize root scope helpers
artypixel-tech Apr 7, 2026
efb81d6
Introduce RootContext for root-owned runtime state
artypixel-tech Apr 7, 2026
f72f4a1
Dispose root-owned runtime state on compat close
artypixel-tech Apr 7, 2026
c6ef0a9
Add privateData infrastructure to RootContext
artypixel-tech Apr 7, 2026
a270d9b
Move private collection storage into RootContext.privateData
artypixel-tech Apr 7, 2026
3d36b86
Move query runtime into privateData and drop view hash
artypixel-tech Apr 7, 2026
737224f
Rename root-owned query runtime APIs after privateData migration
artypixel-tech Apr 7, 2026
5b181e7
Add root finalization fallback
artypixel-tech Apr 7, 2026
5e534ae
v0.4.0-alpha.81
artypixel-tech Apr 7, 2026
e65e1f1
Disable publicOnly guard in compat mode
artypixel-tech Apr 7, 2026
defb6e4
v0.4.0-alpha.82
artypixel-tech Apr 7, 2026
a1689ba
Store fetchOnly on RootContext
artypixel-tech Apr 7, 2026
d6bf3c2
Route compat fetch through root transport intent
artypixel-tech Apr 7, 2026
b6ad1b9
Coordinate query transport mode by root fetch intent
artypixel-tech Apr 7, 2026
25a51dc
Clean up fetchOnly defaults and cover aggregation transport modes
artypixel-tech Apr 7, 2026
cf9710f
v0.4.0-alpha.83
artypixel-tech Apr 7, 2026
10a54b8
Harden stale query cleanup paths
artypixel-tech Apr 7, 2026
780ddaf
v0.4.0-alpha.84
artypixel-tech Apr 7, 2026
229a0d7
Make query transport unsubscribe idempotent
artypixel-tech Apr 7, 2026
4fb5a7f
v0.4.0-alpha.85
artypixel-tech Apr 7, 2026
211ae40
Harden root finalization coverage
artypixel-tech Apr 7, 2026
ce267f9
Harden stale doc cleanup paths
artypixel-tech Apr 8, 2026
8214ea0
Harden stale root close cleanup paths
artypixel-tech Apr 8, 2026
5e89c06
Refactor query transport ownership around entries and owner records
artypixel-tech Apr 8, 2026
352b42a
Refactor doc transport ownership around entries and owner records
artypixel-tech Apr 8, 2026
70e529e
Remove mutable subscription mirror counters
artypixel-tech Apr 8, 2026
bb4e0ab
Move query pending destroy into transport entries
artypixel-tech Apr 8, 2026
10905b7
Move doc pending destroy into transport entries
artypixel-tech Apr 8, 2026
955d3e2
Normalize subscription destroy paths
artypixel-tech Apr 8, 2026
36e637a
Add subscription manager consistency assertions
artypixel-tech Apr 8, 2026
f724834
Extend subscription consistency assertions to root cleanup tests
artypixel-tech Apr 8, 2026
1a97cd5
v0.4.0-alpha.86
artypixel-tech Apr 8, 2026
e717866
Harden doc retain cleanup coverage
artypixel-tech Apr 8, 2026
1d99c69
fix(compat): preserve empty private objects in setDiffDeep
artypixel-tech Apr 8, 2026
dd7b2ff
v0.4.0-alpha.87
artypixel-tech Apr 8, 2026
937eeb2
fix(root): merge private collections into global snapshot
artypixel-tech Apr 8, 2026
201887a
v0.4.0-alpha.88
artypixel-tech Apr 8, 2026
2d22bf9
feat(react): add useSuspendMemo hooks for suspense gates
artypixel-tech Apr 8, 2026
07c0361
v0.4.0-alpha.89
artypixel-tech Apr 8, 2026
8515fc6
fix(react): scope compat thenable handling to armed suspense
artypixel-tech Apr 8, 2026
12533f0
v0.4.0-alpha.90
artypixel-tech Apr 8, 2026
b2e1ffb
fix(compat): use direct replace ops for public set
artypixel-tech Apr 9, 2026
cd61f3a
v0.4.0-alpha.91
artypixel-tech Apr 9, 2026
f612d3d
fix(orm): ignore late private writes after root close
artypixel-tech Apr 9, 2026
d55bd04
v0.4.0-alpha.92
artypixel-tech Apr 9, 2026
81b3c55
fix(compat): align setDiff with racer semantics
artypixel-tech Apr 9, 2026
286165f
v0.4.0-alpha.93
artypixel-tech Apr 9, 2026
36f97a7
fix(teamplay): normalize compat query owner root id
artypixel-tech Apr 9, 2026
28a9de4
v0.4.0-alpha.94
artypixel-tech Apr 9, 2026
b462140
fix(compat): cancel query readiness wait on root dispose
artypixel-tech Apr 9, 2026
43c7349
v0.4.0-alpha.95
artypixel-tech Apr 9, 2026
63e55f3
fix compat suspense shell loop when no attempt cleanup handlers
artypixel-tech Apr 9, 2026
78f33dc
v0.4.0-alpha.96
artypixel-tech Apr 9, 2026
c91ac05
fix(compat): enforce private ref sources and dedupe ref mirroring
artypixel-tech Apr 9, 2026
633e39d
v0.4.0-alpha.97
artypixel-tech Apr 9, 2026
f26397b
fix(compat): preserve racer-like nested set semantics
artypixel-tech Apr 10, 2026
8ecb5f3
fix(compat): restore private ref mirroring fallback
artypixel-tech Apr 10, 2026
78afac8
chore: run full test suite in pre-commit
artypixel-tech Apr 10, 2026
d657f53
fix(react): keep previous snapshots on resubscribe
artypixel-tech Apr 10, 2026
ae4e0e6
v0.4.0-alpha.98
artypixel-tech Apr 10, 2026
937fe21
Align compat sparse sync with racer semantics
artypixel-tech Apr 14, 2026
78b411d
Cover compat undefined semantics in tests
artypixel-tech Apr 14, 2026
22d0358
v0.4.0-alpha.99
artypixel-tech Apr 14, 2026
9738326
Fix compat extra-query hook wrappers
artypixel-tech Apr 16, 2026
d6f8d6c
v0.4.0-alpha.100
artypixel-tech Apr 16, 2026
0d5d5dd
Add Signal TypeScript typings
cray0000 Apr 23, 2026
12265fc
Convert Signal sources to TypeScript
cray0000 Apr 23, 2026
2cd58ec
Modernize lint and test tooling
cray0000 Apr 23, 2026
eb503c2
Improve deep Signal type inference
cray0000 Apr 23, 2026
917f536
Fix Signal array forwarding regressions
cray0000 Apr 24, 2026
725611d
Document ORM typing setup
cray0000 Apr 24, 2026
6207a98
Refine ORM guide example
cray0000 Apr 24, 2026
4934d09
Expand Signal type chain coverage
cray0000 Apr 24, 2026
94ea0a2
add docs for usage in startupjs, add jsdoc for methods
cray0000 Apr 26, 2026
7b9ebfe
Add file-based model loader and typings
cray0000 Apr 30, 2026
ab1a98a
Improve collection array signal typings
cray0000 Apr 30, 2026
bf37329
docs: add typing-architecture with the current state and suggestions
cray0000 Apr 30, 2026
03d16e1
Refactor TeamPlay typing architecture
cray0000 Apr 30, 2026
48d8e86
Improve ORM typing and file-based model docs
cray0000 May 1, 2026
c51a951
Use underscore aggregation file convention
cray0000 May 1, 2026
435fc02
Run model elimination based on source usage
cray0000 May 1, 2026
7adb6e0
TS improvements (#40)
cray0000 May 2, 2026
42d53fe
Merge branch 'master' into alpha
cray0000 May 3, 2026
2f93740
Merge branch 'alpha' into typescript
cray0000 May 3, 2026
6a1b923
Merge pull request #39 from startupjs/typescript
cray0000 May 3, 2026
9f32bb0
Build TS packages for publishing
cray0000 May 4, 2026
9f3ebb8
v0.5.0-alpha.0
cray0000 May 4, 2026
198cb9b
Use public Ajv imports
cray0000 May 4, 2026
94e1eca
v0.5.0-alpha.1
cray0000 May 4, 2026
394e887
fix(teamplay): add .toString on Signal and handle conversion to primi…
cray0000 May 5, 2026
6d03dc3
v0.5.0-alpha.2
cray0000 May 5, 2026
5196d24
fix(teamplay/types): improve types of using dotted keys in queries
cray0000 May 6, 2026
08829f3
v0.5.0-alpha.3
cray0000 May 6, 2026
b392c94
fix: support nested collections for .getId() and return the id only i…
cray0000 May 6, 2026
7ec37ca
v0.5.0-alpha.4
cray0000 May 7, 2026
99293a2
feat(teamplay/types): support getting the type augmentation for model…
cray0000 May 11, 2026
4527ba3
v0.5.0-alpha.5
cray0000 May 11, 2026
7c18a4b
chore: do push when publishing alpha
cray0000 May 11, 2026
1fe4a03
chore: update docs on plugin typings
cray0000 May 11, 2026
337c69c
feat(teamplay): add setReplace and narrow compat API
artypixel-tech May 12, 2026
5b71d9b
chore(test): use latest node 25 for tests github action
cray0000 May 12, 2026
5b580b6
v0.5.0-alpha.6
artypixel-tech May 12, 2026
e800dc2
chore(babel-plugin-teamplay): fix tests to use correct export resolut…
cray0000 May 12, 2026
e234d66
Merge branch 'alpha' of github.com:startupjs/teamplay into alpha
cray0000 May 12, 2026
a854bf3
v0.5.0-alpha.7
cray0000 May 12, 2026
617782b
feat(teamplay): add explicit root signal method
artypixel-tech May 13, 2026
a883c9d
v0.5.0-alpha.8
artypixel-tech May 13, 2026
2fcfef4
fix(backend): use node-redis instead of ioredis for sharedb-redis-pub…
cray0000 May 13, 2026
4c2afb2
v0.5.0-alpha.9
cray0000 May 13, 2026
5c88f33
fix(channel): use the latest forked sockjs which is published to npm
cray0000 May 15, 2026
618cf6d
v0.5.0-alpha.10
cray0000 May 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
node-version: 25
- name: Install dependencies
run: corepack enable && yarn
- name: Run tests
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

# Node dependencies
node_modules
packages/*/dist

# npm-debug log
npm-debug.*
Expand Down
2 changes: 2 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
enableScripts: true

nodeLinker: node-modules
18 changes: 18 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# TeamPlay Agent Notes

TeamPlay is a full-stack signal ORM built on top of ShareDB. The main user-facing API is the object-tree signal model: `$`, `$.collection[id]`, `sub()`, `useSub()`, and `Signal<SchemaType>`.

Before making nontrivial changes, read:

- [architecture.md](./architecture.md) for the monorepo layout and runtime architecture.
- [typing-architecture.md](./typing-architecture.md) for the TypeScript and generated type architecture.
- [tasks.md](./tasks.md) for the current backlog, known priorities, and verification guidance. Treat it as context unless the user explicitly asks you to work through backlog items.

Basic working rules:

- Preserve public runtime APIs and the object-tree UX unless the user explicitly asks for a product change.
- Prefer small, focused changes with nearby tests. Run focused tests while iterating and broader tests before commits.
- Keep runtime behavior and TypeScript behavior aligned; update the architecture docs when the direction changes.
- Do not invest in broad Compat rewrites. Compat is temporary; touch it only when needed to preserve behavior.
- Work only in this project. Neighboring folders mentioned in old notes are not available in this environment.
- The TS-authored packages (`teamplay`, `@teamplay/schema`, and `@teamplay/utils`) publish compiled `dist/` files but use the `teamplay-ts` export condition for source during development. When running hand-written Node checks against workspace packages, pass `-C teamplay-ts` (or `--conditions=teamplay-ts`) so Node resolves the current `src/` files instead of the generated `dist/` files.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
570 changes: 570 additions & 0 deletions architecture.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions docs-theme/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export * from '@rspress/core/theme-original'

export function Layout () {
return (
<div className="project-layout">
<ProjectSidebar activeProject="teamplay" />
<div className="project-layout-content">
<div className='project-layout'>
<ProjectSidebar activeProject='teamplay' />
<div className='project-layout-content'>
<DefaultLayout />
</div>
</div>
Expand Down Expand Up @@ -58,16 +58,16 @@ interface ProjectSidebarProps {

function ProjectSidebar ({ activeProject }: ProjectSidebarProps) {
return (
<nav className="project-sidebar">
<nav className='project-sidebar'>
{PROJECTS.map((project) => (
<a
key={project.id}
href={project.url}
className={`project-sidebar-button project-sidebar-button--${project.id} ${project.id === activeProject ? 'active' : ''}`}
aria-label={project.name}
>
<span className="project-sidebar-button__text">{project.label}</span>
<span className="project-sidebar-button__tooltip">{project.name}</span>
<span className='project-sidebar-button__text'>{project.label}</span>
<span className='project-sidebar-button__tooltip'>{project.name}</span>
</a>
))}
</nav>
Expand Down
13 changes: 12 additions & 1 deletion docs/api/query-signals.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ A signal containing an array of IDs for the documents in the query result.
const userIds = $activeUsers.ids.get()
```

### extra

A signal containing extra query metadata returned by the server, such as count metadata.

```javascript
const extra = $activeUsers.extra.get()
```

### getIds()

Returns an array of ids for the query results.
Expand All @@ -26,6 +34,8 @@ Returns an array of ids for the query results.
const ids = $activeUsers.getIds()
```

The result is always a `string[]`. Non-string ids are filtered out.

### map(callback)

Maps over the documents in the query result.
Expand Down Expand Up @@ -64,4 +74,5 @@ for (const $user of $activeUsers) {

- Query signals are reactive. Changes to the underlying data or to the query result will automatically update components using the query signal.
- The documents within a query signal are themselves signals, allowing for nested reactivity.
- For public documents in query results, `_id` is available in `get()` results and matches the document id.
- For public documents in query results, `_id` is available in `get()` results and matches the document id.
- `ids` and `extra` are reserved metadata properties on query signals. Use the collection path, such as `$.users['ids']`, when you need a document whose id has one of those names.
24 changes: 24 additions & 0 deletions docs/api/root-signal.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,34 @@ For convenience, TeamPlay allows you to access the private '_session' collection
// These are equivalent:
const $sessionData1 = $._session
const $sessionData2 = $.session
const $sessionData3 = $.$session
```

This simplification makes it easier to work with session data without constantly typing the underscore.

Private collections are client-local values, not database collections. They do not need `sub()` or `useSub()`, and they are not collection signals with `.add()`.

If a private root collection has a schema, the schema describes the whole private value:

```ts
// models/_session/schema.ts
import { defineSchema } from 'teamplay'

export default defineSchema({
userId: { type: 'string' }
})
```

After `teamplay-env.d.ts` is generated, all aliases share the same field types:

```ts
$._session.userId.get()
$.session.userId.get()
$.$session.userId.get()

const { $userId } = $.session
```

### Destructuring Assignment Simplification

When destructuring properties from a signal object, TeamPlay provides a convenient shorthand for properties starting with '$'. The '$' is automatically removed from the property name:
Expand Down
18 changes: 18 additions & 0 deletions docs/api/server-side.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@ import { createBackend } from 'teamplay/server'
const backend = createBackend()
```

Common options:

```ts
const backend = createBackend({
validateSchema: true,
accessControl: true,
serverAggregate: true,
serverOnlyCollections: ['service']
})
```

- `validateSchema`: validate public collection writes with registered schemas.
- `accessControl`: enable access-control middleware for all collections. Collections without rules are denied by default.
- `serverAggregate`: enable server-side aggregations.
- `serverOnlyCollections`: collections that clients may not read or write through ShareDB.

`serverOnlyCollections` forces the access middleware to initialize even when global `accessControl` is off. In that mode, only server-only collections and collections marked with `accessControl(..., { force: true })` are protected; all other collections keep the normal open behavior.

## initConnection(backend, options)

Initializes the connection handler for WebSocket connections.
Expand Down
46 changes: 44 additions & 2 deletions docs/api/signal-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ Retrieves the current value of the signal.
const value = $signal.get()
```

## peek()

Retrieves the current value without tracking it for reactive rendering.

```javascript
const value = $signal.peek()
```

## set(value)

Updates the value of the signal.
Expand Down Expand Up @@ -123,20 +131,26 @@ If both are provided, they must be equal, otherwise `add()` throws.

## getId()

Returns the id for the current signal.
Returns the usable string id for the document-like value represented by the current signal.

```javascript
const id = $.users[userId].getId()
```

For direct public document signals and query item signals, TeamPlay already knows the document id from the path and returns that id directly. For nested document-like values, private values, and aggregation rows, TeamPlay first checks string `_id` and `id` fields on the current value. If neither exists, it falls back to the string leaf segment of the signal path.

If an explicit `_id` or `id` exists but is not a string, `getId()` returns `undefined`. The root signal and collection signals do not have ids and throw.

## getIds()

Returns document ids for query or aggregation signals.
Returns usable string ids for query or aggregation signals.

```javascript
const ids = $activeUsers.getIds()
```

For query signals, ids come from the subscribed query metadata. For aggregation signals, ids are read from each row's string `_id` or `id` field. Rows without a usable string id are omitted, so the result is always a `string[]`.

## getCollection()

Returns the collection name for the signal.
Expand All @@ -162,6 +176,34 @@ Returns the last path segment as a string.
const key = $.users[userId].leaf()
```

## path()

Returns the dot-separated path of the signal.

```javascript
const path = $.users[userId].name.path() // 'users.abc123.name'
```

## toString()

Returns a debug label for the signal. Primitive string coercion uses only the path, while `toString()` includes the `Signal` label:

```javascript
String($.users[userId].name) // 'users.abc123.name'
$.users[userId].name.toString() // '[Signal users.abc123.name]'
Object.prototype.toString.call($.users[userId]) // '[object Signal]'
```

## getAssociations()

Returns association metadata registered on the signal's model class.

```javascript
const associations = $.users[userId].getAssociations()
```

This is mostly useful for model-integration libraries and legacy ORM compatibility helpers.

## assign(object)

Assigns multiple properties to a signal at once. This method iterates through the object's own properties and sets or deletes them on the signal.
Expand Down
41 changes: 24 additions & 17 deletions docs/guide/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ TeamPlay can run in three different modes. Pick the one that matches your needs

## Modes

- **In-memory (default)**: in-memory only, no server, no persistence across reloads.
- **In-memory Mode (default)**: in-memory only, no server, no persistence across reloads.
- **Offline Mode**: client-only with local persistence (browser or React Native), no server.
- **Server Sync**: real-time synchronization with a backend server.
- **Server Sync Mode**: real-time synchronization with a backend server.

## In-memory Mode

Expand All @@ -27,22 +27,17 @@ await connect()

See [Offline Mode](/guide/offline-mode) for details and React Native setup.

## Synchronization with Server
## Server Sync Mode

To enable synchronization with the server, follow these steps:

### Client Setup

Enable the connection on the client somewhere early in your client app:
To sync data with a server, connect from the client somewhere early in your app startup:

```js
import connect from 'teamplay/connect'

await connect()
```

### Server Setup

On the server, you need to create the TeamPlay backend and then create a connection handler for WebSockets:
On the server, create the TeamPlay backend and attach its WebSocket upgrade handler to your Node HTTP server:

```js
import { createBackend, initConnection } from 'teamplay/server'
Expand All @@ -52,17 +47,29 @@ const { upgrade } = initConnection(backend)
server.on('upgrade', upgrade) // Node's 'http' server instance
```

## Database Configuration
## Production Setup

For development, no extra database setup is needed. If `MONGO_URL` is not set, TeamPlay stores server data in an SQLite file named `local.db` in the root of your project.

You can still write MongoDB-style queries and aggregations in this local setup. TeamPlay emulates that query behavior with [`mingo`](https://github.com/kofrasa/mingo).

For production, configure the services your deployment needs:

- `MONGO_URL`: use [MongoDB](https://mongodb.com) instead of the local SQLite file.
- `REDIS_URL`: required when you run multiple server instances, so real-time updates can be coordinated through [Redis](https://redis.io).

:::note
TeamPlay's `createBackend()` is a wrapper around creating a [ShareDB backend](https://share.github.io/sharedb/api/backend). If you need lower-level control, you can create a ShareDB backend yourself and pass it to `initConnection()`. `ShareDB` is re-exported from `teamplay/server`, so you can import it as `import { ShareDB } from 'teamplay/server'`.
:::

By default no extra database setup is needed and the data is gonna be saved into an SQLite file `local.db` in the root of your project.
## Optional ORM Setup

You can still use the MongoDB query syntax with aggregations which is emulated using [`mingo`](https://github.com/kofrasa/mingo).
TeamPlay works without an ORM setup: you can use signals, subscriptions, and real-time sync directly. When your app starts to have named collections such as users, games, orders, or events, the ORM gives you a conventional place to define document schemas, model methods, access rules, and server aggregations.

- For production use, it's recommended to use [MongoDB](https://mongodb.com). It will be automatically used if you set the environment variable `MONGO_URL`.
- When deploying to a cluster with multiple instances, you also have to provide the environment variable `REDIS_URL` ([Redis](https://redis.io)).
To use the full ORM features, follow the [ORM Quick Start](/orm/index#quick-start). It shows the extra setup for the `models/` folder, the Babel plugin, and the shared `models.setup.ts` file used by both client and server.

:::note
TeamPlay's `createBackend()` is a wrapper around creating a [ShareDB's backend](https://share.github.io/sharedb/api/backend). You can instead manually create a ShareDB backend yourself and pass it to `initConnection()`. `ShareDB` is re-exported from `teamplay/server`, you can get it as `import { ShareDB } from 'teamplay/server'`.
StartupJS apps can skip the manual ORM setup. StartupJS configures model loading and initializes TeamPlay models automatically.
:::

Now that you have TeamPlay installed and configured, you're ready to start using it in your application!
Loading
Loading