@interop/was-client 0.100.0 → 0.101.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.
Files changed (76) hide show
  1. package/README.md +123 -53
  2. package/dist/Collection.d.ts +21 -9
  3. package/dist/Collection.d.ts.map +1 -1
  4. package/dist/Collection.js +39 -37
  5. package/dist/Collection.js.map +1 -1
  6. package/dist/Resource.d.ts +0 -4
  7. package/dist/Resource.d.ts.map +1 -1
  8. package/dist/Resource.js +1 -6
  9. package/dist/Resource.js.map +1 -1
  10. package/dist/Space.d.ts +97 -24
  11. package/dist/Space.d.ts.map +1 -1
  12. package/dist/Space.js +168 -84
  13. package/dist/Space.js.map +1 -1
  14. package/dist/WasClient.d.ts +135 -55
  15. package/dist/WasClient.d.ts.map +1 -1
  16. package/dist/WasClient.js +220 -100
  17. package/dist/WasClient.js.map +1 -1
  18. package/dist/edv/EdvCodec.d.ts.map +1 -1
  19. package/dist/edv/EdvCodec.js +7 -4
  20. package/dist/edv/EdvCodec.js.map +1 -1
  21. package/dist/edv/docCipher.js +2 -2
  22. package/dist/edv/docCipher.js.map +1 -1
  23. package/dist/index.d.ts +0 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/internal/codec.d.ts +11 -1
  27. package/dist/internal/codec.d.ts.map +1 -1
  28. package/dist/internal/codec.js +11 -1
  29. package/dist/internal/codec.js.map +1 -1
  30. package/dist/internal/describe.d.ts +6 -0
  31. package/dist/internal/describe.d.ts.map +1 -1
  32. package/dist/internal/describe.js +18 -1
  33. package/dist/internal/describe.js.map +1 -1
  34. package/dist/internal/grant.js +1 -1
  35. package/dist/internal/grant.js.map +1 -1
  36. package/dist/internal/indexSchema.d.ts +19 -4
  37. package/dist/internal/indexSchema.d.ts.map +1 -1
  38. package/dist/internal/indexSchema.js +33 -6
  39. package/dist/internal/indexSchema.js.map +1 -1
  40. package/dist/internal/paths.d.ts +113 -18
  41. package/dist/internal/paths.d.ts.map +1 -1
  42. package/dist/internal/paths.js +224 -40
  43. package/dist/internal/paths.js.map +1 -1
  44. package/dist/internal/request.d.ts +47 -14
  45. package/dist/internal/request.d.ts.map +1 -1
  46. package/dist/internal/request.js +64 -44
  47. package/dist/internal/request.js.map +1 -1
  48. package/dist/internal/reserved.d.ts +15 -3
  49. package/dist/internal/reserved.d.ts.map +1 -1
  50. package/dist/internal/reserved.js +37 -8
  51. package/dist/internal/reserved.js.map +1 -1
  52. package/dist/internal/revoke.d.ts +1 -65
  53. package/dist/internal/revoke.d.ts.map +1 -1
  54. package/dist/internal/revoke.js +5 -136
  55. package/dist/internal/revoke.js.map +1 -1
  56. package/dist/internal/rootCapability.d.ts +66 -0
  57. package/dist/internal/rootCapability.d.ts.map +1 -0
  58. package/dist/internal/rootCapability.js +144 -0
  59. package/dist/internal/rootCapability.js.map +1 -0
  60. package/dist/internal/service.d.ts +5 -3
  61. package/dist/internal/service.d.ts.map +1 -1
  62. package/dist/internal/service.js +5 -3
  63. package/dist/internal/service.js.map +1 -1
  64. package/dist/internal/withCodec.d.ts +19 -4
  65. package/dist/internal/withCodec.d.ts.map +1 -1
  66. package/dist/internal/withCodec.js +18 -2
  67. package/dist/internal/withCodec.js.map +1 -1
  68. package/dist/internal/write.js +13 -9
  69. package/dist/internal/write.js.map +1 -1
  70. package/dist/paths.d.ts +5 -3
  71. package/dist/paths.d.ts.map +1 -1
  72. package/dist/paths.js +5 -3
  73. package/dist/paths.js.map +1 -1
  74. package/dist/sync/provisioning.js +1 -1
  75. package/dist/sync/provisioning.js.map +1 -1
  76. package/package.json +3 -3
