create-tinybase 0.2.5 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +62 -18
  2. package/cli.js +2 -2
  3. package/package.json +7 -4
  4. package/screenshots/chat.png +0 -0
  5. package/screenshots/drawing.png +0 -0
  6. package/screenshots/todos.png +0 -0
  7. package/templates/README.md.hbs +130 -12
  8. package/templates/client/eslint.config.js.hbs +7 -0
  9. package/templates/client/package.json.hbs +28 -8
  10. package/templates/client/src/chat/App.tsx.hbs +28 -22
  11. package/templates/client/src/chat/ChatStore.tsx.hbs +108 -27
  12. package/templates/client/src/chat/Message.tsx.hbs +8 -9
  13. package/templates/client/src/chat/MessageInput.tsx.hbs +7 -7
  14. package/templates/client/src/chat/Messages.tsx.hbs +5 -15
  15. package/templates/client/src/chat/SettingsStore.tsx.hbs +86 -9
  16. package/templates/client/src/chat/UsernameInput.tsx.hbs +6 -11
  17. package/templates/client/src/chat/app.ts.hbs +18 -18
  18. package/templates/client/src/chat/chatStore.ts.hbs +97 -35
  19. package/templates/client/src/chat/message.ts.hbs +4 -3
  20. package/templates/client/src/chat/messageInput.css.hbs +1 -1
  21. package/templates/client/src/chat/messageInput.ts.hbs +7 -8
  22. package/templates/client/src/chat/messages.ts.hbs +7 -12
  23. package/templates/client/src/chat/settingsStore.ts.hbs +65 -6
  24. package/templates/client/src/chat/usernameInput.css.hbs +1 -1
  25. package/templates/client/src/chat/usernameInput.ts.hbs +6 -6
  26. package/templates/client/src/chat/utils.ts.hbs +26 -0
  27. package/templates/client/src/drawing/App.tsx.hbs +26 -20
  28. package/templates/client/src/drawing/BrushSize.tsx.hbs +8 -11
  29. package/templates/client/src/drawing/Canvas.tsx.hbs +65 -73
  30. package/templates/client/src/drawing/CanvasStore.tsx.hbs +104 -18
  31. package/templates/client/src/drawing/ColorPicker.tsx.hbs +4 -11
  32. package/templates/client/src/drawing/DrawingControls.tsx.hbs +7 -7
  33. package/templates/client/src/drawing/SettingsStore.tsx.hbs +81 -8
  34. package/templates/client/src/drawing/app.ts.hbs +18 -8
  35. package/templates/client/src/drawing/brushSize.ts.hbs +12 -5
  36. package/templates/client/src/drawing/canvas.ts.hbs +84 -86
  37. package/templates/client/src/drawing/canvasStore.ts.hbs +93 -26
  38. package/templates/client/src/drawing/colorPicker.ts.hbs +3 -3
  39. package/templates/client/src/drawing/drawingControls.ts.hbs +7 -7
  40. package/templates/client/src/drawing/settingsStore.ts.hbs +63 -8
  41. package/templates/client/src/game/App.tsx.hbs +20 -16
  42. package/templates/client/src/game/Board.tsx.hbs +8 -8
  43. package/templates/client/src/game/Game.tsx.hbs +14 -21
  44. package/templates/client/src/game/GameStatus.tsx.hbs +5 -5
  45. package/templates/client/src/game/Square.tsx.hbs +6 -11
  46. package/templates/client/src/game/Store.tsx.hbs +106 -16
  47. package/templates/client/src/game/app.ts.hbs +17 -6
  48. package/templates/client/src/game/board.ts.hbs +7 -7
  49. package/templates/client/src/game/game.ts.hbs +12 -18
  50. package/templates/client/src/game/gameStatus.ts.hbs +3 -3
  51. package/templates/client/src/game/square.ts.hbs +4 -4
  52. package/templates/client/src/game/store.ts.hbs +95 -23
  53. package/templates/client/src/index.tsx.hbs +5 -7
  54. package/templates/client/src/shared/Button.tsx.hbs +3 -3
  55. package/templates/client/src/shared/Input.tsx.hbs +2 -2
  56. package/templates/client/src/shared/Loading.tsx.hbs +5 -0
  57. package/templates/client/src/shared/button.ts.hbs +2 -2
  58. package/templates/client/src/shared/config.ts.hbs +4 -6
  59. package/templates/client/src/shared/input.ts.hbs +2 -2
  60. package/templates/client/src/shared/loading.css.hbs +21 -0
  61. package/templates/client/src/shared/loading.ts.hbs +13 -0
  62. package/templates/client/src/shared/pglite.ts.hbs +10 -0
  63. package/templates/client/src/shared/sqlite.ts.hbs +17 -0
  64. package/templates/client/src/todos/App.tsx.hbs +22 -22
  65. package/templates/client/src/todos/Store.tsx.hbs +106 -23
  66. package/templates/client/src/todos/TodoInput.tsx.hbs +6 -8
  67. package/templates/client/src/todos/TodoItem.tsx.hbs +5 -6
  68. package/templates/client/src/todos/TodoList.tsx.hbs +5 -6
  69. package/templates/client/src/todos/app.ts.hbs +16 -10
  70. package/templates/client/src/todos/store.ts.hbs +94 -30
  71. package/templates/client/src/todos/todoInput.ts.hbs +5 -8
  72. package/templates/client/src/todos/todoItem.ts.hbs +3 -4
  73. package/templates/client/src/todos/todoList.ts.hbs +6 -8
  74. package/templates/client/vite-env.d.ts.hbs +4 -0
  75. package/templates/client/vite.config.js.hbs +53 -3
  76. package/templates/server/index.ts.hbs +43 -0
  77. package/templates/server/package.json.hbs +6 -7
  78. package/templates/server/wrangler.toml.hbs +1 -1
  79. package/templates/server/index-do.ts.hbs +0 -22
  80. package/templates/server/index-node.ts.hbs +0 -8
  81. /package/templates/client/{.prettierrc.hbs → .prettierrc.json.hbs} +0 -0
