Initial commit
This commit is contained in:
commit
12bbf65057
32 changed files with 2373 additions and 0 deletions
.envrc.gitignore
.vscode
client
.gitignoreindex.htmlpackage.jsonpnpm-lock.yaml
flake.lockflake.nixpublic
src
App.cssApp.tsx
tsconfig.app.jsontsconfig.jsontsconfig.node.jsonvite.config.tsbindings
counter_table.tscounter_type.tscreate_counter_reducer.tsdelete_counter_reducer.tsincrease_counter_reducer.tsindex.ts
index.cssindex.tsxvite-env.d.tsserver
treefmt.nix
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.direnv
|
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"rust-lang.rust-analyzer",
|
||||
"jnoortheen.nix-ide",
|
||||
"mkhl.direnv"
|
||||
]
|
||||
}
|
24
client/.gitignore
vendored
Normal file
24
client/.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
13
client/index.html
Normal file
13
client/index.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Solid + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
21
client/package.json
Normal file
21
client/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "client",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clockworklabs/spacetimedb-sdk": "^1.0.3",
|
||||
"solid-js": "^1.9.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "~5.7.2",
|
||||
"vite": "^6.2.0",
|
||||
"vite-plugin-oxlint": "^1.3.0",
|
||||
"vite-plugin-solid": "^2.11.2"
|
||||
}
|
||||
}
|
1202
client/pnpm-lock.yaml
generated
Normal file
1202
client/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
1
client/public/vite.svg
Normal file
1
client/public/vite.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After (image error) Size: 1.5 KiB |
4
client/src/App.css
Normal file
4
client/src/App.css
Normal file
|
@ -0,0 +1,4 @@
|
|||
#root {
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
137
client/src/App.tsx
Normal file
137
client/src/App.tsx
Normal file
|
@ -0,0 +1,137 @@
|
|||
import { createEffect, createSignal, For, Show, Signal } from 'solid-js'
|
||||
import './App.css'
|
||||
import { Counter, DbConnection, ErrorContext, EventContext } from './bindings'
|
||||
import { Identity } from '@clockworklabs/spacetimedb-sdk'
|
||||
|
||||
export async function wait(ms: number) {
|
||||
return new Promise((resolve) => { setTimeout(resolve, ms) });
|
||||
}
|
||||
|
||||
enum Status {
|
||||
Connecting,
|
||||
Loading,
|
||||
Connected,
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [connection, setConnection] = createSignal<DbConnection | undefined>();
|
||||
const [status, setStatus] = createSignal<Status>(Status.Connecting);
|
||||
|
||||
createEffect(() => {
|
||||
const counterOnInsert = (_ctx: EventContext, row: Counter) => {
|
||||
const newCounter: [number, Signal<number>] = [row.id, createSignal(row.value)];
|
||||
// Asserting here that a newly inserted Counter will always be at the end, and skip sorting
|
||||
setCounters([...counters(), newCounter])
|
||||
}
|
||||
const counterOnUpdate = (_ctx: EventContext, row: Counter) => {
|
||||
const counter = counters().find(([id]) => id === row.id);
|
||||
if (counter) {
|
||||
const [, [, setCount]] = counter;
|
||||
|
||||
console.debug("server setting to", row.value)
|
||||
setCount(row.value);
|
||||
}
|
||||
};
|
||||
const counterOnDelete = (_ctx: EventContext, row: Counter) => {
|
||||
setCounters(counters().filter(([id]) => id !== row.id));
|
||||
};
|
||||
const onConnect = (connection: DbConnection, identity: Identity, token: string) => {
|
||||
console.debug("onConnect")
|
||||
localStorage.setItem("auth_token", token);
|
||||
console.debug("Connected with Identity ", identity.toHexString());
|
||||
|
||||
const counter = connection.db.counter;
|
||||
counter.onInsert(counterOnInsert)
|
||||
counter.onUpdate(counterOnUpdate)
|
||||
counter.onDelete(counterOnDelete)
|
||||
|
||||
setStatus(Status.Loading);
|
||||
connection.subscriptionBuilder().onApplied(() => {
|
||||
console.debug("onApplied", "SELECT * FROM counter");
|
||||
setStatus(Status.Connected)
|
||||
})
|
||||
.onError(console.error)
|
||||
.subscribe("SELECT * FROM counter");
|
||||
}
|
||||
|
||||
const onDisconnect = (_ctx: ErrorContext, error?: Error) => {
|
||||
if (error)
|
||||
console.error("Disconnecting", error)
|
||||
else
|
||||
console.error("Disconnecting")
|
||||
setStatus(Status.Disconnected)
|
||||
const conn = connection();
|
||||
if (!conn) return;
|
||||
const counter = conn.db.counter;
|
||||
counter.removeOnInsert(counterOnInsert);
|
||||
counter.removeOnUpdate(counterOnUpdate);
|
||||
counter.removeOnDelete(counterOnDelete);
|
||||
}
|
||||
|
||||
setConnection(DbConnection.builder()
|
||||
.withUri("ws://localhost:3000")
|
||||
.withModuleName("test")
|
||||
.withToken(localStorage.getItem("auth_token") ?? "")
|
||||
.onConnect(onConnect)
|
||||
.onDisconnect(onDisconnect)
|
||||
.onConnectError(console.error)
|
||||
.build())
|
||||
})
|
||||
|
||||
const [counters, setCounters] = createSignal<[number, Signal<number>][]>([])
|
||||
|
||||
const tryAddCounter = () => {
|
||||
connection()?.reducers.createCounter();
|
||||
}
|
||||
|
||||
const tryIncreaseCounter = ([id, [count, setCount]]: [number, Signal<number>]) => {
|
||||
connection()?.reducers.increaseCounter(id);
|
||||
// Predict!
|
||||
console.debug("client setting to", count() + 1)
|
||||
setCount(count() + 1);
|
||||
}
|
||||
|
||||
const tryDeleteCounter = (id: number) => {
|
||||
connection()?.reducers.deleteCounter(id);
|
||||
setCounters(counters().filter(([counterId]) => counterId !== id));
|
||||
}
|
||||
|
||||
const getStatusText = () => {
|
||||
switch (status()) {
|
||||
case Status.Connecting:
|
||||
return "connecting...";
|
||||
case Status.Loading:
|
||||
return "loading...";
|
||||
case Status.Connected:
|
||||
return "connected"
|
||||
case Status.Disconnected:
|
||||
return "disconnected";
|
||||
default:
|
||||
return "Huh?";
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Show when={status() === Status.Connected} fallback={<span>{getStatusText()}</span>}>
|
||||
<button on:click={tryAddCounter}>+</button>
|
||||
<br />
|
||||
<For each={counters()}>
|
||||
{
|
||||
(counter) => {
|
||||
const [id, [count,]] = counter;
|
||||
return <>
|
||||
<span>
|
||||
<button id={`counter${id}`} on:click={_ => tryIncreaseCounter(counter)}>{count()}</button>
|
||||
<button id={`delCounter${id}`} on:click={_ => tryDeleteCounter(id)}>-</button>
|
||||
</span>
|
||||
<br />
|
||||
</>
|
||||
}
|
||||
}
|
||||
</For>
|
||||
</Show >
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
106
client/src/bindings/counter_table.ts
Normal file
106
client/src/bindings/counter_table.ts
Normal file
|
@ -0,0 +1,106 @@
|
|||
// 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 */
|
||||
// @ts-nocheck
|
||||
import {
|
||||
AlgebraicType,
|
||||
AlgebraicValue,
|
||||
BinaryReader,
|
||||
BinaryWriter,
|
||||
CallReducerFlags,
|
||||
ConnectionId,
|
||||
DbConnectionBuilder,
|
||||
DbConnectionImpl,
|
||||
DbContext,
|
||||
ErrorContextInterface,
|
||||
Event,
|
||||
EventContextInterface,
|
||||
Identity,
|
||||
ProductType,
|
||||
ProductTypeElement,
|
||||
ReducerEventContextInterface,
|
||||
SubscriptionBuilderImpl,
|
||||
SubscriptionEventContextInterface,
|
||||
SumType,
|
||||
SumTypeVariant,
|
||||
TableCache,
|
||||
TimeDuration,
|
||||
Timestamp,
|
||||
deepEqual,
|
||||
} from "@clockworklabs/spacetimedb-sdk";
|
||||
import { Counter } from "./counter_type";
|
||||
import { EventContext, Reducer, RemoteReducers, RemoteTables } from ".";
|
||||
|
||||
/**
|
||||
* Table handle for the table `counter`.
|
||||
*
|
||||
* Obtain a handle from the [`counter`] property on [`RemoteTables`],
|
||||
* like `ctx.db.counter`.
|
||||
*
|
||||
* Users are encouraged not to explicitly reference this type,
|
||||
* but to directly chain method calls,
|
||||
* like `ctx.db.counter.on_insert(...)`.
|
||||
*/
|
||||
export class CounterTableHandle {
|
||||
tableCache: TableCache<Counter>;
|
||||
|
||||
constructor(tableCache: TableCache<Counter>) {
|
||||
this.tableCache = tableCache;
|
||||
}
|
||||
|
||||
count(): number {
|
||||
return this.tableCache.count();
|
||||
}
|
||||
|
||||
iter(): Iterable<Counter> {
|
||||
return this.tableCache.iter();
|
||||
}
|
||||
/**
|
||||
* Access to the `id` unique index on the table `counter`,
|
||||
* which allows point queries on the field of the same name
|
||||
* via the [`CounterIdUnique.find`] method.
|
||||
*
|
||||
* Users are encouraged not to explicitly reference this type,
|
||||
* but to directly chain method calls,
|
||||
* like `ctx.db.counter.id().find(...)`.
|
||||
*
|
||||
* Get a handle on the `id` unique index on the table `counter`.
|
||||
*/
|
||||
id = {
|
||||
// Find the subscribed row whose `id` column value is equal to `col_val`,
|
||||
// if such a row is present in the client cache.
|
||||
find: (col_val: number): Counter | undefined => {
|
||||
for (let row of this.tableCache.iter()) {
|
||||
if (deepEqual(row.id, col_val)) {
|
||||
return row;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
onInsert = (cb: (ctx: EventContext, row: Counter) => void) => {
|
||||
return this.tableCache.onInsert(cb);
|
||||
}
|
||||
|
||||
removeOnInsert = (cb: (ctx: EventContext, row: Counter) => void) => {
|
||||
return this.tableCache.removeOnInsert(cb);
|
||||
}
|
||||
|
||||
onDelete = (cb: (ctx: EventContext, row: Counter) => void) => {
|
||||
return this.tableCache.onDelete(cb);
|
||||
}
|
||||
|
||||
removeOnDelete = (cb: (ctx: EventContext, row: Counter) => void) => {
|
||||
return this.tableCache.removeOnDelete(cb);
|
||||
}
|
||||
|
||||
// Updates are only defined for tables with primary keys.
|
||||
onUpdate = (cb: (ctx: EventContext, oldRow: Counter, newRow: Counter) => void) => {
|
||||
return this.tableCache.onUpdate(cb);
|
||||
}
|
||||
|
||||
removeOnUpdate = (cb: (ctx: EventContext, onRow: Counter, newRow: Counter) => void) => {
|
||||
return this.tableCache.removeOnUpdate(cb);
|
||||
}}
|
63
client/src/bindings/counter_type.ts
Normal file
63
client/src/bindings/counter_type.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
// 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 */
|
||||
// @ts-nocheck
|
||||
import {
|
||||
AlgebraicType,
|
||||
AlgebraicValue,
|
||||
BinaryReader,
|
||||
BinaryWriter,
|
||||
CallReducerFlags,
|
||||
ConnectionId,
|
||||
DbConnectionBuilder,
|
||||
DbConnectionImpl,
|
||||
DbContext,
|
||||
ErrorContextInterface,
|
||||
Event,
|
||||
EventContextInterface,
|
||||
Identity,
|
||||
ProductType,
|
||||
ProductTypeElement,
|
||||
ReducerEventContextInterface,
|
||||
SubscriptionBuilderImpl,
|
||||
SubscriptionEventContextInterface,
|
||||
SumType,
|
||||
SumTypeVariant,
|
||||
TableCache,
|
||||
TimeDuration,
|
||||
Timestamp,
|
||||
deepEqual,
|
||||
} from "@clockworklabs/spacetimedb-sdk";
|
||||
export type Counter = {
|
||||
id: number,
|
||||
value: number,
|
||||
};
|
||||
|
||||
/**
|
||||
* A namespace for generated helper functions.
|
||||
*/
|
||||
export namespace Counter {
|
||||
/**
|
||||
* A function which returns this type represented as an AlgebraicType.
|
||||
* This function is derived from the AlgebraicType used to generate this type.
|
||||
*/
|
||||
export function getTypeScriptAlgebraicType(): AlgebraicType {
|
||||
return AlgebraicType.createProductType([
|
||||
new ProductTypeElement("id", AlgebraicType.createU32Type()),
|
||||
new ProductTypeElement("value", AlgebraicType.createU32Type()),
|
||||
]);
|
||||
}
|
||||
|
||||
export function serialize(writer: BinaryWriter, value: Counter): void {
|
||||
Counter.getTypeScriptAlgebraicType().serialize(writer, value);
|
||||
}
|
||||
|
||||
export function deserialize(reader: BinaryReader): Counter {
|
||||
return Counter.getTypeScriptAlgebraicType().deserialize(reader);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
58
client/src/bindings/create_counter_reducer.ts
Normal file
58
client/src/bindings/create_counter_reducer.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
// 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 */
|
||||
// @ts-nocheck
|
||||
import {
|
||||
AlgebraicType,
|
||||
AlgebraicValue,
|
||||
BinaryReader,
|
||||
BinaryWriter,
|
||||
CallReducerFlags,
|
||||
ConnectionId,
|
||||
DbConnectionBuilder,
|
||||
DbConnectionImpl,
|
||||
DbContext,
|
||||
ErrorContextInterface,
|
||||
Event,
|
||||
EventContextInterface,
|
||||
Identity,
|
||||
ProductType,
|
||||
ProductTypeElement,
|
||||
ReducerEventContextInterface,
|
||||
SubscriptionBuilderImpl,
|
||||
SubscriptionEventContextInterface,
|
||||
SumType,
|
||||
SumTypeVariant,
|
||||
TableCache,
|
||||
TimeDuration,
|
||||
Timestamp,
|
||||
deepEqual,
|
||||
} from "@clockworklabs/spacetimedb-sdk";
|
||||
|
||||
export type CreateCounter = {};
|
||||
|
||||
/**
|
||||
* A namespace for generated helper functions.
|
||||
*/
|
||||
export namespace CreateCounter {
|
||||
/**
|
||||
* A function which returns this type represented as an AlgebraicType.
|
||||
* This function is derived from the AlgebraicType used to generate this type.
|
||||
*/
|
||||
export function getTypeScriptAlgebraicType(): AlgebraicType {
|
||||
return AlgebraicType.createProductType([
|
||||
]);
|
||||
}
|
||||
|
||||
export function serialize(writer: BinaryWriter, value: CreateCounter): void {
|
||||
CreateCounter.getTypeScriptAlgebraicType().serialize(writer, value);
|
||||
}
|
||||
|
||||
export function deserialize(reader: BinaryReader): CreateCounter {
|
||||
return CreateCounter.getTypeScriptAlgebraicType().deserialize(reader);
|
||||
}
|
||||
|
||||
}
|
||||
|
61
client/src/bindings/delete_counter_reducer.ts
Normal file
61
client/src/bindings/delete_counter_reducer.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
// 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 */
|
||||
// @ts-nocheck
|
||||
import {
|
||||
AlgebraicType,
|
||||
AlgebraicValue,
|
||||
BinaryReader,
|
||||
BinaryWriter,
|
||||
CallReducerFlags,
|
||||
ConnectionId,
|
||||
DbConnectionBuilder,
|
||||
DbConnectionImpl,
|
||||
DbContext,
|
||||
ErrorContextInterface,
|
||||
Event,
|
||||
EventContextInterface,
|
||||
Identity,
|
||||
ProductType,
|
||||
ProductTypeElement,
|
||||
ReducerEventContextInterface,
|
||||
SubscriptionBuilderImpl,
|
||||
SubscriptionEventContextInterface,
|
||||
SumType,
|
||||
SumTypeVariant,
|
||||
TableCache,
|
||||
TimeDuration,
|
||||
Timestamp,
|
||||
deepEqual,
|
||||
} from "@clockworklabs/spacetimedb-sdk";
|
||||
|
||||
export type DeleteCounter = {
|
||||
id: number,
|
||||
};
|
||||
|
||||
/**
|
||||
* A namespace for generated helper functions.
|
||||
*/
|
||||
export namespace DeleteCounter {
|
||||
/**
|
||||
* A function which returns this type represented as an AlgebraicType.
|
||||
* This function is derived from the AlgebraicType used to generate this type.
|
||||
*/
|
||||
export function getTypeScriptAlgebraicType(): AlgebraicType {
|
||||
return AlgebraicType.createProductType([
|
||||
new ProductTypeElement("id", AlgebraicType.createU32Type()),
|
||||
]);
|
||||
}
|
||||
|
||||
export function serialize(writer: BinaryWriter, value: DeleteCounter): void {
|
||||
DeleteCounter.getTypeScriptAlgebraicType().serialize(writer, value);
|
||||
}
|
||||
|
||||
export function deserialize(reader: BinaryReader): DeleteCounter {
|
||||
return DeleteCounter.getTypeScriptAlgebraicType().deserialize(reader);
|
||||
}
|
||||
|
||||
}
|
||||
|
61
client/src/bindings/increase_counter_reducer.ts
Normal file
61
client/src/bindings/increase_counter_reducer.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
// 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 */
|
||||
// @ts-nocheck
|
||||
import {
|
||||
AlgebraicType,
|
||||
AlgebraicValue,
|
||||
BinaryReader,
|
||||
BinaryWriter,
|
||||
CallReducerFlags,
|
||||
ConnectionId,
|
||||
DbConnectionBuilder,
|
||||
DbConnectionImpl,
|
||||
DbContext,
|
||||
ErrorContextInterface,
|
||||
Event,
|
||||
EventContextInterface,
|
||||
Identity,
|
||||
ProductType,
|
||||
ProductTypeElement,
|
||||
ReducerEventContextInterface,
|
||||
SubscriptionBuilderImpl,
|
||||
SubscriptionEventContextInterface,
|
||||
SumType,
|
||||
SumTypeVariant,
|
||||
TableCache,
|
||||
TimeDuration,
|
||||
Timestamp,
|
||||
deepEqual,
|
||||
} from "@clockworklabs/spacetimedb-sdk";
|
||||
|
||||
export type IncreaseCounter = {
|
||||
id: number,
|
||||
};
|
||||
|
||||
/**
|
||||
* A namespace for generated helper functions.
|
||||
*/
|
||||
export namespace IncreaseCounter {
|
||||
/**
|
||||
* A function which returns this type represented as an AlgebraicType.
|
||||
* This function is derived from the AlgebraicType used to generate this type.
|
||||
*/
|
||||
export function getTypeScriptAlgebraicType(): AlgebraicType {
|
||||
return AlgebraicType.createProductType([
|
||||
new ProductTypeElement("id", AlgebraicType.createU32Type()),
|
||||
]);
|
||||
}
|
||||
|
||||
export function serialize(writer: BinaryWriter, value: IncreaseCounter): void {
|
||||
IncreaseCounter.getTypeScriptAlgebraicType().serialize(writer, value);
|
||||
}
|
||||
|
||||
export function deserialize(reader: BinaryReader): IncreaseCounter {
|
||||
return IncreaseCounter.getTypeScriptAlgebraicType().deserialize(reader);
|
||||
}
|
||||
|
||||
}
|
||||
|
192
client/src/bindings/index.ts
Normal file
192
client/src/bindings/index.ts
Normal file
|
@ -0,0 +1,192 @@
|
|||
// 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 */
|
||||
// @ts-nocheck
|
||||
import {
|
||||
AlgebraicType,
|
||||
AlgebraicValue,
|
||||
BinaryReader,
|
||||
BinaryWriter,
|
||||
CallReducerFlags,
|
||||
ConnectionId,
|
||||
DbConnectionBuilder,
|
||||
DbConnectionImpl,
|
||||
DbContext,
|
||||
ErrorContextInterface,
|
||||
Event,
|
||||
EventContextInterface,
|
||||
Identity,
|
||||
ProductType,
|
||||
ProductTypeElement,
|
||||
ReducerEventContextInterface,
|
||||
SubscriptionBuilderImpl,
|
||||
SubscriptionEventContextInterface,
|
||||
SumType,
|
||||
SumTypeVariant,
|
||||
TableCache,
|
||||
TimeDuration,
|
||||
Timestamp,
|
||||
deepEqual,
|
||||
} from "@clockworklabs/spacetimedb-sdk";
|
||||
|
||||
// Import and reexport all reducer arg types
|
||||
import { CreateCounter } from "./create_counter_reducer.ts";
|
||||
export { CreateCounter };
|
||||
import { DeleteCounter } from "./delete_counter_reducer.ts";
|
||||
export { DeleteCounter };
|
||||
import { IncreaseCounter } from "./increase_counter_reducer.ts";
|
||||
export { IncreaseCounter };
|
||||
|
||||
// Import and reexport all table handle types
|
||||
import { CounterTableHandle } from "./counter_table.ts";
|
||||
export { CounterTableHandle };
|
||||
|
||||
// Import and reexport all types
|
||||
import { Counter } from "./counter_type.ts";
|
||||
export { Counter };
|
||||
|
||||
const REMOTE_MODULE = {
|
||||
tables: {
|
||||
counter: {
|
||||
tableName: "counter",
|
||||
rowType: Counter.getTypeScriptAlgebraicType(),
|
||||
primaryKey: "id",
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
create_counter: {
|
||||
reducerName: "create_counter",
|
||||
argsType: CreateCounter.getTypeScriptAlgebraicType(),
|
||||
},
|
||||
delete_counter: {
|
||||
reducerName: "delete_counter",
|
||||
argsType: DeleteCounter.getTypeScriptAlgebraicType(),
|
||||
},
|
||||
increase_counter: {
|
||||
reducerName: "increase_counter",
|
||||
argsType: IncreaseCounter.getTypeScriptAlgebraicType(),
|
||||
},
|
||||
},
|
||||
// Constructors which are used by the DbConnectionImpl to
|
||||
// extract type information from the generated RemoteModule.
|
||||
//
|
||||
// NOTE: This is not strictly necessary for `eventContextConstructor` because
|
||||
// all we do is build a TypeScript object which we could have done inside the
|
||||
// SDK, but if in the future we wanted to create a class this would be
|
||||
// necessary because classes have methods, so we'll keep it.
|
||||
eventContextConstructor: (imp: DbConnectionImpl, event: Event<Reducer>) => {
|
||||
return {
|
||||
...(imp as DbConnection),
|
||||
event
|
||||
}
|
||||
},
|
||||
dbViewConstructor: (imp: DbConnectionImpl) => {
|
||||
return new RemoteTables(imp);
|
||||
},
|
||||
reducersConstructor: (imp: DbConnectionImpl, setReducerFlags: SetReducerFlags) => {
|
||||
return new RemoteReducers(imp, setReducerFlags);
|
||||
},
|
||||
setReducerFlagsConstructor: () => {
|
||||
return new SetReducerFlags();
|
||||
}
|
||||
}
|
||||
|
||||
// A type representing all the possible variants of a reducer.
|
||||
export type Reducer = never
|
||||
| { name: "CreateCounter", args: CreateCounter }
|
||||
| { name: "DeleteCounter", args: DeleteCounter }
|
||||
| { name: "IncreaseCounter", args: IncreaseCounter }
|
||||
;
|
||||
|
||||
export class RemoteReducers {
|
||||
constructor(private connection: DbConnectionImpl, private setCallReducerFlags: SetReducerFlags) {}
|
||||
|
||||
createCounter() {
|
||||
this.connection.callReducer("create_counter", new Uint8Array(0), this.setCallReducerFlags.createCounterFlags);
|
||||
}
|
||||
|
||||
onCreateCounter(callback: (ctx: ReducerEventContext) => void) {
|
||||
this.connection.onReducer("create_counter", callback);
|
||||
}
|
||||
|
||||
removeOnCreateCounter(callback: (ctx: ReducerEventContext) => void) {
|
||||
this.connection.offReducer("create_counter", callback);
|
||||
}
|
||||
|
||||
deleteCounter(id: number) {
|
||||
const __args = { id };
|
||||
let __writer = new BinaryWriter(1024);
|
||||
DeleteCounter.getTypeScriptAlgebraicType().serialize(__writer, __args);
|
||||
let __argsBuffer = __writer.getBuffer();
|
||||
this.connection.callReducer("delete_counter", __argsBuffer, this.setCallReducerFlags.deleteCounterFlags);
|
||||
}
|
||||
|
||||
onDeleteCounter(callback: (ctx: ReducerEventContext, id: number) => void) {
|
||||
this.connection.onReducer("delete_counter", callback);
|
||||
}
|
||||
|
||||
removeOnDeleteCounter(callback: (ctx: ReducerEventContext, id: number) => void) {
|
||||
this.connection.offReducer("delete_counter", callback);
|
||||
}
|
||||
|
||||
increaseCounter(id: number) {
|
||||
const __args = { id };
|
||||
let __writer = new BinaryWriter(1024);
|
||||
IncreaseCounter.getTypeScriptAlgebraicType().serialize(__writer, __args);
|
||||
let __argsBuffer = __writer.getBuffer();
|
||||
this.connection.callReducer("increase_counter", __argsBuffer, this.setCallReducerFlags.increaseCounterFlags);
|
||||
}
|
||||
|
||||
onIncreaseCounter(callback: (ctx: ReducerEventContext, id: number) => void) {
|
||||
this.connection.onReducer("increase_counter", callback);
|
||||
}
|
||||
|
||||
removeOnIncreaseCounter(callback: (ctx: ReducerEventContext, id: number) => void) {
|
||||
this.connection.offReducer("increase_counter", callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class SetReducerFlags {
|
||||
createCounterFlags: CallReducerFlags = 'FullUpdate';
|
||||
createCounter(flags: CallReducerFlags) {
|
||||
this.createCounterFlags = flags;
|
||||
}
|
||||
|
||||
deleteCounterFlags: CallReducerFlags = 'FullUpdate';
|
||||
deleteCounter(flags: CallReducerFlags) {
|
||||
this.deleteCounterFlags = flags;
|
||||
}
|
||||
|
||||
increaseCounterFlags: CallReducerFlags = 'FullUpdate';
|
||||
increaseCounter(flags: CallReducerFlags) {
|
||||
this.increaseCounterFlags = flags;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class RemoteTables {
|
||||
constructor(private connection: DbConnectionImpl) {}
|
||||
|
||||
get counter(): CounterTableHandle {
|
||||
return new CounterTableHandle(this.connection.clientCache.getOrCreateTable<Counter>(REMOTE_MODULE.tables.counter));
|
||||
}
|
||||
}
|
||||
|
||||
export class SubscriptionBuilder extends SubscriptionBuilderImpl<RemoteTables, RemoteReducers, SetReducerFlags> { }
|
||||
|
||||
export class DbConnection extends DbConnectionImpl<RemoteTables, RemoteReducers, SetReducerFlags> {
|
||||
static builder = (): DbConnectionBuilder<DbConnection, ErrorContext, SubscriptionEventContext> => {
|
||||
return new DbConnectionBuilder<DbConnection, ErrorContext, SubscriptionEventContext>(REMOTE_MODULE, (imp: DbConnectionImpl) => imp as DbConnection);
|
||||
}
|
||||
subscriptionBuilder = (): SubscriptionBuilder => {
|
||||
return new SubscriptionBuilder(this);
|
||||
}
|
||||
}
|
||||
|
||||
export type EventContext = EventContextInterface<RemoteTables, RemoteReducers, SetReducerFlags, Reducer>;
|
||||
export type ReducerEventContext = ReducerEventContextInterface<RemoteTables, RemoteReducers, SetReducerFlags, Reducer>;
|
||||
export type SubscriptionEventContext = SubscriptionEventContextInterface<RemoteTables, RemoteReducers, SetReducerFlags>;
|
||||
export type ErrorContext = ErrorContextInterface<RemoteTables, RemoteReducers, SetReducerFlags>;
|
44
client/src/index.css
Normal file
44
client/src/index.css
Normal file
|
@ -0,0 +1,44 @@
|
|||
:root {
|
||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: dark light;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
text-rendering: optimizeSpeed;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
8
client/src/index.tsx
Normal file
8
client/src/index.tsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* @refresh reload */
|
||||
import { render } from 'solid-js/web'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
|
||||
const root = document.getElementById('root')
|
||||
|
||||
render(() => <App />, root!)
|
1
client/src/vite-env.d.ts
vendored
Normal file
1
client/src/vite-env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/// <reference types="vite/client" />
|
27
client/tsconfig.app.json
Normal file
27
client/tsconfig.app.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
7
client/tsconfig.json
Normal file
7
client/tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
24
client/tsconfig.node.json
Normal file
24
client/tsconfig.node.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
7
client/vite.config.ts
Normal file
7
client/vite.config.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import solid from 'vite-plugin-solid'
|
||||
import oxlint from 'vite-plugin-oxlint'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [solid(), oxlint()],
|
||||
})
|
85
flake.lock
generated
Normal file
85
flake.lock
generated
Normal file
|
@ -0,0 +1,85 @@
|
|||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1742394900,
|
||||
"narHash": "sha256-vVOAp9ahvnU+fQoKd4SEXB2JG2wbENkpqcwlkIXgUC0=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "70947c1908108c0c551ddfd73d4f750ff2ea67cd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1742546557,
|
||||
"narHash": "sha256-QyhimDBaDBtMfRc7kyL28vo+HTwXRPq3hz+BgSJDotw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "bfa9810ff7104a17555ab68ebdeafb6705f129b1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742524367,
|
||||
"narHash": "sha256-KzTwk/5ETJavJZYV1DEWdCx05M4duFCxCpRbQSKWpng=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "70bf752d176b2ce07417e346d85486acea9040ef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742370146,
|
||||
"narHash": "sha256-XRE8hL4vKIQyVMDXykFh4ceo3KSpuJF3ts8GKwh5bIU=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "adc195eef5da3606891cedf80c0d9ce2d3190808",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
83
flake.nix
Normal file
83
flake.nix
Normal file
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
description = "A Nix-flake-based Rust development environment";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||
|
||||
crane.url = "github:ipetkov/crane";
|
||||
|
||||
treefmt-nix = {
|
||||
url = "github:numtide/treefmt-nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
crane,
|
||||
treefmt-nix,
|
||||
rust-overlay,
|
||||
}:
|
||||
let
|
||||
supportedSystems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
forEachSupportedSystem =
|
||||
f:
|
||||
nixpkgs.lib.genAttrs supportedSystems (
|
||||
system:
|
||||
f (rec {
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ (import rust-overlay) ];
|
||||
config = {
|
||||
allowUnfreePredicate =
|
||||
pkg:
|
||||
builtins.elem (nixpkgs.lib.getName pkg) [
|
||||
"spacetimedb"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
rustToolchainFor = pkgs: pkgs.rust-bin.fromRustupToolchainFile ./server/rust-toolchain.toml;
|
||||
rustToolchain = rustToolchainFor pkgs;
|
||||
|
||||
# NB: we don't need to overlay our custom toolchain for the *entire*
|
||||
# pkgs (which would require rebuidling anything else which uses rust).
|
||||
# Instead, we just want to update the scope that crane will use by appending
|
||||
# our specific toolchain there.
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchainFor;
|
||||
})
|
||||
);
|
||||
in
|
||||
{
|
||||
formatter = forEachSupportedSystem (
|
||||
{ pkgs, ... }: (treefmt-nix.lib.evalModule pkgs ./treefmt.nix).config.build.wrapper
|
||||
);
|
||||
devShells = forEachSupportedSystem (
|
||||
{ pkgs, rustToolchain, ... }:
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
rustToolchain
|
||||
spacetimedb
|
||||
binaryen
|
||||
pnpm
|
||||
nodejs
|
||||
oxlint
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
1
server/.gitattributes
vendored
Normal file
1
server/.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
flake.lock linguist-generated=true
|
17
server/.gitignore
vendored
Normal file
17
server/.gitignore
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# Spacetime ignore
|
||||
/.spacetime
|
32
server/Cargo.toml
Normal file
32
server/Cargo.toml
Normal file
|
@ -0,0 +1,32 @@
|
|||
[package]
|
||||
authors = ["Toby <toby@tobot.dev>"]
|
||||
edition = "2024"
|
||||
name = "rust-nix-template"
|
||||
version = "0.1.0"
|
||||
|
||||
[profile.release]
|
||||
strip = "symbols"
|
||||
lto = true
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
[profile.release.package."*"]
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
[profile.release.build-override]
|
||||
codegen-units = 1
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies.colog]
|
||||
version = "1.3.0"
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.spacetimedb]
|
||||
version = "1.0.0"
|
||||
features = ["unstable"]
|
21
server/LICENSE
Normal file
21
server/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 Sridhar Ratnakumar
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
4
server/rust-toolchain.toml
Normal file
4
server/rust-toolchain.toml
Normal file
|
@ -0,0 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "nightly"
|
||||
components = ["rustfmt", "cargo", "rustc"]
|
||||
targets = ["wasm32-unknown-unknown"]
|
52
server/src/lib.rs
Normal file
52
server/src/lib.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use spacetimedb::{ReducerContext, Table};
|
||||
|
||||
#[spacetimedb::table(name = counter, public)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Counter {
|
||||
#[auto_inc]
|
||||
#[primary_key]
|
||||
id: u32,
|
||||
value: u32,
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer(init)]
|
||||
pub fn init(ctx: &ReducerContext) {
|
||||
log::error!("TESTA");
|
||||
colog::basic_builder().filter_level(if cfg!(debug_assertions) {
|
||||
log::LevelFilter::Trace
|
||||
} else {
|
||||
log::LevelFilter::Warn
|
||||
});
|
||||
log::error!("TESTB");
|
||||
for _ in 0..10 {
|
||||
create_counter(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer]
|
||||
pub fn create_counter(ctx: &ReducerContext) {
|
||||
let new_counter = ctx.db.counter().insert(Default::default());
|
||||
log::debug!("Created counter {new_counter:?}");
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer]
|
||||
pub fn delete_counter(ctx: &ReducerContext, id: u32) {
|
||||
let deleted = ctx.db.counter().id().delete(id);
|
||||
log::debug!(
|
||||
"Deletion of counter {id} {}",
|
||||
if deleted { "succeeded" } else { "failed" }
|
||||
)
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer]
|
||||
pub fn increase_counter(ctx: &ReducerContext, id: u32) {
|
||||
let counter = ctx.db.counter();
|
||||
if let Some(old) = counter.id().find(id) {
|
||||
let new = Counter {
|
||||
value: old.value + 1,
|
||||
..old
|
||||
};
|
||||
log::debug!("Updating counter {old:?} to {new:?}");
|
||||
counter.id().update(new);
|
||||
}
|
||||
}
|
8
treefmt.nix
Normal file
8
treefmt.nix
Normal file
|
@ -0,0 +1,8 @@
|
|||
{ ... }:
|
||||
{
|
||||
projectRootFile = "flake.nix";
|
||||
programs = {
|
||||
nixfmt.enable = true;
|
||||
rustfmt.enable = true;
|
||||
};
|
||||
}
|
Loading…
Add table
Reference in a new issue