@telemetryos/cli 1.9.0 → 1.11.0
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.
- package/CHANGELOG.md +25 -0
- package/dist/commands/auth.js +8 -15
- package/dist/commands/init.js +131 -68
- package/dist/commands/publish.d.ts +22 -0
- package/dist/commands/publish.js +238 -0
- package/dist/index.js +2 -0
- package/dist/plugins/math-tools.d.ts +2 -0
- package/dist/plugins/math-tools.js +18 -0
- package/dist/services/api-client.d.ts +18 -0
- package/dist/services/api-client.js +70 -0
- package/dist/services/archiver.d.ts +4 -0
- package/dist/services/archiver.js +65 -0
- package/dist/services/build-poller.d.ts +10 -0
- package/dist/services/build-poller.js +63 -0
- package/dist/services/cli-config.d.ts +10 -0
- package/dist/services/cli-config.js +45 -0
- package/dist/services/generate-application.d.ts +2 -1
- package/dist/services/generate-application.js +31 -32
- package/dist/services/project-config.d.ts +24 -0
- package/dist/services/project-config.js +51 -0
- package/dist/services/run-server.js +29 -73
- package/dist/types/api.d.ts +44 -0
- package/dist/types/api.js +1 -0
- package/dist/types/applications.d.ts +44 -0
- package/dist/types/applications.js +1 -0
- package/dist/utils/ansi.d.ts +10 -0
- package/dist/utils/ansi.js +10 -0
- package/dist/utils/path-utils.d.ts +55 -0
- package/dist/utils/path-utils.js +99 -0
- package/package.json +4 -2
- package/templates/vite-react-typescript/CLAUDE.md +14 -6
- package/templates/vite-react-typescript/_claude/skills/tos-architecture/SKILL.md +4 -28
- package/templates/vite-react-typescript/_claude/skills/tos-multi-mode/SKILL.md +359 -0
- package/templates/vite-react-typescript/_claude/skills/tos-render-design/SKILL.md +304 -12
- package/templates/vite-react-typescript/_claude/skills/tos-render-kiosk-design/SKILL.md +384 -0
- package/templates/vite-react-typescript/_claude/skills/tos-render-signage-design/SKILL.md +515 -0
- package/templates/vite-react-typescript/_claude/skills/tos-render-ui-design/SKILL.md +325 -0
- package/templates/vite-react-typescript/_claude/skills/tos-requirements/SKILL.md +405 -125
- package/templates/vite-react-typescript/_claude/skills/tos-store-sync/SKILL.md +96 -5
- package/templates/vite-react-typescript/_claude/skills/tos-weather-api/SKILL.md +443 -269
- package/templates/vite-react-typescript/index.html +1 -1
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
createUseInstanceStoreState,
|
|
27
27
|
createUseApplicationStoreState,
|
|
28
28
|
createUseDeviceStoreState,
|
|
29
|
+
createUseDynamicNamespaceStoreState,
|
|
29
30
|
} from '@telemetryos/sdk/react'
|
|
30
31
|
|
|
31
32
|
// Localization (instance scope)
|
|
@@ -39,16 +40,33 @@ export const useApiKeyStoreState = createUseApplicationStoreState<string>('apiKe
|
|
|
39
40
|
export const useBrightnessStoreState = createUseDeviceStoreState<number>('brightness', 100)
|
|
40
41
|
```
|
|
41
42
|
|
|
42
|
-
**Usage:**
|
|
43
|
+
**Usage (Always Handle isLoading):**
|
|
44
|
+
|
|
45
|
+
⚠️ **Important:** The `isLoading` boolean is `true` until the store returns the first value. During this time, the `value` is either the `initialValue` or potentially `undefined`. Always check `isLoading` before relying on the value.
|
|
46
|
+
|
|
43
47
|
```typescript
|
|
44
48
|
// Instance-scoped (Settings + Render) - 250ms debounce for text input
|
|
45
|
-
const [, city, setCity] = useCityStoreState(250)
|
|
49
|
+
const [isLoading, city, setCity] = useCityStoreState(250)
|
|
46
50
|
|
|
47
|
-
//
|
|
48
|
-
const [,
|
|
51
|
+
// ❌ BAD: Ignoring isLoading can cause bugs - value may not be from store yet!
|
|
52
|
+
// const [, city, setCity] = useCityStoreState(250)
|
|
53
|
+
// return <div>{city}</div> // May show default value instead of real data
|
|
54
|
+
|
|
55
|
+
// ✅ GOOD Pattern 1: Check isLoading before rendering
|
|
56
|
+
if (isLoading) return <Spinner />
|
|
57
|
+
return <div>Weather for {city}</div>
|
|
58
|
+
|
|
59
|
+
// ✅ GOOD Pattern 2: Use fallback value with nullish coalescing
|
|
60
|
+
return <div>Weather for {city ?? "Unknown City"}</div>
|
|
61
|
+
|
|
62
|
+
// Application-scoped (shared across all instances) - 250ms debounce
|
|
63
|
+
const [isLoading, apiKey, setApiKey] = useApiKeyStoreState(250)
|
|
64
|
+
if (isLoading) return <LoadingState />
|
|
65
|
+
return <APIClient apiKey={apiKey} />
|
|
49
66
|
|
|
50
67
|
// Device-scoped (Render only - NOT available in Settings) - 5ms for slider
|
|
51
|
-
const [, brightness, setBrightness] = useBrightnessStoreState(5)
|
|
68
|
+
const [isLoading, brightness, setBrightness] = useBrightnessStoreState(5)
|
|
69
|
+
const safeValue = brightness ?? 100 // Fallback to default if still loading
|
|
52
70
|
```
|
|
53
71
|
|
|
54
72
|
## Quick Pattern
|
|
@@ -179,6 +197,73 @@ const [isLoading, temp] = useTempStoreState()
|
|
|
179
197
|
- Event broadcasting
|
|
180
198
|
- Coordinated updates
|
|
181
199
|
|
|
200
|
+
### createUseDynamicNamespaceStoreState
|
|
201
|
+
|
|
202
|
+
Like shared store, but the namespace is passed at **call time** instead of definition time. Use when the namespace is dynamic — derived from other data at runtime (e.g., a user-selected location, a route parameter, or any runtime key).
|
|
203
|
+
|
|
204
|
+
> **Building a multi-mode app?** For the complete architecture pattern using dynamic namespaces with mode switching and entity management, see the `tos-multi-mode` skill.
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { createUseDynamicNamespaceStoreState } from '@telemetryos/sdk/react'
|
|
208
|
+
|
|
209
|
+
// Define with key + default only (no namespace yet)
|
|
210
|
+
export const useItemsStoreState = createUseDynamicNamespaceStoreState<Item[]>('items', [])
|
|
211
|
+
|
|
212
|
+
// Usage - pass namespace AND debounceDelay at call time
|
|
213
|
+
const [isLoading, items, setItems] = useItemsStoreState(namespace, 250)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Key difference from `createUseSharedStoreState`:**
|
|
217
|
+
|
|
218
|
+
| | `createUseSharedStoreState` | `createUseDynamicNamespaceStoreState` |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| **Namespace** | Fixed at hook definition | Passed at call time |
|
|
221
|
+
| **Definition** | `(key, default, namespace)` | `(key, default)` |
|
|
222
|
+
| **Call signature** | `(debounceDelay?)` | `(namespace, debounceDelay)` |
|
|
223
|
+
| **Use when** | Namespace is always the same | Namespace depends on runtime data |
|
|
224
|
+
|
|
225
|
+
**Use cases:**
|
|
226
|
+
- Multi-location apps (same data structure per location)
|
|
227
|
+
- User-selected scopes or categories
|
|
228
|
+
- Data partitioned by a runtime key (route param, selected item, etc.)
|
|
229
|
+
|
|
230
|
+
**Pattern: Namespace helper + instance-scoped selector**
|
|
231
|
+
|
|
232
|
+
A common pattern is combining an instance-scoped hook (to select which namespace) with dynamic namespace hooks (to access that namespace's data):
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// hooks/store.ts
|
|
236
|
+
import {
|
|
237
|
+
createUseInstanceStoreState,
|
|
238
|
+
createUseDynamicNamespaceStoreState,
|
|
239
|
+
} from '@telemetryos/sdk/react'
|
|
240
|
+
|
|
241
|
+
// Instance-scoped: which location this device is assigned to
|
|
242
|
+
export const useSelectedLocationStoreState = createUseInstanceStoreState<string>('selected-location', 'Location A')
|
|
243
|
+
|
|
244
|
+
// Dynamic namespace: per-location data
|
|
245
|
+
export const useQueuesStoreState = createUseDynamicNamespaceStoreState<Queue[]>('queues', [])
|
|
246
|
+
export const useCountersStoreState = createUseDynamicNamespaceStoreState<Counter[]>('counters', [])
|
|
247
|
+
|
|
248
|
+
// Helper to build namespace from location
|
|
249
|
+
export function locationNamespace(location: string): string {
|
|
250
|
+
return `my-app-${location}`
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// In a component
|
|
256
|
+
const [isLoadingLocation, selectedLocation] = useSelectedLocationStoreState()
|
|
257
|
+
const ns = locationNamespace(selectedLocation)
|
|
258
|
+
|
|
259
|
+
const [isLoadingQueues, queues, setQueues] = useQueuesStoreState(ns, 250)
|
|
260
|
+
const [isLoadingCounters, counters, setCounters] = useCountersStoreState(ns, 250)
|
|
261
|
+
|
|
262
|
+
if (isLoadingLocation || isLoadingQueues || isLoadingCounters) return <Spinner />
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
When `selectedLocation` changes, the namespace changes, and the hooks automatically re-subscribe to the new namespace's data.
|
|
266
|
+
|
|
182
267
|
## Return Value
|
|
183
268
|
|
|
184
269
|
All hooks return a tuple:
|
|
@@ -199,6 +284,12 @@ The default debounce delay is 0ms (immediate updates). Pass a value for debounce
|
|
|
199
284
|
const [isLoading, city, setCity] = useCityStoreState(250) // 250ms debounce for text inputs
|
|
200
285
|
```
|
|
201
286
|
|
|
287
|
+
**Note:** `createUseDynamicNamespaceStoreState` hooks take `(namespace, debounceDelay)` — namespace is required at call time:
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
const [isLoading, items, setItems] = useItemsStoreState(namespace, 250)
|
|
291
|
+
```
|
|
292
|
+
|
|
202
293
|
## TypeScript Types
|
|
203
294
|
|
|
204
295
|
### Primitive Types
|