@interop/was-client 0.12.0 → 0.13.1
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 +21 -0
- package/dist/Collection.d.ts +13 -0
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +61 -52
- package/dist/Collection.js.map +1 -1
- package/dist/Resource.d.ts +39 -25
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +89 -74
- package/dist/Resource.js.map +1 -1
- package/dist/Space.d.ts +43 -0
- package/dist/Space.d.ts.map +1 -1
- package/dist/Space.js +98 -56
- package/dist/Space.js.map +1 -1
- package/dist/WasClient.d.ts.map +1 -1
- package/dist/WasClient.js +33 -32
- package/dist/WasClient.js.map +1 -1
- package/dist/edv/EdvCodec.d.ts +8 -3
- package/dist/edv/EdvCodec.d.ts.map +1 -1
- package/dist/edv/EdvCodec.js +43 -31
- package/dist/edv/EdvCodec.js.map +1 -1
- package/dist/edv/WasTransport.d.ts +28 -10
- package/dist/edv/WasTransport.d.ts.map +1 -1
- package/dist/edv/WasTransport.js +66 -16
- package/dist/edv/WasTransport.js.map +1 -1
- package/dist/edv/constants.d.ts +8 -0
- package/dist/edv/constants.d.ts.map +1 -1
- package/dist/edv/constants.js +10 -0
- package/dist/edv/constants.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +10 -7
- package/dist/errors.js.map +1 -1
- package/dist/internal/codec.d.ts +6 -43
- package/dist/internal/codec.d.ts.map +1 -1
- package/dist/internal/codec.js +19 -40
- package/dist/internal/codec.js.map +1 -1
- package/dist/internal/conditional.d.ts +8 -3
- package/dist/internal/conditional.d.ts.map +1 -1
- package/dist/internal/conditional.js +5 -3
- package/dist/internal/conditional.js.map +1 -1
- package/dist/internal/content.d.ts +42 -8
- package/dist/internal/content.d.ts.map +1 -1
- package/dist/internal/content.js +70 -21
- package/dist/internal/content.js.map +1 -1
- package/dist/internal/grant.d.ts +20 -2
- package/dist/internal/grant.d.ts.map +1 -1
- package/dist/internal/grant.js +22 -2
- package/dist/internal/grant.js.map +1 -1
- package/dist/internal/pagination.d.ts +16 -0
- package/dist/internal/pagination.d.ts.map +1 -1
- package/dist/internal/pagination.js +21 -1
- package/dist/internal/pagination.js.map +1 -1
- package/dist/internal/paths.d.ts +48 -17
- package/dist/internal/paths.d.ts.map +1 -1
- package/dist/internal/paths.js +85 -6
- package/dist/internal/paths.js.map +1 -1
- package/dist/internal/request.d.ts +21 -12
- package/dist/internal/request.d.ts.map +1 -1
- package/dist/internal/request.js +22 -0
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/reserved.d.ts +8 -4
- package/dist/internal/reserved.d.ts.map +1 -1
- package/dist/internal/reserved.js +5 -4
- package/dist/internal/reserved.js.map +1 -1
- package/dist/internal/write.d.ts +47 -6
- package/dist/internal/write.d.ts.map +1 -1
- package/dist/internal/write.js +71 -1
- package/dist/internal/write.js.map +1 -1
- package/package.json +2 -2
package/dist/Resource.js
CHANGED
|
@@ -1,19 +1,47 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* A navigational handle to a single Resource (a JSON object or binary blob
|
|
6
|
+
* keyed by id within a Collection). Sugar over the Collection item operations,
|
|
7
|
+
* with explicit `getText()` / `getBytes()` escape hatches.
|
|
8
|
+
*/
|
|
1
9
|
import { resourcePath, resourcePolicy, resourceMeta } from './internal/paths.js';
|
|
2
10
|
import { assertNotReserved } from './internal/reserved.js';
|
|
3
11
|
import { send } from './internal/request.js';
|
|
4
|
-
import { CodecHolder, resolveCodec
|
|
12
|
+
import { CodecHolder, resolveCodec } from './internal/codec.js';
|
|
5
13
|
import { writeHeaders, readEtag } from './internal/conditional.js';
|
|
6
|
-
import {
|
|
14
|
+
import { upsertResource } from './internal/write.js';
|
|
7
15
|
import { readPolicy, writePolicy, deletePolicy } from './internal/policy.js';
|
|
16
|
+
/**
|
|
17
|
+
* A shared `TextEncoder` for re-serializing a pre-parsed JSON body to bytes in
|
|
18
|
+
* `getBytes()` (stateless, so one instance is reused).
|
|
19
|
+
*/
|
|
20
|
+
const ENCODER = new TextEncoder();
|
|
8
21
|
export class Resource {
|
|
9
22
|
spaceId;
|
|
10
23
|
collectionId;
|
|
11
24
|
id;
|
|
12
25
|
_context;
|
|
13
26
|
_capability;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Resolves the codec for this resource: the parent collection's shared codec
|
|
29
|
+
* when this handle came from `collection.resource(id)`, otherwise one
|
|
30
|
+
* resolved (and memoized per handle) for its own collection. A standalone
|
|
31
|
+
* resource discovers its collection's `encryption` marker (one GET on the
|
|
32
|
+
* collection, cached per handle) unless a per-handle override is set, and
|
|
33
|
+
* fails closed if it cannot key an encrypted collection. A fresh standalone
|
|
34
|
+
* handle re-reads the marker, so retain the handle to reuse it. A failed
|
|
35
|
+
* resolution (e.g. a transient 500/network error during marker discovery) is
|
|
36
|
+
* not memoized: the cache is cleared so the next call retries rather than
|
|
37
|
+
* re-throwing the stale error forever.
|
|
38
|
+
*
|
|
39
|
+
* A handle obtained via `collection.resource(id)` delegates to the parent's
|
|
40
|
+
* shared resolver on every call rather than memoizing locally: the parent
|
|
41
|
+
* already memoizes (so this adds no round-trip), and delegating lets a parent
|
|
42
|
+
* reset (e.g. after `configure()` adds the encryption marker) propagate here.
|
|
43
|
+
*/
|
|
44
|
+
_codec;
|
|
17
45
|
/**
|
|
18
46
|
* @param options {object}
|
|
19
47
|
* @param options.context {ClientContext}
|
|
@@ -38,53 +66,28 @@ export class Resource {
|
|
|
38
66
|
// collision exists for `backend` / `quota` / `linkset` / `meta`. Guarding in
|
|
39
67
|
// the constructor covers every operation (read, delete, meta, policy, put),
|
|
40
68
|
// not just writes.
|
|
41
|
-
assertNotReserved(resourceId, 'resource');
|
|
69
|
+
assertNotReserved({ id: resourceId, kind: 'resource' });
|
|
42
70
|
this._context = context;
|
|
43
71
|
this.spaceId = spaceId;
|
|
44
72
|
this.collectionId = collectionId;
|
|
45
73
|
this.id = resourceId;
|
|
46
74
|
this._capability = capability;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
override: this._encryptionOverride,
|
|
53
|
-
readMarker: () => readCollectionMarker(this._context, {
|
|
75
|
+
if (codec) {
|
|
76
|
+
this._codec = codec;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
const holder = new CodecHolder(() => resolveCodec(this._context, {
|
|
54
80
|
spaceId: this.spaceId,
|
|
55
81
|
collectionId: this.collectionId,
|
|
82
|
+
override: encryption,
|
|
56
83
|
capability: this._capability
|
|
57
|
-
})
|
|
58
|
-
|
|
84
|
+
}));
|
|
85
|
+
this._codec = () => holder.get();
|
|
86
|
+
}
|
|
59
87
|
}
|
|
60
88
|
get _path() {
|
|
61
89
|
return resourcePath(this.spaceId, this.collectionId, this.id);
|
|
62
90
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Resolves (once, then caches) the codec for this resource: the parent
|
|
65
|
-
* collection's shared codec when this handle came from
|
|
66
|
-
* `collection.resource(id)`, otherwise one resolved for its own collection. A
|
|
67
|
-
* standalone resource discovers its collection's `encryption` marker (one GET
|
|
68
|
-
* on the collection, cached per handle) unless a per-handle override is set,
|
|
69
|
-
* and fails closed if it cannot key an encrypted collection. A fresh
|
|
70
|
-
* standalone handle re-reads the marker, so retain the handle to reuse it. A
|
|
71
|
-
* failed resolution (e.g. a transient 500/network error during marker
|
|
72
|
-
* discovery) is not memoized: the cache is cleared so the next call retries
|
|
73
|
-
* rather than re-throwing the stale error forever.
|
|
74
|
-
*
|
|
75
|
-
* A handle obtained via `collection.resource(id)` delegates to the parent's
|
|
76
|
-
* shared thunk on every call rather than memoizing locally: the parent already
|
|
77
|
-
* memoizes (so this adds no round-trip), and delegating lets a parent reset
|
|
78
|
-
* (e.g. after `configure()` adds the encryption marker) propagate here.
|
|
79
|
-
*
|
|
80
|
-
* @returns {Promise<ResourceCodec>}
|
|
81
|
-
*/
|
|
82
|
-
_codec() {
|
|
83
|
-
if (this._codecThunk) {
|
|
84
|
-
return this._codecThunk();
|
|
85
|
-
}
|
|
86
|
-
return this._codecHolder.get();
|
|
87
|
-
}
|
|
88
91
|
/**
|
|
89
92
|
* Reads the resource, auto-parsing JSON to an object and returning binary as
|
|
90
93
|
* a `Blob`. Returns `null` if the resource is missing or not visible to you
|
|
@@ -108,6 +111,12 @@ export class Resource {
|
|
|
108
111
|
* codec, so on an encrypted collection it never decrypts -- use `get()` to
|
|
109
112
|
* decrypt.
|
|
110
113
|
*
|
|
114
|
+
* For a JSON content-type the request layer has already consumed and parsed
|
|
115
|
+
* the body stream (`@interop/http-client` offers no opt-out through ezcap),
|
|
116
|
+
* so the text is re-serialized from the parsed value: semantically identical
|
|
117
|
+
* JSON, but not guaranteed byte-identical to what was uploaded (insignificant
|
|
118
|
+
* whitespace is not preserved).
|
|
119
|
+
*
|
|
111
120
|
* @returns {Promise<string | null>}
|
|
112
121
|
*/
|
|
113
122
|
async getText() {
|
|
@@ -117,7 +126,13 @@ export class Resource {
|
|
|
117
126
|
capability: this._capability,
|
|
118
127
|
read: true
|
|
119
128
|
});
|
|
120
|
-
|
|
129
|
+
if (response === null) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
if (response.data !== undefined) {
|
|
133
|
+
return JSON.stringify(response.data);
|
|
134
|
+
}
|
|
135
|
+
return response.text();
|
|
121
136
|
}
|
|
122
137
|
/**
|
|
123
138
|
* Reads the resource body as raw bytes. Returns `null` on a
|
|
@@ -125,6 +140,12 @@ export class Resource {
|
|
|
125
140
|
* it does NOT run the codec, so on an encrypted collection it never decrypts
|
|
126
141
|
* -- use `get()` to decrypt.
|
|
127
142
|
*
|
|
143
|
+
* For a JSON content-type the request layer has already consumed and parsed
|
|
144
|
+
* the body stream (`@interop/http-client` offers no opt-out through ezcap),
|
|
145
|
+
* so the bytes are re-serialized from the parsed value: semantically
|
|
146
|
+
* identical JSON, but not guaranteed byte-identical to what was uploaded
|
|
147
|
+
* (insignificant whitespace is not preserved).
|
|
148
|
+
*
|
|
128
149
|
* @returns {Promise<Uint8Array | null>}
|
|
129
150
|
*/
|
|
130
151
|
async getBytes() {
|
|
@@ -137,6 +158,9 @@ export class Resource {
|
|
|
137
158
|
if (response === null) {
|
|
138
159
|
return null;
|
|
139
160
|
}
|
|
161
|
+
if (response.data !== undefined) {
|
|
162
|
+
return ENCODER.encode(JSON.stringify(response.data));
|
|
163
|
+
}
|
|
140
164
|
return new Uint8Array(await response.arrayBuffer());
|
|
141
165
|
}
|
|
142
166
|
/**
|
|
@@ -155,7 +179,10 @@ export class Resource {
|
|
|
155
179
|
* `ifNoneMatch: true` for a create-if-absent. A failed precondition throws
|
|
156
180
|
* `PreconditionFailedError` (412). On an encrypted collection these are managed
|
|
157
181
|
* automatically by the codec (the EDV `sequence` becomes the enforced ETag), so
|
|
158
|
-
* the explicit options are for plaintext collections
|
|
182
|
+
* the explicit options are for plaintext collections -- and because the codec
|
|
183
|
+
* pre-reads the current document to compute them, updating an existing
|
|
184
|
+
* encrypted document needs read access (a PUT-only capability can only create;
|
|
185
|
+
* see `upsertResource`). Returns the new `etag`.
|
|
159
186
|
*
|
|
160
187
|
* @param data {ResourceData}
|
|
161
188
|
* @param options {object}
|
|
@@ -166,35 +193,17 @@ export class Resource {
|
|
|
166
193
|
*/
|
|
167
194
|
async put(data, options = {}) {
|
|
168
195
|
const codec = await this._codec();
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
let current;
|
|
173
|
-
if (codec.conditionalWrites) {
|
|
174
|
-
current = await send(this._context, {
|
|
175
|
-
path: this._path,
|
|
176
|
-
method: 'GET',
|
|
177
|
-
capability: this._capability,
|
|
178
|
-
read: true
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
const encoded = await codec.encode({
|
|
196
|
+
const response = await upsertResource(this._context, {
|
|
197
|
+
path: this._path,
|
|
198
|
+
codec,
|
|
182
199
|
id: this.id,
|
|
183
200
|
data,
|
|
184
201
|
contentType: options.contentType,
|
|
185
|
-
current
|
|
186
|
-
});
|
|
187
|
-
// A conditional codec computes the precondition itself (from the sequence /
|
|
188
|
-
// ETag); a plaintext codec defers to the caller's explicit options.
|
|
189
|
-
const precondition = codec.conditionalWrites
|
|
190
|
-
? { ifMatch: encoded.ifMatch, ifNoneMatch: encoded.ifNoneMatch }
|
|
191
|
-
: { ifMatch: options.ifMatch, ifNoneMatch: options.ifNoneMatch };
|
|
192
|
-
const response = await sendEncodedWrite(this._context, {
|
|
193
|
-
path: this._path,
|
|
194
|
-
method: 'PUT',
|
|
195
202
|
capability: this._capability,
|
|
196
|
-
|
|
197
|
-
|
|
203
|
+
precondition: {
|
|
204
|
+
ifMatch: options.ifMatch,
|
|
205
|
+
ifNoneMatch: options.ifNoneMatch
|
|
206
|
+
}
|
|
198
207
|
});
|
|
199
208
|
return { etag: readEtag(response) };
|
|
200
209
|
}
|
|
@@ -215,7 +224,7 @@ export class Resource {
|
|
|
215
224
|
// A conditional delete is not idempotent: a stale `If-Match` must surface
|
|
216
225
|
// as a 412 rather than being swallowed as an absent-target success.
|
|
217
226
|
idempotent: options.ifMatch === undefined,
|
|
218
|
-
headers: writeHeaders(
|
|
227
|
+
headers: writeHeaders({ precondition: { ifMatch: options.ifMatch } })
|
|
219
228
|
});
|
|
220
229
|
}
|
|
221
230
|
get _metaPath() {
|
|
@@ -291,9 +300,11 @@ export class Resource {
|
|
|
291
300
|
method: 'PUT',
|
|
292
301
|
capability: this._capability,
|
|
293
302
|
json: { custom },
|
|
294
|
-
headers: writeHeaders(
|
|
295
|
-
|
|
296
|
-
|
|
303
|
+
headers: writeHeaders({
|
|
304
|
+
precondition: {
|
|
305
|
+
ifMatch: options.ifMatch,
|
|
306
|
+
ifNoneMatch: options.ifNoneMatch
|
|
307
|
+
}
|
|
297
308
|
})
|
|
298
309
|
});
|
|
299
310
|
return { etag: readEtag(response) };
|
|
@@ -301,24 +312,28 @@ export class Resource {
|
|
|
301
312
|
/**
|
|
302
313
|
* Sets the resource's human-readable `name` (the value surfaced in collection
|
|
303
314
|
* listings), preserving any existing `tags`. Convenience over `setMeta()`.
|
|
315
|
+
* The write is pinned to the `etag` the `meta()` read returned (when the
|
|
316
|
+
* backend supports `conditional-writes`), so a concurrent metadata write
|
|
317
|
+
* surfaces as `PreconditionFailedError` instead of being silently erased by
|
|
318
|
+
* this full-replacement write.
|
|
304
319
|
*
|
|
305
320
|
* @param name {string}
|
|
306
321
|
* @returns {Promise<void>}
|
|
307
322
|
*/
|
|
308
323
|
async setName(name) {
|
|
309
324
|
const current = await this.meta();
|
|
310
|
-
await this.setMeta({ custom: { ...current?.custom, name } });
|
|
325
|
+
await this.setMeta({ custom: { ...current?.custom, name } }, { ifMatch: current?.etag });
|
|
311
326
|
}
|
|
312
327
|
/**
|
|
313
328
|
* Sets the resource's `tags`, preserving any existing `name`. Convenience over
|
|
314
|
-
* `setMeta()`.
|
|
329
|
+
* `setMeta()`. Pinned to the `meta()` read's `etag` like {@link setName}.
|
|
315
330
|
*
|
|
316
331
|
* @param tags {Record<string, string>}
|
|
317
332
|
* @returns {Promise<void>}
|
|
318
333
|
*/
|
|
319
334
|
async setTags(tags) {
|
|
320
335
|
const current = await this.meta();
|
|
321
|
-
await this.setMeta({ custom: { ...current?.custom, tags } });
|
|
336
|
+
await this.setMeta({ custom: { ...current?.custom, tags } }, { ifMatch: current?.etag });
|
|
322
337
|
}
|
|
323
338
|
get _policyPath() {
|
|
324
339
|
return resourcePolicy(this.spaceId, this.collectionId, this.id);
|
package/dist/Resource.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Resource.js","sourceRoot":"","sources":["../src/Resource.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Resource.js","sourceRoot":"","sources":["../src/Resource.ts"],"names":[],"mappings":"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"}
|
package/dist/Space.d.ts
CHANGED
|
@@ -164,12 +164,55 @@ export declare class Space {
|
|
|
164
164
|
* @returns {Promise<IDelegatedZcap>}
|
|
165
165
|
*/
|
|
166
166
|
grant(options: GrantOptions): Promise<IDelegatedZcap>;
|
|
167
|
+
/**
|
|
168
|
+
* Sends the export request and returns the raw response with its body stream
|
|
169
|
+
* intact, shared by `export`/`exportBlob`/`exportStream`.
|
|
170
|
+
*
|
|
171
|
+
* Guards the JSON-mislabel edge: `@interop/http-client` pre-consumes a
|
|
172
|
+
* response body into `.data` for JSON content-types, so a non-conformant
|
|
173
|
+
* server that labels the tar archive `application/json` would leave us a dead
|
|
174
|
+
* stream. Detecting the consumed body here fails with a typed `WasServerError`
|
|
175
|
+
* naming the mislabeled content-type, rather than a raw "body stream already
|
|
176
|
+
* read" `TypeError` downstream.
|
|
177
|
+
*
|
|
178
|
+
* @returns {Promise<HttpResponse>}
|
|
179
|
+
*/
|
|
180
|
+
private _exportResponse;
|
|
167
181
|
/**
|
|
168
182
|
* Exports the whole space as a tar (`application/x-tar`) archive.
|
|
169
183
|
*
|
|
184
|
+
* The entire archive is buffered into memory (a `Uint8Array` cannot be
|
|
185
|
+
* produced incrementally), so exporting a very large space costs its full
|
|
186
|
+
* size in RAM. For a constant-memory path use {@link exportStream}; for the
|
|
187
|
+
* `import()` companion container use {@link exportBlob}.
|
|
188
|
+
*
|
|
170
189
|
* @returns {Promise<Uint8Array>}
|
|
171
190
|
*/
|
|
172
191
|
export(): Promise<Uint8Array>;
|
|
192
|
+
/**
|
|
193
|
+
* Exports the whole space as a tar (`application/x-tar`) archive, as a Blob
|
|
194
|
+
* typed `application/x-tar`. Pairs directly with `import(tar)`, so copying a
|
|
195
|
+
* space is `spaceB.import(await spaceA.exportBlob())`.
|
|
196
|
+
*
|
|
197
|
+
* Note: in Node a Blob is memory-backed, so this does not reduce peak memory
|
|
198
|
+
* versus {@link export} -- it is a typed-container convenience (browsers may
|
|
199
|
+
* spill large Blobs to disk). For the true constant-memory path use
|
|
200
|
+
* {@link exportStream}.
|
|
201
|
+
*
|
|
202
|
+
* @returns {Promise<Blob>}
|
|
203
|
+
*/
|
|
204
|
+
exportBlob(): Promise<Blob>;
|
|
205
|
+
/**
|
|
206
|
+
* Exports the whole space as a tar (`application/x-tar`) archive, as a lazily
|
|
207
|
+
* consumed byte stream -- constant memory, for piping to a file, a
|
|
208
|
+
* `CompressionStream`, or another request.
|
|
209
|
+
*
|
|
210
|
+
* The stream must be consumed or cancelled; an abandoned stream holds its
|
|
211
|
+
* connection open.
|
|
212
|
+
*
|
|
213
|
+
* @returns {Promise<ReadableStream<Uint8Array>>}
|
|
214
|
+
*/
|
|
215
|
+
exportStream(): Promise<ReadableStream<Uint8Array>>;
|
|
173
216
|
/**
|
|
174
217
|
* Imports (merges) a tar archive into the space.
|
|
175
218
|
*
|
package/dist/Space.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Space.d.ts","sourceRoot":"","sources":["../src/Space.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"Space.d.ts","sourceRoot":"","sources":["../src/Space.ts"],"names":[],"mappings":"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"}
|
package/dist/Space.js
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* A navigational handle to a Space. Exposes its own lifecycle
|
|
6
|
-
* (`describe`/`configure`/`delete`), contained Collections
|
|
7
|
-
* (`collection`/`createCollection`/`collections`), delegation (`grant`), and
|
|
8
|
-
* whole-space `export`/`import`.
|
|
9
|
-
*/
|
|
10
|
-
import { spacePath, spaceItems, spaceCollections, spaceExport, spaceImport, spaceBackends, registeredBackend, spaceQuotas, spacePolicy, spaceLinkset, toUrl } from './internal/paths.js';
|
|
1
|
+
import { spacePath, spaceItems, spaceCollections, spaceExport, spaceImport, spaceBackends, registeredBackend, spaceQuotas, spacePolicy, spaceLinkset } from './internal/paths.js';
|
|
11
2
|
import { assertNotReserved } from './internal/reserved.js';
|
|
12
|
-
import {
|
|
13
|
-
import { send } from './internal/request.js';
|
|
3
|
+
import { delegateGrantAt } from './internal/grant.js';
|
|
4
|
+
import { send, readData } from './internal/request.js';
|
|
5
|
+
import { WasServerError } from './errors.js';
|
|
14
6
|
import { createdId, dataOrNull, toPlainBytes } from './internal/content.js';
|
|
15
7
|
import { readPolicy, writePolicy, deletePolicy } from './internal/policy.js';
|
|
16
8
|
import { Collection } from './Collection.js';
|
|
@@ -42,13 +34,10 @@ export class Space {
|
|
|
42
34
|
* @returns {Promise<SpaceDescription | null>}
|
|
43
35
|
*/
|
|
44
36
|
async describe() {
|
|
45
|
-
|
|
37
|
+
return readData(this._context, {
|
|
46
38
|
path: this._path,
|
|
47
|
-
|
|
48
|
-
capability: this._capability,
|
|
49
|
-
read: true
|
|
39
|
+
capability: this._capability
|
|
50
40
|
});
|
|
51
|
-
return dataOrNull(response);
|
|
52
41
|
}
|
|
53
42
|
/**
|
|
54
43
|
* Creates or updates the space by id (upsert). Merges the given fields over
|
|
@@ -124,7 +113,7 @@ export class Space {
|
|
|
124
113
|
*/
|
|
125
114
|
async createCollection(desc = {}) {
|
|
126
115
|
if (desc.id !== undefined) {
|
|
127
|
-
assertNotReserved(desc.id, 'collection');
|
|
116
|
+
assertNotReserved({ id: desc.id, kind: 'collection' });
|
|
128
117
|
}
|
|
129
118
|
const body = {};
|
|
130
119
|
if (desc.id !== undefined) {
|
|
@@ -160,13 +149,10 @@ export class Space {
|
|
|
160
149
|
* @returns {Promise<CollectionsList | null>}
|
|
161
150
|
*/
|
|
162
151
|
async collections() {
|
|
163
|
-
|
|
152
|
+
return readData(this._context, {
|
|
164
153
|
path: spaceCollections(this.id),
|
|
165
|
-
|
|
166
|
-
capability: this._capability,
|
|
167
|
-
read: true
|
|
154
|
+
capability: this._capability
|
|
168
155
|
});
|
|
169
|
-
return dataOrNull(response);
|
|
170
156
|
}
|
|
171
157
|
/**
|
|
172
158
|
* Lists the storage backends available within this space. Returns `null` if
|
|
@@ -180,13 +166,10 @@ export class Space {
|
|
|
180
166
|
* @returns {Promise<BackendDescriptor[] | null>}
|
|
181
167
|
*/
|
|
182
168
|
async backends() {
|
|
183
|
-
|
|
169
|
+
return readData(this._context, {
|
|
184
170
|
path: spaceBackends(this.id),
|
|
185
|
-
|
|
186
|
-
capability: this._capability,
|
|
187
|
-
read: true
|
|
171
|
+
capability: this._capability
|
|
188
172
|
});
|
|
189
|
-
return dataOrNull(response);
|
|
190
173
|
}
|
|
191
174
|
/**
|
|
192
175
|
* Registers a new `external` ("Bring Your Own Storage") backend against this
|
|
@@ -213,7 +196,8 @@ export class Space {
|
|
|
213
196
|
capability: this._capability,
|
|
214
197
|
json: registration
|
|
215
198
|
});
|
|
216
|
-
|
|
199
|
+
// A successful registration always carries the sanitized descriptor body.
|
|
200
|
+
return dataOrNull(response);
|
|
217
201
|
}
|
|
218
202
|
/**
|
|
219
203
|
* Creates or replaces a registered `external` backend by id
|
|
@@ -240,9 +224,8 @@ export class Space {
|
|
|
240
224
|
json: registration
|
|
241
225
|
});
|
|
242
226
|
// 201 (create) carries the sanitized descriptor; 204 (in-place replace)
|
|
243
|
-
// carries no body,
|
|
244
|
-
return (response
|
|
245
|
-
null);
|
|
227
|
+
// carries no body, which `dataOrNull` maps to `null`.
|
|
228
|
+
return dataOrNull(response);
|
|
246
229
|
}
|
|
247
230
|
/**
|
|
248
231
|
* Deregisters (forgets) a registered `external` backend by id
|
|
@@ -279,13 +262,10 @@ export class Space {
|
|
|
279
262
|
const path = includeCollections
|
|
280
263
|
? `${spaceQuotas(this.id)}?include=collections`
|
|
281
264
|
: spaceQuotas(this.id);
|
|
282
|
-
|
|
265
|
+
return readData(this._context, {
|
|
283
266
|
path,
|
|
284
|
-
|
|
285
|
-
capability: this._capability,
|
|
286
|
-
read: true
|
|
267
|
+
capability: this._capability
|
|
287
268
|
});
|
|
288
|
-
return dataOrNull(response);
|
|
289
269
|
}
|
|
290
270
|
/**
|
|
291
271
|
* Delegates access to this space. Prefills the grant `target` with this
|
|
@@ -295,27 +275,91 @@ export class Space {
|
|
|
295
275
|
* @returns {Promise<IDelegatedZcap>}
|
|
296
276
|
*/
|
|
297
277
|
async grant(options) {
|
|
298
|
-
return
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
capability: options.capability ?? this._capability
|
|
278
|
+
return delegateGrantAt(this._context, {
|
|
279
|
+
path: this._path,
|
|
280
|
+
options,
|
|
281
|
+
capability: this._capability
|
|
303
282
|
});
|
|
304
283
|
}
|
|
305
284
|
/**
|
|
306
|
-
*
|
|
285
|
+
* Sends the export request and returns the raw response with its body stream
|
|
286
|
+
* intact, shared by `export`/`exportBlob`/`exportStream`.
|
|
307
287
|
*
|
|
308
|
-
*
|
|
288
|
+
* Guards the JSON-mislabel edge: `@interop/http-client` pre-consumes a
|
|
289
|
+
* response body into `.data` for JSON content-types, so a non-conformant
|
|
290
|
+
* server that labels the tar archive `application/json` would leave us a dead
|
|
291
|
+
* stream. Detecting the consumed body here fails with a typed `WasServerError`
|
|
292
|
+
* naming the mislabeled content-type, rather than a raw "body stream already
|
|
293
|
+
* read" `TypeError` downstream.
|
|
294
|
+
*
|
|
295
|
+
* @returns {Promise<HttpResponse>}
|
|
309
296
|
*/
|
|
310
|
-
async
|
|
311
|
-
const response = await send(this._context, {
|
|
297
|
+
async _exportResponse() {
|
|
298
|
+
const response = (await send(this._context, {
|
|
312
299
|
path: spaceExport(this.id),
|
|
313
300
|
method: 'POST',
|
|
314
301
|
capability: this._capability
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
302
|
+
// A successful export always returns a response (errors throw via send()).
|
|
303
|
+
}));
|
|
304
|
+
if (response.bodyUsed || response.data !== undefined) {
|
|
305
|
+
const contentType = response.headers.get('content-type') ?? 'an unknown content-type';
|
|
306
|
+
throw new WasServerError(`Export response body was already consumed (mislabeled as ` +
|
|
307
|
+
`${contentType}); expected application/x-tar.`);
|
|
308
|
+
}
|
|
309
|
+
return response;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Exports the whole space as a tar (`application/x-tar`) archive.
|
|
313
|
+
*
|
|
314
|
+
* The entire archive is buffered into memory (a `Uint8Array` cannot be
|
|
315
|
+
* produced incrementally), so exporting a very large space costs its full
|
|
316
|
+
* size in RAM. For a constant-memory path use {@link exportStream}; for the
|
|
317
|
+
* `import()` companion container use {@link exportBlob}.
|
|
318
|
+
*
|
|
319
|
+
* @returns {Promise<Uint8Array>}
|
|
320
|
+
*/
|
|
321
|
+
async export() {
|
|
322
|
+
const response = await this._exportResponse();
|
|
323
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Exports the whole space as a tar (`application/x-tar`) archive, as a Blob
|
|
327
|
+
* typed `application/x-tar`. Pairs directly with `import(tar)`, so copying a
|
|
328
|
+
* space is `spaceB.import(await spaceA.exportBlob())`.
|
|
329
|
+
*
|
|
330
|
+
* Note: in Node a Blob is memory-backed, so this does not reduce peak memory
|
|
331
|
+
* versus {@link export} -- it is a typed-container convenience (browsers may
|
|
332
|
+
* spill large Blobs to disk). For the true constant-memory path use
|
|
333
|
+
* {@link exportStream}.
|
|
334
|
+
*
|
|
335
|
+
* @returns {Promise<Blob>}
|
|
336
|
+
*/
|
|
337
|
+
async exportBlob() {
|
|
338
|
+
const blob = await (await this._exportResponse()).blob();
|
|
339
|
+
// Normalize the type: some servers omit or mislabel the content-type, and
|
|
340
|
+
// `Blob.type` is load-bearing for `import()` / anchor-download flows.
|
|
341
|
+
return blob.type === 'application/x-tar'
|
|
342
|
+
? blob
|
|
343
|
+
: new Blob([blob], { type: 'application/x-tar' });
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Exports the whole space as a tar (`application/x-tar`) archive, as a lazily
|
|
347
|
+
* consumed byte stream -- constant memory, for piping to a file, a
|
|
348
|
+
* `CompressionStream`, or another request.
|
|
349
|
+
*
|
|
350
|
+
* The stream must be consumed or cancelled; an abandoned stream holds its
|
|
351
|
+
* connection open.
|
|
352
|
+
*
|
|
353
|
+
* @returns {Promise<ReadableStream<Uint8Array>>}
|
|
354
|
+
*/
|
|
355
|
+
async exportStream() {
|
|
356
|
+
const response = await this._exportResponse();
|
|
357
|
+
if (response.body === null) {
|
|
358
|
+
// A body-less 2xx (204, or an exotic fetch impl) -- fail with a typed
|
|
359
|
+
// error rather than returning a null stream.
|
|
360
|
+
throw new WasServerError('Export response carried no body stream.');
|
|
361
|
+
}
|
|
362
|
+
return response.body;
|
|
319
363
|
}
|
|
320
364
|
/**
|
|
321
365
|
* Imports (merges) a tar archive into the space.
|
|
@@ -332,7 +376,8 @@ export class Space {
|
|
|
332
376
|
body,
|
|
333
377
|
headers: { 'content-type': 'application/x-tar' }
|
|
334
378
|
});
|
|
335
|
-
|
|
379
|
+
// A successful import always carries the stats body.
|
|
380
|
+
return dataOrNull(response);
|
|
336
381
|
}
|
|
337
382
|
/**
|
|
338
383
|
* Reads the space's access-control policy. Returns `null` when no policy is
|
|
@@ -399,13 +444,10 @@ export class Space {
|
|
|
399
444
|
* @returns {Promise<LinkSet | null>}
|
|
400
445
|
*/
|
|
401
446
|
async linkset() {
|
|
402
|
-
|
|
447
|
+
return readData(this._context, {
|
|
403
448
|
path: spaceLinkset(this.id),
|
|
404
|
-
|
|
405
|
-
capability: this._capability,
|
|
406
|
-
read: true
|
|
449
|
+
capability: this._capability
|
|
407
450
|
});
|
|
408
|
-
return dataOrNull(response);
|
|
409
451
|
}
|
|
410
452
|
}
|
|
411
453
|
//# sourceMappingURL=Space.js.map
|