The Citadel Workspace project has a complex dependency chain with three TypeScript client directories that all need to stay synchronized with the WASM build. This guide explains the architecture and provides automation for keeping everything in sync.
── citadel-workspace/
├── wasm-client-ts/ # Mirror of typescript-client
├── citadel-workspace-client-ts/ # High-level workspace client
└── citadel-workspaces/public/wasm/ # Static WASM files for UI
├── citadel-internal-service/
├── citadel-internal-service-wasm-client/ # Rust WASM source
├── typescript-client/ # Original WASM output location
└── generate_types.sh # TypeScript type generator
-
citadel-internal-service-wasm-client (Rust)
- Source of truth for WASM functionality
- Built with
wasm-packto generate JavaScript bindings
-
typescript-client (TypeScript/WASM)
- Original output location for WASM build
- Contains raw WASM files and JavaScript bindings
-
wasm-client-ts (TypeScript/WASM)
- Mirror copy in workspace repository
- Provides
InternalServiceWasmClientclass wrapper - Referenced by
citadel-workspace-client-tsviafile:dependency
-
citadel-workspace-client-ts (TypeScript)
- Extends
InternalServiceWasmClientwith workspace-specific functionality - Imports from
citadel-websocket-client(which resolves towasm-client-ts)
- Extends
-
citadel-workspaces (React UI)
- Uses
citadel-workspace-client-tsfor all WebSocket communication - Also needs WASM files in
public/wasm/(though not actively used)
- Uses
Large CID values (u64 in Rust) can lose precision when converted to JavaScript numbers.
Problem:
const cid = 2283033082066832407n;
Number(cid) // Returns: 2283033082066832400 (lost precision!)Solution:
- Keep CIDs as strings in JavaScript
- Update
convert_string_cids_to_numbersin WASM client to handlesession_cid
wasm-pack overwrites package.json with minimal content.
Solution:
The sync script restores the correct package.json with:
{
"name": "citadel-internal-service-wasm-client",
"type": "module",
"version": "0.1.0",
"files": ["*.wasm", "*.js", "*.d.ts", "src/**/*", "dist/**/*"],
"main": "src/index.ts",
"types": "src/index.ts"
}Vite may try to import from raw WASM files instead of TypeScript wrappers.
Solution: Ensure imports use the TypeScript wrapper:
import { InternalServiceWasmClient } from 'citadel-websocket-client';
// NOT from '../citadel_internal_service_wasm_client.js'# Run from citadel-workspace directory
./sync-wasm-clients.shThe script automatically:
- Builds WASM from source
- Generates TypeScript types
- Copies files to all three locations
- Restores correct package.json files
- Rebuilds citadel-workspace-client-ts
- Verifies synchronization
If you need to build manually:
# 1. Build WASM
cd citadel-internal-service/citadel-internal-service-wasm-client
wasm-pack build --target web --out-dir pkg
# 2. Generate types
cd ../
./generate_types.sh
# 3. Copy WASM files
cp citadel-internal-service-wasm-client/pkg/*.{wasm,js,d.ts} typescript-client/
cp citadel-internal-service-wasm-client/pkg/*.{wasm,js,d.ts} ../citadel-workspace/wasm-client-ts/
cp citadel-internal-service-wasm-client/pkg/*.{wasm,js,d.ts} ../citadel-workspace/citadel-workspaces/public/wasm/
# 4. Copy TypeScript types
cp citadel-internal-service-types/bindings/*.ts ../citadel-workspace/wasm-client-ts/src/types/
cp citadel-internal-service-types/bindings/*.ts ../citadel-workspace/citadel-workspace-client-ts/src/types/
# 5. Rebuild workspace client
cd ../citadel-workspace/citadel-workspace-client-ts
npm run build
# 6. Restart dev server
cd ../citadel-workspaces
pkill -f vite || true
npm run devThe citadel-workspace-internal-service/build.rs script also builds WASM automatically when building the internal service. However, it may not update all locations correctly. Use sync-wasm-clients.sh for complete synchronization.
The WASM files are out of sync. Run sync-wasm-clients.sh.
Vite is importing from the wrong file. Check import paths in your TypeScript files.
Ensure convert_string_cids_to_numbers includes all CID field names:
if (key == "cid" || key == "peer_cid" || key == "session_cid") && v.is_string() {- Ensure all WASM files are synchronized (check file sizes)
- Restart the Vite dev server
- Clear browser cache and hard refresh
- Always use the sync script after modifying WASM client code
- Commit synchronized files to ensure CI/CD builds work correctly
- Test CID handling with large values to ensure no precision loss
- Document WASM API changes in both Rust and TypeScript sides
- Keep package.json files in sync across all client directories