@fitzzero/quickdraw-core 5.0.0-rc.4 → 5.0.0-rc.5
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 +110 -25
- package/dist/{admin-ByHvKBth.d.ts → admin-CsXR7Zwy.d.ts} +2 -2
- package/dist/{adminSchemas-C1U6_voe.d.ts → adminSchemas-Dufu8r7a.d.ts} +1 -1
- package/dist/{auth-Cc_XKBKj.d.ts → auth-CMyRkfjZ.d.ts} +33 -4
- package/dist/{caller-B-7Ib98g.d.ts → caller-C2sBNmyT.d.ts} +4 -4
- package/dist/{chunk-RDCIZR4I.js → chunk-HKXLRZAO.js} +3 -3
- package/dist/{chunk-TDK6S6V7.js → chunk-NKVWV3FL.js} +1 -1
- package/dist/chunk-NKVWV3FL.js.map +1 -0
- package/dist/{chunk-IJTZQX6Z.js → chunk-NTKYU2M5.js} +160 -108
- package/dist/chunk-NTKYU2M5.js.map +1 -0
- package/dist/{chunk-QMCIKLWC.js → chunk-OM6LDFJL.js} +1 -1
- package/dist/{chunk-QMCIKLWC.js.map → chunk-OM6LDFJL.js.map} +1 -1
- package/dist/{chunk-7MPXURIO.js → chunk-RSYYHO3Q.js} +62 -17
- package/dist/chunk-RSYYHO3Q.js.map +1 -0
- package/dist/{chunk-Y5YAG75H.js → chunk-RVGJG5P2.js} +2 -2
- package/dist/{chunk-Y5YAG75H.js.map → chunk-RVGJG5P2.js.map} +1 -1
- package/dist/{chunk-DMUGWMNJ.js → chunk-TSQGR7GH.js} +1 -1
- package/dist/{chunk-DMUGWMNJ.js.map → chunk-TSQGR7GH.js.map} +1 -1
- package/dist/{chunk-7EWHLDGN.js → chunk-UZVC74SC.js} +138 -31
- package/dist/chunk-UZVC74SC.js.map +1 -0
- package/dist/{chunk-B4IOFSM6.js → chunk-X2YCUIEK.js} +16 -5
- package/dist/chunk-X2YCUIEK.js.map +1 -0
- package/dist/{chunk-OZ7DJUJY.js → chunk-Y6IH3B4W.js} +1 -1
- package/dist/chunk-Y6IH3B4W.js.map +1 -0
- package/dist/{chunk-4PK6O7VL.js → chunk-ZHPUY3QZ.js} +97 -35
- package/dist/chunk-ZHPUY3QZ.js.map +1 -0
- package/dist/cli/quickdraw-docs.js +29 -7
- package/dist/cli/quickdraw-docs.js.map +1 -1
- package/dist/client/index.d.ts +14 -7
- package/dist/client/index.js +78 -52
- package/dist/client/index.js.map +1 -1
- package/dist/{clientTypes-CKqjWKdP.d.ts → clientTypes-BPdAdy5t.d.ts} +87 -9
- package/dist/{connection-GcBHwKgF.d.ts → connection-Dld74yBn.d.ts} +9 -2
- package/dist/{createServer-6ZLgE-Vs.d.ts → createServer-BAHtmsBo.d.ts} +6 -6
- package/dist/{createTestApp-BTFzRxV8.d.ts → createTestApp-BhDUhx8B.d.ts} +6 -6
- package/dist/{envelope-B6TUGKsk.d.ts → envelope-VWu-kXQf.d.ts} +6 -1
- package/dist/{http-GTJIh3Hm.d.ts → http-DL5mLeFE.d.ts} +12 -12
- package/dist/index.d.ts +6 -6
- package/dist/index.js +18 -5
- package/dist/index.js.map +1 -1
- package/dist/{infer-Zs7dAWlI.d.ts → infer-Dw21kmLw.d.ts} +18 -5
- package/dist/{metrics-C77VTXEa.d.ts → metrics-C0WvB7-I.d.ts} +2 -2
- package/dist/prisma/index.d.ts +4 -4
- package/dist/prisma/index.js +140 -8
- package/dist/prisma/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +17 -18
- package/dist/server/auth/index.js +26 -4
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/index.d.ts +45 -16
- package/dist/server/index.js +74 -19
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/index.d.ts +7 -7
- package/dist/server/mcp/index.js +2 -2
- package/dist/server/otel.d.ts +3 -3
- package/dist/{sharing-F3blmuVL.d.ts → sharing-BSTPqvgD.d.ts} +3 -3
- package/dist/testing/client.d.ts +13 -13
- package/dist/testing/client.js +5 -5
- package/dist/testing/index.d.ts +11 -11
- package/dist/testing/index.js +6 -6
- package/dist/testing/mock.d.ts +11 -6
- package/dist/testing/mock.js +4 -4
- package/dist/{types-BBU3rSbi.d.ts → types-Bwg3kIEc.d.ts} +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-4PK6O7VL.js.map +0 -1
- package/dist/chunk-7EWHLDGN.js.map +0 -1
- package/dist/chunk-7MPXURIO.js.map +0 -1
- package/dist/chunk-B4IOFSM6.js.map +0 -1
- package/dist/chunk-IJTZQX6Z.js.map +0 -1
- package/dist/chunk-OZ7DJUJY.js.map +0 -1
- package/dist/chunk-TDK6S6V7.js.map +0 -1
- /package/dist/{chunk-RDCIZR4I.js.map → chunk-HKXLRZAO.js.map} +0 -0
package/README.md
CHANGED
|
@@ -753,6 +753,18 @@ tracked client as `db`; the server finds the rest on it.
|
|
|
753
753
|
recorded with its row ids, merged per row, and handed to the flush sinks
|
|
754
754
|
once the response has been sent, with one revision per flush. A handler
|
|
755
755
|
may return `db.task.update(...)` without awaiting it.
|
|
756
|
+
- A write that changed nothing is not recorded, so it sends no frame, no
|
|
757
|
+
collection delta, no topic change and no `refreshEntry`: an
|
|
758
|
+
`updateMany`, `updateManyAndReturn` or `deleteMany` that matched no row;
|
|
759
|
+
a `data` (or an upsert's `update`) with nothing to write, `{}`; and an
|
|
760
|
+
update that sets only columns the framework reads before writing (scope,
|
|
761
|
+
`where`, membership, owner and access columns) to the values they held.
|
|
762
|
+
An upsert with `update: {}` ("make sure this row exists") reads the row
|
|
763
|
+
first in its place: one statement when the row is there, and the upsert
|
|
764
|
+
after it when it is not. A write that sets any other column is recorded
|
|
765
|
+
whatever it wrote, since its old value was never read; the `@updatedAt`
|
|
766
|
+
column Prisma moves on an unchanged write is not signalled, as no write's
|
|
767
|
+
is on its own.
|
|
756
768
|
- Writes inside `db.$transaction` join the unit only when it commits; a
|
|
757
769
|
rollback drops them. Prefer the interactive form
|
|
758
770
|
(`db.$transaction(async (tx) => ...)`): an array-form
|
|
@@ -882,7 +894,19 @@ export const taskService = qd.defineService(task, {
|
|
|
882
894
|
rows (a `Date` is fine where the wire has a string, extra columns are
|
|
883
895
|
dropped); with `map`, it returns what `map` takes.
|
|
884
896
|
- Fields the contract's `fields` map puts above the caller's level on a row
|
|
885
|
-
are stripped from that caller's copy, after any shared run.
|
|
897
|
+
are stripped from that caller's copy, after any shared run. Only a
|
|
898
|
+
projection output is stripped (`"entity"`, a named projection, and
|
|
899
|
+
`nullable(...)` or `listOf(...)` of one): a method whose output is a
|
|
900
|
+
schema of its own sends what its handler returns to every caller its
|
|
901
|
+
access admits, so a tiered key in that schema (`email` in a hand-written
|
|
902
|
+
`{ id, name, email }`) reaches callers below its level. When a server is
|
|
903
|
+
made, each such method raises the development warning
|
|
904
|
+
`[quickdraw:tiered-field-in-output]` (thrown by
|
|
905
|
+
`createTestApp({ strictWarnings: true })`, so the test app fails to
|
|
906
|
+
start): answer `"entity"` or a projection, or leave the key out. Not
|
|
907
|
+
warned: a method whose access admits no caller below the field's level
|
|
908
|
+
(`{ service: "Admin" }` with the Admin bypass on, `{ entry: L }` with `L`
|
|
909
|
+
at the field's level or above), and an output without JSON Schema (Zod 3).
|
|
886
910
|
- `affects` names rows of other services a write changes too
|
|
887
911
|
(`{ service, id: column }`, or `{ service, id: (row) => ids, columns }`);
|
|
888
912
|
they are sent again after the flush, one hop.
|
|
@@ -1009,7 +1033,13 @@ export const taskService = qd.defineService(task, {
|
|
|
1009
1033
|
authorized like a subscribe to that scope, or `service`, which changes
|
|
1010
1034
|
whenever any row of the service does, or a row of a model it lists in
|
|
1011
1035
|
`writes` (a game's high scores, which no service owns). A query declares
|
|
1012
|
-
`watch: "service"` to be invalidated by it.
|
|
1036
|
+
`watch: "service"` to be invalidated by it. A query over some of those
|
|
1037
|
+
models names them, `watch: { service: ["gameScore"] }` (the service's
|
|
1038
|
+
`model` and models in its `writes`; `defineService` refuses others), and
|
|
1039
|
+
is invalidated only after a flush that wrote one of them: high scores are
|
|
1040
|
+
not read again when a chat membership the same service writes changes.
|
|
1041
|
+
It is the same topic: its `qd:changed` frame names the models that
|
|
1042
|
+
changed it (`models`). The service topic is closed
|
|
1013
1043
|
(`FORBIDDEN`) unless the service declares `watchAccess` (`"public"`,
|
|
1014
1044
|
`"authenticated"` or `{ service: level }`). A watcher that loses access
|
|
1015
1045
|
leaves the topic after one last `qd:changed`.
|
|
@@ -1041,7 +1071,9 @@ over three transports (design: sections 3, 8 and 10):
|
|
|
1041
1071
|
principal comes from the session cookie (`__Host-session` over HTTPS,
|
|
1042
1072
|
`session` over plain HTTP or with `COOKIE_DOMAIN`, as the auth routes name
|
|
1043
1073
|
it) or an `Authorization: Bearer` token through the same
|
|
1044
|
-
`authenticate
|
|
1074
|
+
`authenticate`, which is told which one it was (`request.credential`):
|
|
1075
|
+
`socketAuth` answers a cookie sent from a page outside `allowedOrigins`
|
|
1076
|
+
with `FORBIDDEN`, as it refuses such a socket; the reply is `{ ok: true, d }` or
|
|
1045
1077
|
`{ ok: false, e: { code, message, data? } }` with the code's HTTP status.
|
|
1046
1078
|
Works on Express 4 and 5, and on a bare Node server. Move it with
|
|
1047
1079
|
`http: { path }`, turn it off with `http: false`, or mount
|
|
@@ -1211,6 +1243,19 @@ export function TaskDetail({ id }: { readonly id: string }) {
|
|
|
1211
1243
|
}
|
|
1212
1244
|
```
|
|
1213
1245
|
|
|
1246
|
+
- A row that does not exist is refused the way a row the reader may not
|
|
1247
|
+
see is: `FORBIDDEN`, for a subscribe and for a method whose access names
|
|
1248
|
+
the row (`{ entry }`), since a policy that cannot find the row grants
|
|
1249
|
+
nothing (fail closed), and telling the two apart would tell a stranger
|
|
1250
|
+
which ids exist (a service-wide `Admin` grant, which needs no row to
|
|
1251
|
+
pass, gets `NOT_FOUND`). So a page cannot tell "deleted" from "no access" by the
|
|
1252
|
+
refusal: it learns of a delete while it holds the row, live: the `r`
|
|
1253
|
+
frame sets `useEntity`'s `isRemoved` (as above), and a collection's
|
|
1254
|
+
`removed` delta takes the item out of `items`. A page opened after the
|
|
1255
|
+
delete (a link, a reload, a reconnect after the row went) gets only
|
|
1256
|
+
`FORBIDDEN`; where the difference matters, say "not found or not shared
|
|
1257
|
+
with you", or ask a method of the parent row (a list of the project's
|
|
1258
|
+
tasks) that can answer without leaking.
|
|
1214
1259
|
- A field the contract's `fields` map tiers (`notes` here) is optional in
|
|
1215
1260
|
every row type a reader gets (`useEntity`, collection items, `"entity"`
|
|
1216
1261
|
outputs, `EntityOf`, `ItemOf`), because a reader below its level receives
|
|
@@ -1260,7 +1305,14 @@ A create shows its row before the server answers with `cache.addItem(collection,
|
|
|
1260
1305
|
scope, item)`: the item appears in the scope at once, in its place by the
|
|
1261
1306
|
collection's `order` (give it the order's fields; without them it goes
|
|
1262
1307
|
last), and `useCollection`'s `pending` names it while the call is in flight.
|
|
1263
|
-
A refused call removes it
|
|
1308
|
+
A refused call removes it, unless it was added with `{ onRefused: "keep" }`
|
|
1309
|
+
(`cache.addItem(collection, scope, item, { onRefused: "keep" })`, or the
|
|
1310
|
+
same for `addEntity`): it then leaves `items` for `useCollection`'s
|
|
1311
|
+
`refused`, each `{ item, error, dismiss(), retry() }`, until the app
|
|
1312
|
+
dismisses it or sends the same call again with `retry()` (which shows it
|
|
1313
|
+
`pending` again, and never rejects: a second refusal shows in `refused`
|
|
1314
|
+
again), so a chat shows a failed message with "retry" without a copy of
|
|
1315
|
+
its own. The reply's `id` (the created row's) and values
|
|
1264
1316
|
replace the item's own, and once the scope's own copy arrives (its `added`
|
|
1265
1317
|
delta, or a load) that copy shows in its place: never both, never a gap.
|
|
1266
1318
|
`cache.addEntity(row)` adds a row to every collection of entity rows whose
|
|
@@ -1397,8 +1449,10 @@ The methods most services write by hand, as one-line opt-ins (design:
|
|
|
1397
1449
|
section 12). Each kit's contract half comes from the package root and makes
|
|
1398
1450
|
ordinary contract entries; its handlers come from `./server`. Lint's
|
|
1399
1451
|
`prefer-kit` reports a method written by hand that a kit implements (`get`,
|
|
1400
|
-
`list`, `create`, `getTask`, ...) in a service that uses no kit
|
|
1401
|
-
|
|
1452
|
+
`list`, `create`, `getTask`, ...) in a service that uses no kit, and one
|
|
1453
|
+
that duplicates what a kit spread beside it serves (a `getNote` beside
|
|
1454
|
+
`crud.handlers(note, { access: { get } })`); one that must stay
|
|
1455
|
+
hand-written says why in a `// quickdraw: hand-written because ...`
|
|
1402
1456
|
comment above it.
|
|
1403
1457
|
|
|
1404
1458
|
### Read/write kit
|
|
@@ -1943,9 +1997,14 @@ before?, after }, ctx, db)` after each `adminCreate`, `adminUpdate` and
|
|
|
1943
1997
|
transaction's tracked client; a throw undoes the write and fails the
|
|
1944
1998
|
call): what an admin edit must set off, such as a game reloading its
|
|
1945
1999
|
tunables, without wrapping the kit's handlers. The rows are the entity,
|
|
1946
|
-
every field.
|
|
1947
|
-
|
|
1948
|
-
|
|
2000
|
+
every field. `onCommitted({ method, id, before?, after }, ctx)` runs once
|
|
2001
|
+
the write has committed (after `onWrite`'s transaction), in a detached
|
|
2002
|
+
unit of work of its own: the reply does not wait for it, its writes flush
|
|
2003
|
+
on their own, and a throw is logged, the write standing. Apply an edit to
|
|
2004
|
+
what runs in memory (a game's simulation) there, so an edit that rolled
|
|
2005
|
+
back is never applied. Without either hook the kit opens no transaction.
|
|
2006
|
+
Each handler `admin.handlers` returns resolves with its method's output
|
|
2007
|
+
type, so a wrapper reads the row and returns it with no cast.
|
|
1949
2008
|
- `adminSubscribers({ id })` counts the sockets subscribed to a row per
|
|
1950
2009
|
access level (`{ id, count, levels, complete }`; behind a Redis adapter
|
|
1951
2010
|
the counts are this server's and `complete` is `false`), and
|
|
@@ -2158,8 +2217,10 @@ input, { enabled?, onJoined? })` (from `./client`) runs the joining call
|
|
|
2158
2217
|
(`enterBoard` above) on every `qd:hello` and when its input changes by
|
|
2159
2218
|
value, never on a re-render, and shows `status` (`idle` with no socket to
|
|
2160
2219
|
join with, `joining`, `joined`, `error`), `isJoined`, `data` and `error`;
|
|
2161
|
-
a refusal stands until the next hello
|
|
2162
|
-
|
|
2220
|
+
a refusal stands until the next hello or `retry()` (which runs the call
|
|
2221
|
+
again at once on the current socket, and does nothing while there is
|
|
2222
|
+
none or `enabled` is false), `RATE_LIMITED` is tried again after its
|
|
2223
|
+
backoff, and it never leaves the room itself.
|
|
2163
2224
|
`connection.onHello(listener)` is the same hook without React.
|
|
2164
2225
|
|
|
2165
2226
|
Code that is not a handler (a game loop, a timer, a job) reaches rooms
|
|
@@ -2351,8 +2412,16 @@ nothing is cached:
|
|
|
2351
2412
|
any page's handshake). A handshake without `Origin` is refused unless it
|
|
2352
2413
|
is a browser's same-origin request (`Sec-Fetch-Site: same-origin`) or
|
|
2353
2414
|
`allowMissingOrigin: true` is set for native clients that keep cookies.
|
|
2354
|
-
|
|
2355
|
-
|
|
2415
|
+
An HTTP call (`/qd/...`) that sends the cookie is checked the same way
|
|
2416
|
+
and answered `FORBIDDEN` (403) from an `Origin` outside `allowedOrigins`,
|
|
2417
|
+
besides needing its JSON content type. One without `Origin` is accepted:
|
|
2418
|
+
a browser sends `Origin` with every POST, so it comes from curl or a
|
|
2419
|
+
server rendering a page with the user's forwarded cookie (refused only
|
|
2420
|
+
when `Sec-Fetch-Site` names another site). Bearer tokens need no Origin
|
|
2421
|
+
on either transport. An app's own `authenticate` learns where an HTTP
|
|
2422
|
+
call's token came from in `request.credential` (`"cookie"` or
|
|
2423
|
+
`"bearer"`), and a `QuickdrawError("FORBIDDEN")` it throws on HTTP is
|
|
2424
|
+
answered as it is.
|
|
2356
2425
|
- `socketAuth({ devCredentials })` signs a socket in by the user id its
|
|
2357
2426
|
handshake names (`auth: { userId }`, no token), as the function answers
|
|
2358
2427
|
(the principal, or `null` to refuse): for a game editor or load-test bots
|
|
@@ -2689,16 +2758,17 @@ one format and names the method call it happened in:
|
|
|
2689
2758
|
[quickdraw:n-plus-one] taskService.board: task.findUnique by id ran 10 times in one call, once per item (N+1); ...
|
|
2690
2759
|
```
|
|
2691
2760
|
|
|
2692
|
-
| Kind
|
|
2693
|
-
|
|
|
2694
|
-
| `n-plus-one`
|
|
2695
|
-
| `unbounded-read`
|
|
2696
|
-
| `oversized-response`
|
|
2697
|
-
| `nested-write`
|
|
2698
|
-
| `ambient-write`
|
|
2699
|
-
| `batch-read`
|
|
2700
|
-
| `batch-create-many`
|
|
2701
|
-
| `repeated-call`
|
|
2761
|
+
| Kind | Raised when |
|
|
2762
|
+
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
2763
|
+
| `n-plus-one` | a call ran 10 statements of one shape (model, operation, `where` keys), outside a `$transaction([])` |
|
|
2764
|
+
| `unbounded-read` | a call ran `findMany` with neither `take` nor ids to read (`id`, `{ in }` or `{ equals }`) |
|
|
2765
|
+
| `oversized-response` | a reply was larger than `maxResponseBytes` (default 1 MiB) |
|
|
2766
|
+
| `nested-write` | a write's `data` wrote a related row, which is not tracked |
|
|
2767
|
+
| `ambient-write` | a tracked write ran outside any unit of work |
|
|
2768
|
+
| `batch-read` | a write in an array-form `$transaction` read its rows outside the batch |
|
|
2769
|
+
| `batch-create-many` | a `createMany` in an array-form `$transaction` could not report its rows |
|
|
2770
|
+
| `repeated-call` | one connection repeated a call or was refused `RATE_LIMITED` again and again (below) |
|
|
2771
|
+
| `tiered-field-in-output` | a method's own output schema names a field the contract tiers, which only projection outputs strip; raised when the server is made |
|
|
2702
2772
|
|
|
2703
2773
|
Updates and deletes by id inside an interactive transaction are not counted
|
|
2704
2774
|
toward `n-plus-one`: that is how per-row writes are written (see tracked
|
|
@@ -2716,7 +2786,9 @@ fails: the call it happened in fails with `INTERNAL` and the error as its
|
|
|
2716
2786
|
once the reply was recorded (over a socket or HTTP the reply was already
|
|
2717
2787
|
sent, so that error is logged, not thrown). Strictness belongs to the app:
|
|
2718
2788
|
warnings outside its calls (an ambient write while seeding, another app's
|
|
2719
|
-
calls) are logged as usual, and `app.close()` ends it.
|
|
2789
|
+
calls) are logged as usual, and `app.close()` ends it. The one raised when
|
|
2790
|
+
the app is made, `tiered-field-in-output`, is thrown from `createTestApp`
|
|
2791
|
+
itself, so a strict app over such a method does not start.
|
|
2720
2792
|
|
|
2721
2793
|
A `repeated-call` warning names a client caught in a loop (a mutation fired
|
|
2722
2794
|
from an effect that its own result runs again, a refetch that triggers
|
|
@@ -2817,6 +2889,12 @@ it("lets a signed-in user through the gate", () => {
|
|
|
2817
2889
|
|
|
2818
2890
|
In Storybook, a decorator renders every story inside `qd.$Provider`, and a
|
|
2819
2891
|
story's `beforeEach` sets its session (`qd.$session(...)`) beside its data.
|
|
2892
|
+
A docs page renders its stories side by side, where one mock session would
|
|
2893
|
+
show the last story's in all of them: give each its own with the
|
|
2894
|
+
provider's `session` prop, `<qd.$Provider session={{ userId: null }}>`,
|
|
2895
|
+
laid over the mock's session field by field for that subtree alone (the
|
|
2896
|
+
real `useQuickdraw()` and `usePresence`, and the mock's views and admin
|
|
2897
|
+
grants, read it there).
|
|
2820
2898
|
|
|
2821
2899
|
### Test databases
|
|
2822
2900
|
|
|
@@ -2916,7 +2994,14 @@ topic (`watchAccess`) and the field levels; each method's access form, in
|
|
|
2916
2994
|
words, and its `rowless`; who may open a collection's scope; a channel's
|
|
2917
2995
|
access; a stream's computed seed and when its items are checked. A
|
|
2918
2996
|
contract the services module has no service for says so, and a service
|
|
2919
|
-
without a contract is an error. Pass the same flag to `--check`.
|
|
2997
|
+
without a contract is an error. Pass the same flag to `--check`. The
|
|
2998
|
+
services module is imported with everything it imports, as the server
|
|
2999
|
+
loads it: the workspace packages it uses (`@project/db`, `@project/shared`)
|
|
3000
|
+
load from their built output when their `package.json` points there, so
|
|
3001
|
+
build them first (`bun run build`, or `turbo run build --filter` for those
|
|
3002
|
+
packages) in a script that runs the docs on a fresh checkout; the error
|
|
3003
|
+
says so when a built file is missing. The contracts module, which imports
|
|
3004
|
+
only the shared package's own sources, needs no build.
|
|
2920
3005
|
|
|
2921
3006
|
The module may export each contract, or a map of them as given to
|
|
2922
3007
|
`createQuickdrawClient`. A TypeScript module loads through Node's type
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { e as StandardSchemaWithJSON, d as StandardSchemaV1, I as InferInput, c as InferOutput,
|
|
2
|
-
import { d as ListSort, c as ListQuery, b as ListPage, u as AdminListInput, v as AdminListQuery, y as AdminPage, r as AdminCreateInput, s as AdminCreateQuery, B as AdminUpdateInput, C as AdminUpdateQuery, w as AdminMetaInput, n as AdminServiceMeta, z as AdminSubscribers } from './adminSchemas-
|
|
1
|
+
import { e as StandardSchemaWithJSON, d as StandardSchemaV1, I as InferInput, c as InferOutput, X as RowSchema, Q as QueryDef, P as ProjectionList, p as MutationDef, J as AnyContract, ap as MethodName } from './infer-Dw21kmLw.js';
|
|
2
|
+
import { d as ListSort, c as ListQuery, b as ListPage, u as AdminListInput, v as AdminListQuery, y as AdminPage, r as AdminCreateInput, s as AdminCreateQuery, B as AdminUpdateInput, C as AdminUpdateQuery, w as AdminMetaInput, n as AdminServiceMeta, z as AdminSubscribers } from './adminSchemas-Dufu8r7a.js';
|
|
3
3
|
|
|
4
4
|
/** A schema a kit generates: validation, and its JSON Schema. */
|
|
5
5
|
type KitSchema<Input, Output = Input> = StandardSchemaWithJSON<Input, Output>;
|
|
@@ -1,7 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IncomingMessage, IncomingHttpHeaders } from 'node:http';
|
|
2
2
|
import { Socket } from 'socket.io';
|
|
3
|
-
import { A as AccessLevel } from './infer-
|
|
4
|
-
import { P as Principal, M as MaybePromise } from './types-
|
|
3
|
+
import { A as AccessLevel } from './infer-Dw21kmLw.js';
|
|
4
|
+
import { P as Principal, M as MaybePromise } from './types-Bwg3kIEc.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A request as Express leaves it: maybe with `body` from `express.json()`,
|
|
8
|
+
* `cookies` from `cookie-parser`, and Express's own `secure`.
|
|
9
|
+
*/
|
|
10
|
+
type HttpRequest = IncomingMessage & {
|
|
11
|
+
readonly body?: unknown;
|
|
12
|
+
readonly cookies?: unknown;
|
|
13
|
+
readonly secure?: unknown;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Where an HTTP call's token came from. `"cookie"`: the session cookie, which
|
|
17
|
+
* a browser sends with a request any page makes, so whoever accepts it checks
|
|
18
|
+
* the request's `Origin` (`socketAuth` does). `"bearer"`: an
|
|
19
|
+
* `Authorization: Bearer` header, which a page sends only on purpose.
|
|
20
|
+
*/
|
|
21
|
+
type HttpCredentialSource = "cookie" | "bearer";
|
|
5
22
|
|
|
6
23
|
/** A principal's service-wide grants by service name: `{ taskService: "Admin" }`. */
|
|
7
24
|
type ServiceGrants = Readonly<Record<string, AccessLevel>>;
|
|
@@ -24,6 +41,14 @@ interface SocketAuthenticateRequest extends AuthenticateRequestBase {
|
|
|
24
41
|
interface HttpAuthenticateRequest extends AuthenticateRequestBase {
|
|
25
42
|
readonly transport: "http";
|
|
26
43
|
readonly req: IncomingMessage;
|
|
44
|
+
/**
|
|
45
|
+
* Where `auth.token` came from (finding F7.1): `"cookie"`, the session
|
|
46
|
+
* cookie, which a browser sends with a request any page makes, so an
|
|
47
|
+
* `authenticate` that accepts it checks the request's `Origin` as
|
|
48
|
+
* `socketAuth` does; `"bearer"`, an `Authorization: Bearer` header, which
|
|
49
|
+
* a page sends only on purpose. Absent without a token.
|
|
50
|
+
*/
|
|
51
|
+
readonly credential?: HttpCredentialSource;
|
|
27
52
|
}
|
|
28
53
|
/** What `authenticate` is asked about: a socket connecting, or an HTTP call. */
|
|
29
54
|
type AuthenticateRequest = SocketAuthenticateRequest | HttpAuthenticateRequest;
|
|
@@ -44,6 +69,10 @@ interface ServerAuth<P extends Principal = Principal> {
|
|
|
44
69
|
* caller in anonymously, so only `"public"` methods pass. Throw a
|
|
45
70
|
* `QuickdrawError("UNAUTHENTICATED", ...)` for a refusal that is the
|
|
46
71
|
* caller's doing (it logs at debug; anything else thrown logs at error).
|
|
72
|
+
* On an HTTP call a thrown `QuickdrawError("FORBIDDEN", ...)` is answered
|
|
73
|
+
* as it is, with 403 (logged at debug): a credential the request may not
|
|
74
|
+
* use from where it came, as `socketAuth` answers a session cookie sent
|
|
75
|
+
* from a page outside `allowedOrigins`.
|
|
47
76
|
*/
|
|
48
77
|
readonly authenticate?: (request: AuthenticateRequest) => MaybePromise<AuthenticateResult<P>>;
|
|
49
78
|
/**
|
|
@@ -77,4 +106,4 @@ interface ServiceAccessSource {
|
|
|
77
106
|
*/
|
|
78
107
|
declare function recordSocketSession(socket: object, sessionId: string): void;
|
|
79
108
|
|
|
80
|
-
export { type AuthenticateResult as A, type
|
|
109
|
+
export { type AuthenticateResult as A, type HttpRequest as H, type ServerAuth as S, type ServiceGrants as a, type AuthenticateRequest as b, type HttpAuthenticateRequest as c, type HttpCredentialSource as d, type ServiceAccessSource as e, type SocketAuthenticateRequest as f, recordSocketSession as r };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ad as Version, a5 as Revision } from './envelope-
|
|
1
|
+
import { ad as Version, a5 as Revision } from './envelope-VWu-kXQf.js';
|
|
2
2
|
import { L as Logger } from './logger-BY28acW-.js';
|
|
3
|
-
import { A as AccessLevel,
|
|
4
|
-
import { P as Principal, Q as QuickdrawTypes, M as MaybePromise, c as PrincipalOf, a as McpContext, T as Transport, C as ContextExtensionOf, b as McpContextOf, D as DbOf } from './types-
|
|
3
|
+
import { A as AccessLevel, J as AnyContract, y as CollectionWhere, O as OrderBy, k as MethodKind, d as StandardSchemaV1, ag as EventName, ah as EventPayloadOf, aa as ChannelName, ab as ChannelPayloadOf, az as StreamName, am as IsScopedStream, ay as StreamItemOf, ae as ContractMap, ap as MethodName, al as InputOf, ar as OutputOf } from './infer-Dw21kmLw.js';
|
|
4
|
+
import { P as Principal, Q as QuickdrawTypes, M as MaybePromise, c as PrincipalOf, a as McpContext, T as Transport, C as ContextExtensionOf, b as McpContextOf, D as DbOf } from './types-Bwg3kIEc.js';
|
|
5
5
|
|
|
6
6
|
/** What a development warning is about. */
|
|
7
|
-
type DevWarningKind = "n-plus-one" | "unbounded-read" | "oversized-response" | "nested-write" | "ambient-write" | "batch-read" | "batch-create-many" | "repeated-call";
|
|
7
|
+
type DevWarningKind = "n-plus-one" | "unbounded-read" | "oversized-response" | "nested-write" | "ambient-write" | "batch-read" | "batch-create-many" | "repeated-call" | "tiered-field-in-output";
|
|
8
8
|
/** One development warning. */
|
|
9
9
|
interface DevWarning {
|
|
10
10
|
readonly kind: DevWarningKind;
|
|
@@ -22,11 +22,11 @@ import {
|
|
|
22
22
|
reorderInput,
|
|
23
23
|
unknownKeys,
|
|
24
24
|
withId
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-NKVWV3FL.js";
|
|
26
26
|
import {
|
|
27
27
|
ACCESS_LEVELS,
|
|
28
28
|
isAccessLevel
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-RVGJG5P2.js";
|
|
30
30
|
import {
|
|
31
31
|
isStandardSchema
|
|
32
32
|
} from "./chunk-47AEXVDM.js";
|
|
@@ -513,4 +513,4 @@ export {
|
|
|
513
513
|
sharingSpecOf,
|
|
514
514
|
sharing
|
|
515
515
|
};
|
|
516
|
-
//# sourceMappingURL=chunk-
|
|
516
|
+
//# sourceMappingURL=chunk-HKXLRZAO.js.map
|