@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,133 @@
1
+ <div class="card">
2
+ <div class="card-header">
3
+ <h2>
4
+ <span class="icon">🔄</span>
5
+ Dexie ORM for IndexedDB — Overview
6
+ </h2>
7
+ </div>
8
+ <div class="card-content">
9
+ <p class="description">
10
+ TypeScript ORM built on the latest Dexie 4 with first-class type safety and Zod runtime validation.
11
+ </p>
12
+ <div class="features-grid">
13
+ <div class="feature-item">
14
+ <span class="feature-icon">💻</span>
15
+ <span><strong>Entity config</strong> via defineEntity()</span>
16
+ </div>
17
+ <div class="feature-item">
18
+ <span class="feature-icon">🗄️</span>
19
+ <span><strong>Automatic schema</strong> with PK, indexes, unique</span>
20
+ </div>
21
+ <div class="feature-item">
22
+ <span class="feature-icon">👥</span>
23
+ <span><strong>Relations</strong> with helpers</span>
24
+ </div>
25
+ <div class="feature-item">
26
+ <span class="feature-icon">🧪</span>
27
+ <span><strong>Zod validation</strong> at runtime</span>
28
+ </div>
29
+ <div class="feature-item">
30
+ <span class="feature-icon">📊</span>
31
+ <span><strong>Aggregations</strong> (count, avg, sum)</span>
32
+ </div>
33
+ <div class="feature-item">
34
+ <span class="feature-icon">📈</span>
35
+ <span><strong>Live queries</strong> with useLiveQuery()</span>
36
+ </div>
37
+ <div class="feature-item">
38
+ <span class="feature-icon">🔷</span>
39
+ <span><strong>TypeScript</strong> full type safety</span>
40
+ </div>
41
+ <div class="feature-item">
42
+ <span class="feature-icon">☁️</span>
43
+ <span><strong>Cloud sync</strong> with Dexie Cloud</span>
44
+ </div>
45
+ </div>
46
+
47
+ <div class="divider"></div>
48
+
49
+ <a
50
+ href="https://github.com/radommaciej/indexed-db-orm/blob/main/README.md"
51
+ target="_blank"
52
+ rel="noopener noreferrer"
53
+ class="doc-link"
54
+ >
55
+ 📖 View full documentation
56
+ </a>
57
+ </div>
58
+ </div>
59
+
60
+ <style>
61
+ .card {
62
+ border: 1px solid #ddd;
63
+ border-radius: 8px;
64
+ margin-bottom: 16px;
65
+ background: white;
66
+ }
67
+
68
+ .card-header {
69
+ padding: 16px;
70
+ border-bottom: 1px solid #eee;
71
+ }
72
+
73
+ .card-header h2 {
74
+ margin: 0;
75
+ display: flex;
76
+ align-items: center;
77
+ gap: 8px;
78
+ font-size: 1.25rem;
79
+ color: #1976d2;
80
+ }
81
+
82
+ .card-content {
83
+ padding: 16px;
84
+ }
85
+
86
+ .description {
87
+ color: #666;
88
+ margin-bottom: 16px;
89
+ font-size: 0.9rem;
90
+ }
91
+
92
+ .features-grid {
93
+ display: grid;
94
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
95
+ gap: 8px;
96
+ margin-bottom: 16px;
97
+ }
98
+
99
+ .feature-item {
100
+ display: flex;
101
+ align-items: center;
102
+ gap: 8px;
103
+ font-size: 0.9rem;
104
+ }
105
+
106
+ .feature-icon {
107
+ font-size: 1rem;
108
+ }
109
+
110
+ .divider {
111
+ height: 1px;
112
+ background: #eee;
113
+ margin: 16px 0;
114
+ }
115
+
116
+ .doc-link {
117
+ display: inline-flex;
118
+ align-items: center;
119
+ gap: 4px;
120
+ padding: 8px 16px;
121
+ border: 1px solid #1976d2;
122
+ border-radius: 4px;
123
+ color: #1976d2;
124
+ text-decoration: none;
125
+ font-size: 0.9rem;
126
+ transition: all 0.2s;
127
+ }
128
+
129
+ .doc-link:hover {
130
+ background: #1976d2;
131
+ color: white;
132
+ }
133
+ </style>
@@ -0,0 +1,330 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import { onMount } from 'svelte';
4
+ import { loadLiveQueryData } from '../stores/appStore.js';
5
+ import { db } from '$lib/database/Database';
6
+ import { newEntity } from '../../../src/services/EntityFactory';
7
+ import { PostEntity } from '$lib/entities/Post';
8
+
9
+ const allPosts = getContext('allPosts');
10
+ const postStats = getContext('postStats');
11
+
12
+ let publishedPosts = [];
13
+ let topPosts = [];
14
+
15
+ onMount(() => {
16
+ loadLiveQueryData();
17
+ loadPostsData();
18
+ // Refresh data every second for live updates
19
+ const interval = setInterval(() => {
20
+ loadLiveQueryData();
21
+ loadPostsData();
22
+ }, 1000);
23
+ return () => clearInterval(interval);
24
+ });
25
+
26
+ async function loadPostsData() {
27
+ if (!db) return;
28
+ try {
29
+ // Published posts
30
+ publishedPosts = await db.getRepository(PostEntity).where('published').equals(1).toArray();
31
+
32
+ // Most liked posts
33
+ topPosts = await db.getRepository(PostEntity).orderBy('likes').reverse().limit(3).toArray();
34
+ } catch (error) {
35
+ console.error('Error loading posts data:', error);
36
+ }
37
+ }
38
+
39
+ async function addSamplePost() {
40
+ if (!db) return;
41
+ try {
42
+ const post = newEntity(PostEntity, {
43
+ title: `Post ${Date.now()}`,
44
+ content: 'This is a sample post added by the useLiveQuery demo!',
45
+ published: Math.random() > 0.5,
46
+ likes: Math.floor(Math.random() * 100),
47
+ postTags: ['demo', 'useLiveQuery'],
48
+ createdAt: Date.now(),
49
+ updatedAt: Date.now(),
50
+ });
51
+
52
+ await db.getRepository(PostEntity).add(post);
53
+ await loadPostsData();
54
+ } catch (error) {
55
+ console.error('Error adding post:', error);
56
+ }
57
+ }
58
+ </script>
59
+
60
+ <div class="card posts-demo">
61
+ <div class="card-header">
62
+ <h2>
63
+ <span class="icon">📊</span>
64
+ Posts useLiveQuery Demo
65
+ </h2>
66
+ </div>
67
+ <div class="card-content">
68
+ <button on:click={addSamplePost} class="add-post-btn">
69
+ Add sample post
70
+ </button>
71
+
72
+ <div class="demo-grid">
73
+ <div class="demo-section">
74
+ <div class="section-header">
75
+ <span class="icon">📊</span>
76
+ <h3>Statistics</h3>
77
+ </div>
78
+ {#if $postStats}
79
+ <div class="stats">
80
+ <div><strong>Total posts:</strong> {$postStats.total}</div>
81
+ <div><strong>Published:</strong> {$postStats.published}</div>
82
+ <div><strong>Total likes:</strong> {$postStats.totalLikes}</div>
83
+ </div>
84
+ {:else}
85
+ <div>Loading statistics...</div>
86
+ {/if}
87
+ </div>
88
+
89
+ <div class="demo-section">
90
+ <div class="section-header">
91
+ <span class="icon">📈</span>
92
+ <h3>Top 3 posts</h3>
93
+ </div>
94
+ {#if topPosts && topPosts.length > 0}
95
+ <div class="top-posts">
96
+ {#each topPosts as post, index}
97
+ <div class="top-post">
98
+ <strong>#{index + 1}</strong> {post.title}
99
+ <span class="likes">❤️ {post.likes}</span>
100
+ </div>
101
+ {/each}
102
+ </div>
103
+ {/if}
104
+ </div>
105
+
106
+ <div class="demo-section">
107
+ <div class="section-header">
108
+ <span class="icon">📄</span>
109
+ <h3>Published posts</h3>
110
+ </div>
111
+ {#if publishedPosts && publishedPosts.length > 0}
112
+ <div class="published-posts">
113
+ {#each publishedPosts as post}
114
+ <div class="published-post">
115
+ <strong>{post.title}</strong> ❤️ {post.likes}
116
+ </div>
117
+ {/each}
118
+ </div>
119
+ {/if}
120
+ </div>
121
+ </div>
122
+
123
+ {#if $allPosts && $allPosts.length > 0}
124
+ <div class="all-posts-section">
125
+ <div class="section-header">
126
+ <span class="icon">📋</span>
127
+ <h3>All posts (newest first)</h3>
128
+ </div>
129
+ <div class="all-posts">
130
+ {#each $allPosts as post}
131
+ <div class="post-item">
132
+ <div class="post-header">
133
+ <div class="post-title-section">
134
+ <strong>{post.title}</strong>
135
+ <span class="status {post.published ? 'published' : 'draft'}">
136
+ {post.published ? 'Published' : 'Draft'}
137
+ </span>
138
+ </div>
139
+ <div class="post-likes">❤️ {post.likes}</div>
140
+ </div>
141
+ <div class="post-content">
142
+ {post.content?.substring(0, 100)}...
143
+ </div>
144
+ </div>
145
+ {/each}
146
+ </div>
147
+ </div>
148
+ {/if}
149
+
150
+ <div class="info-card">
151
+ <span class="icon">💡</span>
152
+ <strong>Note:</strong> All data updates automatically! Add a post and see how all sections refresh in real time.
153
+ </div>
154
+ </div>
155
+ </div>
156
+
157
+ <style>
158
+ .card {
159
+ border: 1px solid #ddd;
160
+ border-radius: 8px;
161
+ margin: 16px 0;
162
+ background: white;
163
+ }
164
+
165
+ .posts-demo {
166
+ border: 2px solid #9c27b0;
167
+ background: #faf5ff;
168
+ }
169
+
170
+ .card-header {
171
+ padding: 16px;
172
+ border-bottom: 1px solid #eee;
173
+ }
174
+
175
+ .card-header h2 {
176
+ margin: 0;
177
+ display: flex;
178
+ align-items: center;
179
+ gap: 8px;
180
+ font-size: 1.25rem;
181
+ color: #1976d2;
182
+ }
183
+
184
+ .card-content {
185
+ padding: 16px;
186
+ }
187
+
188
+ .add-post-btn {
189
+ background: #9c27b0;
190
+ color: white;
191
+ border: none;
192
+ padding: 12px 24px;
193
+ border-radius: 4px;
194
+ cursor: pointer;
195
+ font-size: 0.9rem;
196
+ margin-bottom: 16px;
197
+ transition: background-color 0.2s;
198
+ }
199
+
200
+ .add-post-btn:hover {
201
+ background: #7b1fa2;
202
+ }
203
+
204
+ .demo-grid {
205
+ display: grid;
206
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
207
+ gap: 16px;
208
+ margin-bottom: 16px;
209
+ }
210
+
211
+ .demo-section {
212
+ border: 1px solid #eee;
213
+ border-radius: 4px;
214
+ padding: 12px;
215
+ background: #fafafa;
216
+ }
217
+
218
+ .section-header {
219
+ display: flex;
220
+ align-items: center;
221
+ gap: 8px;
222
+ margin-bottom: 12px;
223
+ color: #1976d2;
224
+ }
225
+
226
+ .section-header h3 {
227
+ margin: 0;
228
+ font-size: 1rem;
229
+ }
230
+
231
+ .stats {
232
+ display: flex;
233
+ flex-direction: column;
234
+ gap: 4px;
235
+ font-size: 0.9rem;
236
+ }
237
+
238
+ .top-posts, .published-posts {
239
+ max-height: 150px;
240
+ overflow-y: auto;
241
+ }
242
+
243
+ .top-post, .published-post {
244
+ padding: 8px;
245
+ margin: 4px 0;
246
+ background: white;
247
+ border-radius: 4px;
248
+ border: 1px solid #ddd;
249
+ font-size: 0.9rem;
250
+ }
251
+
252
+ .likes {
253
+ color: #9c27b0;
254
+ margin-left: 8px;
255
+ }
256
+
257
+ .all-posts-section {
258
+ margin-top: 16px;
259
+ }
260
+
261
+ .all-posts {
262
+ max-height: 200px;
263
+ overflow-y: auto;
264
+ background: white;
265
+ padding: 10px;
266
+ border-radius: 4px;
267
+ border: 1px solid #ddd;
268
+ }
269
+
270
+ .post-item {
271
+ padding: 8px 0;
272
+ border-bottom: 1px solid #eee;
273
+ font-size: 0.9rem;
274
+ }
275
+
276
+ .post-item:last-child {
277
+ border-bottom: none;
278
+ }
279
+
280
+ .post-header {
281
+ display: flex;
282
+ justify-content: space-between;
283
+ align-items: center;
284
+ margin-bottom: 4px;
285
+ }
286
+
287
+ .post-title-section {
288
+ display: flex;
289
+ align-items: center;
290
+ gap: 8px;
291
+ }
292
+
293
+ .status {
294
+ padding: 2px 6px;
295
+ border-radius: 3px;
296
+ font-size: 0.8rem;
297
+ }
298
+
299
+ .status.published {
300
+ background: #4caf50;
301
+ color: white;
302
+ }
303
+
304
+ .status.draft {
305
+ background: #ff9800;
306
+ color: white;
307
+ }
308
+
309
+ .post-likes {
310
+ color: #9c27b0;
311
+ }
312
+
313
+ .post-content {
314
+ color: #666;
315
+ font-size: 0.8rem;
316
+ margin-top: 2px;
317
+ }
318
+
319
+ .info-card {
320
+ background: #fff3e0;
321
+ border: 1px solid #ffb74d;
322
+ border-radius: 4px;
323
+ padding: 12px;
324
+ margin-top: 16px;
325
+ font-size: 0.9rem;
326
+ display: flex;
327
+ align-items: center;
328
+ gap: 8px;
329
+ }
330
+ </style>
@@ -0,0 +1,251 @@
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
+
10
+ onMount(() => {
11
+ loadLiveQueryData();
12
+ });
13
+
14
+ // Test functions - TypeScript should suggest properties
15
+ function handleUserClick(user) {
16
+ // IDE should suggest: user.id, user.name, user.email, user.age, user.tags, user.metadata
17
+ console.log('User clicked:', user.name, user.email, user.age);
18
+ }
19
+
20
+ function handlePostClick(post) {
21
+ // IDE should suggest: post.id, post.title, post.content, post.published, post.likes, etc.
22
+ console.log('Post clicked:', post.title, post.published, post.likes);
23
+ }
24
+
25
+ function handleProfileClick(profile) {
26
+ // IDE should suggest: profile.id, profile.userId, profile.bio, profile.avatar, etc.
27
+ console.log('Profile clicked:', profile.bio, profile.website);
28
+ }
29
+ </script>
30
+
31
+ <div class="card typescript-demo">
32
+ <div class="card-header">
33
+ <h2>
34
+ <span class="icon">💻</span>
35
+ TypeScript Typing Test
36
+ </h2>
37
+ </div>
38
+ <div class="card-content">
39
+ <p class="description">
40
+ <strong>Instructions:</strong>
41
+ Hover over the variables below in your IDE and
42
+ verify TypeScript shows full types! Click items to
43
+ see auto-complete in the console.
44
+ </p>
45
+
46
+ <div class="demo-grid">
47
+ <div class="demo-section">
48
+ <div class="section-header">
49
+ <span class="icon">👥</span>
50
+ <h3>Users (UserEntity[])</h3>
51
+ </div>
52
+ <p class="type-info">Type: <code>UserEntity[] | undefined</code></p>
53
+ {#if $allUsers && $allUsers.length > 0}
54
+ <div class="items-list">
55
+ {#each $allUsers as user}
56
+ <div
57
+ class="item"
58
+ on:click={() => handleUserClick(user)}
59
+ title="Click to see auto-complete in the console"
60
+ >
61
+ <strong>{user.name}</strong> - {user.email}
62
+ </div>
63
+ {/each}
64
+ </div>
65
+ {/if}
66
+ </div>
67
+
68
+ <div class="demo-section">
69
+ <div class="section-header">
70
+ <span class="icon">📄</span>
71
+ <h3>Posts (PostEntity[])</h3>
72
+ </div>
73
+ <p class="type-info">Type: <code>PostEntity[] | undefined</code></p>
74
+ {#if $allPosts && $allPosts.length > 0}
75
+ <div class="items-list">
76
+ {#each $allPosts as post}
77
+ <div
78
+ class="item"
79
+ on:click={() => handlePostClick(post)}
80
+ title="Click to see auto-complete in the console"
81
+ >
82
+ <strong>{post.title}</strong> - {post.published ? 'Published' : 'Draft'}
83
+ </div>
84
+ {/each}
85
+ </div>
86
+ {/if}
87
+ </div>
88
+
89
+ <div class="demo-section">
90
+ <div class="section-header">
91
+ <span class="icon">👤</span>
92
+ <h3>Profiles (ProfileEntity[])</h3>
93
+ </div>
94
+ <p class="type-info">Type: <code>ProfileEntity[] | undefined</code></p>
95
+ {#if $allProfiles && $allProfiles.length > 0}
96
+ <div class="items-list">
97
+ {#each $allProfiles as profile}
98
+ <div
99
+ class="item"
100
+ on:click={() => handleProfileClick(profile)}
101
+ title="Click to see auto-complete in the console"
102
+ >
103
+ <strong>User {profile.userId}</strong> - {profile.bio?.substring(0, 30)}...
104
+ </div>
105
+ {/each}
106
+ </div>
107
+ {/if}
108
+ </div>
109
+ </div>
110
+
111
+ <div class="info-card">
112
+ <div class="info-text">
113
+ <div class="font-weight-bold">IDE Test:</div>
114
+ <br />
115
+ 1. Hover over variables <code>allUsers</code>, <code>allPosts</code>, <code>allProfiles</code>
116
+ <br />
117
+ 2. Verify TypeScript shows full types: (UserEntity[], PostEntity[], ProfileEntity[])
118
+ <br />
119
+ 3. Click items to see auto-complete inside handle* functions
120
+ <br />
121
+ 4. Check that IDE suggests properties like <code>user.name</code>, <code>post.title</code>, <code>profile.bio</code>
122
+ </div>
123
+ </div>
124
+ </div>
125
+ </div>
126
+
127
+ <style>
128
+ .card {
129
+ border: 1px solid #ddd;
130
+ border-radius: 8px;
131
+ margin: 16px 0;
132
+ background: white;
133
+ }
134
+
135
+ .typescript-demo {
136
+ border: 2px solid #ff9800;
137
+ background: #fff8e1;
138
+ }
139
+
140
+ .card-header {
141
+ padding: 16px;
142
+ border-bottom: 1px solid #eee;
143
+ }
144
+
145
+ .card-header h2 {
146
+ margin: 0;
147
+ display: flex;
148
+ align-items: center;
149
+ gap: 8px;
150
+ font-size: 1.25rem;
151
+ color: #1976d2;
152
+ }
153
+
154
+ .card-content {
155
+ padding: 16px;
156
+ }
157
+
158
+ .description {
159
+ color: #666;
160
+ margin-bottom: 16px;
161
+ font-size: 0.9rem;
162
+ }
163
+
164
+ .demo-grid {
165
+ display: grid;
166
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
167
+ gap: 16px;
168
+ margin-bottom: 16px;
169
+ }
170
+
171
+ .demo-section {
172
+ border: 1px solid #eee;
173
+ border-radius: 4px;
174
+ padding: 12px;
175
+ background: #fafafa;
176
+ }
177
+
178
+ .section-header {
179
+ display: flex;
180
+ align-items: center;
181
+ gap: 8px;
182
+ margin-bottom: 8px;
183
+ color: #1976d2;
184
+ }
185
+
186
+ .section-header h3 {
187
+ margin: 0;
188
+ font-size: 1rem;
189
+ }
190
+
191
+ .type-info {
192
+ font-size: 0.8rem;
193
+ color: #666;
194
+ margin-bottom: 8px;
195
+ }
196
+
197
+ .type-info code {
198
+ background: #f0f0f0;
199
+ padding: 2px 4px;
200
+ border-radius: 3px;
201
+ font-family: monospace;
202
+ }
203
+
204
+ .items-list {
205
+ max-height: 150px;
206
+ overflow-y: auto;
207
+ border: 1px solid #eee;
208
+ border-radius: 4px;
209
+ padding: 8px;
210
+ }
211
+
212
+ .item {
213
+ padding: 4px 0;
214
+ border-bottom: 1px solid #eee;
215
+ cursor: pointer;
216
+ font-size: 0.9rem;
217
+ transition: background-color 0.2s;
218
+ }
219
+
220
+ .item:hover {
221
+ background-color: #f5f5f5;
222
+ }
223
+
224
+ .item:last-child {
225
+ border-bottom: none;
226
+ }
227
+
228
+ .info-card {
229
+ background: #e3f2fd;
230
+ border: 1px solid #1976d2;
231
+ border-radius: 4px;
232
+ padding: 12px;
233
+ font-size: 0.9rem;
234
+ }
235
+
236
+ .info-text {
237
+ color: #666;
238
+ }
239
+
240
+ .font-weight-bold {
241
+ font-weight: bold;
242
+ }
243
+
244
+ code {
245
+ background: #f0f0f0;
246
+ padding: 2px 4px;
247
+ border-radius: 3px;
248
+ font-family: monospace;
249
+ font-size: 0.85rem;
250
+ }
251
+ </style>