ugly-app 0.1.106 → 0.1.107

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/README.md CHANGED
@@ -84,6 +84,7 @@ The returned `App` object has:
84
84
  - `registerRoutes(fn)` — mount additional Express routes after creation
85
85
  - `httpServer` — the underlying Node.js HTTP server
86
86
  - `db` — the `TypedDB` instance for direct database access
87
+ - `wss` — the main `WebSocketServer` instance (path configured via `setWsPath`, default `'/rpc'`)
87
88
  - `dispatch(name, input, userId)` — invoke an RPC handler programmatically
88
89
 
89
90
  ### `AppConfigurator`
@@ -99,6 +100,12 @@ The optional fourth argument to `createApp` receives a configurator object:
99
100
  | `setOnSocketMessage(handler)` | Handle raw WebSocket messages. Return `true` to consume, `false` to let the framework handle it |
100
101
  | `registerRoutes(fn)` | Mount custom Express routes — `(router: express.Router) => void` |
101
102
  | `setWorkerQueue(queue)` | Register a background worker queue with `start()` and `stop()` |
103
+ | `setWsPath(path)` | Override the WebSocket path (default: `'/rpc'`) |
104
+ | `setOnWsAuth(handler)` | Called after a WebSocket session is authenticated. `(ws, userId, req) => void` |
105
+ | `setOnAfterStart(handler)` | Called once after MongoDB, Redis, and NATS are ready. `(db) => Promise<void>` |
106
+ | `setOnMinuteTick(handler)` | Fires every minute (only when `CLOCK_ENABLED=true`). `() => Promise<void>` |
107
+ | `setOnHourlyTick(handler)` | Fires when the hour changes (only when `CLOCK_ENABLED=true`). `(now, currentHour) => Promise<void>` |
108
+ | `setHealthHandler(handler)` | Override the default `GET /health` endpoint handler. `(req, res) => void` |
102
109
 
103
110
  ### Handler signatures
104
111
 
@@ -163,11 +170,11 @@ import type { Note } from './types';
163
170
  export const collections = defineCollections({
164
171
  note: {
165
172
  type: {} as Note,
166
- meta: { cache: true, trackable: true, public: false, parent: null },
173
+ meta: { cache: true, trackable: true, public: false, cascadeFrom: null },
167
174
  },
168
175
  user: {
169
176
  type: {} as User,
170
- meta: { cache: true, trackable: false, public: false, parent: null },
177
+ meta: { cache: true, trackable: false, public: false, cascadeFrom: null },
171
178
  },
172
179
  });