@@ -1,21 +1,18 @@
1
1
  {{#if schemas}}
2
- import {createMergeableStore} from 'tinybase/with-schemas';
3
- {{else}}
4
- import {createMergeableStore} from 'tinybase';
5
- {{/if}}
6
-
7
- const STORE_ID = 'todos';
8
-
9
- {{#if schemas}}
2
+ {{addImport "import {createMergeableStore, type Row} from 'tinybase/with-schemas';"}}
10
3
  const TODOS_SCHEMA = {
11
4
  todos: {
12
- text: {type: 'string'},
13
- completed: {type: 'boolean'},
5
+ text: {type: 'string', default: ''},
6
+ completed: {type: 'boolean', default: false},
14
7
  },
15
8
  } as const;
16
-
9
+ {{else}}
10
+ {{addImport "import {createMergeableStore} from 'tinybase';"}}
17
11
  {{/if}}
18
- export const store = createMergeableStore(STORE_ID){{#if schemas}}
12
+
13
+ export type TodoRow = {{#if schemas}}Row<typeof TODOS_SCHEMA, 'todos'>{{else}}{text: string; completed: boolean}{{/if}};
14
+
15
+ export const store = createMergeableStore(){{#if schemas}}
19
16
  .setTablesSchema(TODOS_SCHEMA){{/if}}
20
17
  .setDefaultContent([
21
18
  {
@@ -27,23 +24,90 @@ todos: {
27
24
  {},
28
25
  ]);
29
26
 
30
- {{#if sync}}
31
- {{includeFile template="client/src/shared/config.ts.hbs" output="client/src/config.ts"}}
32
- {{addImport "import {SERVER} from './config';"}}
33
- {{addImport "import ReconnectingWebSocket from 'reconnecting-websocket';"}}
34
- {{addImport "import {createWsSynchronizer} from 'tinybase/synchronizers/synchronizer-ws-client';"}}
35
-
36
- const serverPathId = location.pathname;
37
- createWsSynchronizer(
38
- store,
39
- new ReconnectingWebSocket(SERVER + serverPathId),
40
- ).then(async (synchronizer) => {
41
- await synchronizer.startSync();
42
-
43
- synchronizer.getWebSocket().addEventListener('open', () => {
44
- synchronizer.load().then(() => synchronizer.save());
45
- });
27
+ let resolveReady: () => void;
28
+ export const storeReady = new Promise<void>((resolve) => {
29
+ resolveReady = resolve;
46
30
  });
47
- {{/if}}
48
31
 
49
- export type TodosStore = typeof store;
32
+ {{#if persist}}
33
+ {{#if persistLocalStorage}}
34
+ {{#if schemas}}
35
+ {{addImport "import {createLocalPersister} from 'tinybase/persisters/persister-browser/with-schemas';"}}
36
+ {{else}}
37
+ {{addImport "import {createLocalPersister} from 'tinybase/persisters/persister-browser';"}}
38
+ {{/if}}
39
+
40
+ const persister = createLocalPersister(store, 'todos');
41
+ persister.load().then(() => {
42
+ persister.startAutoSave();
43
+ resolveReady();
44
+ });
45
+ {{/if}}
46
+ {{#if persistSqlite}}
47
+ {{#if schemas}}
48
+ {{addImport "import {createSqliteWasmPersister} from 'tinybase/persisters/persister-sqlite-wasm/with-schemas';"}}
49
+ {{else}}
50
+ {{addImport "import {createSqliteWasmPersister} from 'tinybase/persisters/persister-sqlite-wasm';"}}
51
+ {{/if}}
52
+ {{includeFile template="client/src/shared/sqlite.ts.hbs" output="client/src/sqlite.ts"}}
53
+ {{addImport "import {getDb} from './sqlite';"}}
54
+
55
+ getDb().then(({sqlite3, db}) => {
56
+ const persister = createSqliteWasmPersister(store, sqlite3, db, 'todos');
57
+ persister.load().then(() => {
58
+ persister.startAutoSave();
59
+ resolveReady();
60
+ });
61
+ });
62
+ {{/if}}
63
+ {{#if persistPglite}}
64
+ {{#if schemas}}
65
+ {{addImport "import {createPglitePersister} from 'tinybase/persisters/persister-pglite/with-schemas';"}}
66
+ {{else}}
67
+ {{addImport "import {createPglitePersister} from 'tinybase/persisters/persister-pglite';"}}
68
+ {{/if}}
69
+ {{includeFile template="client/src/shared/pglite.ts.hbs" output="client/src/pglite.{{ext}}"}}
70
+ {{addImport "import {getPgLite} from './pglite';"}}
71
+
72
+ getPgLite().then((pgLite) => {
73
+ createPglitePersister(store, pgLite, 'todos').then((persister) => {
74
+ persister.load().then(() => {
75
+ persister.startAutoSave();
76
+ resolveReady();
77
+ });
78
+ });
79
+ });
80
+ {{/if}}
81
+ {{/if}}
82
+
83
+ {{#if sync}}
84
+ {{includeFile template="client/src/shared/config.ts.hbs" output="client/src/config.ts"}}
85
+ {{addImport "import {SERVER} from './config';"}}
86
+ {{addImport "import ReconnectingWebSocket from 'reconnecting-websocket';"}}
87
+ {{#if schemas}}
88
+ {{addImport "import {createWsSynchronizer} from 'tinybase/synchronizers/synchronizer-ws-client/with-schemas';"}}
89
+ {{else}}
90
+ {{addImport "import {createWsSynchronizer} from 'tinybase/synchronizers/synchronizer-ws-client';"}}
91
+ {{/if}}
92
+
93
+ const serverPathId = location.pathname;
94
+ createWsSynchronizer(
95
+ store,
96
+ new ReconnectingWebSocket(SERVER + serverPathId),
97
+ ).then(async (synchronizer) => {
98
+ await synchronizer.startSync();
99
+
100
+ synchronizer.getWebSocket().addEventListener('open', () => {
101
+ synchronizer.load().then(() => {
102
+ synchronizer.save();
103
+ {{#unless persist}}resolveReady();{{/unless}}
104
+ });
105
+ });
106
+ });
107
+ {{/if}}
108
+
109
+ {{#unless persist}}{{#unless sync}}
110
+ resolveReady();
111
+ {{/unless}}{{/unless}}
112
+
113
+ export type TodosStore = typeof store;
@@ -1,12 +1,10 @@
1
1
  {{includeFile template="client/src/todos/todoInput.css.hbs" output="client/src/todoInput.css"}}
2
- import './todoInput.css';
3
- import {type TodosStore} from './store';
4
-
2
+ {{addImport "import './todoInput.css';"}}
3
+ {{addImport "import {type TodosStore} from './store';"}}
5
4
  {{includeFile template="client/src/shared/button.ts.hbs" output="client/src/button.{{ext}}"}}
6
- import {createButton} from './button';
7
-
5
+ {{addImport "import {createButton} from './button';"}}
8
6
  {{includeFile template="client/src/shared/input.ts.hbs" output="client/src/input.{{ext}}"}}
9
- import {createInput} from './input';
7
+ {{addImport "import {createInput} from './input';"}}
10
8
 
11
9
  export const createTodoInput = (store: TodosStore): HTMLDivElement => {
12
10
  const container = document.createElement('div');
@@ -19,7 +17,6 @@ const text = input.value.trim();
19
17
  if (text) {
20
18
  store.addRow('todos', {text, completed: false});
21
19
  input.value = '';
22
- input.focus();
23
20
  }
24
21
  };
25
22
 
@@ -35,4 +32,4 @@ container.appendChild(input);
35
32
  container.appendChild(addButton);
36
33
 
37
34
  return container;
38
- };
35
+ };
@@ -1,8 +1,7 @@
1
1
  {{includeFile template="client/src/todos/todoItem.css.hbs" output="client/src/todoItem.css"}}
2
- import './todoItem.css';
3
-
2
+ {{addImport "import './todoItem.css';"}}
4
3
  {{includeFile template="client/src/shared/button.ts.hbs" output="client/src/button.{{ext}}"}}
5
- import {createButton} from './button';
4
+ {{addImport "import {createButton} from './button';"}}
6
5
 
7
6
  export const createTodoItem = (id: string, text: string, completed: boolean, onToggle: () => void, onDelete: () => void): HTMLDivElement => {
8
7
  const item = document.createElement('div');
@@ -25,4 +24,4 @@ item.appendChild(label);
25
24
  item.appendChild(deleteBtn);
26
25
 
27
26
  return item;
28
- };
27
+ };
@@ -1,21 +1,19 @@
1
1
  {{includeFile template="client/src/todos/todoList.css.hbs" output="client/src/todoList.css"}}
2
- import './todoList.css';
3
- import {type TodosStore} from './store';
4
-
2
+ {{addImport "import './todoList.css';"}}
3
+ {{addImport "import {type TodosStore, type TodoRow} from './store';"}}
5
4
  {{includeFile template="client/src/todos/todoItem.ts.hbs" output="client/src/todoItem.{{ext}}"}}
6
- import {createTodoItem} from './todoItem';
5
+ {{addImport "import {createTodoItem} from './todoItem';"}}
7
6
 
8
7
  export const createTodoList = (store: TodosStore): HTMLDivElement => {
9
8
  const list = document.createElement('div');
10
9
  list.id = 'todoList';
11
10
 
12
11
  const render = () => {
13
- const todos = store.getTable('todos');
14
- const todoIds = Object.keys(todos);
12
+ const todoIds = store.getSortedRowIds('todos');
15
13
 
16
14
  list.innerHTML = '';
17
15
  todoIds.forEach((id) => {
18
- const todo = todos[id];
16
+ const todo = store.getRow('todos', id) as TodoRow;
19
17
  const item = createTodoItem(
20
18
  id,
21
19
  todo.text,
@@ -35,4 +33,4 @@ store.addTablesListener(render);
35
33
  render();
36
34
 
37
35
  return list;
38
- };
36
+ };
@@ -0,0 +1,4 @@
1
+ declare module '*.css' {
2
+ const content: string;
3
+ export default content;
4
+ }
@@ -2,11 +2,61 @@
2
2
  {{#if react}}
3
3
  {{addImport "import react from '@vitejs/plugin-react';"}}
4
4
  {{/if}}
5
+ {{#if persistSqlite}}
6
+ {{addImport "import {viteStaticCopy} from 'vite-plugin-static-copy';"}}
7
+ {{/if}}
8
+ {{#if persistPglite}}
9
+ {{addImport "import {viteStaticCopy} from 'vite-plugin-static-copy';"}}
10
+ {{/if}}
5
11
 
6
12
  export default defineConfig({
13
+ plugins: [
7
14
  {{#if react}}
8
- plugins: [react({
9
- jsxRuntime: 'automatic',
10
- })],
15
+ react({
16
+ jsxRuntime: 'automatic',
17
+ }),
18
+ {{/if}}
19
+ {{#if persistSqlite}}
20
+ viteStaticCopy({
21
+ targets: [
22
+ {
23
+ src: 'node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm/sqlite3.wasm',
24
+ dest: '.'
25
+ }
26
+ ]
27
+ }),
28
+ {{/if}}
29
+ {{#if persistPglite}}
30
+ viteStaticCopy({
31
+ targets: [
32
+ {
33
+ src: 'node_modules/@electric-sql/pglite/dist/*.wasm',
34
+ dest: '.'
35
+ }
36
+ ]
37
+ }),
38
+ {{/if}}
39
+ ],
40
+ {{#if persistSqlite}}
41
+ server: {
42
+ headers: {
43
+ 'Cross-Origin-Opener-Policy': 'same-origin',
44
+ 'Cross-Origin-Embedder-Policy': 'require-corp',
45
+ },
46
+ },
47
+ optimizeDeps: {
48
+ exclude: ['@sqlite.org/sqlite-wasm'],
49
+ },
50
+ {{/if}}
51
+ {{#if persistPglite}}
52
+ server: {
53
+ headers: {
54
+ 'Cross-Origin-Opener-Policy': 'same-origin',
55
+ 'Cross-Origin-Embedder-Policy': 'require-corp',
56
+ },
57
+ },
58
+ optimizeDeps: {
59
+ exclude: ['@electric-sql/pglite'],
60
+ },
11
61
  {{/if}}
12
62
  });
@@ -0,0 +1,43 @@
1
+ {{#if isDurableObject}}
2
+ {{addImport "import {createMergeableStore} from 'tinybase';"}}
3
+ {{addImport "import {createDurableObjectSqlStoragePersister} from 'tinybase/persisters/persister-durable-object-sql-storage';"}}
4
+ {{addImport "import {getWsServerDurableObjectFetch, WsServerDurableObject} from 'tinybase/synchronizers/synchronizer-ws-server-durable-object';"}}
5
+
6
+ export class TinyBaseDurableObject extends WsServerDurableObject {
7
+ createPersister() {
8
+ const store = createMergeableStore();
9
+ const persister = createDurableObjectSqlStoragePersister(
10
+ store,
11
+ this.ctx.storage.sql,
12
+ );
13
+ return persister;
14
+ }
15
+
16
+ onClientId(
17
+ pathId: string,
18
+ clientId: string,
19
+ addedOrRemoved: IdAddedOrRemoved,
20
+ ) {
21
+ console.log(
22
+ `Client ${clientId} ${addedOrRemoved == 1 ? 'joined' : 'left'} /${pathId}`,
23
+ );
24
+ }
25
+ }
26
+
27
+ export default {
28
+ fetch: getWsServerDurableObjectFetch('TinyBaseDurableObjects'),
29
+ };
30
+ {{else}}
31
+ {{addImport "import {createWsServer} from 'tinybase/synchronizers/synchronizer-ws-server';"}}
32
+ {{addImport "import {WebSocketServer} from 'ws';"}}
33
+
34
+ const PORT = 8043;
35
+
36
+ const wsServer = createWsServer(new WebSocketServer({port: PORT}));
37
+
38
+ wsServer.addClientIdsListener(null, (wsServer, pathId, clientId, addedOrRemoved) => {
39
+ console.log(`Client ${clientId} ${addedOrRemoved == 1 ? 'joined' : 'left'} /${pathId}`);
40
+ });
41
+
42
+ console.log(`WebSocket server running on ws://localhost:${PORT}`);
43
+ {{/if}}
@@ -5,12 +5,11 @@
5
5
  "main": "index.ts",
6
6
  "scripts": {
7
7
  {{#list}}
8
+ {{includeFile template="server/index.ts.hbs" output="server/index.ts"}}
8
9
  {{#if (eq serverType "node")}}
9
- {{includeFile template="server/index-node.ts.hbs" output="server/index.ts"}}
10
10
  "dev": "tsx watch index.ts"
11
11
  "start": "node index.js"
12
12
  {{else}}
13
- {{includeFile template="server/index-do.ts.hbs" output="server/index.ts"}}
14
13
  {{includeFile template="server/wrangler.toml.hbs" output="server/wrangler.toml"}}
15
14
  {{#if typescript}}
16
15
  {{includeFile template="server/tsconfig.json.hbs" output="server/tsconfig.json"}}
@@ -23,9 +22,9 @@
23
22
  },
24
23
  "dependencies": {
25
24
  {{#list}}
26
- "tinybase": "^7.3.1"
25
+ "tinybase": "^7.3.2"
27
26
  {{#if (eq serverType "node")}}
28
- "ws": "^8.18.3"
27
+ "ws": "^8.19.0"
29
28
  {{/if}}
30
29
  {{/list}}
31
30
  },
@@ -34,16 +33,16 @@
34
33
  {{#if (eq serverType "node")}}
35
34
  "@types/ws": "^8.18.1"
36
35
  {{else}}
37
- "@cloudflare/workers-types": "^4.20250828.1"
36
+ "@cloudflare/workers-types": "^4.20260120.0"
38
37
  {{/if}}
39
38
  {{#if typescript}}
40
39
  "typescript": "^5.9.3"
41
40
  {{#if (eq serverType "node")}}
42
- "tsx": "^4.19.3"
41
+ "tsx": "^4.21.0"
43
42
  {{/if}}
44
43
  {{/if}}
45
44
  {{#if (eq serverType "durable-objects")}}
46
- "wrangler": "^4.33.1"
45
+ "wrangler": "^4.59.2"
47
46
  {{/if}}
48
47
  {{/list}}
49
48
  }
@@ -9,4 +9,4 @@ class_name = "TinyBaseDurableObject"
9
9
 
10
10
  [[migrations]]
11
11
  tag = "v1"
12
- new_classes = ["TinyBaseDurableObject"]
12
+ new_sqlite_classes = ["TinyBaseDurableObject"]
@@ -1,22 +0,0 @@
1
- import {Id, IdAddedOrRemoved} from 'tinybase';
2
- import {
3
- getWsServerDurableObjectFetch,
4
- WsServerDurableObject,
5
- } from 'tinybase/synchronizers/synchronizer-ws-server-durable-object';
6
-
7
- export class TinyBaseDurableObject extends WsServerDurableObject {
8
- onPathId(pathId: Id, addedOrRemoved: IdAddedOrRemoved) {
9
- console.info((addedOrRemoved ? 'Added' : 'Removed') + ` path ${pathId}`);
10
- }
11
-
12
- onClientId(pathId: Id, clientId: Id, addedOrRemoved: IdAddedOrRemoved) {
13
- console.info(
14
- (addedOrRemoved ? 'Added' : 'Removed') +
15
- ` client ${clientId} on path ${pathId}`,
16
- );
17
- }
18
- }
19
-
20
- export default {
21
- fetch: getWsServerDurableObjectFetch('TinyBaseDurableObjects'),
22
- };
@@ -1,8 +0,0 @@
1
- import {createWsServer} from 'tinybase/synchronizers/synchronizer-ws-server';
2
- import {WebSocketServer} from 'ws';
3
-
4
- const PORT = 8043;
5
-
6
- const wsServer = createWsServer(new WebSocketServer({port: PORT}));
7
-
8
- console.log(`WebSocket server running on ws://localhost:${PORT}`);