@interop/was-client 0.48.1 → 0.50.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
@@ -840,7 +840,17 @@ plugs into:
840
840
  itself never touches keys. A rejected precondition throws
841
841
  `WasSyncConflictError` (412); a delete of an already-gone resource throws
842
842
  `WasSyncNotFoundError` (404) -- both catchable subtypes of the core
843
- `PreconditionFailedError` / `NotFoundError`.
843
+ `PreconditionFailedError` / `NotFoundError`. Every other failure arrives as
844
+ the typed `WasError` subclass for its status, carrying the server's
845
+ `problem+json` fields.
846
+ - **`isSyncConflictError` / `isSyncNotFoundError` / `isSyncAuthError` /
847
+ `isUnknownEpochError`** classify those signals by `err.name`. Use them rather
848
+ than `instanceof`: the port and the `DocCipher` are seams your app injects,
849
+ and a tree that resolves two copies of this package makes an `instanceof`
850
+ check quietly false. Read what you need off the matched value, such as
851
+ `err.status` on an auth error to tell a 401 from the masked 404.
852
+ - **`SyncStatus`** (`'idle' | 'syncing' | 'synced' | 'error'`) is the closed
853
+ vocabulary a replication driver reports one feed's state through.
844
854
  - **`DocCipher`** is the per-collection encrypt/decrypt seam sitting above the
845
855
  port: it turns a JSON document into its stored body (minting the resource id)
846
856
  and back. `createPlaintextDocCipher(...)` is the crypto-free identity
@@ -869,7 +879,7 @@ import {
869
879
  createPlaintextDocCipher,
870
880
  deriveSpaceId,
871
881
  ensureSpaceAndCollection,
872
- WasSyncConflictError
882
+ isSyncConflictError
873
883
  } from '@interop/was-client/sync'
874
884
 
875
885
  const spaceId = deriveSpaceId(controllerDid) // same Space on every device
