@interop/was-client 0.12.0 → 0.13.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 (68) hide show
  1. package/README.md +21 -0
  2. package/dist/Collection.d.ts +13 -0
  3. package/dist/Collection.d.ts.map +1 -1
  4. package/dist/Collection.js +61 -52
  5. package/dist/Collection.js.map +1 -1
  6. package/dist/Resource.d.ts +39 -25
  7. package/dist/Resource.d.ts.map +1 -1
  8. package/dist/Resource.js +89 -74
  9. package/dist/Resource.js.map +1 -1
  10. package/dist/Space.d.ts +43 -0
  11. package/dist/Space.d.ts.map +1 -1
  12. package/dist/Space.js +98 -56
  13. package/dist/Space.js.map +1 -1
  14. package/dist/WasClient.d.ts.map +1 -1
  15. package/dist/WasClient.js +33 -32
  16. package/dist/WasClient.js.map +1 -1
  17. package/dist/edv/EdvCodec.d.ts +8 -3
  18. package/dist/edv/EdvCodec.d.ts.map +1 -1
  19. package/dist/edv/EdvCodec.js +43 -31
  20. package/dist/edv/EdvCodec.js.map +1 -1
  21. package/dist/edv/WasTransport.d.ts +28 -10
  22. package/dist/edv/WasTransport.d.ts.map +1 -1
  23. package/dist/edv/WasTransport.js +66 -16
  24. package/dist/edv/WasTransport.js.map +1 -1
  25. package/dist/edv/constants.d.ts +8 -0
  26. package/dist/edv/constants.d.ts.map +1 -1
  27. package/dist/edv/constants.js +10 -0
  28. package/dist/edv/constants.js.map +1 -1
  29. package/dist/errors.d.ts.map +1 -1
  30. package/dist/errors.js +10 -7
  31. package/dist/errors.js.map +1 -1
  32. package/dist/internal/codec.d.ts +6 -43
  33. package/dist/internal/codec.d.ts.map +1 -1
  34. package/dist/internal/codec.js +19 -40
  35. package/dist/internal/codec.js.map +1 -1
  36. package/dist/internal/conditional.d.ts +8 -3
  37. package/dist/internal/conditional.d.ts.map +1 -1
  38. package/dist/internal/conditional.js +5 -3
  39. package/dist/internal/conditional.js.map +1 -1
  40. package/dist/internal/content.d.ts +42 -8
  41. package/dist/internal/content.d.ts.map +1 -1
  42. package/dist/internal/content.js +70 -21
  43. package/dist/internal/content.js.map +1 -1
  44. package/dist/internal/grant.d.ts +20 -2
  45. package/dist/internal/grant.d.ts.map +1 -1
  46. package/dist/internal/grant.js +22 -2
  47. package/dist/internal/grant.js.map +1 -1
  48. package/dist/internal/pagination.d.ts +16 -0
  49. package/dist/internal/pagination.d.ts.map +1 -1
  50. package/dist/internal/pagination.js +21 -1
  51. package/dist/internal/pagination.js.map +1 -1
  52. package/dist/internal/paths.d.ts +48 -17
  53. package/dist/internal/paths.d.ts.map +1 -1
  54. package/dist/internal/paths.js +85 -6
  55. package/dist/internal/paths.js.map +1 -1
  56. package/dist/internal/request.d.ts +21 -12
  57. package/dist/internal/request.d.ts.map +1 -1
  58. package/dist/internal/request.js +22 -0
  59. package/dist/internal/request.js.map +1 -1
  60. package/dist/internal/reserved.d.ts +8 -4
  61. package/dist/internal/reserved.d.ts.map +1 -1
  62. package/dist/internal/reserved.js +5 -4
  63. package/dist/internal/reserved.js.map +1 -1
  64. package/dist/internal/write.d.ts +47 -6
  65. package/dist/internal/write.d.ts.map +1 -1
  66. package/dist/internal/write.js +71 -1
  67. package/dist/internal/write.js.map +1 -1
  68. package/package.json +1 -1
@@ -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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"}
@@ -2,10 +2,14 @@
2
2
  * Throws a `ValidationError` if the given id collides with a reserved path
3
3
  * segment for its kind.
4
4
  *
5
- * @param id {string} the proposed collection or resource id
6
- * @param kind {string} 'collection' or 'resource', selects the reserved set
7
- * and is used in the message
5
+ * @param options {object}
6
+ * @param options.id {string} the proposed collection or resource id
7
+ * @param options.kind {string} 'collection' or 'resource', selects the
8
+ * reserved set and is used in the message
8
9
  * @returns {void}
