foldkit-remote 0.18.1 → 0.20.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/README.md CHANGED
@@ -1382,6 +1382,12 @@ the store the answer left:
1382
1382
  it. Declare the order in the body (`Query.orderBy`) to keep a list that a
1383
1383
  change provably did not move.
1384
1384
 
1385
+ **The client runs a body's primitive operators by its own table.**
1386
+ `Remote.make({ ..., operators })` (`Operators.kernel` by default) is the table
1387
+ it matches, filters and places rows with. A body calling an operator the table
1388
+ does not run is judged by the server, as any row the client cannot judge is:
1389
+ `Data.filtered` answers it incomplete and a change to it refetches.
1390
+
1385
1391
  **A placement can be checked against the server.** `Remote.make({ ...,
1386
1392
  verifyPlacement: true })` places as usual, and also fetches each list it placed
1387
1393
  what the server said in (an answer, as above, or a read or a live patch, as
@@ -1424,6 +1430,15 @@ effect on rows it did not return.
1424
1430
  `Unknown` for an id never started here (or settled so long ago it left the
1425
1431
  bounded ledger). A retry reuses its id, and the latest outcome wins.
1426
1432
 
1433
+ A request id names a request to this client only: it is a counter in the
1434
+ Model, so it restarts on reload and two clients' first requests share it. To a
1435
+ server, a mutation is named by its **operation**, an id minted where it is first
1436
+ sent (`crypto.randomUUID()`), unique across clients. A failed request keeps its
1437
+ operation, and a retry with the same `requestId` (`Data.mutate(model, M, input,
1438
+ { requestId })`) sends it again, so a server that keeps a record of its writes
1439
+ can recognise the retry. After a reload the record of it is gone, and the same
1440
+ request id is a new operation.
1441
+
1427
1442
  A mutation can say what the server may refuse it with, as data rather than a
1428
1443
  message to parse:
1429
1444
 
@@ -1441,7 +1456,14 @@ A mutation can also be a declared write: `Mutation.write(name, write)` over a
1441
1456
  `foldkit-entity` `Write.update`, `Write.insert` or `Write.delete`. Its input is
1442
1457
  the write's, it answers nothing of its own, and `Data.mutate` shows an update's
1443
1458
  or an insert's row until the server answers, so it needs no `optimistic` list;
1444
- a delete shows nothing until its answer removes the row everywhere. `keys` names the input keys
1459
+ a delete shows nothing until its answer removes the row everywhere. An update's
1460
+ `increment` is shown as a prediction: its amount is added to the value the store
1461
+ holds whenever the row is read, so a change that reaches the store meanwhile is
1462
+ added to rather than hidden, and two pending increments add up. A field the
1463
+ client has not read is not guessed; it shows the server's sum when the answer
1464
+ comes. The prediction is never authority: the server decides, and its answer
1465
+ replaces it. The [declared writes guide](../../docs/declared-writes.md) follows
1466
+ one write from here to the statement that lands it. `keys` names the input keys
1445
1467
  an author changed: only those are shown, and the request carries them for the
1446
1468
  server to write; the input is still sent and validated whole.
1447
1469
 
@@ -1454,7 +1476,18 @@ Data.mutate(model, EditProject, { id: 'p1', name: 'Apollo II', status: 'active'
1454
1476
  ```
1455
1477
 
1456
1478
  `Refusal.field(key, reason)` names an input key and why; `Refusal.conflict`
1457
- says the row moved on. The server sends the refusal encoded by this schema and
1479
+ says the row moved on, and `Refusal.unmet` that it does not hold what a declared
1480
+ write's `when` asks of it. A `Mutation.write` is refused as unmet only when its
1481
+ write has a `when`, and its `Refusal` type says so: without one it stays
1482
+ `Conflict`, so a match over it needs no `Unmet` arm. `Refusal.invalid` says the
1483
+ row it would leave breaks an invariant of its Entity (`Entity.invariant`): its
1484
+ `rule` and `path`, which a form shows the `message` beside, or none and empty
1485
+ when the invariant reads something the caller may not see. Every
1486
+ `Mutation.write` may be refused so, since the server's Entity may hold
1487
+ invariants the client's does not show. `Refusal.isInvalidBy(refusal, invariant)`
1488
+ asks whether it names one invariant, given as `Entity.invariant` returned it
1489
+ (export it beside the Entity), so its id is never spelled again; an unnamed
1490
+ refusal matches none. The server sends the refusal encoded by this schema and
1458
1491
  `Data.refusal` decodes it by the same one; it is none while the mutation is
1459
1492
  pending or applied, or when it failed for another reason.
1460
1493
 
@@ -2074,9 +2107,11 @@ above.
2074
2107
  `Remote.mutateInto(bound, model, mutation, input, requestId, { optimistic, now })` is
2075
2108
  the one-step imperative start/run/settle form for SSR and tests.
2076
2109
 
2077
- `Remote.mutate(mutation, input, requestId)` is the transport call itself. It
2078
- decodes the typed `Output` and returns normalized entity patches and confirmed
2079
- connection changes for a caller to reduce through `updateRemote`.
2110
+ `Remote.mutate(mutation, input, requestId, { keys, operation })` is the
2111
+ transport call itself. It decodes the typed `Output` and returns normalized
2112
+ entity patches and confirmed connection changes for a caller to reduce through
2113
+ `updateRemote`. It mints an operation id when none is given; a caller retrying
2114
+ a request passes the one it first sent.
2080
2115
 
2081
2116
  `MutationSucceeded` reconciles at most once per `requestId`; an unknown or
2082
2117
  already-applied settlement is a no-op. It carries `now`, the clock reading of