@@ -889,7 +899,7 @@ const { id, envelope } = await cipher.encrypt({ data: { note: 'hello' } })
889
899
  try {
890
900
  await port.putContent({ id, data: envelope, ifNoneMatch: true })
891
901
  } catch (err) {
892
- if (!(err instanceof WasSyncConflictError)) {
902
+ if (!isSyncConflictError(err)) {
893
903
  throw err
894
904
  }
895
905
  // 412 on a content-addressed insert: another replica already wrote this
@@ -16,25 +16,36 @@
16
16
  * - `ensureSpaceAndCollection` / `ensureSpace` -- idempotent Space +
17
17
  * Collection provisioning, and its Space half alone (ensure the Space once,
18
18
  * then thread the returned description through every collection).
19
+ * - `isSyncConflictError` / `isSyncNotFoundError` / `isSyncAuthError` /
20
+ * `isUnknownEpochError` -- the classification contract for the signals
21
+ * below. A consumer matches by `err.name` and never with `instanceof`,
22
+ * because every one of these errors is raised inside a seam the app injects
23
+ * (the port, the caller's `DocCipher`) and that seam can resolve to a second
24
+ * copy of this package. Reading a property off the matched value, such as
25
+ * `status` on an auth error, is the intended shape.
19
26
  *
20
27
  * The 412 conflict / 404 not-found port signals (`WasSyncConflictError` /
21
28
  * `WasSyncNotFoundError`), and the opt-in revoked-access signal
22
29
  * (`WasSyncAuthError`, raised only under `mapAuthErrors`), live in the client's
23
30
  * typed error hierarchy and are re-exported here for convenience -- as are the
24
- * two decrypt-routing signals, so a crypto-free sync consumer can
25
- * `instanceof`-match them without importing the `/edv` entry that throws them:
26
- * the stale-descriptor signal (`UnknownEpochError`: the envelope's epoch is not
27
- * on the descriptor at all, so re-read it and rebuild the cipher) and the
28
- * membership signal (`KeyUnwrapError`: the epoch is on the descriptor but this
29
- * reader holds no key for it, so a refresh cannot help). `EncryptionError`, the
30
- * fail-closed umbrella `KeyUnwrapError` falls under, rides along.
31
+ * two decrypt-routing signals, so a crypto-free sync consumer can classify them
32
+ * without importing the `/edv` entry that throws them: the stale-descriptor
33
+ * signal (`UnknownEpochError`: the envelope's epoch is not on the descriptor at
34
+ * all, so re-read it and rebuild the cipher) and the membership signal
35
+ * (`KeyUnwrapError`: the epoch is on the descriptor but this reader holds no
36
+ * key for it, so a refresh cannot help). `EncryptionError`, the fail-closed
37
+ * umbrella `KeyUnwrapError` falls under, rides along. The classes are exported
38
+ * for construction and for a caller inside one resolved copy; across a package
39
+ * boundary the predicates are the contract
40
+ * (`decisions/0001-cross-package-errors-match-by-name.md`).
31
41
  */
32
- export { createWasSyncPort, KEY_EPOCH_HEADER, formatEtag, parseEtag } from './port.js';
42
+ export { createWasSyncPort, KEY_EPOCH_HEADER, parseEtag } from './port.js';
33
43
  export { httpStatus as errorStatus, errorMessage } from '../errors.js';
34
44
  export { contentCid, cidFrom, deriveSpaceId } from './cid.js';
35
45
  export { isEncryptedEnvelope } from './envelope.js';
36
46
  export { createPlaintextDocCipher } from './plaintextCipher.js';
37
47
  export { ensureSpace, ensureSpaceAndCollection } from './provisioning.js';
48
+ export { isSyncAuthError, isSyncConflictError, isSyncNotFoundError, isUnknownEpochError } from './predicates.js';
38
49
  export { EncryptionError, KeyUnwrapError, UnknownEpochError, WasSyncAuthError, WasSyncConflictError, WasSyncNotFoundError } from '../errors.js';
39
- export type { Json, SyncCheckpoint, WireDoc, SyncPage, MasterState, WasSyncPort, DocCipher } from './types.js';
50
+ export type { Json, SyncCheckpoint, WireDoc, SyncPage, MasterState, WriteAck, SyncStatus, WasSyncPort, DocCipher } from './types.js';
40
51
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,SAAS,EACV,MAAM,WAAW,CAAA;AAIlB,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,cAAc,CAAA;AAErB,YAAY,EACV,IAAI,EACJ,cAAc,EACd,OAAO,EACP,QAAQ,EACR,WAAW,EACX,WAAW,EACX,SAAS,EACV,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAI1E,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,cAAc,CAAA;AAErB,YAAY,EACV,IAAI,EACJ,cAAc,EACd,OAAO,EACP,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,UAAU,EACV,WAAW,EACX,SAAS,EACV,MAAM,YAAY,CAAA"}
@@ -16,20 +16,30 @@
16
16
  * - `ensureSpaceAndCollection` / `ensureSpace` -- idempotent Space +
17
17
  * Collection provisioning, and its Space half alone (ensure the Space once,
18
18
  * then thread the returned description through every collection).
19
+ * - `isSyncConflictError` / `isSyncNotFoundError` / `isSyncAuthError` /
20
+ * `isUnknownEpochError` -- the classification contract for the signals
21
+ * below. A consumer matches by `err.name` and never with `instanceof`,
22
+ * because every one of these errors is raised inside a seam the app injects
23
+ * (the port, the caller's `DocCipher`) and that seam can resolve to a second
24
+ * copy of this package. Reading a property off the matched value, such as
25
+ * `status` on an auth error, is the intended shape.
19
26
  *
20
27
  * The 412 conflict / 404 not-found port signals (`WasSyncConflictError` /
21
28
  * `WasSyncNotFoundError`), and the opt-in revoked-access signal
22
29
  * (`WasSyncAuthError`, raised only under `mapAuthErrors`), live in the client's
23
30
  * typed error hierarchy and are re-exported here for convenience -- as are the
24
- * two decrypt-routing signals, so a crypto-free sync consumer can
25
- * `instanceof`-match them without importing the `/edv` entry that throws them:
26
- * the stale-descriptor signal (`UnknownEpochError`: the envelope's epoch is not
27
- * on the descriptor at all, so re-read it and rebuild the cipher) and the
28
- * membership signal (`KeyUnwrapError`: the epoch is on the descriptor but this
29
- * reader holds no key for it, so a refresh cannot help). `EncryptionError`, the
30
- * fail-closed umbrella `KeyUnwrapError` falls under, rides along.
31
+ * two decrypt-routing signals, so a crypto-free sync consumer can classify them
32
+ * without importing the `/edv` entry that throws them: the stale-descriptor
33
+ * signal (`UnknownEpochError`: the envelope's epoch is not on the descriptor at
34
+ * all, so re-read it and rebuild the cipher) and the membership signal
35
+ * (`KeyUnwrapError`: the epoch is on the descriptor but this reader holds no
36
+ * key for it, so a refresh cannot help). `EncryptionError`, the fail-closed
37
+ * umbrella `KeyUnwrapError` falls under, rides along. The classes are exported
38
+ * for construction and for a caller inside one resolved copy; across a package
39
+ * boundary the predicates are the contract
40
+ * (`decisions/0001-cross-package-errors-match-by-name.md`).
31
41
  */
32
- export { createWasSyncPort, KEY_EPOCH_HEADER, formatEtag, parseEtag } from './port.js';
42
+ export { createWasSyncPort, KEY_EPOCH_HEADER, parseEtag } from './port.js';
33
43
  // The sync subpath's names for the client's own error accessors, so a
34
44
  // sync-only consumer reads a raw ky/ezcap failure without importing the core
35
45
  // entry.
@@ -38,5 +48,6 @@ export { contentCid, cidFrom, deriveSpaceId } from './cid.js';
38
48
  export { isEncryptedEnvelope } from './envelope.js';
39
49
  export { createPlaintextDocCipher } from './plaintextCipher.js';
40
50
  export { ensureSpace, ensureSpaceAndCollection } from './provisioning.js';
51
+ export { isSyncAuthError, isSyncConflictError, isSyncNotFoundError, isUnknownEpochError } from './predicates.js';
41
52
  export { EncryptionError, KeyUnwrapError, UnknownEpochError, WasSyncAuthError, WasSyncConflictError, WasSyncNotFoundError } from '../errors.js';
42
53
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,SAAS,EACV,MAAM,WAAW,CAAA;AAClB,sEAAsE;AACtE,6EAA6E;AAC7E,SAAS;AACT,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC1E,sEAAsE;AACtE,6EAA6E;AAC7E,SAAS;AACT,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,cAAc,CAAA"}
@@ -19,11 +19,21 @@
19
19
  * `POST /space/:s/:c/query` (profile `changes`) as a root invocation and, like
20
20
  * the raw writes, ships the stored bodies verbatim without decrypting.
21
21
  *
22
- * Conditional writes ride the server's monotonic content `version` (`ETag`),
23
- * enforced uniformly for plaintext and encrypted resources, so there is no
24
- * plaintext-vs-encrypted fork. `putContent`/`deleteContent` return the server-
25
- * acked `version` (parsed from the write's `ETag`, re-read only if the backend
26
- * sent none), so a caller can record acked revisions immediately.
22
+ * Conditional writes ride the server's `ETag`: an opaque quoted string
23
+ * (`"<generation>.<version>"`, a per-record generation marker ahead of the
24
+ * monotonic content `version` so a hard-deleted-and-recreated id can never
25
+ * collide with its predecessor's validators), enforced uniformly for
26
+ * plaintext and encrypted resources, so there is no plaintext-vs-encrypted
27
+ * fork. `putContent`/`deleteContent` return the server-acked {@link
28
+ * WriteAck} -- the write's raw `etag` (re-read only if the backend sent
29
+ * none) plus its `version` parsed out of it -- so a caller can record acked
30
+ * revisions immediately and echo `etag` back verbatim as a later write's
31
+ * `ifMatch`.
32
+ *
33
+ * Bypassing the codec is not bypassing the error mapper. Every failure caught
34
+ * here goes through the client's own `mapError` first, so the port's signals
35
+ * carry the server's `problem+json` fields and a `cause`, and a status the
36
+ * port has no signal for still leaves this subpath as a typed `WasError`.
27
37
  */
28
38
  import type { WasClient } from '../WasClient.js';
29
39
  import { KEY_EPOCH_HEADER } from '../internal/conditional.js';
@@ -37,17 +47,17 @@ import type { WasSyncPort } from './types.js';
37
47
  */
38
48
  export { KEY_EPOCH_HEADER };
39
49
  /**
40
- * Formats a numeric content `version` as the quoted strong `ETag` an
41
- * update-if-unchanged write passes as its `ifMatch` precondition (e.g. `3` to
42
- * `"3"`). Inverse of {@link parseEtag}.
50
+ * Parses a quoted strong `ETag` into its numeric revision: the decimal
51
+ * integer after the LAST `.` inside the quotes (`"3mJr7AoUXx2.3"` to `3`).
52
+ * Returns `undefined` when the header is absent, has no `.`, or the trailing
53
+ * segment is anything other than a run of digits.
43
54
  *
44
- * @param version {number}
45
- * @returns {string}
46
- */
47
- export declare function formatEtag(version: number): string;
48
- /**
49
- * Parses a quoted strong `ETag` (`"3"`) into its numeric revision, or
50
- * `undefined` when the header is absent or non-numeric (no such revision yet).
55
+ * The quoted string as a whole is opaque -- it also carries a per-record
56
+ * generation marker ahead of the version, minted once and kept for the
57
+ * record's life, so this is one-way: there is no `formatEtag` to build a
58
+ * validator back out of a bare revision number. Always echo the `etag` a read
59
+ * or write returned back verbatim for `ifMatch`/`ifNoneMatch`; this helper
60
+ * only reads the revision out of it for comparison or display.
51
61
  *
52
62
  * @param etag {string | null | undefined}
53
63
  * @returns {number | undefined}
@@ -1 +1 @@
1
- {"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../src/sync/port.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EACL,gBAAgB,EAGjB,MAAM,4BAA4B,CAAA;AAQnC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAAqB,WAAW,EAAE,MAAM,YAAY,CAAA;AAEhE;;;;;GAKG;AACH,OAAO,EAAE,gBAAgB,EAAE,CAAA;AA4D3B;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAM7E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,OAAO,EACP,YAAY,EACZ,UAAU,EACV,aAAqB,EACtB,EAAE;IACD,GAAG,EAAE,SAAS,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,GAAG,WAAW,CAsMd"}
1
+ {"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../src/sync/port.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EACL,gBAAgB,EAGjB,MAAM,4BAA4B,CAAA;AAWnC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAAqB,WAAW,EAAY,MAAM,YAAY,CAAA;AAE1E;;;;;GAKG;AACH,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAwG3B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAW7E;AAwBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,OAAO,EACP,YAAY,EACZ,UAAU,EACV,aAAqB,EACtB,EAAE;IACD,GAAG,EAAE,SAAS,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,GAAG,WAAW,CAiNd"}
package/dist/sync/port.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { KEY_EPOCH_HEADER, readEtag, writeHeaders } from '../internal/conditional.js';
2
2
  import { resourceMeta, resourcePath } from '../internal/paths.js';
3
- import { httpStatus, WasSyncAuthError, WasSyncConflictError, WasSyncNotFoundError } from '../errors.js';
3
+ import { mapError, NotFoundError, PreconditionFailedError, WasSyncAuthError, WasSyncConflictError, WasSyncNotFoundError } from '../errors.js';
4
4
  /**
5
5
  * The request header the server reads a content write's key-epoch id from,
6
6
  * stamping it onto the Resource's metadata. Defined next to the header
@@ -28,49 +28,87 @@ function isAuthStatus(status) {
28
28
  return status === 401 || status === 403 || status === 404;
29
29
  }
30
30
  /**
31
- * Maps a raw write error onto the port's typed signals, rethrowing anything
32
- * else unchanged: `412` becomes a {@link WasSyncConflictError} for every write.
33
- * `notFound` opts in to the `404` mapping, which only `deleteContent` performs
34
- * (an already-gone target is a settled outcome for a delete, but a hard error
35
- * for a content or metadata write). `authErrors` is the port's `mapAuthErrors`
36
- * option: it maps `401` / `403` / the masked `404` to a
37
- * {@link WasSyncAuthError}. `notFound` is checked first, so a port that asked
38
- * for both still gets the delete-specific signal.
31
+ * Carries a mapped error's `problem+json` fields onto the port signal built
32
+ * from it. The `cause` is the raw transport error `mapError` recorded, or the
33
+ * mapped error itself when there was none. A port signal is a narrowing of the
34
+ * classification `mapError` already made, so it must not lose what the server
35
+ * said.
36
+ *
37
+ * @param mapped {WasError} the classified error
38
+ * @returns {WasErrorOptions}
39
+ */
40
+ function signalOptions(mapped) {
41
+ return {
42
+ status: mapped.status,
43
+ type: mapped.type,
44
+ title: mapped.title,
45
+ details: mapped.details,
46
+ requestUrl: mapped.requestUrl,
47
+ cause: mapped.cause ?? mapped
48
+ };
49
+ }
50
+ /**
51
+ * Whether a mapped error is already one of the port's own signals, which a
52
+ * nested port call (the write-ack re-read inside a write) can raise through a
53
+ * write's catch block. Re-wrapping one would drop its cause for no gain.
54
+ *
55
+ * @param mapped {WasError}
56
+ * @returns {boolean}
57
+ */
58
+ function isPortSignal(mapped) {
59
+ return (mapped instanceof WasSyncConflictError ||
60
+ mapped instanceof WasSyncNotFoundError ||
61
+ mapped instanceof WasSyncAuthError);
62
+ }
63
+ /**
64
+ * Maps a caught write error onto the port's typed signals, rethrowing anything
65
+ * else as the classified {@link WasError} the client's own `mapError` builds
66
+ * (so a status outside this list -- a `500`, a `507` quota-exceeded -- still
67
+ * leaves the sync subpath typed and carrying the server's problem details).
68
+ * A rejected precondition becomes a {@link WasSyncConflictError} for every
69
+ * write. `notFound` opts in to the not-found mapping, which only
70
+ * `deleteContent` performs (an already-gone target is a settled outcome for a
71
+ * delete, but a hard error for a content or metadata write). `authErrors` is
72
+ * the port's `mapAuthErrors` option: it maps `401` / `403` / the masked `404`
73
+ * to a {@link WasSyncAuthError}. `notFound` is checked first, so a port that
74
+ * asked for both still gets the delete-specific signal.
39
75
  *
40
76
  * @param err {unknown} the caught error
41
77
  * @param [options] {object}
42
- * @param [options.notFound] {boolean} map `404` to {@link WasSyncNotFoundError}
78
+ * @param [options.notFound] {boolean} map a not-found to
79
+ * {@link WasSyncNotFoundError}
43
80
  * @param [options.authErrors] {boolean} map `401`/`403`/`404` to
44
81
  * {@link WasSyncAuthError}
45
82
  * @returns {never} always throws
46
83
  */
47
84
  function mapWriteError(err, { notFound = false, authErrors = false } = {}) {
48
- const status = httpStatus(err);
49
- if (notFound && status === 404) {
50
- throw new WasSyncNotFoundError();
85
+ const mapped = mapError(err);
86
+ if (isPortSignal(mapped)) {
87
+ throw mapped;
88
+ }
89
+ if (notFound && mapped instanceof NotFoundError) {
90
+ throw new WasSyncNotFoundError(mapped.message, signalOptions(mapped));
51
91
  }
52
- if (status === 412) {
53
- throw new WasSyncConflictError();
92
+ if (mapped instanceof PreconditionFailedError) {
93
+ throw new WasSyncConflictError(mapped.message, signalOptions(mapped));
54
94
  }
55
- if (authErrors && isAuthStatus(status)) {
56
- throw new WasSyncAuthError(status);
95
+ if (authErrors && isAuthStatus(mapped.status)) {
96
+ throw new WasSyncAuthError(mapped.status, signalOptions(mapped));
57
97
  }
58
- throw err;
98
+ throw mapped;
59
99
  }
60
100
  /**
61
- * Formats a numeric content `version` as the quoted strong `ETag` an
62
- * update-if-unchanged write passes as its `ifMatch` precondition (e.g. `3` to
63
- * `"3"`). Inverse of {@link parseEtag}.
101
+ * Parses a quoted strong `ETag` into its numeric revision: the decimal
102
+ * integer after the LAST `.` inside the quotes (`"3mJr7AoUXx2.3"` to `3`).
103
+ * Returns `undefined` when the header is absent, has no `.`, or the trailing
104
+ * segment is anything other than a run of digits.
64
105
  *
65
- * @param version {number}
66
- * @returns {string}
67
- */
68
- export function formatEtag(version) {
69
- return `"${version}"`;
70
- }
71
- /**
72
- * Parses a quoted strong `ETag` (`"3"`) into its numeric revision, or
73
- * `undefined` when the header is absent or non-numeric (no such revision yet).
106
+ * The quoted string as a whole is opaque -- it also carries a per-record
107
+ * generation marker ahead of the version, minted once and kept for the
108
+ * record's life, so this is one-way: there is no `formatEtag` to build a
109
+ * validator back out of a bare revision number. Always echo the `etag` a read
110
+ * or write returned back verbatim for `ifMatch`/`ifNoneMatch`; this helper
111
+ * only reads the revision out of it for comparison or display.
74
112
  *
75
113
  * @param etag {string | null | undefined}
76
114
  * @returns {number | undefined}
@@ -79,8 +117,31 @@ export function parseEtag(etag) {
79
117
  if (!etag) {
80
118
  return undefined;
81
119
  }
82
- const revision = Number(etag.replace(/"/g, ''));
83
- return Number.isFinite(revision) ? revision : undefined;
120
+ const unquoted = etag.replace(/"/g, '');
121
+ const lastDot = unquoted.lastIndexOf('.');
122
+ if (lastDot === -1) {
123
+ return undefined;
124
+ }
125
+ const versionPart = unquoted.slice(lastDot + 1);
126
+ return /^\d+$/.test(versionPart) ? Number(versionPart) : undefined;
127
+ }
128
+ /**
129
+ * Reads a response's `ETag` together with the revision parsed out of it, the
130
+ * one place the two are paired. `etag` is absent when the response carried no
131
+ * validator (a backend that does not version the resource); `version` is
132
+ * absent whenever `etag` is, and also when the validator does not end in a
133
+ * revision number. Callers decide what an absent value means for them.
134
+ *
135
+ * @param response {HttpResponse}
136
+ * @returns {{ etag?: string, version?: number }}
137
+ */
138
+ function versionedEtag(response) {
139
+ const etag = readEtag(response);
140
+ const version = parseEtag(etag);
141
+ return {
142
+ ...(etag !== undefined && { etag }),
143
+ ...(version !== undefined && { version })
144
+ };
84
145
  }
85
146
  /**
86
147
  * Builds a {@link WasSyncPort} bound to one Space + Collection, backed by the
@@ -136,31 +197,36 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
136
197
  });
137
198
  }
138
199
  catch (err) {
139
- const status = httpStatus(err);
200
+ const mapped = mapError(err);
140
201
  // A read's `404` stays "absent or tombstoned" even under
141
202
  // `mapAuthErrors`: it is a modeled outcome here, and the callers read it
142
203
  // as deletion-wins.
143
- if (status === 404) {
204
+ if (mapped instanceof NotFoundError) {
144
205
  return null;
145
206
  }
146
- if (mapAuthErrors && isAuthStatus(status)) {
147
- throw new WasSyncAuthError(status);
207
+ if (mapAuthErrors && isAuthStatus(mapped.status)) {
208
+ throw new WasSyncAuthError(mapped.status, signalOptions(mapped));
148
209
  }
149
- throw err;
210
+ throw mapped;
150
211
  }
212
+ const { etag, version } = versionedEtag(response);
151
213
  return {
152
- version: parseEtag(readEtag(response)) ?? 0,
214
+ version: version ?? 0,
215
+ etag,
153
216
  updatedAt: UNKNOWN_UPDATED_AT,
154
217
  data: response.data
155
218
  };
156
219
  };
157
- /** Resolves the acked version from a write response, or via a content re-read. */
158
- const ackedVersion = async (response, id) => {
159
- const version = parseEtag(readEtag(response));
160
- if (version !== undefined) {
161
- return version;
162
- }
163
- return (await readContent(id))?.version ?? 0;
220
+ /**
221
+ * The acked {@link WriteAck} of a write response. Taken from the response's
222
+ * own `ETag` only: a re-read after the fact could return a concurrent
223
+ * writer's validator as this write's ack. A response with no `ETag` acks
224
+ * `version: 0` and no `etag`, the shape of a backend that does not version
225
+ * resources.
226
+ */
227
+ const writeAck = (response) => {
228
+ const { etag, version } = versionedEtag(response);
229
+ return { version: version ?? 0, etag };
164
230
  };
165
231
  return {
166
232
  async query({ checkpoint, limit }) {
@@ -171,11 +237,11 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
171
237
  // The pull path is where revoked access surfaces reliably: unlike a
172
238
  // read or a delete, a `404` on the collection's own query endpoint has
173
239
  // no benign reading once the collection is known to exist.
174
- const status = httpStatus(err);
175
- if (mapAuthErrors && isAuthStatus(status)) {
176
- throw new WasSyncAuthError(status);
240
+ const mapped = mapError(err);
241
+ if (mapAuthErrors && isAuthStatus(mapped.status)) {
242
+ throw new WasSyncAuthError(mapped.status, signalOptions(mapped));
177
243
  }
178
- throw err;
244
+ throw mapped;
179
245
  }
180
246
  },
181
247
  async putContent({ id, data, ifMatch, ifNoneMatch, epoch }) {
@@ -190,7 +256,7 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
190
256
  epoch
191
257
  })
192
258
  });
193
- return await ackedVersion(response, id);
259
+ return writeAck(response);
194
260
  }
195
261
  catch (err) {
196
262
  mapWriteError(err, { authErrors: mapAuthErrors });
@@ -204,7 +270,7 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
204
270
  method: 'DELETE',
205
271
  headers: writeHeaders({ precondition: { ifMatch } })
206
272
  });
207
- return await ackedVersion(response, id);
273
+ return writeAck(response);
208
274
  }
209
275
  catch (err) {
210
276
  // Under `mapAuthErrors` a delete's `404` is an idempotent success: the
@@ -213,10 +279,11 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
213
279
  // holds and the batch must not be retried forever. A masked
214
280
  // authorization `404` is swallowed with it -- indistinguishable by
215
281
  // design -- but revoked access still surfaces on the next `query`.
216
- if (mapAuthErrors && httpStatus(err) === 404) {
282
+ const mapped = mapError(err);
283
+ if (mapAuthErrors && mapped instanceof NotFoundError) {
217
284
  return undefined;
218
285
  }
219
- mapWriteError(err, {
286
+ mapWriteError(mapped, {
220
287
  notFound: !mapAuthErrors,
221
288
  authErrors: mapAuthErrors
222
289
  });
@@ -236,7 +303,8 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
236
303
  json: custom === undefined ? {} : { custom },
237
304
  headers: writeHeaders({ precondition: { ifMatch, ifNoneMatch } })
238
305
  });
239
- return parseEtag(readEtag(response));
306
+ const { etag, version } = versionedEtag(response);
307
+ return etag !== undefined ? { version: version ?? 0, etag } : undefined;
240
308
  }
241
309
  catch (err) {
242
310
  mapWriteError(err, { authErrors: mapAuthErrors });
@@ -256,21 +324,21 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
256
324
  }
257
325
  // Metadata (best-effort): the `/meta` body carries the server-managed
258
326
  // `updatedAt`, the creator DID, the key-epoch id, and the user-writable
259
- // `custom`, plus its own `metaVersion` ETag. A resource with no metadata
260
- // yet 404s here; only a hard error propagates.
327
+ // `custom`, plus its own `metaVersion`/`metaEtag` ETag. A resource with
328
+ // no metadata yet 404s here; only a hard error propagates.
261
329
  const meta = await metaRead;
262
330
  if (!meta.ok) {
263
- const status = httpStatus(meta.err);
331
+ const mapped = mapError(meta.err);
264
332
  // A `/meta` `404` is routine (the resource has no metadata document
265
333
  // yet), so it stays benign under `mapAuthErrors` -- only `401`/`403`
266
334
  // map there.
267
- if (status === 404) {
335
+ if (mapped instanceof NotFoundError) {
268
336
  return master;
269
337
  }
270
- if (mapAuthErrors && isAuthStatus(status)) {
271
- throw new WasSyncAuthError(status);
338
+ if (mapAuthErrors && isAuthStatus(mapped.status)) {
339
+ throw new WasSyncAuthError(mapped.status, signalOptions(mapped));
272
340
  }
273
- throw meta.err;
341
+ throw mapped;
274
342
  }
275
343
  const metaBody = meta.response.data;
276
344
  if (metaBody?.updatedAt) {
@@ -285,7 +353,12 @@ export function createWasSyncPort({ was, spaceId, collectionId, capability, mapA
285
353
  if (metaBody?.custom !== undefined) {
286
354
  master.custom = metaBody.custom;
287
355
  }
288
- const metaVersion = parseEtag(readEtag(meta.response));
356
+ // The validator is kept whenever the server sent one, so a later
357
+ // `putMeta` can pin on it even when no revision number parses out of it.
358
+ const { etag: metaEtag, version: metaVersion } = versionedEtag(meta.response);
359
+ if (metaEtag !== undefined) {
360
+ master.metaEtag = metaEtag;
361
+ }
289
362
  if (metaVersion !== undefined) {
290
363
  master.metaVersion = metaVersion;
291
364
  }
@@ -1 +1 @@
1
- {"version":3,"file":"port.js","sourceRoot":"","sources":["../../src/sync/port.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"port.js","sourceRoot":"","sources":["../../src/sync/port.ts"],"names":[],"mappings":"AAuCA,OAAO,EACL,gBAAgB,EAChB,QAAQ,EACR,YAAY,EACb,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACjE,OAAO,EACL,QAAQ,EACR,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,cAAc,CAAA;AAKrB;;;;;GAKG;AACH,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAE3B;;;;;;GAMG;AACH,MAAM,kBAAkB,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;AAEpD;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,MAA0B;IAC9C,OAAO,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,CAAA;AAC3D,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,aAAa,CAAC,MAAgB;IACrC,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,MAAM;KAC9B,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,MAAgB;IACpC,OAAO,CACL,MAAM,YAAY,oBAAoB;QACtC,MAAM,YAAY,oBAAoB;QACtC,MAAM,YAAY,gBAAgB,CACnC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAS,aAAa,CACpB,GAAY,EACZ,EACE,QAAQ,GAAG,KAAK,EAChB,UAAU,GAAG,KAAK,KAC8B,EAAE;IAEpD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC5B,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,MAAM,MAAM,CAAA;IACd,CAAC;IACD,IAAI,QAAQ,IAAI,MAAM,YAAY,aAAa,EAAE,CAAC;QAChD,MAAM,IAAI,oBAAoB,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;IACvE,CAAC;IACD,IAAI,MAAM,YAAY,uBAAuB,EAAE,CAAC;QAC9C,MAAM,IAAI,oBAAoB,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;IACvE,CAAC;IACD,IAAI,UAAU,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;IAClE,CAAC;IACD,MAAM,MAAM,CAAA;AACd,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,SAAS,CAAC,IAA+B;IACvD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACzC,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;QACnB,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAA;IAC/C,OAAO,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AACpE,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,aAAa,CAAC,QAAsB;IAI3C,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAC/B,OAAO;QACL,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,CAAC;QACnC,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,CAAC;KAC1C,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,GAAG,EACH,OAAO,EACP,YAAY,EACZ,UAAU,EACV,aAAa,GAAG,KAAK,EAOtB;IACC,wEAAwE;IACxE,sEAAsE;IACtE,MAAM,WAAW,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,CAAA;IAC3E,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,CAAA;IAExE,0EAA0E;IAC1E,sEAAsE;IACtE,uDAAuD;IACvD,MAAM,iBAAiB,GAAG,GAAG;SAC1B,KAAK,CAAC,OAAO,CAAC;SACd,UAAU,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;IAE3C,iFAAiF;IACjF,MAAM,WAAW,GAAG,KAAK,EAAE,EAAU,EAA+B,EAAE;QACpE,IAAI,QAAsB,CAAA;QAC1B,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;gBAC3B,UAAU;gBACV,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;gBACrB,MAAM,EAAE,KAAK;aACd,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;YAC5B,yDAAyD;YACzD,yEAAyE;YACzE,oBAAoB;YACpB,IAAI,MAAM,YAAY,aAAa,EAAE,CAAC;gBACpC,OAAO,IAAI,CAAA;YACb,CAAC;YACD,IAAI,aAAa,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBACjD,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;YAClE,CAAC;YACD,MAAM,MAAM,CAAA;QACd,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QACjD,OAAO;YACL,OAAO,EAAE,OAAO,IAAI,CAAC;YACrB,IAAI;YACJ,SAAS,EAAE,kBAAkB;YAC7B,IAAI,EAAE,QAAQ,CAAC,IAAY;SAC5B,CAAA;IACH,CAAC,CAAA;IAED;;;;;;OAMG;IACH,MAAM,QAAQ,GAAG,CAAC,QAAsB,EAAY,EAAE;QACpD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QACjD,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,CAAC,EAAE,IAAI,EAAE,CAAA;IACxC,CAAC,CAAA;IAED,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE;YAC/B,IAAI,CAAC;gBACH,OAAO,MAAM,iBAAiB,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAA;YAC/D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,oEAAoE;gBACpE,uEAAuE;gBACvE,2DAA2D;gBAC3D,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;gBAC5B,IAAI,aAAa,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;oBACjD,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;gBAClE,CAAC;gBACD,MAAM,MAAM,CAAA;YACd,CAAC;QACH,CAAC;QAED,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE;YACxD,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;oBACjC,UAAU;oBACV,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;oBACrB,MAAM,EAAE,KAAK;oBACb,IAAI,EAAE,IAAc;oBACpB,OAAO,EAAE,YAAY,CAAC;wBACpB,YAAY,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE;wBACtC,KAAK;qBACN,CAAC;iBACH,CAAC,CAAA;gBACF,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAC3B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,aAAa,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAA;YACnD,CAAC;QACH,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE;YACjC,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;oBACjC,UAAU;oBACV,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;oBACrB,MAAM,EAAE,QAAQ;oBAChB,OAAO,EAAE,YAAY,CAAC,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC;iBACrD,CAAC,CAAA;gBACF,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAC3B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,uEAAuE;gBACvE,uEAAuE;gBACvE,sEAAsE;gBACtE,4DAA4D;gBAC5D,mEAAmE;gBACnE,mEAAmE;gBACnE,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;gBAC5B,IAAI,aAAa,IAAI,MAAM,YAAY,aAAa,EAAE,CAAC;oBACrD,OAAO,SAAS,CAAA;gBAClB,CAAC;gBACD,aAAa,CAAC,MAAM,EAAE;oBACpB,QAAQ,EAAE,CAAC,aAAa;oBACxB,UAAU,EAAE,aAAa;iBAC1B,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE;YAChD,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;oBACjC,UAAU;oBACV,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;oBAClB,MAAM,EAAE,KAAK;oBACb,qEAAqE;oBACrE,+DAA+D;oBAC/D,+DAA+D;oBAC/D,oEAAoE;oBACpE,4DAA4D;oBAC5D,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE;oBAC5C,OAAO,EAAE,YAAY,CAAC,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,CAAC;iBAClE,CAAC,CAAA;gBACF,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;gBACjD,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;YACzE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,aAAa,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAA;YACnD,CAAC;QACH,CAAC;QAED,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE;YACd,wEAAwE;YACxE,0EAA0E;YAC1E,0EAA0E;YAC1E,4CAA4C;YAC5C,MAAM,QAAQ,GAAG,GAAG;iBACjB,OAAO,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;iBAC1D,IAAI,CACH,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAa,EAAE,QAAQ,EAAE,CAAC,EAC7C,CAAC,GAAY,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAc,EAAE,GAAG,EAAE,CAAC,CAChD,CAAA;YAEH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,CAAC,CAAA;YACpC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,OAAO,IAAI,CAAA,CAAC,uDAAuD;YACrE,CAAC;YAED,sEAAsE;YACtE,wEAAwE;YACxE,wEAAwE;YACxE,2DAA2D;YAC3D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAA;YAC3B,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBACjC,oEAAoE;gBACpE,qEAAqE;gBACrE,aAAa;gBACb,IAAI,MAAM,YAAY,aAAa,EAAE,CAAC;oBACpC,OAAO,MAAM,CAAA;gBACf,CAAC;gBACD,IAAI,aAAa,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;oBACjD,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;gBAClE,CAAC;gBACD,MAAM,MAAM,CAAA;YACd,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAOlB,CAAA;YACb,IAAI,QAAQ,EAAE,SAAS,EAAE,CAAC;gBACxB,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAA;YACvC,CAAC;YACD,IAAI,QAAQ,EAAE,SAAS,KAAK,SAAS,EAAE,CAAC;gBACtC,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAA;YACvC,CAAC;YACD,IAAI,QAAQ,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;gBAClC,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAA;YAC/B,CAAC;YACD,IAAI,QAAQ,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;gBACnC,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAA;YACjC,CAAC;YACD,iEAAiE;YACjE,yEAAyE;YACzE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,aAAa,CAC5D,IAAI,CAAC,QAAQ,CACd,CAAA;YACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAA;YAC5B,CAAC;YACD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,MAAM,CAAC,WAAW,GAAG,WAAW,CAAA;YAClC,CAAC;YAED,OAAO,MAAM,CAAA;QACf,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,67 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The `err.name` predicates that classify the errors a replication path can
6
+ * meet: the port's two wire signals (`WasSyncConflictError` /
7
+ * `WasSyncNotFoundError`), its opt-in revoked-access signal
8
+ * (`WasSyncAuthError`), and the cipher's stale-descriptor signal
9
+ * (`UnknownEpochError`).
10
+ *
11
+ * They live beside the classes that assign the names they match (`errors.ts`)
12
+ * because every one of those errors is raised inside a seam the consuming app
13
+ * injects -- the port for the wire signals, the caller's `DocCipher` for the
14
+ * unknown epoch -- and that seam can resolve to a SECOND copy of this package
15
+ * (a `link:` dev setup, a dedupe miss through a dependency tree). So the match
16
+ * is on the `name` string alone and never `instanceof`, which cannot see across
17
+ * that boundary. The cost of a miss is silent and expensive: every push 412
18
+ * becomes a fatal cycle error, and a create-loss re-mint rethrows instead of
19
+ * re-minting. Each class assigns its `name` explicitly, which is what makes the
20
+ * string a contract (`decisions/0001-cross-package-errors-match-by-name.md`).
21
+ *
22
+ * Each returns a plain boolean rather than a type guard: the guard would narrow
23
+ * to this copy's class, the very identity the rule declines to depend on. A
24
+ * caller reading a property after the match (`err.status` on an auth error)
25
+ * reads it off the value itself.
26
+ */
27
+ /**
28
+ * Whether an error is the replication port's rejected-conditional-write signal
29
+ * (`WasSyncConflictError`, HTTP 412): a lost-update `If-Match` mismatch, or a
30
+ * create-if-absent whose target already exists. The push loop's one settle-and-
31
+ * reconcile branch; everything else propagates to the engine's backoff.
32
+ *
33
+ * @param err {unknown}
34
+ * @returns {boolean}
35
+ */
36
+ export declare function isSyncConflictError(err: unknown): boolean;
37
+ /**
38
+ * Whether an error is the replication port's absent-target signal
39
+ * (`WasSyncNotFoundError`, HTTP 404). On a delete that is a settled outcome
40
+ * -- already gone, or the write never reached the server -- not a conflict.
41
+ *
42
+ * @param err {unknown}
43
+ * @returns {boolean}
44
+ */
45
+ export declare function isSyncNotFoundError(err: unknown): boolean;
46
+ /**
47
+ * Whether an error is the replication port's refused-authorization signal
48
+ * (`WasSyncAuthError`), raised only by a port built with `mapAuthErrors`. It
49
+ * covers `401`, `403`, and the `404` a WAS server returns when it masks an
50
+ * authorization failure as "not found", so a caller that needs the three apart
51
+ * reads `status` off the matched value as a plain property.
52
+ *
53
+ * @param err {unknown}
54
+ * @returns {boolean}
55
+ */
56
+ export declare function isSyncAuthError(err: unknown): boolean;
57
+ /**
58
+ * Whether an error is the cipher's unknown-epoch signal (`UnknownEpochError`):
59
+ * an envelope naming recipient key ids whose epoch the descriptor this reader
60
+ * holds does not list at all. Distinct from a key the reader simply does not
61
+ * have (`KeyUnwrapError`), which re-reading the descriptor cannot fix.
62
+ *
63
+ * @param err {unknown}
64
+ * @returns {boolean}
65
+ */
66
+ export declare function isUnknownEpochError(err: unknown): boolean;
67
+ //# sourceMappingURL=predicates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predicates.d.ts","sourceRoot":"","sources":["../../src/sync/predicates.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAaH;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAErD;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEzD"}
@@ -0,0 +1,85 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The `err.name` predicates that classify the errors a replication path can
6
+ * meet: the port's two wire signals (`WasSyncConflictError` /
7
+ * `WasSyncNotFoundError`), its opt-in revoked-access signal
8
+ * (`WasSyncAuthError`), and the cipher's stale-descriptor signal
9
+ * (`UnknownEpochError`).
10
+ *
11
+ * They live beside the classes that assign the names they match (`errors.ts`)
12
+ * because every one of those errors is raised inside a seam the consuming app
13
+ * injects -- the port for the wire signals, the caller's `DocCipher` for the
14
+ * unknown epoch -- and that seam can resolve to a SECOND copy of this package
15
+ * (a `link:` dev setup, a dedupe miss through a dependency tree). So the match
16
+ * is on the `name` string alone and never `instanceof`, which cannot see across
17
+ * that boundary. The cost of a miss is silent and expensive: every push 412
18
+ * becomes a fatal cycle error, and a create-loss re-mint rethrows instead of
19
+ * re-minting. Each class assigns its `name` explicitly, which is what makes the
20
+ * string a contract (`decisions/0001-cross-package-errors-match-by-name.md`).
21
+ *
22
+ * Each returns a plain boolean rather than a type guard: the guard would narrow
23
+ * to this copy's class, the very identity the rule declines to depend on. A
24
+ * caller reading a property after the match (`err.status` on an auth error)
25
+ * reads it off the value itself.
26
+ */
27
+ /**
28
+ * Reads the `name` off an unknown caught value, without raising on a nullish
29
+ * or non-object rejection.
30
+ *
31
+ * @param err {unknown} the caught error
32
+ * @returns {unknown}
33
+ */
34
+ function nameOf(err) {
35
+ return err?.name;
36
+ }
37
+ /**
38
+ * Whether an error is the replication port's rejected-conditional-write signal
39
+ * (`WasSyncConflictError`, HTTP 412): a lost-update `If-Match` mismatch, or a
40
+ * create-if-absent whose target already exists. The push loop's one settle-and-
41
+ * reconcile branch; everything else propagates to the engine's backoff.
42
+ *
43
+ * @param err {unknown}
44
+ * @returns {boolean}
45
+ */
46
+ export function isSyncConflictError(err) {
47
+ return nameOf(err) === 'WasSyncConflictError';
48
+ }
49
+ /**
50
+ * Whether an error is the replication port's absent-target signal
51
+ * (`WasSyncNotFoundError`, HTTP 404). On a delete that is a settled outcome
52
+ * -- already gone, or the write never reached the server -- not a conflict.
53
+ *
54
+ * @param err {unknown}
55
+ * @returns {boolean}
56
+ */
57
+ export function isSyncNotFoundError(err) {
58
+ return nameOf(err) === 'WasSyncNotFoundError';
59
+ }
60
+ /**
61
+ * Whether an error is the replication port's refused-authorization signal
62
+ * (`WasSyncAuthError`), raised only by a port built with `mapAuthErrors`. It
63
+ * covers `401`, `403`, and the `404` a WAS server returns when it masks an
64
+ * authorization failure as "not found", so a caller that needs the three apart
65
+ * reads `status` off the matched value as a plain property.
66
+ *
67
+ * @param err {unknown}
68
+ * @returns {boolean}
69
+ */
70
+ export function isSyncAuthError(err) {
71
+ return nameOf(err) === 'WasSyncAuthError';
72
+ }
73
+ /**
74
+ * Whether an error is the cipher's unknown-epoch signal (`UnknownEpochError`):
75
+ * an envelope naming recipient key ids whose epoch the descriptor this reader
76
+ * holds does not list at all. Distinct from a key the reader simply does not
77
+ * have (`KeyUnwrapError`), which re-reading the descriptor cannot fix.
78
+ *
79
+ * @param err {unknown}
80
+ * @returns {boolean}
81
+ */
82
+ export function isUnknownEpochError(err) {
83
+ return nameOf(err) === 'UnknownEpochError';
84
+ }
85
+ //# sourceMappingURL=predicates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predicates.js","sourceRoot":"","sources":["../../src/sync/predicates.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;GAMG;AACH,SAAS,MAAM,CAAC,GAAY;IAC1B,OAAQ,GAAiC,EAAE,IAAI,CAAA;AACjD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,sBAAsB,CAAA;AAC/C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,sBAAsB,CAAA;AAC/C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,kBAAkB,CAAA;AAC3C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,mBAAmB,CAAA;AAC5C,CAAC"}
@@ -9,7 +9,8 @@
9
9
  * here under replication-facing names so a sync consumer imports one module.
10
10
  * `WasSyncPort` and `MasterState` are the injectable access seam the change
11
11
  * engine depends on, and `DocCipher` is the encrypt/decrypt seam a per-
12
- * collection cipher implements.
12
+ * collection cipher implements. `SyncStatus` is the closed status vocabulary
13
+ * every replication driver reports one feed's state through.
13
14
  */
14
15
  import type { ChangeDocument, ChangesCheckpoint, ChangesPage } from '@interop/storage-core';
15
16
  import type { Json } from '../types.js';
@@ -24,12 +25,17 @@ export type { Json };
24
25
  export type SyncCheckpoint = ChangesCheckpoint;
25
26
  /**
26
27
  * One document as it travels on the `changes` feed wire: `id` is the WAS
27
- * resource id, `version` the content revision (the push `If-Match` ETag), and
28
- * the stored body is under `data`. A tombstone carries `_deleted: true` with no
29
- * `data`. This is the shared `ChangeDocument` from `@interop/storage-core`; on
30
- * an encrypted collection `data`/`custom` are the opaque stored envelope, moved
31
- * verbatim (decrypt is a projection-time concern the engine's `DocCipher`
32
- * handles, never the port).
28
+ * resource id, `version` its monotonic content revision number, and the
29
+ * stored body is under `data`. `version` is for comparison/ordering only and
30
+ * is not an `ifMatch` value on its own; the server's `ETag` is an opaque
31
+ * string that embeds more than the version. The feed carries the validators
32
+ * themselves: `etag` (content) and `metaEtag` (the `/meta` object), quoted
33
+ * exactly as the server emits them, so a puller passes one back verbatim as a
34
+ * conditional write's `ifMatch` without a {@link WasSyncPort.get} first. A
35
+ * tombstone carries `_deleted: true` with no `data`. This is the shared
36
+ * `ChangeDocument` from `@interop/storage-core`; on an encrypted collection
37
+ * `data`/`custom` are the opaque stored envelope, moved verbatim (decrypt is a
38
+ * projection-time concern the engine's `DocCipher` handles, never the port).
33
39
  */
34
40
  export type WireDoc = ChangeDocument;
35
41
  /**
@@ -42,20 +48,41 @@ export type SyncPage = ChangesPage;
42
48
  * The current master state of a single resource, read back for the 412-conflict
43
49
  * path ({@link WasSyncPort.get}). An absent or tombstoned resource surfaces as
44
50
  * `get` resolving `null`, never as a `MasterState`. `updatedAt`, `metaVersion`,
45
- * `custom`, `createdBy`, and `epoch` are populated from the resource's `/meta`
46
- * document when it exists; a resource with no metadata yet reports an
47
- * epoch-zero `updatedAt` placeholder (a valid, sortable timestamp -- the
48
- * change feed remains the authority on ordering).
51
+ * `metaEtag`, `custom`, `createdBy`, and `epoch` are populated from the
52
+ * resource's `/meta` document when it exists; a resource with no metadata yet
53
+ * reports an epoch-zero `updatedAt` placeholder (a valid, sortable timestamp --
54
+ * the change feed remains the authority on ordering).
55
+ *
56
+ * `etag` and `metaEtag` are the raw, opaque `ETag` validators the content and
57
+ * `/meta` reads returned (absent against a backend that does not version
58
+ * resources) -- pass one back verbatim as a later write's `ifMatch`. `version`
59
+ * and `metaVersion` are the revision numbers parsed out of them, for
60
+ * comparison or display only.
49
61
  */
50
62
  export interface MasterState {
51
63
  version: number;
64
+ etag?: string;
52
65
  updatedAt: string;
53
66
  metaVersion?: number;
67
+ metaEtag?: string;
54
68
  data?: Json;
55
69
  custom?: Json;
56
70
  createdBy?: string;
57
71
  epoch?: string;
58
72
  }
73
+ /**
74
+ * The acknowledgment a conditional write returns: the new `version` plus the
75
+ * opaque `etag` validator it lives behind, exactly as the server sent it.
76
+ * Pass `etag` back verbatim as a later write's `ifMatch` -- it can no longer
77
+ * be synthesized from `version` alone, since the server's `ETag` also embeds a
78
+ * per-record generation marker ahead of the version. `etag` is absent against
79
+ * a backend that does not version resources; read `version` only to compare
80
+ * or display a revision number.
81
+ */
82
+ export interface WriteAck {
83
+ version: number;
84
+ etag?: string;
85
+ }
59
86
  /**
60
87
  * The injected WAS-access seam. `createWasSyncPort` implements this over
61
88
  * `@interop/was-client`'s `was.request()` and the `Collection.changes()` feed;
@@ -77,10 +104,10 @@ export interface WasSyncPort {
77
104
  }): Promise<SyncPage>;
78
105
  /**
79
106
  * Conditionally writes the content body verbatim (`PUT /:id`). Pass
80
- * `ifNoneMatch: true` for create-if-absent, or `ifMatch` (a quoted ETag over
81
- * the content `version`) for update-if-unchanged. `epoch` stamps the opaque
82
- * key-epoch id the body was encrypted under (absent clears any prior stamp).
83
- * Returns the new server `version` (parsed from the write's `ETag`). Throws
107
+ * `ifNoneMatch: true` for create-if-absent, or `ifMatch` (the opaque `ETag`
108
+ * from a prior read/write, echoed back verbatim) for update-if-unchanged.
109
+ * `epoch` stamps the opaque key-epoch id the body was encrypted under
110
+ * (absent clears any prior stamp). Returns the new {@link WriteAck}. Throws
84
111
  * {@link WasSyncConflictError} on `412`.
85
112
  */
86
113
  putContent(options: {
@@ -89,13 +116,14 @@ export interface WasSyncPort {
89
116
  ifMatch?: string;
90
117
  ifNoneMatch?: boolean;
91
118
  epoch?: string;
92
- }): Promise<number>;
119
+ }): Promise<WriteAck>;
93
120
  /**
94
121
  * Conditionally deletes a resource (writes a tombstone; `DELETE /:id`). Pass
95
- * `ifMatch` (a quoted ETag over the content `version`) to delete only if
96
- * unchanged. Returns the tombstone's new server `version`. Throws
97
- * {@link WasSyncConflictError} on `412`, {@link WasSyncNotFoundError} on `404`
98
- * (already gone -- a settled outcome for a delete).
122
+ * `ifMatch` (the opaque `ETag` from a prior read/write, echoed back
123
+ * verbatim) to delete only if unchanged. Returns the tombstone's new
124
+ * {@link WriteAck}. Throws {@link WasSyncConflictError} on `412`,
125
+ * {@link WasSyncNotFoundError} on `404` (already gone -- a settled outcome
126
+ * for a delete).
99
127
  *
100
128
  * Resolves `undefined` instead when the port was built with
101
129
  * `mapAuthErrors: true` and the target was already absent: there the delete
@@ -104,22 +132,22 @@ export interface WasSyncPort {
104
132
  deleteContent(options: {
105
133
  id: string;
106
134
  ifMatch?: string;
107
- }): Promise<number | undefined>;
135
+ }): Promise<WriteAck | undefined>;
108
136
  /**
109
137
  * Conditionally writes the user-writable metadata `custom` (`PUT /:id/meta`).
110
138
  * Optional -- present only on a port that syncs metadata. The write fully
111
139
  * replaces `custom`, so omitting it writes the CLEARED state (the server
112
140
  * clears every property the body leaves out) -- that is how a metadata clear
113
- * replicates. Returns the new `metaVersion` (parsed from the write's `ETag`),
114
- * or `undefined` when the response carried none. Throws
115
- * {@link WasSyncConflictError} on `412`.
141
+ * replicates. Returns the new metadata {@link WriteAck}, or `undefined` when
142
+ * the response carried no `ETag`. Throws {@link WasSyncConflictError} on
143
+ * `412`.
116
144
  */
117
145
  putMeta?(options: {
118
146
  id: string;
119
147
  custom?: Json;
120
148
  ifMatch?: string;
121
149
  ifNoneMatch?: boolean;
122
- }): Promise<number | undefined>;
150
+ }): Promise<WriteAck | undefined>;
123
151
  /**
124
152
  * Re-reads a single resource's current master state for the 412-conflict
125
153
  * assembler. Returns `null` when the resource is genuinely absent OR a
@@ -169,4 +197,11 @@ export interface DocCipher {
169
197
  envelope: Json;
170
198
  }): Promise<Json>;
171
199
  }
200
+ /**
201
+ * Per-feed replication status, surfaced to the app's state layer. The
202
+ * vocabulary is closed: a consumer may render a status through a lookup keyed
203
+ * on the string, so a widened value would fail at runtime rather than at
204
+ * compile time.
205
+ */
206
+ export type SyncStatus = 'idle' | 'syncing' | 'synced' | 'error';
172
207
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;GASG;AACH,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,WAAW,EACZ,MAAM,uBAAuB,CAAA;AAC9B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC,YAAY,EAAE,IAAI,EAAE,CAAA;AAEpB;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,iBAAiB,CAAA;AAE9C;;;;;;;;GAQG;AACH,MAAM,MAAM,OAAO,GAAG,cAAc,CAAA;AAEpC;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAA;AAElC;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,MAAM,CAAC,EAAE,IAAI,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE;QACb,UAAU,CAAC,EAAE,cAAc,CAAA;QAC3B,KAAK,EAAE,MAAM,CAAA;KACd,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAErB;;;;;;;OAOG;IACH,UAAU,CAAC,OAAO,EAAE;QAClB,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,IAAI,CAAA;QACV,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,WAAW,CAAC,EAAE,OAAO,CAAA;QACrB,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAEnB;;;;;;;;;;OAUG;IACH,aAAa,CAAC,OAAO,EAAE;QACrB,EAAE,EAAE,MAAM,CAAA;QACV,OAAO,CAAC,EAAE,MAAM,CAAA;KACjB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAE/B;;;;;;;;OAQG;IACH,OAAO,CAAC,CAAC,OAAO,EAAE;QAChB,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,CAAC,EAAE,IAAI,CAAA;QACb,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,WAAW,CAAC,EAAE,OAAO,CAAA;KACtB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAE/B;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;CAC1D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,OAAO,EAAE;QACf,IAAI,EAAE,IAAI,CAAA;KACX,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3D,aAAa,CAAC,CAAC,OAAO,EAAE;QACtB,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,IAAI,CAAA;QACV,OAAO,EAAE,IAAI,CAAA;KACd,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3D,OAAO,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACpD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@interop/was-client",
3
3
  "description": "A developer-friendly client for Wallet Attached Storage (WAS) servers.",
4
- "version": "0.48.1",
4
+ "version": "0.50.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "pnpm run clear && tsc",
@@ -67,7 +67,7 @@
67
67
  "@interop/ezcap": "^7.4.6",
68
68
  "@interop/http-client": "^1.0.5",
69
69
  "@interop/minimal-cipher": "^7.10.0",
70
- "@interop/storage-core": "^0.10.0",
70
+ "@interop/storage-core": "^0.11.0",
71
71
  "@interop/vh-resource-log": "^0.4.1",
72
72
  "@interop/x25519-key-agreement-key": "^5.3.0",
73
73
  "@noble/hashes": "^2.3.0",