9
10
  */
10
- export declare function assertNotReserved(id: string, kind: 'collection' | 'resource'): void;
11
+ export declare function assertNotReserved({ id, kind }: {
12
+ id: string;
13
+ kind: 'collection' | 'resource';
14
+ }): void;
11
15
  //# sourceMappingURL=reserved.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reserved.d.ts","sourceRoot":"","sources":["../../src/internal/reserved.ts"],"names":[],"mappings":"AAmBA;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,YAAY,GAAG,UAAU,GAC9B,IAAI,CAQN"}
1
+ {"version":3,"file":"reserved.d.ts","sourceRoot":"","sources":["../../src/internal/reserved.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;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"}
@@ -16,12 +16,13 @@ import { ValidationError } from '../errors.js';
16
16
  * Throws a `ValidationError` if the given id collides with a reserved path
17
17
  * segment for its kind.
18
18
  *
19
- * @param id {string} the proposed collection or resource id
20
- * @param kind {string} 'collection' or 'resource', selects the reserved set
21
- * and is used in the message
19
+ * @param options {object}
20
+ * @param options.id {string} the proposed collection or resource id
21
+ * @param options.kind {string} 'collection' or 'resource', selects the
22
+ * reserved set and is used in the message
22
23
  * @returns {void}
23
24
  */
24
- export function assertNotReserved(id, kind) {
25
+ export function assertNotReserved({ id, kind }) {
25
26
  const reserved = kind === 'collection' ? RESERVED_COLLECTION_IDS : RESERVED_RESOURCE_IDS;
26
27
  if (reserved.has(id)) {
27
28
  throw new ValidationError(`Cannot use reserved path segment "${id}" as a ${kind} id.`);
@@ -1 +1 @@
1
- {"version":3,"file":"reserved.js","sourceRoot":"","sources":["../../src/internal/reserved.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AACH,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,EAAU,EACV,IAA+B;IAE/B,MAAM,QAAQ,GACZ,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,qBAAqB,CAAA;IACzE,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QACrB,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;;;;;;;;GAQG;AACH,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,EAAE,EACF,IAAI,EAIL;IACC,MAAM,QAAQ,GACZ,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,qBAAqB,CAAA;IACzE,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,eAAe,CACvB,qCAAqC,EAAE,UAAU,IAAI,MAAM,CAC5D,CAAA;IACH,CAAC;AACH,CAAC"}
@@ -2,14 +2,17 @@
2
2
  * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
3
  */
4
4
  /**
5
- * The shared write orchestration: turn a codec's {@link EncodedWrite} plus a
6
- * conditional-write precondition into request headers and send it. Captures the
7
- * `writeHeaders(...) + send(...)` shape that `Collection.add` and `Resource.put`
8
- * would otherwise each re-implement.
5
+ * The shared write orchestration. `sendEncodedWrite` turns a codec's
6
+ * {@link EncodedWrite} plus a conditional-write precondition into request
7
+ * headers and sends it (the shape `Collection.add` and `Resource.put` would
8
+ * otherwise each re-implement). `upsertResource` layers the upsert flow on
9
+ * top: the conditional-codec pre-read of the current document, the
10
+ * codec-vs-caller precondition selection, and the masked-404 policy for a
11
+ * document that exists but is not readable with the bound capability.
9
12
  */
10
13
  import type { HttpResponse } from '@interop/http-client';
11
- import type { EncodedWrite } from '../codec.js';
12
- import type { IZcap } from '../types.js';
14
+ import type { EncodedWrite, ResourceCodec } from '../codec.js';
15
+ import type { IZcap, ResourceData } from '../types.js';
13
16
  import type { ClientContext } from './request.js';
14
17
  import type { WritePrecondition } from './conditional.js';
15
18
  /**
@@ -34,4 +37,42 @@ export declare function sendEncodedWrite(context: ClientContext, { path, method,
34
37
  capability?: IZcap;
35
38
  precondition?: WritePrecondition;
36
39
  }): Promise<HttpResponse>;
40
+ /**
41
+ * Creates or replaces a resource by id (upsert) through its codec, owning the
42
+ * conditional-write orchestration in one place:
43
+ *
44
+ * - A conditional codec (e.g. the EDV codec) needs the current stored document
45
+ * to advance its sequence and pin the write to the current ETag, so the
46
+ * current document is pre-read; the codec then computes the precondition
47
+ * itself. A plaintext codec needs no pre-read and defers to the caller's
48
+ * explicit precondition.
49
+ * - The pre-read cannot distinguish "absent" from "unreadable with this
50
+ * capability" (WAS masks unauthorized reads as 404), so a conditional codec
51
+ * encodes a fresh insert (`If-None-Match: *`) in both cases. When the target
52
+ * in fact exists, a conditional-writes backend rejects that insert with 412;
53
+ * that 412 is re-thrown here with a message naming the real cause, instead
54
+ * of surfacing as an inexplicable failed create. Conditional codecs
55
+ * therefore need read access to update an existing document.
56
+ *
57
+ * @param context {ClientContext}
58
+ * @param options {object}
59
+ * @param options.path {string} the resource path to write
60
+ * @param options.codec {ResourceCodec} the collection's resolved codec
61
+ * @param options.id {string} the resource id
62
+ * @param options.data {ResourceData} the plaintext value
63
+ * @param [options.contentType] {string} caller-supplied content type
64
+ * @param [options.capability] {IZcap}
65
+ * @param [options.precondition] {WritePrecondition} the caller's explicit
66
+ * precondition (used only for a non-conditional codec)
67
+ * @returns {Promise<HttpResponse>}
68
+ */
69
+ export declare function upsertResource(context: ClientContext, { path, codec, id, data, contentType, capability, precondition }: {
70
+ path: string;
71
+ codec: ResourceCodec;
72
+ id: string;
73
+ data: ResourceData;
74
+ contentType?: string;
75
+ capability?: IZcap;
76
+ precondition?: WritePrecondition;
77
+ }): Promise<HttpResponse>;
37
78
  //# sourceMappingURL=write.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/internal/write.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;GAKG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAGjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEzD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,EACE,IAAI,EACJ,MAAM,EACN,OAAO,EACP,UAAU,EACV,YAAY,EACb,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,YAAY,CAAA;IACrB,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,YAAY,CAAC,EAAE,iBAAiB,CAAA;CACjC,GACA,OAAO,CAAC,YAAY,CAAC,CAUvB"}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/internal/write.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE9D,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAGjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEzD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,EACE,IAAI,EACJ,MAAM,EACN,OAAO,EACP,UAAU,EACV,YAAY,EACb,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,YAAY,CAAA;IACrB,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,YAAY,CAAC,EAAE,iBAAiB,CAAA;CACjC,GACA,OAAO,CAAC,YAAY,CAAC,CAUvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,aAAa,EACtB,EACE,IAAI,EACJ,KAAK,EACL,EAAE,EACF,IAAI,EACJ,WAAW,EACX,UAAU,EACV,YAAY,EACb,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,aAAa,CAAA;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,YAAY,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,YAAY,CAAC,EAAE,iBAAiB,CAAA;CACjC,GACA,OAAO,CAAC,YAAY,CAAC,CA2CvB"}
@@ -1,3 +1,4 @@
1
+ import { PreconditionFailedError } from '../errors.js';
1
2
  import { send } from './request.js';
2
3
  import { writeHeaders } from './conditional.js';
3
4
  /**
@@ -22,8 +23,77 @@ export async function sendEncodedWrite(context, { path, method, encoded, capabil
22
23
  capability,
23
24
  json: encoded.json,
24
25
  body: encoded.body,
25
- headers: writeHeaders(encoded.contentType, precondition)
26
+ headers: writeHeaders({ contentType: encoded.contentType, precondition })
26
27
  });
27
28
  return response;
28
29
  }
30
+ /**
31
+ * Creates or replaces a resource by id (upsert) through its codec, owning the
32
+ * conditional-write orchestration in one place:
33
+ *
34
+ * - A conditional codec (e.g. the EDV codec) needs the current stored document
35
+ * to advance its sequence and pin the write to the current ETag, so the
36
+ * current document is pre-read; the codec then computes the precondition
37
+ * itself. A plaintext codec needs no pre-read and defers to the caller's
38
+ * explicit precondition.
39
+ * - The pre-read cannot distinguish "absent" from "unreadable with this
40
+ * capability" (WAS masks unauthorized reads as 404), so a conditional codec
41
+ * encodes a fresh insert (`If-None-Match: *`) in both cases. When the target
42
+ * in fact exists, a conditional-writes backend rejects that insert with 412;
43
+ * that 412 is re-thrown here with a message naming the real cause, instead
44
+ * of surfacing as an inexplicable failed create. Conditional codecs
45
+ * therefore need read access to update an existing document.
46
+ *
47
+ * @param context {ClientContext}
48
+ * @param options {object}
49
+ * @param options.path {string} the resource path to write
50
+ * @param options.codec {ResourceCodec} the collection's resolved codec
51
+ * @param options.id {string} the resource id
52
+ * @param options.data {ResourceData} the plaintext value
53
+ * @param [options.contentType] {string} caller-supplied content type
54
+ * @param [options.capability] {IZcap}
55
+ * @param [options.precondition] {WritePrecondition} the caller's explicit
56
+ * precondition (used only for a non-conditional codec)
57
+ * @returns {Promise<HttpResponse>}
58
+ */
59
+ export async function upsertResource(context, { path, codec, id, data, contentType, capability, precondition }) {
60
+ let current;
61
+ if (codec.conditionalWrites) {
62
+ current = await send(context, {
63
+ path,
64
+ method: 'GET',
65
+ capability,
66
+ read: true
67
+ });
68
+ }
69
+ const encoded = await codec.encode({ id, data, contentType, current });
70
+ // A conditional codec computes the precondition itself (from the sequence /
71
+ // ETag); a plaintext codec defers to the caller's explicit options.
72
+ const chosen = codec.conditionalWrites
73
+ ? { ifMatch: encoded.ifMatch, ifNoneMatch: encoded.ifNoneMatch }
74
+ : precondition;
75
+ try {
76
+ return await sendEncodedWrite(context, {
77
+ path,
78
+ method: 'PUT',
79
+ capability,
80
+ encoded,
81
+ precondition: chosen
82
+ });
83
+ }
84
+ catch (err) {
85
+ if (err instanceof PreconditionFailedError &&
86
+ codec.conditionalWrites &&
87
+ current === null) {
88
+ const { status, type, title, details, requestUrl } = err;
89
+ throw new PreconditionFailedError(`Cannot update the document at "${path}": it exists, but its current ` +
90
+ 'version is not readable with this capability (WAS masks ' +
91
+ 'unauthorized reads as 404), so the write was encoded as a fresh ' +
92
+ 'insert and the server rejected it. A conditional-writes codec ' +
93
+ '(e.g. the EDV codec) needs read access to update an existing ' +
94
+ 'document.', { status, type, title, details, requestUrl, cause: err });
95
+ }
96
+ throw err;
97
+ }
98
+ }
29
99
  //# sourceMappingURL=write.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/internal/write.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAG/C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAsB,EACtB,EACE,IAAI,EACJ,MAAM,EACN,OAAO,EACP,UAAU,EACV,YAAY,EAOb;IAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE;QACnC,IAAI;QACJ,MAAM;QACN,UAAU;QACV,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC;KACzD,CAAC,CAAA;IACF,OAAO,QAAwB,CAAA;AACjC,CAAC"}
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/internal/write.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAGtD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAG/C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAsB,EACtB,EACE,IAAI,EACJ,MAAM,EACN,OAAO,EACP,UAAU,EACV,YAAY,EAOb;IAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE;QACnC,IAAI;QACJ,MAAM;QACN,UAAU;QACV,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,OAAO,EAAE,YAAY,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,YAAY,EAAE,CAAC;KAC1E,CAAC,CAAA;IACF,OAAO,QAAwB,CAAA;AACjC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAsB,EACtB,EACE,IAAI,EACJ,KAAK,EACL,EAAE,EACF,IAAI,EACJ,WAAW,EACX,UAAU,EACV,YAAY,EASb;IAED,IAAI,OAAwC,CAAA;IAC5C,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC5B,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE;YAC5B,IAAI;YACJ,MAAM,EAAE,KAAK;YACb,UAAU;YACV,IAAI,EAAE,IAAI;SACX,CAAC,CAAA;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAA;IACtE,4EAA4E;IAC5E,oEAAoE;IACpE,MAAM,MAAM,GAAG,KAAK,CAAC,iBAAiB;QACpC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE;QAChE,CAAC,CAAC,YAAY,CAAA;IAChB,IAAI,CAAC;QACH,OAAO,MAAM,gBAAgB,CAAC,OAAO,EAAE;YACrC,IAAI;YACJ,MAAM,EAAE,KAAK;YACb,UAAU;YACV,OAAO;YACP,YAAY,EAAE,MAAM;SACrB,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IACE,GAAG,YAAY,uBAAuB;YACtC,KAAK,CAAC,iBAAiB;YACvB,OAAO,KAAK,IAAI,EAChB,CAAC;YACD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,GAAG,CAAA;YACxD,MAAM,IAAI,uBAAuB,CAC/B,kCAAkC,IAAI,gCAAgC;gBACpE,0DAA0D;gBAC1D,kEAAkE;gBAClE,gEAAgE;gBAChE,+DAA+D;gBAC/D,WAAW,EACb,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,CACzD,CAAA;QACH,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC"}
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.12.0",
4
+ "version": "0.13.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "pnpm run clear && tsc",