@@ -11,7 +11,8 @@
11
11
  * server whose protocol version this client does not speak.
12
12
  */
13
13
  import type { ZcapClient } from '@interop/ezcap';
14
- import type { HttpResponse } from '@interop/http-client';
14
+ import { type HttpResponse } from '@interop/http-client';
15
+ import { WasServerError } from '../errors.js';
15
16
  import type { EncryptionProvider } from '../codec.js';
16
17
  import type { IZcap, RequestInput, ServiceInfo } from '../types.js';
17
18
  /**
@@ -63,7 +64,9 @@ export declare function rawRequest(context: ClientContext, input: SendInput): Pr
63
64
  /**
64
65
  * A plain unsigned `fetch` that maps a network failure to a `WasError`, the
65
66
  * way the rest of the transport does. The response is returned as is,
66
- * whatever its status.
67
+ * whatever its status: this is the probe primitive for service discovery,
68
+ * which reads the status itself. Everything else sends through
69
+ * `unsignedRequest` or `send()`.
67
70
  *
68
71
  * @param url {string}
69
72
  * @param init {RequestInit}
@@ -71,10 +74,15 @@ export declare function rawRequest(context: ClientContext, input: SendInput): Pr
71
74
  */
72
75
  export declare function fetchMapped(url: string, init: RequestInit): Promise<Response>;
73
76
  /**
74
- * Sends an **unsigned** request (a plain `fetch`, no capability invocation), for
75
- * reading public (`PublicCanRead`) resources that need no authorization. Applies
76
- * the same typed-error mapping and null-on-404 read translation as `send()`.
77
- * Takes an absolute `url` -- public reads address a resource by its link.
77
+ * Sends an **unsigned** request (no capability invocation), for reading public
78
+ * (`PublicCanRead`) resources that need no authorization. Applies the same
79
+ * typed-error mapping and null-on-404 read translation as `send()`. Takes an
80
+ * absolute `url` -- public reads address a resource by its link.
81
+ *
82
+ * Sends through `@interop/http-client`, the same client as `send()`, so the
83
+ * response has the same shape (JSON pre-parsed into `data`) and the same
84
+ * retry and timeout behavior, and `dataOrNull` and `readJsonData` read it
85
+ * exactly as they read a signed one.
78
86
  *
79
87
  * @param input {object}
80
88
  * @param input.url {string} absolute URL to read
@@ -108,37 +116,62 @@ export declare function unsignedRequest(input: {
108
116
  * @returns {Promise<HttpResponse | null>}
109
117
  */
110
118
  export declare function send(context: ClientContext, input: SendInput): Promise<HttpResponse | null>;
