@interop/was-react 0.1.0 → 0.1.3
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 +9 -1
- package/dist/auth/chapi.d.ts +3 -1
- package/dist/auth/chapi.d.ts.map +1 -1
- package/dist/auth/chapi.js +6 -2
- package/dist/auth/chapi.js.map +1 -1
- package/dist/auth/loginFlow.d.ts +30 -10
- package/dist/auth/loginFlow.d.ts.map +1 -1
- package/dist/auth/loginFlow.js +3 -1
- package/dist/auth/loginFlow.js.map +1 -1
- package/dist/auth/loginRequest.d.ts +9 -3
- package/dist/auth/loginRequest.d.ts.map +1 -1
- package/dist/auth/loginRequest.js +9 -3
- package/dist/auth/loginRequest.js.map +1 -1
- package/dist/auth/verifyResponse.d.ts +9 -3
- package/dist/auth/verifyResponse.d.ts.map +1 -1
- package/dist/auth/verifyResponse.js +6 -2
- package/dist/auth/verifyResponse.js.map +1 -1
- package/dist/config.d.ts +60 -20
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -4
- package/dist/config.js.map +1 -1
- package/dist/dev/cli.d.ts.map +1 -1
- package/dist/dev/cli.js +4 -7
- package/dist/dev/cli.js.map +1 -1
- package/dist/dev/provisionDevGrants.d.ts +15 -5
- package/dist/dev/provisionDevGrants.d.ts.map +1 -1
- package/dist/dev/provisionDevGrants.js +2 -2
- package/dist/dev/provisionDevGrants.js.map +1 -1
- package/dist/grants.d.ts +7 -19
- package/dist/grants.d.ts.map +1 -1
- package/dist/grants.js +28 -7
- package/dist/grants.js.map +1 -1
- package/dist/identity/appSession.d.ts +9 -3
- package/dist/identity/appSession.d.ts.map +1 -1
- package/dist/identity/appSession.js +3 -1
- package/dist/identity/appSession.js.map +1 -1
- package/dist/identity/documentLoader.d.ts +3 -1
- package/dist/identity/documentLoader.d.ts.map +1 -1
- package/dist/identity/documentLoader.js +6 -2
- package/dist/identity/documentLoader.js.map +1 -1
- package/dist/identity/seedCredential.d.ts +9 -3
- package/dist/identity/seedCredential.d.ts.map +1 -1
- package/dist/identity/seedCredential.js +9 -15
- package/dist/identity/seedCredential.js.map +1 -1
- package/dist/identity/seedStore.d.ts +18 -6
- package/dist/identity/seedStore.d.ts.map +1 -1
- package/dist/identity/seedStore.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react/WasSessionProvider.d.ts.map +1 -1
- package/dist/react/WasSessionProvider.js +10 -1
- package/dist/react/WasSessionProvider.js.map +1 -1
- package/dist/react/hooks.d.ts +10 -5
- package/dist/react/hooks.d.ts.map +1 -1
- package/dist/react/hooks.js +6 -30
- package/dist/react/hooks.js.map +1 -1
- package/dist/session/authStore.d.ts +29 -7
- package/dist/session/authStore.d.ts.map +1 -1
- package/dist/session/authStore.js +123 -63
- package/dist/session/authStore.js.map +1 -1
- package/dist/storage/entityStore.d.ts +32 -9
- package/dist/storage/entityStore.d.ts.map +1 -1
- package/dist/storage/entityStore.js +88 -48
- package/dist/storage/entityStore.js.map +1 -1
- package/dist/storage/localStore.d.ts +13 -0
- package/dist/storage/localStore.d.ts.map +1 -1
- package/dist/storage/localStore.js +17 -0
- package/dist/storage/localStore.js.map +1 -1
- package/dist/storage/rehydrate.d.ts.map +1 -1
- package/dist/storage/rehydrate.js +3 -1
- package/dist/storage/rehydrate.js.map +1 -1
- package/dist/storage/syncController.d.ts +7 -3
- package/dist/storage/syncController.d.ts.map +1 -1
- package/dist/storage/syncController.js +28 -15
- package/dist/storage/syncController.js.map +1 -1
- package/dist/storage/syncStatusStore.d.ts +26 -1
- package/dist/storage/syncStatusStore.d.ts.map +1 -1
- package/dist/storage/syncStatusStore.js +40 -0
- package/dist/storage/syncStatusStore.js.map +1 -1
- package/dist/storage/wasRemoteStore.d.ts +3 -1
- package/dist/storage/wasRemoteStore.d.ts.map +1 -1
- package/dist/storage/wasRemoteStore.js +3 -3
- package/dist/storage/wasRemoteStore.js.map +1 -1
- package/dist/sync/feedMasterPort.d.ts +21 -19
- package/dist/sync/feedMasterPort.d.ts.map +1 -1
- package/dist/sync/feedMasterPort.js +18 -5
- package/dist/sync/feedMasterPort.js.map +1 -1
- package/dist/sync/index.d.ts +3 -3
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +2 -2
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/lwwConflictHandler.d.ts +35 -2
- package/dist/sync/lwwConflictHandler.d.ts.map +1 -1
- package/dist/sync/lwwConflictHandler.js +47 -9
- package/dist/sync/lwwConflictHandler.js.map +1 -1
- package/dist/sync/pushWrites.d.ts +27 -8
- package/dist/sync/pushWrites.d.ts.map +1 -1
- package/dist/sync/pushWrites.js +43 -15
- package/dist/sync/pushWrites.js.map +1 -1
- package/dist/sync/types.d.ts +49 -16
- package/dist/sync/types.d.ts.map +1 -1
- package/dist/sync/types.js +17 -0
- package/dist/sync/types.js.map +1 -1
- package/dist/sync/wasReplication.d.ts.map +1 -1
- package/dist/sync/wasReplication.js +38 -1
- package/dist/sync/wasReplication.js.map +1 -1
- package/dist/sync/wasSyncPort.d.ts +29 -6
- package/dist/sync/wasSyncPort.d.ts.map +1 -1
- package/dist/sync/wasSyncPort.js +105 -101
- package/dist/sync/wasSyncPort.js.map +1 -1
- package/package.json +7 -5
- package/dist/auth/verifyResponse.test.d.ts +0 -2
- package/dist/auth/verifyResponse.test.d.ts.map +0 -1
- package/dist/auth/verifyResponse.test.js +0 -282
- package/dist/auth/verifyResponse.test.js.map +0 -1
- package/dist/dev/cli.test.d.ts +0 -2
- package/dist/dev/cli.test.d.ts.map +0 -1
- package/dist/dev/cli.test.js +0 -39
- package/dist/dev/cli.test.js.map +0 -1
- package/dist/grants.test.d.ts +0 -2
- package/dist/grants.test.d.ts.map +0 -1
- package/dist/grants.test.js +0 -79
- package/dist/grants.test.js.map +0 -1
- package/dist/identity/seedCredential.test.d.ts +0 -2
- package/dist/identity/seedCredential.test.d.ts.map +0 -1
- package/dist/identity/seedCredential.test.js +0 -205
- package/dist/identity/seedCredential.test.js.map +0 -1
- package/dist/storage/rehydrate.test.d.ts +0 -2
- package/dist/storage/rehydrate.test.d.ts.map +0 -1
- package/dist/storage/rehydrate.test.js +0 -172
- package/dist/storage/rehydrate.test.js.map +0 -1
- package/dist/sync/changesQuery.test.d.ts +0 -2
- package/dist/sync/changesQuery.test.d.ts.map +0 -1
- package/dist/sync/changesQuery.test.js +0 -145
- package/dist/sync/changesQuery.test.js.map +0 -1
- package/dist/sync/lww.test.d.ts +0 -2
- package/dist/sync/lww.test.d.ts.map +0 -1
- package/dist/sync/lww.test.js +0 -28
- package/dist/sync/lww.test.js.map +0 -1
- package/dist/sync/lwwConflictHandler.test.d.ts +0 -2
- package/dist/sync/lwwConflictHandler.test.d.ts.map +0 -1
- package/dist/sync/lwwConflictHandler.test.js +0 -78
- package/dist/sync/lwwConflictHandler.test.js.map +0 -1
- package/dist/sync/pushWrites.test.d.ts +0 -2
- package/dist/sync/pushWrites.test.d.ts.map +0 -1
- package/dist/sync/pushWrites.test.js +0 -287
- package/dist/sync/pushWrites.test.js.map +0 -1
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* The app-side seam between the generic sync adapter and `@interop/was-client`.
|
|
6
|
-
* Implements the `
|
|
7
|
-
* raw, signed `was.request()` escape hatch.
|
|
6
|
+
* Implements the `WasSyncBasePort` interface (query + conditional writes) for one
|
|
7
|
+
* remote WAS Collection using the raw, signed `was.request()` escape hatch. The
|
|
8
|
+
* 412 conflict re-read (`get`) is supplied separately by `withFeedMasterRead`,
|
|
9
|
+
* which resolves the master state from the changes-feed body -- origin-
|
|
10
|
+
* independent, unlike a cross-origin `GET` ETag header.
|
|
8
11
|
*
|
|
9
12
|
* Using `request()` (rather than the `Resource` / `Collection` handles) is
|
|
10
13
|
* deliberate: it moves the stored body VERBATIM, bypassing the encryption codec.
|
|
@@ -20,9 +23,29 @@
|
|
|
20
23
|
* for plaintext and encrypted resources alike -- so there is no plaintext-vs-
|
|
21
24
|
* encrypted fork here.
|
|
22
25
|
*/
|
|
23
|
-
import type
|
|
26
|
+
import { type WasClient } from '@interop/was-client';
|
|
24
27
|
import type { IZcap } from '@interop/data-integrity-core';
|
|
25
|
-
import { type
|
|
28
|
+
import { type WasSyncBasePort } from './types.js';
|
|
29
|
+
/**
|
|
30
|
+
* Extracts an HTTP status from a raw ky/ezcap error. `was.request()` rejects on
|
|
31
|
+
* any non-2xx with `err.status` set (see `@interop/http-client`'s error
|
|
32
|
+
* normaliser); this reads it defensively from either location. Shared with the
|
|
33
|
+
* remote store's marker PUT and the dev-grant provisioner, which need the raw
|
|
34
|
+
* status for diagnostics rather than the mapped sync error.
|
|
35
|
+
*
|
|
36
|
+
* @param err {unknown}
|
|
37
|
+
* @returns {number | undefined}
|
|
38
|
+
*/
|
|
39
|
+
export declare function errorStatus(err: unknown): number | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Normalizes an unknown caught error into a display string: the `Error`'s
|
|
42
|
+
* `message` when it is one, else its `String(...)` coercion. Shared by the
|
|
43
|
+
* remote store's marker PUT and the session activation error path.
|
|
44
|
+
*
|
|
45
|
+
* @param err {unknown}
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
48
|
+
export declare function errorMessage(err: unknown): string;
|
|
26
49
|
/**
|
|
27
50
|
* Builds a `WasSyncPort` bound to a single Space + Collection on the remote WAS
|
|
28
51
|
* server, backed by the session's signed `WasClient`.
|
|
@@ -34,12 +57,12 @@ import { type WasSyncPort } from './types.js';
|
|
|
34
57
|
* @param [options.capability] {IZcap} the delegated session capability for
|
|
35
58
|
* this collection (a restored `delegated` tier session); absent in the full
|
|
36
59
|
* tier, where requests invoke root capabilities
|
|
37
|
-
* @returns {
|
|
60
|
+
* @returns {WasSyncBasePort}
|
|
38
61
|
*/
|
|
39
62
|
export declare function createWasSyncPort({ was, spaceId, collectionId, capability }: {
|
|
40
63
|
was: WasClient;
|
|
41
64
|
spaceId: string;
|
|
42
65
|
collectionId: string;
|
|
43
66
|
capability?: IZcap;
|
|
44
|
-
}):
|
|
67
|
+
}): WasSyncBasePort;
|
|
45
68
|
//# sourceMappingURL=wasSyncPort.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasSyncPort.d.ts","sourceRoot":"","sources":["../../src/sync/wasSyncPort.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"wasSyncPort.d.ts","sourceRoot":"","sources":["../../src/sync/wasSyncPort.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC5E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK5D;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAEjD;AAuCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,OAAO,EACP,YAAY,EACZ,UAAU,EACX,EAAE;IACD,GAAG,EAAE,SAAS,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB,GAAG,eAAe,CAsFlB"}
|
package/dist/sync/wasSyncPort.js
CHANGED
|
@@ -1,25 +1,85 @@
|
|
|
1
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The app-side seam between the generic sync adapter and `@interop/was-client`.
|
|
6
|
+
* Implements the `WasSyncBasePort` interface (query + conditional writes) for one
|
|
7
|
+
* remote WAS Collection using the raw, signed `was.request()` escape hatch. The
|
|
8
|
+
* 412 conflict re-read (`get`) is supplied separately by `withFeedMasterRead`,
|
|
9
|
+
* which resolves the master state from the changes-feed body -- origin-
|
|
10
|
+
* independent, unlike a cross-origin `GET` ETag header.
|
|
11
|
+
*
|
|
12
|
+
* Using `request()` (rather than the `Resource` / `Collection` handles) is
|
|
13
|
+
* deliberate: it moves the stored body VERBATIM, bypassing the encryption codec.
|
|
14
|
+
* The `changes` feed already ships opaque stored bodies (plaintext for a
|
|
15
|
+
* plaintext collection, the EDV envelope for an encrypted one), and the push
|
|
16
|
+
* side must write those same bytes back unchanged -- running them through
|
|
17
|
+
* `resource.put()` would re-encrypt an already-encrypted envelope. Encrypt /
|
|
18
|
+
* decrypt stays a read/write-time concern above this layer; this port is
|
|
19
|
+
* collection-agnostic and never touches keys.
|
|
20
|
+
*
|
|
21
|
+
* Conditional writes ride the server's monotonic `version` (content) and
|
|
22
|
+
* `metaVersion` (metadata) ETags, which the reference server enforces uniformly
|
|
23
|
+
* for plaintext and encrypted resources alike -- so there is no plaintext-vs-
|
|
24
|
+
* encrypted fork here.
|
|
25
|
+
*/
|
|
26
|
+
import { readEtag, writeHeaders } from '@interop/was-client';
|
|
27
|
+
import { WasSyncAuthError, WasSyncConflictError } from './types.js';
|
|
2
28
|
/**
|
|
3
29
|
* Extracts an HTTP status from a raw ky/ezcap error. `was.request()` rejects on
|
|
4
30
|
* any non-2xx with `err.status` set (see `@interop/http-client`'s error
|
|
5
|
-
* normaliser); this reads it defensively from either location.
|
|
31
|
+
* normaliser); this reads it defensively from either location. Shared with the
|
|
32
|
+
* remote store's marker PUT and the dev-grant provisioner, which need the raw
|
|
33
|
+
* status for diagnostics rather than the mapped sync error.
|
|
6
34
|
*
|
|
7
35
|
* @param err {unknown}
|
|
8
36
|
* @returns {number | undefined}
|
|
9
37
|
*/
|
|
10
|
-
function errorStatus(err) {
|
|
38
|
+
export function errorStatus(err) {
|
|
11
39
|
return (err.status ??
|
|
12
40
|
err.response?.status);
|
|
13
41
|
}
|
|
14
42
|
/**
|
|
15
|
-
*
|
|
16
|
-
* when
|
|
43
|
+
* Normalizes an unknown caught error into a display string: the `Error`'s
|
|
44
|
+
* `message` when it is one, else its `String(...)` coercion. Shared by the
|
|
45
|
+
* remote store's marker PUT and the session activation error path.
|
|
46
|
+
*
|
|
47
|
+
* @param err {unknown}
|
|
48
|
+
* @returns {string}
|
|
49
|
+
*/
|
|
50
|
+
export function errorMessage(err) {
|
|
51
|
+
return err instanceof Error ? err.message : String(err);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Maps a raw `was.request()` rejection to the sync layer's typed errors: `412`
|
|
55
|
+
* to {@link WasSyncConflictError} (a lost-update conflict) and `401` / `403` to
|
|
56
|
+
* {@link WasSyncAuthError} (expired/revoked storage access). Every other error
|
|
57
|
+
* is returned unchanged so RxDB's retry/backoff handles it. Returns the error to
|
|
58
|
+
* throw (the caller re-throws) rather than throwing itself.
|
|
59
|
+
*
|
|
60
|
+
* @param err {unknown}
|
|
61
|
+
* @returns {unknown}
|
|
62
|
+
*/
|
|
63
|
+
function toPortError(err) {
|
|
64
|
+
const status = errorStatus(err);
|
|
65
|
+
if (status === 412) {
|
|
66
|
+
return new WasSyncConflictError();
|
|
67
|
+
}
|
|
68
|
+
if (status === 401 || status === 403) {
|
|
69
|
+
return new WasSyncAuthError(status);
|
|
70
|
+
}
|
|
71
|
+
return err;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parses a quoted strong ETag (`"3"`, as read by `readEtag`) into its numeric
|
|
75
|
+
* revision, or `undefined` when the header was absent (the resource has no such
|
|
76
|
+
* revision yet).
|
|
17
77
|
*
|
|
18
|
-
* @param etag {string |
|
|
78
|
+
* @param etag {string | undefined}
|
|
19
79
|
* @returns {number | undefined}
|
|
20
80
|
*/
|
|
21
81
|
function parseEtag(etag) {
|
|
22
|
-
if (
|
|
82
|
+
if (etag === undefined) {
|
|
23
83
|
return undefined;
|
|
24
84
|
}
|
|
25
85
|
const revision = Number(etag.replace(/"/g, ''));
|
|
@@ -36,134 +96,78 @@ function parseEtag(etag) {
|
|
|
36
96
|
* @param [options.capability] {IZcap} the delegated session capability for
|
|
37
97
|
* this collection (a restored `delegated` tier session); absent in the full
|
|
38
98
|
* tier, where requests invoke root capabilities
|
|
39
|
-
* @returns {
|
|
99
|
+
* @returns {WasSyncBasePort}
|
|
40
100
|
*/
|
|
41
101
|
export function createWasSyncPort({ was, spaceId, collectionId, capability }) {
|
|
42
102
|
const collectionPath = `/space/${spaceId}/${collectionId}`;
|
|
43
103
|
const resourcePath = (id) => `${collectionPath}/${encodeURIComponent(id)}`;
|
|
44
|
-
/**
|
|
45
|
-
* Builds the conditional-write headers from the port's precondition options.
|
|
46
|
-
*/
|
|
47
|
-
const writeHeaders = ({ ifMatch, ifNoneMatch }) => {
|
|
48
|
-
const headers = {};
|
|
49
|
-
if (ifMatch !== undefined) {
|
|
50
|
-
headers['if-match'] = ifMatch;
|
|
51
|
-
}
|
|
52
|
-
if (ifNoneMatch) {
|
|
53
|
-
headers['if-none-match'] = '*';
|
|
54
|
-
}
|
|
55
|
-
return Object.keys(headers).length > 0 ? headers : undefined;
|
|
56
|
-
};
|
|
57
104
|
/**
|
|
58
105
|
* Runs a conditional write, mapping the server's `412 precondition-failed`
|
|
59
|
-
* into the core's `WasSyncConflictError` and
|
|
106
|
+
* into the core's `WasSyncConflictError` and a `401` / `403` into
|
|
107
|
+
* `WasSyncAuthError` (see {@link toPortError}), and letting all else propagate.
|
|
108
|
+
* Returns the accepted write's new revision parsed from the response ETag
|
|
109
|
+
* (`version` for content writes, `metaVersion` for `/meta` writes), or
|
|
110
|
+
* `undefined` when the response carries no ETag.
|
|
60
111
|
*/
|
|
61
|
-
const conditionalWrite = async (
|
|
112
|
+
const conditionalWrite = async (
|
|
113
|
+
// Typed off readEtag's parameter (was-client's HttpResponse) so the type
|
|
114
|
+
// needn't be imported from @interop/http-client, which is not a direct
|
|
115
|
+
// dependency here.
|
|
116
|
+
run) => {
|
|
62
117
|
try {
|
|
63
|
-
await run();
|
|
118
|
+
const response = await run();
|
|
119
|
+
return parseEtag(readEtag(response));
|
|
64
120
|
}
|
|
65
121
|
catch (err) {
|
|
66
|
-
|
|
67
|
-
throw new WasSyncConflictError();
|
|
68
|
-
}
|
|
69
|
-
throw err;
|
|
122
|
+
throw toPortError(err);
|
|
70
123
|
}
|
|
71
124
|
};
|
|
72
125
|
return {
|
|
73
126
|
async query({ checkpoint, limit }) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
127
|
+
try {
|
|
128
|
+
const response = await was.request({
|
|
129
|
+
capability,
|
|
130
|
+
path: `${collectionPath}/query`,
|
|
131
|
+
method: 'POST',
|
|
132
|
+
json: {
|
|
133
|
+
profile: 'changes',
|
|
134
|
+
...(checkpoint !== undefined && { checkpoint }),
|
|
135
|
+
limit
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return response.data;
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
// Map a pull-path 401/403 to WasSyncAuthError too, so expired access is
|
|
142
|
+
// recognised whether it surfaces on the pull or the push side.
|
|
143
|
+
throw toPortError(err);
|
|
144
|
+
}
|
|
85
145
|
},
|
|
86
146
|
async putContent({ id, data, ifMatch, ifNoneMatch }) {
|
|
87
|
-
|
|
147
|
+
return conditionalWrite(() => was.request({
|
|
88
148
|
capability,
|
|
89
149
|
path: resourcePath(id),
|
|
90
150
|
method: 'PUT',
|
|
91
151
|
json: data,
|
|
92
|
-
headers: writeHeaders({ ifMatch, ifNoneMatch })
|
|
152
|
+
headers: writeHeaders({ precondition: { ifMatch, ifNoneMatch } })
|
|
93
153
|
}));
|
|
94
154
|
},
|
|
95
155
|
async deleteContent({ id, ifMatch }) {
|
|
96
|
-
|
|
156
|
+
return conditionalWrite(() => was.request({
|
|
97
157
|
capability,
|
|
98
158
|
path: resourcePath(id),
|
|
99
159
|
method: 'DELETE',
|
|
100
|
-
headers: writeHeaders({ ifMatch })
|
|
160
|
+
headers: writeHeaders({ precondition: { ifMatch } })
|
|
101
161
|
}));
|
|
102
162
|
},
|
|
103
163
|
async putMeta({ id, custom, ifMatch, ifNoneMatch }) {
|
|
104
|
-
|
|
164
|
+
return conditionalWrite(() => was.request({
|
|
105
165
|
capability,
|
|
106
166
|
path: `${resourcePath(id)}/meta`,
|
|
107
167
|
method: 'PUT',
|
|
108
168
|
json: { custom },
|
|
109
|
-
headers: writeHeaders({ ifMatch, ifNoneMatch })
|
|
169
|
+
headers: writeHeaders({ precondition: { ifMatch, ifNoneMatch } })
|
|
110
170
|
}));
|
|
111
|
-
},
|
|
112
|
-
async get({ id }) {
|
|
113
|
-
// Content re-read: raw GET returns the stored body verbatim (no decrypt)
|
|
114
|
-
// and the content `version` in the ETag. A 404 means the resource is gone
|
|
115
|
-
// (or tombstoned) -- report absent so the core synthesizes a tombstone.
|
|
116
|
-
let contentResponse;
|
|
117
|
-
try {
|
|
118
|
-
contentResponse = await was.request({
|
|
119
|
-
capability,
|
|
120
|
-
path: resourcePath(id),
|
|
121
|
-
method: 'GET'
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
catch (err) {
|
|
125
|
-
if (errorStatus(err) === 404) {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
throw err;
|
|
129
|
-
}
|
|
130
|
-
const master = {
|
|
131
|
-
version: parseEtag(contentResponse.headers.get('etag')) ?? 0,
|
|
132
|
-
// Filled from the `/meta` body's server-managed `updatedAt` below; the
|
|
133
|
-
// change feed remains the authority on ordering, so this only feeds the
|
|
134
|
-
// one-off conflict entry and is corrected on the next pull.
|
|
135
|
-
updatedAt: '',
|
|
136
|
-
deleted: false,
|
|
137
|
-
data: contentResponse.data
|
|
138
|
-
};
|
|
139
|
-
// Metadata re-read: the `/meta` body carries the server-managed
|
|
140
|
-
// `updatedAt` plus the user-writable `custom` (opaque), and its own
|
|
141
|
-
// `metaVersion` ETag (absent until metadata has been written).
|
|
142
|
-
try {
|
|
143
|
-
const metaResponse = await was.request({
|
|
144
|
-
capability,
|
|
145
|
-
path: `${resourcePath(id)}/meta`,
|
|
146
|
-
method: 'GET'
|
|
147
|
-
});
|
|
148
|
-
const metaBody = metaResponse.data;
|
|
149
|
-
if (metaBody?.updatedAt) {
|
|
150
|
-
master.updatedAt = metaBody.updatedAt;
|
|
151
|
-
}
|
|
152
|
-
const metaVersion = parseEtag(metaResponse.headers.get('etag'));
|
|
153
|
-
if (metaVersion !== undefined) {
|
|
154
|
-
master.metaVersion = metaVersion;
|
|
155
|
-
}
|
|
156
|
-
if (metaBody?.custom !== undefined) {
|
|
157
|
-
master.custom = metaBody.custom;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
catch (err) {
|
|
161
|
-
// Metadata is optional; only a hard error (not 404) should propagate.
|
|
162
|
-
if (errorStatus(err) !== 404) {
|
|
163
|
-
throw err;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return master;
|
|
167
171
|
}
|
|
168
172
|
};
|
|
169
173
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasSyncPort.js","sourceRoot":"","sources":["../../src/sync/wasSyncPort.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wasSyncPort.js","sourceRoot":"","sources":["../../src/sync/wasSyncPort.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interop/was-react",
|
|
3
3
|
"description": "React library for building 'Bring Your Own Everything' (BYOE) apps on Wallet Attached Storage: DID Auth login via CHAPI wallet, local-first encrypted storage, and background sync to a WAS server.",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "pnpm run clear && tsc",
|
|
@@ -49,15 +49,16 @@
|
|
|
49
49
|
"types": "dist/index.d.ts",
|
|
50
50
|
"sideEffects": false,
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@interop/data-integrity-core": "^8.
|
|
52
|
+
"@interop/data-integrity-core": "^8.2.0",
|
|
53
53
|
"@interop/ed25519-signature": "^7.1.3",
|
|
54
54
|
"@interop/ezcap": "^7.3.2",
|
|
55
55
|
"@interop/security-document-loader": "^9.4.1",
|
|
56
56
|
"@interop/vc": "^11.0.5",
|
|
57
57
|
"@interop/verifier-core": "^3.3.1",
|
|
58
|
-
"@interop/was-client": "^0.
|
|
58
|
+
"@interop/was-client": "^0.14.5",
|
|
59
59
|
"@interop/webkms-client": "^14.7.1",
|
|
60
|
-
"@interop/x25519-key-agreement-key": "^5.
|
|
60
|
+
"@interop/x25519-key-agreement-key": "^5.2.0",
|
|
61
|
+
"@scure/base": "^2.2.0",
|
|
61
62
|
"credential-handler-polyfill": "^4.1.0",
|
|
62
63
|
"uuidv7": "^1.2.1"
|
|
63
64
|
},
|
|
@@ -113,7 +114,8 @@
|
|
|
113
114
|
"zustand": "^5.0.12"
|
|
114
115
|
},
|
|
115
116
|
"publishConfig": {
|
|
116
|
-
"access": "public"
|
|
117
|
+
"access": "public",
|
|
118
|
+
"provenance": true
|
|
117
119
|
},
|
|
118
120
|
"keywords": [
|
|
119
121
|
"react",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"verifyResponse.test.d.ts","sourceRoot":"","sources":["../../src/auth/verifyResponse.test.ts"],"names":[],"mappings":""}
|