173
180
  ```
@@ -175,13 +182,14 @@ export const collections = defineCollections({
175
182
  Each collection definition has:
176
183
  - `type` — phantom field for TypeScript type inference (never read at runtime)
177
184
  - `meta` — runtime metadata:
178
- - `cache` — enable in-memory caching
179
- - `trackable` — allow real-time `trackDoc`/`trackDocs` subscriptions
180
- - `public` — accessible without auth
181
- - `parent` — parent collection name for cascade deletes (or `null`)
182
- - `onDelete?` — optional callback invoked on document deletion
185
+ - `cache` — enable in-memory LRU caching for `getDoc`; `setDoc`/`deleteDoc` invalidate it
186
+ - `trackable` — allow real-time `trackDoc`/`trackDocs` subscriptions via Change Streams
187
+ - `public` — allows client reads via `getDoc`/`trackDoc`/`trackDocs` without auth
188
+ - `cascadeFrom` — parent collection name for cascade deletes (or `null`)
189
+ - `trackKeys?` — fields usable as NATS routing keys for `trackDocs`
190
+ - `onDelete?` — optional async callback invoked on document deletion
183
191
 
184
- All documents extend `DBObject`: `{ id: string, version: number, created: Date, updated: Date }`.
192
+ All documents extend `DBObject`: `{ _id: string, version: number, created: Date, updated: Date }`.
185
193
 
186
194
  ### Pages (`shared/pages.ts`)
187
195
 
@@ -254,13 +262,30 @@ await socket.connect(token); // returns UserBase
254
262
  | Method | Description |
255
263
  |--------|-------------|
256
264
  | `connect(token)` | Authenticate and connect. Returns the user object |
257
- | `request(name, input)` | Invoke a request (query or mutation) |
265
+ | `request(name, input)` | Invoke a typed request (query or mutation) |
258
266
  | `getDoc(collection, id)` | Fetch a single document |
267
+ | `getDocs(collection, filter?, opts?)` | Query documents (filter, sort, limit, skip) |
268
+ | `getQuery(collection, pipeline, opts?)` | Run an aggregation pipeline |
259
269
  | `trackDoc(collection, id, cb)` | Subscribe to real-time doc changes. Returns unsubscribe fn |
260
- | `trackDocs(collection, filter, cb, opts?)` | Subscribe to query results. Returns unsubscribe fn |
270
+ | `trackDocs(collection, params, cb)` | Subscribe to query results (`keys`, `filter`, `sort`, `limit`, `skip`). Returns unsubscribe fn |
261
271
  | `uploadFile(file, key)` | Upload a file via presigned URL |
272
+ | `emit(type, data)` | Send a fire-and-forget message over WebSocket |
273
+ | `send(type, data, timeout?)` | Send a message and wait for a response |
274
+ | `waitForConnection(timeout?)` | Wait until the socket is connected |
275
+ | `connectionState` | Current state: `'connecting'` \| `'connected'` \| `'reconnecting'` \| `'disconnected'` \| `'idle-disconnected'` |
262
276
  | `disconnect()` | Close the connection |
263
277
 
278
+ **`createSocket()` options:**
279
+
280
+ | Option | Description |
281
+ |--------|-------------|
282
+ | `requests` | The requests registry from `shared/api.ts` |
283
+ | `url?` | WebSocket path (default: `'/rpc'`) |
284
+ | `buildId?` | Build identifier sent on connect |
285
+ | `onCustomMessage?` | Handle custom server-pushed messages |
286
+ | `getUrlParams?` | Extra query params appended to the WebSocket URL |
287
+ | `messageReviver?` | JSON reviver for incoming messages (e.g. Date parsing) |
288
+
264
289
  ### `createHttpClient()`
265
290
 
266
291
  Creates a typed HTTP client for RPC communication (no WebSocket needed).
@@ -524,7 +549,7 @@ The `AuthProvider` interface:
524
549
 
525
550
  ```typescript
526
551
  interface AuthProvider {
527
- verify(code: string): Promise<{ userId: string; email?: string; phone?: string }>;
552
+ verify(code: string): Promise<{ userId: string; email?: string; phone?: string; token?: string }>;
528
553
  authUrl(origin: string): string;
529
554
  registerRoutes?(router: express.Router): void;
530
555
  }
@@ -578,8 +603,8 @@ const docs = await db.rawGetDocs(collectionName, filter);
578
603
  ### Deleting
579
604
 
580
605
  ```typescript
581
- await db.deleteDoc(collections.note, id); // single doc (cascades via parent)
582
- await db.deleteQuery(collections.note, { userId }); // bulk delete by filter
606
+ await db.deleteDoc(collections.note, id); // single doc (cascades via cascadeFrom)
607
+ await db.deleteQuery(collections.note, { userId }); // bulk delete by filter (cascades + calls onDelete)
583
608
  ```
584
609
 
585
610
  ### Caching
@@ -948,6 +973,7 @@ Run with `npm run db:migrate`. Use `npm run db:migrate -- --status` to preview p
948
973
  | `KIE_API_KEY` | Kie.ai key |
949
974
  | `KIE_BASE_URL` | Kie.ai base URL override (optional) |
950
975
  | `MAILGUN_FROM` | Default from address |
976
+ | `CLOCK_ENABLED` | Set to `true` to enable `setOnMinuteTick`/`setOnHourlyTick` handlers |
951
977
 
952
978
  Client-side variables must be prefixed with `VITE_`.
953
979
 
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.106";
1
+ export declare const CLI_VERSION = "0.1.107";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.106";
2
+ export const CLI_VERSION = "0.1.107";
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.106",
3
+ "version": "0.1.107",
4
4
  "type": "module",
5
5
  "main": "./dist/server/index.js",
6
6
  "exports": {
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.106";
2
+ export const CLI_VERSION = "0.1.107";