@indexeddb-orm/idb-orm 0.0.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 (216) hide show
  1. package/.vscode/extensions.json +5 -0
  2. package/README.md +1280 -0
  3. package/angular-demo-app/README.md +84 -0
  4. package/angular-demo-app/angular.json +109 -0
  5. package/angular-demo-app/package-lock.json +14215 -0
  6. package/angular-demo-app/package.json +41 -0
  7. package/angular-demo-app/src/app/app.component.ts +481 -0
  8. package/angular-demo-app/src/app/app.routes.ts +8 -0
  9. package/angular-demo-app/src/app/components/actions.component.ts +202 -0
  10. package/angular-demo-app/src/app/components/cloud-sync-demo.component.ts +296 -0
  11. package/angular-demo-app/src/app/components/live-query-demo.component.ts +307 -0
  12. package/angular-demo-app/src/app/components/main-info.component.ts +148 -0
  13. package/angular-demo-app/src/app/components/posts-live-query-demo.component.ts +336 -0
  14. package/angular-demo-app/src/app/components/typescript-demo.component.ts +268 -0
  15. package/angular-demo-app/src/entities/post-tag.entity.ts +25 -0
  16. package/angular-demo-app/src/entities/post.entity.ts +49 -0
  17. package/angular-demo-app/src/entities/profile.entity.ts +42 -0
  18. package/angular-demo-app/src/entities/tag.entity.ts +36 -0
  19. package/angular-demo-app/src/entities/user.entity.ts +59 -0
  20. package/angular-demo-app/src/favicon.ico +1 -0
  21. package/angular-demo-app/src/index.html +16 -0
  22. package/angular-demo-app/src/main.ts +13 -0
  23. package/angular-demo-app/src/services/app-logic.service.ts +449 -0
  24. package/angular-demo-app/src/services/cloud-sync.service.ts +95 -0
  25. package/angular-demo-app/src/services/database.service.ts +26 -0
  26. package/angular-demo-app/src/services/live-query.service.ts +63 -0
  27. package/angular-demo-app/src/services/posts-live-query.service.ts +86 -0
  28. package/angular-demo-app/src/services/typescript-demo.service.ts +59 -0
  29. package/angular-demo-app/src/styles.scss +50 -0
  30. package/angular-demo-app/tsconfig.app.json +13 -0
  31. package/angular-demo-app/tsconfig.json +34 -0
  32. package/angular-demo-app/tsconfig.spec.json +13 -0
  33. package/dist/Database.d.ts +206 -0
  34. package/dist/Database.js +288 -0
  35. package/dist/decorators/Column.d.ts +79 -0
  36. package/dist/decorators/Column.js +236 -0
  37. package/dist/decorators/Entity.d.ts +32 -0
  38. package/dist/decorators/Entity.js +44 -0
  39. package/dist/decorators/Relation.d.ts +70 -0
  40. package/dist/decorators/Relation.js +120 -0
  41. package/dist/decorators/index.d.ts +3 -0
  42. package/dist/decorators/index.js +3 -0
  43. package/dist/errors/ValidationError.d.ts +4 -0
  44. package/dist/errors/ValidationError.js +8 -0
  45. package/dist/index.d.ts +8 -0
  46. package/dist/index.js +7 -0
  47. package/dist/metadata/Column.d.ts +8 -0
  48. package/dist/metadata/Column.js +44 -0
  49. package/dist/metadata/Entity.d.ts +11 -0
  50. package/dist/metadata/Entity.js +21 -0
  51. package/dist/metadata/Relation.d.ts +20 -0
  52. package/dist/metadata/Relation.js +74 -0
  53. package/dist/metadata/index.d.ts +3 -0
  54. package/dist/metadata/index.js +3 -0
  55. package/dist/services/AggregationService.d.ts +38 -0
  56. package/dist/services/AggregationService.js +229 -0
  57. package/dist/services/BaseEntity.d.ts +32 -0
  58. package/dist/services/BaseEntity.js +62 -0
  59. package/dist/services/CloudSyncService.d.ts +100 -0
  60. package/dist/services/CloudSyncService.js +196 -0
  61. package/dist/services/DecoratorUtils.d.ts +12 -0
  62. package/dist/services/DecoratorUtils.js +10 -0
  63. package/dist/services/EntityFactory.d.ts +25 -0
  64. package/dist/services/EntityFactory.js +27 -0
  65. package/dist/services/EntityRegistry.d.ts +61 -0
  66. package/dist/services/EntityRegistry.js +56 -0
  67. package/dist/services/EntitySchema.d.ts +56 -0
  68. package/dist/services/EntitySchema.js +125 -0
  69. package/dist/services/MigrationManager.d.ts +70 -0
  70. package/dist/services/MigrationManager.js +181 -0
  71. package/dist/services/RelationLoader.d.ts +66 -0
  72. package/dist/services/RelationLoader.js +310 -0
  73. package/dist/services/SchemaBuilder.d.ts +68 -0
  74. package/dist/services/SchemaBuilder.js +191 -0
  75. package/dist/services/index.d.ts +7 -0
  76. package/dist/services/index.js +7 -0
  77. package/dist/types.d.ts +152 -0
  78. package/dist/types.js +1 -0
  79. package/dist/utils/logger.d.ts +12 -0
  80. package/dist/utils/logger.js +16 -0
  81. package/eslint.config.js +49 -0
  82. package/homepage/favicon.svg +36 -0
  83. package/homepage/index.html +1725 -0
  84. package/package.json +78 -0
  85. package/react-demo-app/README.md +61 -0
  86. package/react-demo-app/eslint.config.js +60 -0
  87. package/react-demo-app/index.html +13 -0
  88. package/react-demo-app/package-lock.json +4955 -0
  89. package/react-demo-app/package.json +39 -0
  90. package/react-demo-app/src/App.tsx +172 -0
  91. package/react-demo-app/src/assets/react.svg +1 -0
  92. package/react-demo-app/src/components/Actions.tsx +171 -0
  93. package/react-demo-app/src/components/CloudSyncDemo.tsx +191 -0
  94. package/react-demo-app/src/components/LiveQueryDemo.tsx +122 -0
  95. package/react-demo-app/src/components/MainInfo.tsx +75 -0
  96. package/react-demo-app/src/components/PostsLiveQueryDemo.tsx +185 -0
  97. package/react-demo-app/src/components/TypeScriptDemo.tsx +190 -0
  98. package/react-demo-app/src/database/Database.ts +30 -0
  99. package/react-demo-app/src/entities/Post.ts +48 -0
  100. package/react-demo-app/src/entities/PostTag.ts +26 -0
  101. package/react-demo-app/src/entities/Profile.ts +41 -0
  102. package/react-demo-app/src/entities/Tag.ts +35 -0
  103. package/react-demo-app/src/entities/User.ts +61 -0
  104. package/react-demo-app/src/hooks/useAppLogic.ts +565 -0
  105. package/react-demo-app/src/hooks/useCloudSyncDemo.ts +84 -0
  106. package/react-demo-app/src/hooks/useLiveQueryDemo.ts +68 -0
  107. package/react-demo-app/src/hooks/usePostsLiveQueryDemo.ts +64 -0
  108. package/react-demo-app/src/hooks/useTypeScriptDemo.ts +43 -0
  109. package/react-demo-app/src/index.css +26 -0
  110. package/react-demo-app/src/main.tsx +18 -0
  111. package/react-demo-app/src/migrations/001-add-user-email-index.ts +17 -0
  112. package/react-demo-app/src/migrations/002-add-post-category.ts +37 -0
  113. package/react-demo-app/src/migrations/index.ts +8 -0
  114. package/react-demo-app/src/vite-env.d.ts +1 -0
  115. package/react-demo-app/tsconfig.app.json +22 -0
  116. package/react-demo-app/tsconfig.json +6 -0
  117. package/react-demo-app/vite.config.ts +10 -0
  118. package/src/Database.ts +405 -0
  119. package/src/errors/ValidationError.ts +9 -0
  120. package/src/index.ts +13 -0
  121. package/src/metadata/Column.ts +74 -0
  122. package/src/metadata/Entity.ts +42 -0
  123. package/src/metadata/Relation.ts +121 -0
  124. package/src/metadata/index.ts +5 -0
  125. package/src/services/AggregationService.ts +348 -0
  126. package/src/services/BaseEntity.ts +77 -0
  127. package/src/services/CloudSyncService.ts +248 -0
  128. package/src/services/EntityFactory.ts +35 -0
  129. package/src/services/EntityRegistry.ts +109 -0
  130. package/src/services/EntitySchema.ts +154 -0
  131. package/src/services/MigrationManager.ts +276 -0
  132. package/src/services/RelationLoader.ts +532 -0
  133. package/src/services/SchemaBuilder.ts +237 -0
  134. package/src/services/index.ts +7 -0
  135. package/src/types.d.ts +1 -0
  136. package/src/types.ts +169 -0
  137. package/src/utils/logger.ts +40 -0
  138. package/svelte-demo-app/README.md +61 -0
  139. package/svelte-demo-app/package-lock.json +3000 -0
  140. package/svelte-demo-app/package.json +30 -0
  141. package/svelte-demo-app/src/app.d.ts +12 -0
  142. package/svelte-demo-app/src/app.html +13 -0
  143. package/svelte-demo-app/src/components/Actions.svelte +121 -0
  144. package/svelte-demo-app/src/components/CloudSyncDemo.svelte +333 -0
  145. package/svelte-demo-app/src/components/LiveQueryDemo.svelte +191 -0
  146. package/svelte-demo-app/src/components/MainInfo.svelte +133 -0
  147. package/svelte-demo-app/src/components/PostsLiveQueryDemo.svelte +330 -0
  148. package/svelte-demo-app/src/components/TypeScriptDemo.svelte +251 -0
  149. package/svelte-demo-app/src/database/Database.ts +29 -0
  150. package/svelte-demo-app/src/entities/Post.ts +46 -0
  151. package/svelte-demo-app/src/entities/PostTag.ts +22 -0
  152. package/svelte-demo-app/src/entities/Profile.ts +39 -0
  153. package/svelte-demo-app/src/entities/Tag.ts +33 -0
  154. package/svelte-demo-app/src/entities/User.ts +62 -0
  155. package/svelte-demo-app/src/lib/database/Database.ts +30 -0
  156. package/svelte-demo-app/src/lib/entities/Post.ts +47 -0
  157. package/svelte-demo-app/src/lib/entities/PostTag.ts +23 -0
  158. package/svelte-demo-app/src/lib/entities/Profile.ts +40 -0
  159. package/svelte-demo-app/src/lib/entities/Tag.ts +34 -0
  160. package/svelte-demo-app/src/lib/entities/User.ts +59 -0
  161. package/svelte-demo-app/src/lib/index.ts +7 -0
  162. package/svelte-demo-app/src/lib/migrations/001-add-user-email-index.ts +17 -0
  163. package/svelte-demo-app/src/lib/migrations/002-add-post-category.ts +37 -0
  164. package/svelte-demo-app/src/lib/migrations/index.ts +8 -0
  165. package/svelte-demo-app/src/migrations/001-add-user-email-index.ts +17 -0
  166. package/svelte-demo-app/src/migrations/002-add-post-category.ts +37 -0
  167. package/svelte-demo-app/src/migrations/index.ts +8 -0
  168. package/svelte-demo-app/src/routes/+layout.js +3 -0
  169. package/svelte-demo-app/src/routes/+layout.svelte +228 -0
  170. package/svelte-demo-app/src/routes/+page.js +3 -0
  171. package/svelte-demo-app/src/routes/+page.svelte +1305 -0
  172. package/svelte-demo-app/src/stores/appStore.js +603 -0
  173. package/svelte-demo-app/svelte.config.js +18 -0
  174. package/svelte-demo-app/tsconfig.json +14 -0
  175. package/svelte-demo-app/vite.config.ts +6 -0
  176. package/tests/aggregation.e2e.test.ts +87 -0
  177. package/tests/base-entity.e2e.test.ts +47 -0
  178. package/tests/database-api.e2e.test.ts +177 -0
  179. package/tests/decorators.e2e.test.ts +40 -0
  180. package/tests/entity-schema.e2e.test.ts +58 -0
  181. package/tests/relation-loader-table-names.test.ts +192 -0
  182. package/tests/relations.e2e.test.ts +178 -0
  183. package/tests/zod-runtime.e2e.test.ts +69 -0
  184. package/tsconfig.json +21 -0
  185. package/vitest.config.ts +21 -0
  186. package/vitest.setup.ts +27 -0
  187. package/vue-demo-app/README.md +61 -0
  188. package/vue-demo-app/index.html +13 -0
  189. package/vue-demo-app/package-lock.json +1537 -0
  190. package/vue-demo-app/package.json +27 -0
  191. package/vue-demo-app/src/App.vue +100 -0
  192. package/vue-demo-app/src/components/Actions.vue +135 -0
  193. package/vue-demo-app/src/components/CloudSyncDemo.vue +139 -0
  194. package/vue-demo-app/src/components/LiveQueryDemo.vue +122 -0
  195. package/vue-demo-app/src/components/MainInfo.vue +80 -0
  196. package/vue-demo-app/src/components/PostsLiveQueryDemo.vue +136 -0
  197. package/vue-demo-app/src/components/TypeScriptDemo.vue +133 -0
  198. package/vue-demo-app/src/database/Database.ts +29 -0
  199. package/vue-demo-app/src/entities/Post.ts +48 -0
  200. package/vue-demo-app/src/entities/PostTag.ts +24 -0
  201. package/vue-demo-app/src/entities/Profile.ts +41 -0
  202. package/vue-demo-app/src/entities/Tag.ts +35 -0
  203. package/vue-demo-app/src/entities/User.ts +61 -0
  204. package/vue-demo-app/src/main.ts +29 -0
  205. package/vue-demo-app/src/migrations/001-add-user-email-index.ts +23 -0
  206. package/vue-demo-app/src/migrations/002-add-post-category.ts +46 -0
  207. package/vue-demo-app/src/migrations/index.ts +14 -0
  208. package/vue-demo-app/src/services/useAppLogic.ts +565 -0
  209. package/vue-demo-app/src/services/useCloudSyncDemo.ts +84 -0
  210. package/vue-demo-app/src/services/useLiveQueryDemo.ts +82 -0
  211. package/vue-demo-app/src/services/usePostsLiveQueryDemo.ts +77 -0
  212. package/vue-demo-app/src/services/useTypeScriptDemo.ts +56 -0
  213. package/vue-demo-app/src/vite-env.d.ts +1 -0
  214. package/vue-demo-app/tsconfig.json +25 -0
  215. package/vue-demo-app/tsconfig.node.json +10 -0
  216. package/vue-demo-app/vite.config.ts +16 -0
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "svelte-demo-app",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "build": "vite build",
7
+ "dev": "vite dev",
8
+ "preview": "vite preview",
9
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
10
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
11
+ },
12
+ "devDependencies": {
13
+ "@sveltejs/adapter-auto": "^3.0.0",
14
+ "@sveltejs/kit": "^2.0.0",
15
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
16
+ "svelte": "^4.2.0",
17
+ "svelte-check": "^3.6.0",
18
+ "typescript": "^5.0.0",
19
+ "vite": "^5.0.0"
20
+ },
21
+ "dependencies": {
22
+ "@emotion/react": "^11.14.0",
23
+ "@emotion/styled": "^11.14.1",
24
+ "@mui/icons-material": "^7.3.2",
25
+ "@mui/material": "^7.3.2",
26
+ "idb-orm": "^0.0.1",
27
+ "zod": "^3.22.0"
28
+ },
29
+ "type": "module"
30
+ }
@@ -0,0 +1,12 @@
1
+ // See https://kit.svelte.dev/docs/types#app
2
+ // for information about these interfaces
3
+ declare global {
4
+ namespace App {
5
+ // interface Error {}
6
+ // interface Locals {}
7
+ // interface PageData {}
8
+ // interface Platform {}
9
+ }
10
+ }
11
+
12
+ export {};
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="%sveltekit.assets%/favicon.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <title>Dexie ORM Demo - Svelte</title>
8
+ %sveltekit.head%
9
+ </head>
10
+ <body data-sveltekit-preload-data="hover">
11
+ <div style="display: contents">%sveltekit.body%</div>
12
+ </body>
13
+ </html>
@@ -0,0 +1,121 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import {
4
+ addUser,
5
+ testZodValidation,
6
+ testSchemaMigration,
7
+ toggleAutoReset,
8
+ testRelations,
9
+ testTransactions,
10
+ testCompoundIndexes,
11
+ testAggregations,
12
+ clearAll
13
+ } from '../stores/appStore.js';
14
+
15
+ const users = getContext('users');
16
+ </script>
17
+
18
+ <div>
19
+ <h2>Admin Actions</h2>
20
+ <div class="actions-grid">
21
+ <button on:click={addUser} class="action-btn">
22
+ 👤 Add User
23
+ </button>
24
+ <button on:click={testZodValidation} class="action-btn">
25
+ 🧪 Test Zod
26
+ </button>
27
+ <button on:click={testSchemaMigration} class="action-btn">
28
+ 🗄️ Schema
29
+ </button>
30
+ <button on:click={toggleAutoReset} class="action-btn">
31
+ ⚙️ Auto-Reset
32
+ </button>
33
+ <button on:click={testRelations} class="action-btn">
34
+ 🔗 Relations
35
+ </button>
36
+ <button on:click={testTransactions} class="action-btn">
37
+ ⚡ Transactions
38
+ </button>
39
+ <button on:click={testCompoundIndexes} class="action-btn">
40
+ 🔍 Indexes
41
+ </button>
42
+ <button on:click={testAggregations} class="action-btn">
43
+ 📊 Aggregations
44
+ </button>
45
+ <button on:click={clearAll} class="action-btn danger">
46
+ 🗑️ Clear All
47
+ </button>
48
+ </div>
49
+
50
+ <h3>Users ({$users.length})</h3>
51
+ <div class="users-list">
52
+ {#each $users as user}
53
+ <div class="user-card">
54
+ <strong>{user.name}</strong> ({user.email})<br />
55
+ Age: {user.age}, Tags: {user.tags?.join(', ') || 'none'}
56
+ </div>
57
+ {/each}
58
+ </div>
59
+ </div>
60
+
61
+ <style>
62
+ h2 {
63
+ margin-bottom: 16px;
64
+ color: #333;
65
+ }
66
+
67
+ h3 {
68
+ margin: 24px 0 16px 0;
69
+ color: #333;
70
+ }
71
+
72
+ .actions-grid {
73
+ display: grid;
74
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
75
+ gap: 8px;
76
+ margin-bottom: 24px;
77
+ }
78
+
79
+ .action-btn {
80
+ padding: 12px 16px;
81
+ border: 1px solid #ddd;
82
+ border-radius: 4px;
83
+ background: white;
84
+ cursor: pointer;
85
+ font-size: 0.9rem;
86
+ transition: all 0.2s;
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: center;
90
+ gap: 4px;
91
+ }
92
+
93
+ .action-btn:hover {
94
+ background: #f5f5f5;
95
+ border-color: #1976d2;
96
+ }
97
+
98
+ .action-btn.danger {
99
+ border-color: #d32f2f;
100
+ color: #d32f2f;
101
+ }
102
+
103
+ .action-btn.danger:hover {
104
+ background: #d32f2f;
105
+ color: white;
106
+ }
107
+
108
+ .users-list {
109
+ display: grid;
110
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
111
+ gap: 12px;
112
+ }
113
+
114
+ .user-card {
115
+ padding: 12px;
116
+ border: 1px solid #eee;
117
+ border-radius: 4px;
118
+ background: #fafafa;
119
+ font-size: 0.9rem;
120
+ }
121
+ </style>
@@ -0,0 +1,333 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import { db } from '$lib/database/Database';
4
+
5
+ const syncStatus = getContext('syncStatus');
6
+ let isLoading = false;
7
+
8
+ async function handleManualSync() {
9
+ isLoading = true;
10
+ try {
11
+ await db.sync();
12
+ // Update status after sync
13
+ const newStatus = db.getSyncStatus();
14
+ syncStatus.set(newStatus);
15
+ alert('Sync completed successfully!');
16
+ } catch (error) {
17
+ console.error('Sync failed:', error);
18
+ alert(`Sync failed: ${error.message}`);
19
+ } finally {
20
+ isLoading = false;
21
+ }
22
+ }
23
+
24
+ async function handleEnableCloudSync() {
25
+ isLoading = true;
26
+ try {
27
+ await db.enableCloudSync({
28
+ databaseUrl: 'https://your-database-url.dexie.cloud',
29
+ enableOfflineSupport: true,
30
+ syncInterval: 30000,
31
+ });
32
+
33
+ const newStatus = db.getSyncStatus();
34
+ syncStatus.set(newStatus);
35
+ alert('Cloud sync enabled successfully!');
36
+ } catch (error) {
37
+ console.error('Failed to enable cloud sync:', error);
38
+ alert(`Failed to enable cloud sync: ${error.message}`);
39
+ } finally {
40
+ isLoading = false;
41
+ }
42
+ }
43
+
44
+ function handleDisableCloudSync() {
45
+ db.disableCloudSync();
46
+ syncStatus.set({ enabled: false });
47
+ alert('Cloud sync disabled');
48
+ }
49
+
50
+ async function handleSyncTables() {
51
+ isLoading = true;
52
+ try {
53
+ await db.syncTables(['users', 'posts']);
54
+ alert('Tables synced successfully!');
55
+ } catch (error) {
56
+ console.error('Table sync failed:', error);
57
+ alert(`Table sync failed: ${error.message}`);
58
+ } finally {
59
+ isLoading = false;
60
+ }
61
+ }
62
+ </script>
63
+
64
+ <div class="card cloud-sync-demo">
65
+ <div class="card-header">
66
+ <h2>Cloud Sync Demo</h2>
67
+ </div>
68
+ <div class="card-content">
69
+ <p class="description">
70
+ <strong>Dexie Cloud Addon Integration:</strong> Cloud synchronization demo
71
+ </p>
72
+
73
+ <div class="demo-grid">
74
+ <div class="demo-section">
75
+ <div class="section-header">
76
+ <span class="icon">☁️</span>
77
+ <h3>Sync status</h3>
78
+ </div>
79
+ <div class="status-info">
80
+ <div><strong>Enabled:</strong> {$syncStatus.enabled ? 'Yes' : 'No'}</div>
81
+ <div>
82
+ <strong>Online:</strong>
83
+ {$syncStatus.isOnline !== undefined
84
+ ? $syncStatus.isOnline ? 'Yes' : 'No'
85
+ : 'Unknown'}
86
+ </div>
87
+ <div>
88
+ <strong>Last sync:</strong>
89
+ {$syncStatus.lastSync ? $syncStatus.lastSync.toLocaleString() : 'Never'}
90
+ </div>
91
+ </div>
92
+ </div>
93
+
94
+ <div class="demo-section">
95
+ <div class="section-header">
96
+ <span class="icon">⚙️</span>
97
+ <h3>Sync controls</h3>
98
+ </div>
99
+ <div class="controls">
100
+ <button
101
+ on:click={handleManualSync}
102
+ disabled={!$syncStatus.enabled || isLoading}
103
+ class="sync-btn {!$syncStatus.enabled ? 'disabled' : 'success'}"
104
+ >
105
+ {isLoading ? 'Syncing...' : 'Sync manually'}
106
+ </button>
107
+
108
+ <button
109
+ on:click={handleSyncTables}
110
+ disabled={!$syncStatus.enabled || isLoading}
111
+ class="sync-btn {!$syncStatus.enabled ? 'disabled' : 'warning'}"
112
+ >
113
+ Sync tables (users, posts)
114
+ </button>
115
+
116
+ {#if !$syncStatus.enabled}
117
+ <button
118
+ on:click={handleEnableCloudSync}
119
+ disabled={isLoading}
120
+ class="sync-btn primary"
121
+ >
122
+ Enable cloud sync
123
+ </button>
124
+ {:else}
125
+ <button
126
+ on:click={handleDisableCloudSync}
127
+ disabled={isLoading}
128
+ class="sync-btn danger"
129
+ >
130
+ Disable cloud sync
131
+ </button>
132
+ {/if}
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ <div class="instructions-card">
138
+ <div class="instructions-header">
139
+ <span class="icon">ℹ️</span>
140
+ <h4>Instructions:</h4>
141
+ </div>
142
+ <ol>
143
+ <li>
144
+ <strong>Install dexie-cloud-addon:</strong> <code>npm install dexie-cloud-addon</code>
145
+ </li>
146
+ <li>
147
+ <strong>Configure database URL</strong> in <code>demo-app/src/database/Database.ts</code>
148
+ </li>
149
+ <li>
150
+ <strong>Enable cloud sync</strong> using the button above
151
+ </li>
152
+ <li>
153
+ <strong>Test sync</strong> – add data and verify it synchronizes
154
+ </li>
155
+ </ol>
156
+ </div>
157
+
158
+ <div class="info-card">
159
+ <div class="font-weight-bold">Configuration:</div>
160
+ Cloud sync is configured in Database.ts with automatic sync every 30 seconds.
161
+ <br />
162
+ <div class="font-weight-bold">Offline Support:</div>
163
+ The app works offline and syncs when connection is restored.
164
+ <br />
165
+ <div class="font-weight-bold">Reactivity:</div>
166
+ All changes are automatically synchronized with the cloud!
167
+ </div>
168
+ </div>
169
+ </div>
170
+
171
+ <style>
172
+ .card {
173
+ border: 1px solid #ddd;
174
+ border-radius: 8px;
175
+ margin: 16px 0;
176
+ background: white;
177
+ }
178
+
179
+ .cloud-sync-demo {
180
+ border: 2px solid #2196f3;
181
+ background: #e3f2fd;
182
+ }
183
+
184
+ .card-header {
185
+ padding: 16px;
186
+ border-bottom: 1px solid #eee;
187
+ }
188
+
189
+ .card-header h2 {
190
+ margin: 0;
191
+ font-size: 1.25rem;
192
+ color: #1976d2;
193
+ }
194
+
195
+ .card-content {
196
+ padding: 16px;
197
+ }
198
+
199
+ .description {
200
+ color: #666;
201
+ margin-bottom: 16px;
202
+ font-size: 0.9rem;
203
+ }
204
+
205
+ .demo-grid {
206
+ display: grid;
207
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
208
+ gap: 16px;
209
+ margin-bottom: 16px;
210
+ }
211
+
212
+ .demo-section {
213
+ background: white;
214
+ padding: 15px;
215
+ border-radius: 4px;
216
+ border: 1px solid #ddd;
217
+ }
218
+
219
+ .section-header {
220
+ display: flex;
221
+ align-items: center;
222
+ gap: 8px;
223
+ margin-bottom: 12px;
224
+ color: #1976d2;
225
+ }
226
+
227
+ .section-header h3 {
228
+ margin: 0;
229
+ font-size: 1rem;
230
+ }
231
+
232
+ .status-info {
233
+ display: flex;
234
+ flex-direction: column;
235
+ gap: 4px;
236
+ font-size: 0.9rem;
237
+ }
238
+
239
+ .controls {
240
+ display: flex;
241
+ flex-direction: column;
242
+ gap: 8px;
243
+ }
244
+
245
+ .sync-btn {
246
+ padding: 10px 15px;
247
+ border: none;
248
+ border-radius: 4px;
249
+ cursor: pointer;
250
+ font-size: 0.9rem;
251
+ transition: all 0.2s;
252
+ }
253
+
254
+ .sync-btn:disabled {
255
+ cursor: not-allowed;
256
+ opacity: 0.6;
257
+ }
258
+
259
+ .sync-btn.success {
260
+ background: #4caf50;
261
+ color: white;
262
+ }
263
+
264
+ .sync-btn.warning {
265
+ background: #ff9800;
266
+ color: white;
267
+ }
268
+
269
+ .sync-btn.primary {
270
+ background: #2196f3;
271
+ color: white;
272
+ }
273
+
274
+ .sync-btn.danger {
275
+ background: #f44336;
276
+ color: white;
277
+ }
278
+
279
+ .sync-btn.disabled {
280
+ background: #ccc;
281
+ color: #666;
282
+ }
283
+
284
+ .instructions-card {
285
+ background: #fff3e0;
286
+ padding: 15px;
287
+ border-radius: 4px;
288
+ border: 1px solid #ffb74d;
289
+ margin-bottom: 16px;
290
+ }
291
+
292
+ .instructions-header {
293
+ display: flex;
294
+ align-items: center;
295
+ gap: 8px;
296
+ margin-bottom: 12px;
297
+ }
298
+
299
+ .instructions-header h4 {
300
+ margin: 0;
301
+ color: #1976d2;
302
+ }
303
+
304
+ .instructions-card ol {
305
+ margin: 10px 0;
306
+ padding-left: 20px;
307
+ }
308
+
309
+ .instructions-card li {
310
+ margin-bottom: 8px;
311
+ font-size: 0.9rem;
312
+ }
313
+
314
+ .instructions-card code {
315
+ background: #f0f0f0;
316
+ padding: 2px 4px;
317
+ border-radius: 3px;
318
+ font-family: monospace;
319
+ font-size: 0.85rem;
320
+ }
321
+
322
+ .info-card {
323
+ background: #e8f5e8;
324
+ padding: 10px;
325
+ border-radius: 4px;
326
+ font-size: 0.9rem;
327
+ color: #666;
328
+ }
329
+
330
+ .font-weight-bold {
331
+ font-weight: bold;
332
+ }
333
+ </style>
@@ -0,0 +1,191 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import { onMount } from 'svelte';
4
+ import { loadLiveQueryData } from '../stores/appStore.js';
5
+
6
+ const allUsers = getContext('allUsers');
7
+ const allPosts = getContext('allPosts');
8
+ const allProfiles = getContext('allProfiles');
9
+ const userStats = getContext('userStats');
10
+
11
+ onMount(() => {
12
+ loadLiveQueryData();
13
+ // Refresh data every second for live updates
14
+ const interval = setInterval(loadLiveQueryData, 1000);
15
+ return () => clearInterval(interval);
16
+ });
17
+ </script>
18
+
19
+ <div class="card">
20
+ <div class="card-content">
21
+ <div class="demo-grid">
22
+ <div class="demo-section">
23
+ <div class="section-header">
24
+ <span class="icon">📊</span>
25
+ <h3>Statistics (number | undefined)</h3>
26
+ </div>
27
+ <div class="stats">
28
+ <div><strong>Total users:</strong> {$userStats.totalUsers || 'Loading...'}</div>
29
+ <div><strong>Adult users:</strong> {$userStats.adultUsers || 'Loading...'}</div>
30
+ <div><strong>First user:</strong> {$userStats.firstUser || 'None'}</div>
31
+ <div><strong>All users (live):</strong> {$allUsers.length || 'Loading...'}</div>
32
+ <div><strong>Posts:</strong> {$allPosts.length || 'Loading...'}</div>
33
+ <div><strong>Profiles:</strong> {$allProfiles.length || 'Loading...'}</div>
34
+ </div>
35
+ </div>
36
+
37
+ <div class="demo-section">
38
+ <div class="section-header">
39
+ <span class="icon">👥</span>
40
+ <h3>All users (live)</h3>
41
+ </div>
42
+ <div class="users-list">
43
+ {#if $allUsers && $allUsers.length > 0}
44
+ {#each $allUsers as user}
45
+ <div class="user-item">
46
+ <strong>{user.name}</strong> — {user.email}
47
+ </div>
48
+ {/each}
49
+ {/if}
50
+ </div>
51
+ </div>
52
+
53
+ <div class="demo-section">
54
+ <div class="section-header">
55
+ <span class="icon">📄</span>
56
+ <h3>Posts (PostEntity[])</h3>
57
+ </div>
58
+ <div class="posts-list">
59
+ {#if $allPosts && $allPosts.length > 0}
60
+ {#each $allPosts as post}
61
+ <div class="post-item">
62
+ <div class="post-title">{post.title}</div>
63
+ <div class="post-meta">
64
+ {#if post.published}
65
+ <span class="status published">✅ Published</span>
66
+ {:else}
67
+ <span class="status draft">📄 Draft</span>
68
+ {/if}
69
+ <span class="likes">❤️ {post.likes || 0}</span>
70
+ </div>
71
+ </div>
72
+ {/each}
73
+ {/if}
74
+ </div>
75
+ </div>
76
+ </div>
77
+
78
+ <div class="info-card">
79
+ <div><strong>Typing test:</strong> All variables are fully typed with TypeScript!</div>
80
+ <div><strong>Reactivity:</strong> Data updates automatically when you add/remove records!</div>
81
+ <div><strong>Compatibility:</strong> Your library works perfectly with Svelte's reactivity!</div>
82
+ </div>
83
+ </div>
84
+ </div>
85
+
86
+ <style>
87
+ .card {
88
+ border: 1px solid #ddd;
89
+ border-radius: 8px;
90
+ margin: 16px 0;
91
+ background: white;
92
+ }
93
+
94
+ .card-content {
95
+ padding: 16px;
96
+ }
97
+
98
+ .demo-grid {
99
+ display: grid;
100
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
101
+ gap: 16px;
102
+ margin-bottom: 16px;
103
+ }
104
+
105
+ .demo-section {
106
+ border: 1px solid #eee;
107
+ border-radius: 4px;
108
+ padding: 12px;
109
+ background: #fafafa;
110
+ }
111
+
112
+ .section-header {
113
+ display: flex;
114
+ align-items: center;
115
+ gap: 8px;
116
+ margin-bottom: 12px;
117
+ color: #1976d2;
118
+ }
119
+
120
+ .section-header h3 {
121
+ margin: 0;
122
+ font-size: 1rem;
123
+ }
124
+
125
+ .stats {
126
+ display: flex;
127
+ flex-direction: column;
128
+ gap: 4px;
129
+ font-size: 0.9rem;
130
+ }
131
+
132
+ .users-list, .posts-list {
133
+ max-height: 200px;
134
+ overflow-y: auto;
135
+ }
136
+
137
+ .user-item, .post-item {
138
+ padding: 4px 0;
139
+ border-bottom: 1px solid #eee;
140
+ font-size: 0.9rem;
141
+ }
142
+
143
+ .post-title {
144
+ font-weight: 600;
145
+ margin-bottom: 4px;
146
+ }
147
+
148
+ .post-meta {
149
+ display: flex;
150
+ align-items: center;
151
+ gap: 8px;
152
+ font-size: 0.8rem;
153
+ color: #666;
154
+ }
155
+
156
+ .status {
157
+ padding: 2px 6px;
158
+ border-radius: 3px;
159
+ font-size: 0.75rem;
160
+ }
161
+
162
+ .status.published {
163
+ background: #e8f5e8;
164
+ color: #2e7d32;
165
+ }
166
+
167
+ .status.draft {
168
+ background: #fff3e0;
169
+ color: #f57c00;
170
+ }
171
+
172
+ .likes {
173
+ color: #e91e63;
174
+ }
175
+
176
+ .info-card {
177
+ background: #e8f5e8;
178
+ border: 1px solid #4caf50;
179
+ border-radius: 4px;
180
+ padding: 12px;
181
+ font-size: 0.9rem;
182
+ }
183
+
184
+ .info-card div {
185
+ margin-bottom: 4px;
186
+ }
187
+
188
+ .info-card div:last-child {
189
+ margin-bottom: 0;
190
+ }
191
+ </style>