119
+ /**
120
+ * The `WasServerError` for a 2xx whose body was not the JSON object the
121
+ * operation required. The request layer parses a body into `data` only for a
122
+ * JSON content type, so naming the content type the server sent points at the
123
+ * cause (a mislabeled or body-less 2xx).
124
+ *
125
+ * @param options {object}
126
+ * @param options.response {HttpResponse | null}
127
+ * @param options.operation {string} the request, as the message's subject
128
+ * @param options.expected {string} what the body should have carried
129
+ * @returns {WasServerError}
130
+ */
131
+ export declare function missingJsonBodyError({ response, operation, expected }: {
132
+ response: HttpResponse | null;
133
+ operation: string;
134
+ expected: string;
135
+ }): WasServerError;
111
136
  /**
112
137
  * The GET-a-JSON-description read shared across the handles: a signed
113
- * null-on-404 `GET` of `url` whose pre-parsed body is unwrapped as `T`. Both
114
- * a missing/unauthorized target (404) and a bodyless/non-JSON response resolve
115
- * to `null` (see `dataOrNull`).
138
+ * null-on-404 `GET` of `url` whose pre-parsed body is unwrapped as `T`. A
139
+ * missing/unauthorized target (404) resolves to `null`. So does a
140
+ * bodyless/non-JSON 2xx (see `dataOrNull`), unless `expected` names what the
141
+ * body should have carried: then that 2xx is a server fault
142
+ * (`WasServerError`), for a read whose caller must not mistake a misbehaving
143
+ * server for "nothing stored".
116
144
  *
117
145
  * @param context {ClientContext}
118
146
  * @param options {object}
119
147
  * @param options.url {string} the absolute URL to read
120
148
  * @param [options.capability] {IZcap} capability attached to the request
149
+ * @param [options.expected] {string} what a 2xx body must carry, for the
150
+ * error message; absent, a bodyless 2xx reads as `null`
121
151
  * @returns {Promise<T | null>}
122
152
  */
