@fitzzero/quickdraw-core 5.0.0-rc.6 → 5.0.0-rc.7

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
@@ -89,7 +89,10 @@ export const taskContract = defineContract("taskService", {
89
89
  ...crud.contract({
90
90
  entity: taskSchema,
91
91
  get: true,
92
- create: { input: z.object({ projectId: z.string(), title: z.string() }) },
92
+ // `id`: one the client may make (`newId()`), which the create keeps
93
+ create: {
94
+ input: z.object({ id: z.string().optional(), projectId: z.string(), title: z.string() }),
95
+ },
93
96
  }),
94
97
  rename: mutation({
95
98
  input: z.object({ id: z.string(), title: z.string() }),
@@ -1353,7 +1356,9 @@ delta, or a load) that copy shows in its place: never both, never a gap.
1353
1356
  `cache.addEntity(row)` adds a row to every collection of entity rows whose
1354
1357
  scope column (and `where`) it matches; a collection of a projection takes
1355
1358
  `addItem`. The item may give its own `id`, one the client made and the
1356
- server keeps:
1359
+ server keeps: `newId()` from `./client` makes one, a version 4 UUID from
1360
+ `crypto.randomUUID()`, or from `crypto.getRandomValues()` on a page over
1361
+ plain http, which browsers do not give `randomUUID`:
1357
1362
 
1358
1363
  <!-- example: apps/web/src/components/AddTask.tsx#add -->
1359
1364
 
@@ -1364,6 +1369,8 @@ export function TaskList({ projectId }: { readonly projectId: string }) {
1364
1369
  // the new card shows at once, last on the board (its ordinal), until the server's arrives
1365
1370
  optimistic: (input, cache) =>
1366
1371
  cache.addItem("board", input.projectId, {
1372
+ // the id the client made: after a lost answer the board's next load finds the card
1373
+ id: input.id,
1367
1374
  projectId: input.projectId,
1368
1375
  title: input.title,
1369
1376
  status: "open",
@@ -1381,7 +1388,10 @@ export function TaskList({ projectId }: { readonly projectId: string }) {
1381
1388
  </li>
1382
1389
  ))}
1383
1390
  </ul>
1384
- <button type="button" onClick={() => create.mutate({ projectId, title: "New task" })}>
1391
+ <button
1392
+ type="button"
1393
+ onClick={() => create.mutate({ id: newId(), projectId, title: "New task" })}
1394
+ >
1385
1395
  Add
1386
1396
  </button>
1387
1397
  {create.error === null ? null : <p>{`Not added: ${create.error.code}`}</p>}
@@ -2478,22 +2488,28 @@ nothing is cached:
2478
2488
  session's token, for clients that keep no cookies (a game engine, a page
2479
2489
  in a third-party iframe), at the cost of the token being readable by the
2480
2490
  page's scripts.
2481
- - `requireSession({ sessions, jwtSecret }, { loadPrincipal?, allowedOrigins? })`
2491
+ - `requireSession({ sessions, jwtSecret }, { loadPrincipal?, allowedOrigins?, logger? })`
2482
2492
  guards the app's own REST routes (below): the credential is read as `/me`
2483
2493
  reads it, the JWT verified once and the session checked in the store;
2484
2494
  otherwise 401 `{ error: "UNAUTHENTICATED", message }`. The session cookie
2485
2495
  gets the `/qd` calls' Origin rule: from an `Origin` outside
2486
2496
  `allowedOrigins` (by default the list of the `createAuthRoutes` writing to
2487
- the same `sessions`) it answers 403 `{ error: "FORBIDDEN", message }`, so
2497
+ the same store object, `sessions`: a second store over the same table is
2498
+ another object) it answers 403 `{ error: "FORBIDDEN", message }`, so
2488
2499
  another site's form cannot post to a route as the user; a request without
2489
2500
  `Origin` is accepted unless `Sec-Fetch-Site` names another site, and a
2490
- bearer token needs none. 4.1's `createRequireAuth` stays for token-keyed
2491
- sessions.
2501
+ bearer token needs none. With neither list no page may use the cookie
2502
+ there: the first refusal logs an error naming both fixes (to `logger`,
2503
+ default the console), and a page in development is told them in the 403.
2504
+ 4.1's `createRequireAuth` stays for token-keyed sessions.
2492
2505
  - Rate limits: the sign-in routes share `createAuthLimiter({ max: 60 })` (60
2493
- requests per 15 minutes per IP) and the session routes
2494
- `createAuthStatusLimiter()` (120); pass `rateLimit: { signIn, session }`
2495
- to replace them (a shared store across instances, say) or `false`. The
2496
- defaults need the optional peer `express-rate-limit`. The HTTP transport
2506
+ requests per 15 minutes per IP), the session routes
2507
+ `createAuthStatusLimiter()` (120), and `GET /providers` has
2508
+ `createPublicApiLimiter()` (60 per minute) to itself, so the login pages
2509
+ loaded from one address cannot use up its sign-outs; pass
2510
+ `rateLimit: { signIn, session, providers }` to replace them (a shared
2511
+ store across instances, say; one left out keeps its default) or `false`.
2512
+ The defaults need the optional peer `express-rate-limit`. The HTTP transport
2497
2513
  (`/qd`) is not limited unless `http.rateLimit` is set;
2498
2514
  `createCallLimiter()` (300 calls per minute per IP) refuses in the
2499
2515
  transport's own `RATE_LIMITED` reply. A web server that prefetches for
@@ -43,12 +43,12 @@ import {
43
43
  useQuickdrawContext,
44
44
  userOf,
45
45
  viewPredicate
46
- } from "./chunk-ZU6L7PHY.js";
46
+ } from "./chunk-BXN7CACY.js";
47
47
  import {
48
48
  CLIENT_EVENTS,
49
49
  SERVICE_TOPIC,
50
50
  collectionTopic
51
- } from "./chunk-4HOXH4V3.js";
51
+ } from "./chunk-DEXRBC5F.js";
52
52
  import {
53
53
  isScopedStream
54
54
  } from "./chunk-3I7R3DZW.js";
@@ -1410,4 +1410,4 @@ export {
1410
1410
  QuickdrawProvider,
1411
1411
  useQuickdraw
1412
1412
  };
1413
- //# sourceMappingURL=chunk-PDPV254L.js.map
1413
+ //# sourceMappingURL=chunk-3OYVPO4L.js.map