123
- export declare function readData<T>(context: ClientContext, { url, capability }: {
153
+ export declare function readData<T>(context: ClientContext, options: {
124
154
  url: string;
125
155
  capability?: IZcap;
156
+ expected?: string;
126
157
  }): Promise<T | null>;
127
158
  /**
128
159
  * {@link readData} keeping the response's `ETag` validator beside the body:
129
- * the read-with-validator shape a description compare-and-swap starts from.
130
- * `null` on the same conditions as `readData`; `etag` is absent against a
131
- * server that does not version the target.
160
+ * the read-with-validator shape a compare-and-swap starts from. `null` on the
161
+ * same conditions as `readData`, and `expected` has the same meaning; `etag`
162
+ * is absent against a server that does not version the target.
132
163
  *
133
164
  * @param context {ClientContext}
134
165
  * @param options {object}
135
166
  * @param options.url {string} the absolute URL to read
136
167
  * @param [options.capability] {IZcap} capability attached to the request
168
+ * @param [options.expected] {string} see {@link readData}
137
169
  * @returns {Promise<{ data: T; etag?: string } | null>}
138
170
  */
139
- export declare function readDataWithEtag<T>(context: ClientContext, { url, capability }: {
171
+ export declare function readDataWithEtag<T>(context: ClientContext, { url, capability, expected }: {
140
172
  url: string;
141
173
  capability?: IZcap;
174
+ expected?: string;
142
175
  }): Promise<{
143
176
  data: T;
144
177
  etag?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAIxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEnE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,kBAAkB,CAAA;IAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,YAAY,CAAC,CAiBvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,QAAQ,CAAC,CAMnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA4B/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,IAAI,CACxB,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAmC9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,OAAO,EAAE,aAAa,EACtB,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAE,GACvD,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAQnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,OAAO,EAAE,aAAa,EACtB,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAE,GACvD,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAY5C"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEhD,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACpE,OAAO,EAGL,cAAc,EAGf,MAAM,cAAc,CAAA;AAGrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEnE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,kBAAkB,CAAA;IAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,YAAY,CAAC,CAiBvB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,QAAQ,CAAC,CAMnB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAiB/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,IAAI,CACxB,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAmC9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,SAAS,EACT,QAAQ,EACT,EAAE;IACD,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB,GAAG,cAAc,CAMjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAGnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,OAAO,EAAE,aAAa,EACtB,EACE,GAAG,EACH,UAAU,EACV,QAAQ,EACT,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAe5C"}
@@ -1,5 +1,6 @@
1
1
  import { isValidTarget } from '@interop/zcap';
2
- import { NotFoundError, WasError, mapError, httpStatus } from '../errors.js';
2
+ import { httpClient } from '@interop/http-client';
3
+ import { NotFoundError, WasError, WasServerError, mapError, httpStatus } from '../errors.js';
3
4
  import { dataOrNull } from './content.js';
4
5
  import { readEtag } from './conditional.js';
5
6
  /**
@@ -34,7 +35,9 @@ export async function rawRequest(context, input) {
34
35
  /**
35
36
  * A plain unsigned `fetch` that maps a network failure to a `WasError`, the
36
37
  * way the rest of the transport does. The response is returned as is,
37
- * whatever its status.
38
+ * whatever its status: this is the probe primitive for service discovery,
39
+ * which reads the status itself. Everything else sends through
40
+ * `unsignedRequest` or `send()`.
38
41
  *
39
42
  * @param url {string}
40
43
  * @param init {RequestInit}
@@ -49,10 +52,15 @@ export async function fetchMapped(url, init) {
49
52
  }
50
53
  }
51
54
  /**
52
- * Sends an **unsigned** request (a plain `fetch`, no capability invocation), for
53
- * reading public (`PublicCanRead`) resources that need no authorization. Applies
54
- * the same typed-error mapping and null-on-404 read translation as `send()`.
55
- * Takes an absolute `url` -- public reads address a resource by its link.
55
+ * Sends an **unsigned** request (no capability invocation), for reading public
56
+ * (`PublicCanRead`) resources that need no authorization. Applies the same
57
+ * typed-error mapping and null-on-404 read translation as `send()`. Takes an
58
+ * absolute `url` -- public reads address a resource by its link.
59
+ *
60
+ * Sends through `@interop/http-client`, the same client as `send()`, so the
61
+ * response has the same shape (JSON pre-parsed into `data`) and the same
62
+ * retry and timeout behavior, and `dataOrNull` and `readJsonData` read it
63
+ * exactly as they read a signed one.
56
64
  *
57
65
  * @param input {object}
58
66
  * @param input.url {string} absolute URL to read
@@ -62,32 +70,23 @@ export async function fetchMapped(url, init) {
62
70
  * @returns {Promise<HttpResponse | null>}
63
71
  */
64
72
  export async function unsignedRequest(input) {
65
- const response = await fetchMapped(input.url, {
66
- method: input.method ?? 'GET',
67
- headers: input.headers
68
- });
69
- if (response.ok) {
70
- return response;
71
- }
72
- // A public read resolves to `null` for any "not readable by you" status, not
73
- // just 404: a conformant WAS masks unauthorized as 404, but a server that
74
- // answers a missing capability with 401/403 should honor the same
75
- // null-if-not-publicly-readable contract rather than throw.
76
- if (input.read &&
77
- (response.status === 404 ||
78
- response.status === 401 ||
79
- response.status === 403)) {
80
- return null;
81
- }
82
- // Reconstruct a problem+json-shaped error so mapError can dispatch on it.
83
- let data;
84
73
  try {
85
- data = await response.json();
74
+ return await httpClient(input.url, {
75
+ method: input.method ?? 'GET',
76
+ headers: input.headers
77
+ });
86
78
  }
87
- catch {
88
- data = undefined;
79
+ catch (err) {
80
+ // A public read resolves to `null` for any "not readable by you" status,
81
+ // not just 404: a conformant WAS masks unauthorized as 404, but a server
82
+ // that answers a missing capability with 401/403 should honor the same
83
+ // null-if-not-publicly-readable contract rather than throw.
84
+ const status = httpStatus(err);
85
+ if (input.read && (status === 404 || status === 401 || status === 403)) {
86
+ return null;
87
+ }
88
+ throw mapError(err);
89
89
  }
90
- throw mapError({ status: response.status, requestUrl: input.url, data });
91
90
  }
92
91
  /**
93
92
  * Signs and sends a request, applying the typed-error mapping. When `read` is
@@ -137,40 +136,58 @@ export async function send(context, input) {
137
136
  throw mapError(err);
138
137
  }
139
138
  }
139
+ /**
140
+ * The `WasServerError` for a 2xx whose body was not the JSON object the
141
+ * operation required. The request layer parses a body into `data` only for a
142
+ * JSON content type, so naming the content type the server sent points at the
143
+ * cause (a mislabeled or body-less 2xx).
144
+ *
145
+ * @param options {object}
146
+ * @param options.response {HttpResponse | null}
147
+ * @param options.operation {string} the request, as the message's subject
148
+ * @param options.expected {string} what the body should have carried
149
+ * @returns {WasServerError}
150
+ */
151
+ export function missingJsonBodyError({ response, operation, expected }) {
152
+ const contentType = response?.headers.get('content-type') ?? 'no content-type';
153
+ return new WasServerError(`${operation} response carried no JSON body (the server sent ` +
154
+ `${contentType}); expected ${expected}.`);
155
+ }
140
156
  /**
141
157
  * The GET-a-JSON-description read shared across the handles: a signed
142
- * null-on-404 `GET` of `url` whose pre-parsed body is unwrapped as `T`. Both
143
- * a missing/unauthorized target (404) and a bodyless/non-JSON response resolve
144
- * to `null` (see `dataOrNull`).
158
+ * null-on-404 `GET` of `url` whose pre-parsed body is unwrapped as `T`. A
159
+ * missing/unauthorized target (404) resolves to `null`. So does a
160
+ * bodyless/non-JSON 2xx (see `dataOrNull`), unless `expected` names what the
161
+ * body should have carried: then that 2xx is a server fault
162
+ * (`WasServerError`), for a read whose caller must not mistake a misbehaving
163
+ * server for "nothing stored".
145
164
  *
146
165
  * @param context {ClientContext}
147
166
  * @param options {object}
148
167
  * @param options.url {string} the absolute URL to read
149
168
  * @param [options.capability] {IZcap} capability attached to the request
169
+ * @param [options.expected] {string} what a 2xx body must carry, for the
170
+ * error message; absent, a bodyless 2xx reads as `null`
150
171
  * @returns {Promise<T | null>}
151
172
  */
152
- export async function readData(context, { url, capability }) {
153
- const response = await send(context, {
154
- url,
155
- method: 'GET',
156
- capability,
157
- read: true
158
- });
159
- return dataOrNull(response);
173
+ export async function readData(context, options) {
174
+ const read = await readDataWithEtag(context, options);
175
+ return read === null ? null : read.data;
160
176
  }
161
177
  /**
162
178
  * {@link readData} keeping the response's `ETag` validator beside the body:
163
- * the read-with-validator shape a description compare-and-swap starts from.
164
- * `null` on the same conditions as `readData`; `etag` is absent against a
165
- * server that does not version the target.
179
+ * the read-with-validator shape a compare-and-swap starts from. `null` on the
180
+ * same conditions as `readData`, and `expected` has the same meaning; `etag`
181
+ * is absent against a server that does not version the target.
166
182
  *
167
183
  * @param context {ClientContext}
168
184
  * @param options {object}
169
185
  * @param options.url {string} the absolute URL to read
170
186
  * @param [options.capability] {IZcap} capability attached to the request
187
+ * @param [options.expected] {string} see {@link readData}
171
188
  * @returns {Promise<{ data: T; etag?: string } | null>}
172
189
  */
173
- export async function readDataWithEtag(context, { url, capability }) {
190
+ export async function readDataWithEtag(context, { url, capability, expected }) {
174
191
  const response = await send(context, {
175
192
  url,
176
193
  method: 'GET',
@@ -179,6 +196,9 @@ export async function readDataWithEtag(context, { url, capability }) {
179
196
  });
180
197
  const data = dataOrNull(response);
181
198
  if (data === null) {
199
+ if (response !== null && expected !== undefined) {
200
+ throw missingJsonBodyError({ response, operation: 'Read', expected });
201
+ }
182
202
  return null;
183
203
  }
184
204
  return { data, etag: readEtag(response) };
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/internal/request.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,18 @@
1
1
  /**
2
- * Whether `id` is a reserved Collection-id path segment.
2
+ * Whether `id` is a reserved Collection-id path segment. At a Space served
3
+ * from an origin root the Collection id is the first path segment, where a
4
+ * server with a base server URL places its server-level endpoints, so the
5
+ * spec reserves those segments there too (and only there).
3
6
  *
4
7
  * @param id {string}
8
+ * @param options {object}
9
+ * @param [options.originRoot] {boolean} whether the Space is served from an
10
+ * origin root
5
11
  * @returns {boolean}
6
12
  */
7
- export declare function isReservedCollectionId(id: string): boolean;
13
+ export declare function isReservedCollectionId(id: string, { originRoot }?: {
14
+ originRoot?: boolean;
15
+ }): boolean;
8
16
  /**
9
17
  * Whether `id` is a reserved Resource-id path segment.
10
18
  *
@@ -20,10 +28,14 @@ export declare function isReservedResourceId(id: string): boolean;
20
28
  * @param options.id {string} the proposed collection or resource id
21
29
  * @param options.kind {string} 'collection' or 'resource', selects the
22
30
  * reserved set and is used in the message
31
+ * @param [options.originRoot] {boolean} whether the Space is served from an
32
+ * origin root, where the server-level endpoint segments are reserved as
33
+ * Collection ids too
23
34
  * @returns {void}
24
35
  */
25
- export declare function assertNotReserved({ id, kind }: {
36
+ export declare function assertNotReserved({ id, kind, originRoot }: {
26
37
  id: string;
27
38
  kind: 'collection' | 'resource';
39
+ originRoot?: boolean;
28
40
  }): void;
29
41
  //# sourceMappingURL=reserved.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reserved.d.ts","sourceRoot":"","sources":["../../src/internal/reserved.ts"],"names":[],"mappings":"AAoBA;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,EAAE,EACF,IAAI,EACL,EAAE;IACD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,YAAY,GAAG,UAAU,CAAA;CAChC,GAAG,IAAI,CAQP"}
1
+ {"version":3,"file":"reserved.d.ts","sourceRoot":"","sources":["../../src/internal/reserved.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,EACV,EAAE,UAAkB,EAAE,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GACpD,OAAO,CAKT;AAcD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,EAAE,EACF,IAAI,EACJ,UAAkB,EACnB,EAAE;IACD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,YAAY,GAAG,UAAU,CAAA;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,GAAG,IAAI,CAiBP"}
@@ -11,16 +11,34 @@
11
11
  * client-side `ValidationError`-throwing guard and the two membership
12
12
  * predicates the path grammar asks with.
13
13
  */
14
- import { RESERVED_COLLECTION_IDS, RESERVED_RESOURCE_IDS } from '@interop/storage-core';
14
+ import { ORIGIN_ROOT_RESERVED_COLLECTION_IDS, RESERVED_COLLECTION_IDS, RESERVED_RESOURCE_IDS } from '@interop/storage-core';
15
15
  import { ValidationError } from '../errors.js';
16
16
  /**
17
- * Whether `id` is a reserved Collection-id path segment.
17
+ * Whether `id` is a reserved Collection-id path segment. At a Space served
18
+ * from an origin root the Collection id is the first path segment, where a
19
+ * server with a base server URL places its server-level endpoints, so the
20
+ * spec reserves those segments there too (and only there).
21
+ *
22
+ * @param id {string}
23
+ * @param options {object}
24
+ * @param [options.originRoot] {boolean} whether the Space is served from an
25
+ * origin root
26
+ * @returns {boolean}
27
+ */
28
+ export function isReservedCollectionId(id, { originRoot = false } = {}) {
29
+ return (RESERVED_COLLECTION_IDS.has(id) ||
30
+ (originRoot && isOriginRootReservedCollectionId(id)));
31
+ }
32
+ /**
33
+ * Whether `id` is one of the server-level endpoint segments (`service`,
34
+ * `spaces`, `space`), reserved as a Collection id only at a Space served
35
+ * from an origin root.
18
36
  *
19
37
  * @param id {string}
20
38
  * @returns {boolean}
21
39
  */
22
- export function isReservedCollectionId(id) {
23
- return RESERVED_COLLECTION_IDS.has(id);
40
+ function isOriginRootReservedCollectionId(id) {
41
+ return ORIGIN_ROOT_RESERVED_COLLECTION_IDS.has(id);
24
42
  }
25
43
  /**
26
44
  * Whether `id` is a reserved Resource-id path segment.
@@ -39,12 +57,23 @@ export function isReservedResourceId(id) {
39
57
  * @param options.id {string} the proposed collection or resource id
40
58
  * @param options.kind {string} 'collection' or 'resource', selects the
41
59
  * reserved set and is used in the message
60
+ * @param [options.originRoot] {boolean} whether the Space is served from an
61
+ * origin root, where the server-level endpoint segments are reserved as
62
+ * Collection ids too
42
63
  * @returns {void}
43
64
  */
44
- export function assertNotReserved({ id, kind }) {
45
- const isReserved = kind === 'collection' ? isReservedCollectionId : isReservedResourceId;
46
- if (isReserved(id)) {
47
- throw new ValidationError(`Cannot use reserved path segment "${id}" as a ${kind} id.`);
65
+ export function assertNotReserved({ id, kind, originRoot = false }) {
66
+ const reserved = kind === 'collection'
67
+ ? isReservedCollectionId(id, { originRoot })
68
+ : isReservedResourceId(id);
69
+ if (!reserved) {
70
+ return;
48
71
  }
72
+ // The origin-root-only ids are reserved for a reason the plain message
73
+ // would not convey.
74
+ const where = RESERVED_COLLECTION_IDS.has(id) || kind === 'resource'
75
+ ? ''
76
+ : ' at a Space served from an origin root';
77
+ throw new ValidationError(`Cannot use reserved path segment "${id}" as a ${kind} id${where}.`);
49
78
  }
50
79
  //# sourceMappingURL=reserved.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reserved.js","sourceRoot":"","sources":["../../src/internal/reserved.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;GASG;AACH,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,EAAU;IAC/C,OAAO,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACxC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,EAAU;IAC7C,OAAO,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACtC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,EAAE,EACF,IAAI,EAIL;IACC,MAAM,UAAU,GACd,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,oBAAoB,CAAA;IACvE,IAAI,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,eAAe,CACvB,qCAAqC,EAAE,UAAU,IAAI,MAAM,CAC5D,CAAA;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"reserved.js","sourceRoot":"","sources":["../../src/internal/reserved.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;GASG;AACH,OAAO,EACL,mCAAmC,EACnC,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB,CACpC,EAAU,EACV,EAAE,UAAU,GAAG,KAAK,KAA+B,EAAE;IAErD,OAAO,CACL,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,CAAC,UAAU,IAAI,gCAAgC,CAAC,EAAE,CAAC,CAAC,CACrD,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,gCAAgC,CAAC,EAAU;IAClD,OAAO,mCAAmC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,EAAU;IAC7C,OAAO,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACtC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,EAAE,EACF,IAAI,EACJ,UAAU,GAAG,KAAK,EAKnB;IACC,MAAM,QAAQ,GACZ,IAAI,KAAK,YAAY;QACnB,CAAC,CAAC,sBAAsB,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;QAC5C,CAAC,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAA;IAC9B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAM;IACR,CAAC;IACD,uEAAuE;IACvE,oBAAoB;IACpB,MAAM,KAAK,GACT,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,UAAU;QACpD,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,wCAAwC,CAAA;IAC9C,MAAM,IAAI,eAAe,CACvB,qCAAqC,EAAE,UAAU,IAAI,MAAM,KAAK,GAAG,CACpE,CAAA;AACH,CAAC"}
@@ -1,69 +1,5 @@
1
1
  import type { ClientContext } from './request.js';
2
- import type { IDelegatedZcap, IRootZcap, IZcap } from '../types.js';
3
- /**
4
- * The root capability id for an invocation target URL
5
- * (`urn:zcap:root:<encoded target>`) -- the id grammar shared by revocation
6
- * (which invokes the revocation URL's own root capability in object form) and
7
- * grant rooting (which parents an unparented grant on its Space's root
8
- * capability id).
9
- *
10
- * @param target {string} the absolute invocation target URL
11
- * @returns {string}
12
- */
13
- export declare function rootCapabilityId(target: string): string;
14
- /**
15
- * The invocation target a root capability id names: the inverse of
16
- * {@link rootCapabilityId}. Returns `null` for an id that is not a root
17
- * capability id, or whose encoded target is malformed.
18
- *
19
- * @param id {string} a capability id
20
- * @returns {string | null}
21
- */
22
- export declare function rootCapabilityTarget(id: string): string | null;
23
- /**
24
- * Builds the root capability for `target` in **object** form.
25
- *
26
- * The object form is load-bearing: `@interop/ezcap` accepts a *string* root
27
- * capability id only when its invocation target is `https:`, which would break
28
- * against an `http://localhost` server. Both forms reduce to the same
29
- * `zcap id="..."` invocation header.
30
- *
31
- * `controller` is client-side only -- the server re-derives the real controller
32
- * when it synthesizes the root capability -- so the caller's own DID is fine.
33
- *
34
- * @param options {object}
35
- * @param options.target {string} the absolute invocation target URL
36
- * @param options.controller {string} the invoking client's DID
37
- * @returns {IRootZcap}
38
- */
39
- export declare function rootCapability({ target, controller }: {
40
- target: string;
41
- controller: string;
42
- }): IRootZcap;
43
- /**
44
- * The URL of the Space a capability is rooted in, read off its delegation
45
- * chain: a Space-rooted capability's chain starts at the Space's root
46
- * capability, whose id encodes the Space URL. The result is in canonical
47
- * form.
48
- *
49
- * The root's target is taken to be the Space URL. A Space URL has no shape
50
- * of its own (a Collection URL is an http(s) URL ending in a slash too), so
51
- * this function cannot tell a chain rooted at a Space from one rooted at a
52
- * Collection, a Resource, or a Spaces Repository: only the server, which
53
- * knows its hierarchy, can, and it refuses a revocation whose chain does not
54
- * root exactly in the Space. What is refused here is a root whose target
55
- * cannot be a Space URL at all (an origin, a URL with a query, a URN) and a
56
- * chain that starts at no root capability. A capability this client minted
57
- * from a handle is always Space-rooted. A bare `was.grant({ target })` with
58
- * no `spaceUrl`, the mode for a server with no Space hierarchy, roots at
59
- * its target and is not revocable this way by design.
60
- *
61
- * @param zcap {IZcap} the capability to locate
62
- * @returns {string}
63
- * @throws {ValidationError} when the chain does not start at a root
64
- * capability id, or that id names something that cannot be a Space URL
65
- */
66
- export declare function spaceUrlOf(zcap: IZcap): string;
2
+ import type { IDelegatedZcap } from '../types.js';
67
3
  /**
68
4
  * Revokes a Space-rooted delegated capability: `POST`s it to
69
5
  * `{spaceUrl}zcaps/revocations/:capabilityId`, invoking that URL's own root
@@ -1 +1 @@
1
- {"version":3,"file":"revoke.d.ts","sourceRoot":"","sources":["../../src/internal/revoke.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAGjD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAYnE;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS9D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,UAAU,EACX,EAAE;IACD,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB,GAAG,SAAS,CAOZ;AA+BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAmB9C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GAC7D,OAAO,CAAC,IAAI,CAAC,CAgBf"}
1
+ {"version":3,"file":"revoke.d.ts","sourceRoot":"","sources":["../../src/internal/revoke.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAIjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GAC7D,OAAO,CAAC,IAAI,CAAC,CAgBf"}