@haverstack/wire-types 0.40.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth.d.ts +67 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +34 -0
- package/dist/auth.js.map +1 -0
- package/dist/change-feed.d.ts +92 -0
- package/dist/change-feed.d.ts.map +1 -0
- package/dist/change-feed.js +69 -0
- package/dist/change-feed.js.map +1 -0
- package/dist/discovery.d.ts +73 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +74 -0
- package/dist/discovery.js.map +1 -0
- package/dist/errors.d.ts +68 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +151 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +22 -440
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -393
- package/dist/index.js.map +1 -1
- package/dist/installs.d.ts +37 -0
- package/dist/installs.d.ts.map +1 -0
- package/dist/installs.js +11 -0
- package/dist/installs.js.map +1 -0
- package/dist/journal.d.ts +50 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +30 -0
- package/dist/journal.js.map +1 -0
- package/dist/records.d.ts +81 -0
- package/dist/records.d.ts.map +1 -0
- package/dist/records.js +76 -0
- package/dist/records.js.map +1 -0
- package/package.json +2 -2
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication handshake
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* How a server advertises token issuance, the challenge–response bodies,
|
|
5
|
+
* and the handshake's own error vocabulary.
|
|
6
|
+
* See docs/spec/wire-format.md § Authentication.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* How a token can be earned here. Absent means only a scheme arranged out
|
|
10
|
+
* of band, which a client learns at open() rather than as a 404 partway
|
|
11
|
+
* through a handshake. An object so a consent flow can arrive as another
|
|
12
|
+
* entry. See docs/spec/wire-format.md § Advertising it.
|
|
13
|
+
*/
|
|
14
|
+
export type DiscoveryAuth = {
|
|
15
|
+
methods: AuthMethod[];
|
|
16
|
+
};
|
|
17
|
+
/** The challenge–response handshake of docs/spec/wire-format.md § Authentication. */
|
|
18
|
+
export declare const AUTH_METHOD_DID_CHALLENGE = "did-challenge";
|
|
19
|
+
export type AuthMethod = typeof AUTH_METHOD_DID_CHALLENGE;
|
|
20
|
+
/** Whether a server advertises the DID challenge–response handshake. */
|
|
21
|
+
export declare function supportsDidChallenge(discovery: {
|
|
22
|
+
auth?: DiscoveryAuth;
|
|
23
|
+
}): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* The two request bodies, re-exported from `@haverstack/core/wire`, whose
|
|
26
|
+
* parsers return them — one definition, as with `parseDate`.
|
|
27
|
+
*/
|
|
28
|
+
export type { WireAuthChallengeRequest, WireAuthTokenRequest } from '@haverstack/core/wire';
|
|
29
|
+
/** POST /auth/challenge response. */
|
|
30
|
+
export type WireAuthChallengeResponse = {
|
|
31
|
+
/** Opaque, single-use, base64url-charset. Bound to the requested DID. */
|
|
32
|
+
nonce: string;
|
|
33
|
+
expiresAt: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* POST /auth/token response. Both identities are always present, and this
|
|
37
|
+
* endpoint always reports them equal — a handshake proves key possession,
|
|
38
|
+
* which says nothing about whom that key may act for. The pair is reported
|
|
39
|
+
* anyway so an issuance path that does delegate needs no new shape.
|
|
40
|
+
* See docs/spec/wire-format.md § Authentication.
|
|
41
|
+
*/
|
|
42
|
+
export type WireAuthTokenResponse = {
|
|
43
|
+
token: string;
|
|
44
|
+
expiresAt?: string;
|
|
45
|
+
principalId: string;
|
|
46
|
+
subjectId: string;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Auth failures have their own vocabulary, deliberately outside
|
|
50
|
+
* WireErrorCode: no Stack operation has begun, so none of them is a
|
|
51
|
+
* StackError and none has a class to reconstruct. The split a client acts
|
|
52
|
+
* on is retryable versus fatal — a stale nonce warrants a fresh handshake,
|
|
53
|
+
* a rejected signature never will.
|
|
54
|
+
*/
|
|
55
|
+
export type WireAuthErrorCode = 'invalid_did' | 'unknown_nonce' | 'expired_nonce' | 'invalid_signature';
|
|
56
|
+
export type WireAuthError = {
|
|
57
|
+
error: {
|
|
58
|
+
code: WireAuthErrorCode;
|
|
59
|
+
message: string;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export declare const WIRE_AUTH_ERROR_STATUS: Record<WireAuthErrorCode, number>;
|
|
63
|
+
/** Type guard: does this parsed JSON body look like a WireAuthError? */
|
|
64
|
+
export declare function isWireAuthError(body: unknown): body is WireAuthError;
|
|
65
|
+
/** Whether retrying the handshake from a fresh nonce could succeed. */
|
|
66
|
+
export declare function isRetryableAuthError(code: WireAuthErrorCode): boolean;
|
|
67
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,yBAAyB,kBAAkB,CAAC;AAEzD,MAAM,MAAM,UAAU,GAAG,OAAO,yBAAyB,CAAC;AAE1D,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,SAAS,EAAE;IAAE,IAAI,CAAC,EAAE,aAAa,CAAA;CAAE,GAAG,OAAO,CAEjF;AAED;;;GAGG;AACH,YAAY,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE5F,qCAAqC;AACrC,MAAM,MAAM,yBAAyB,GAAG;IACtC,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GACzB,aAAa,GACb,eAAe,GACf,eAAe,GACf,mBAAmB,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE;QACL,IAAI,EAAE,iBAAiB,CAAC;QACxB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAOpE,CAAC;AAOF,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,aAAa,CAEpE;AAED,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAErE"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication handshake
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* How a server advertises token issuance, the challenge–response bodies,
|
|
5
|
+
* and the handshake's own error vocabulary.
|
|
6
|
+
* See docs/spec/wire-format.md § Authentication.
|
|
7
|
+
*/
|
|
8
|
+
import { hasErrorBody } from './errors.js';
|
|
9
|
+
/** The challenge–response handshake of docs/spec/wire-format.md § Authentication. */
|
|
10
|
+
export const AUTH_METHOD_DID_CHALLENGE = 'did-challenge';
|
|
11
|
+
/** Whether a server advertises the DID challenge–response handshake. */
|
|
12
|
+
export function supportsDidChallenge(discovery) {
|
|
13
|
+
return discovery.auth?.methods?.includes(AUTH_METHOD_DID_CHALLENGE) ?? false;
|
|
14
|
+
}
|
|
15
|
+
export const WIRE_AUTH_ERROR_STATUS = {
|
|
16
|
+
// Malformed input, not a rejected credential — there is nothing here to
|
|
17
|
+
// authenticate yet.
|
|
18
|
+
invalid_did: 400,
|
|
19
|
+
unknown_nonce: 401,
|
|
20
|
+
expired_nonce: 401,
|
|
21
|
+
invalid_signature: 401,
|
|
22
|
+
};
|
|
23
|
+
/** Codes a fresh handshake can resolve. Anything else is fatal to retry. */
|
|
24
|
+
const RETRYABLE_AUTH_CODES = new Set(['unknown_nonce', 'expired_nonce']);
|
|
25
|
+
const KNOWN_AUTH_CODES = new Set(Object.keys(WIRE_AUTH_ERROR_STATUS));
|
|
26
|
+
/** Type guard: does this parsed JSON body look like a WireAuthError? */
|
|
27
|
+
export function isWireAuthError(body) {
|
|
28
|
+
return hasErrorBody(body, KNOWN_AUTH_CODES);
|
|
29
|
+
}
|
|
30
|
+
/** Whether retrying the handshake from a fresh nonce could succeed. */
|
|
31
|
+
export function isRetryableAuthError(code) {
|
|
32
|
+
return RETRYABLE_AUTH_CODES.has(code);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAY3C,qFAAqF;AACrF,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAAC;AAIzD,wEAAwE;AACxE,MAAM,UAAU,oBAAoB,CAAC,SAAmC;IACtE,OAAO,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,yBAAyB,CAAC,IAAI,KAAK,CAAC;AAC/E,CAAC;AAiDD,MAAM,CAAC,MAAM,sBAAsB,GAAsC;IACvE,wEAAwE;IACxE,oBAAoB;IACpB,WAAW,EAAE,GAAG;IAChB,aAAa,EAAE,GAAG;IAClB,aAAa,EAAE,GAAG;IAClB,iBAAiB,EAAE,GAAG;CACvB,CAAC;AAEF,4EAA4E;AAC5E,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAoB,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC;AAE5F,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAS,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;AAE9E,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,IAAa;IAC3C,OAAO,YAAY,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;AAC9C,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,oBAAoB,CAAC,IAAuB;IAC1D,OAAO,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Change feed
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* How a server advertises the feed, and the frames it streams.
|
|
5
|
+
* See docs/spec/change-feed.md.
|
|
6
|
+
*/
|
|
7
|
+
import type { ChangeKind, ChangeOp, DataAssociation, RecordChange } from '@haverstack/core';
|
|
8
|
+
import { type WireChangeActor, type WireRecord } from './records.js';
|
|
9
|
+
/**
|
|
10
|
+
* The change feed a server offers, absent when it offers none. An object
|
|
11
|
+
* rather than a boolean for the same reason `auth` is one: this surface
|
|
12
|
+
* grows entries. See docs/spec/change-feed.md.
|
|
13
|
+
*/
|
|
14
|
+
export type DiscoveryChanges = {
|
|
15
|
+
transports: ChangeTransport[];
|
|
16
|
+
/**
|
|
17
|
+
* Whether a resume cursor is honored. `false` is conformant and means
|
|
18
|
+
* every reconnect is answered with a `reset` frame.
|
|
19
|
+
*/
|
|
20
|
+
resume: boolean;
|
|
21
|
+
/** Whether `?include=record` is honored. Never honored for a purge. */
|
|
22
|
+
records: boolean;
|
|
23
|
+
};
|
|
24
|
+
/** Server→client streaming over `fetch`. The only transport in this version. */
|
|
25
|
+
export declare const CHANGE_TRANSPORT_SSE = "sse";
|
|
26
|
+
export type ChangeTransport = typeof CHANGE_TRANSPORT_SSE;
|
|
27
|
+
/**
|
|
28
|
+
* Whether a server offers a change feed this client can consume. A client
|
|
29
|
+
* checks this and fails locally rather than learning it as a 404 partway
|
|
30
|
+
* through a connection — the same reason `auth.methods` exists.
|
|
31
|
+
*/
|
|
32
|
+
export declare function supportsChangeFeed(discovery: {
|
|
33
|
+
changes?: DiscoveryChanges;
|
|
34
|
+
}): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* One change, as a `record` frame carries it. The envelope describes the
|
|
37
|
+
* change and nothing else: the record's own provenance rides `record`,
|
|
38
|
+
* where a consumer that wants it asks for it. See docs/spec/events.md
|
|
39
|
+
* § Attribution.
|
|
40
|
+
*/
|
|
41
|
+
export type WireRecordChange = {
|
|
42
|
+
kind: ChangeKind;
|
|
43
|
+
/** Every aspect this version moved; never empty. See RecordChange.ops. */
|
|
44
|
+
ops: ChangeOp[];
|
|
45
|
+
recordId: string;
|
|
46
|
+
typeId: string;
|
|
47
|
+
version: number;
|
|
48
|
+
updatedAt: string;
|
|
49
|
+
parentId?: string;
|
|
50
|
+
actor?: WireChangeActor;
|
|
51
|
+
/** Present when `ops` includes `associate`. See RecordChange.associationsAdded. */
|
|
52
|
+
associationsAdded?: DataAssociation[];
|
|
53
|
+
/** Present when `ops` includes `dissociate`. See RecordChange.associationsRemoved. */
|
|
54
|
+
associationsRemoved?: DataAssociation[];
|
|
55
|
+
record?: WireRecord;
|
|
56
|
+
cursor?: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* A change as a server frames it. A purge carries neither the record nor
|
|
60
|
+
* its parent, whatever was asked for: purge is the erasure primitive, and
|
|
61
|
+
* the rule lives here because a server still holds the purged record at
|
|
62
|
+
* emission. See docs/spec/events.md § Purged records carry nothing.
|
|
63
|
+
*/
|
|
64
|
+
export declare function serializeChange(c: RecordChange): WireRecordChange;
|
|
65
|
+
/**
|
|
66
|
+
* Frame names. Every frame carries one, and a client MUST ignore a name it
|
|
67
|
+
* does not recognize — which is what makes a new frame an additive, minor
|
|
68
|
+
* change rather than a break. See docs/spec/change-feed.md.
|
|
69
|
+
*/
|
|
70
|
+
export declare const CHANGE_FRAME_READY = "ready";
|
|
71
|
+
export declare const CHANGE_FRAME_RECORD = "record";
|
|
72
|
+
export declare const CHANGE_FRAME_RESET = "reset";
|
|
73
|
+
/**
|
|
74
|
+
* Sent first on every connection, before any change. It is what makes
|
|
75
|
+
* subscribe-then-query gap-free: everything after it is in the stream.
|
|
76
|
+
*/
|
|
77
|
+
export type WireReadyFrame = {
|
|
78
|
+
/** The head cursor. Absent from a server that mints none (`resume: false`). */
|
|
79
|
+
cursor?: string;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Why a cursor could not be honored. Informational — a client's repair is
|
|
83
|
+
* the same for all three, and it is reconciling by query.
|
|
84
|
+
*/
|
|
85
|
+
export type ChangeResetReason = 'cursor_expired' | 'not_supported' | 'overflow';
|
|
86
|
+
/** Your cursor cannot be honored; resynchronize by query. */
|
|
87
|
+
export type WireResetFrame = {
|
|
88
|
+
reason: ChangeResetReason;
|
|
89
|
+
};
|
|
90
|
+
/** Whether a cursor is framable: unreserved base64url characters only. */
|
|
91
|
+
export declare function isValidCursor(cursor: string): boolean;
|
|
92
|
+
//# sourceMappingURL=change-feed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"change-feed.d.ts","sourceRoot":"","sources":["../src/change-feed.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAE1C,MAAM,MAAM,eAAe,GAAG,OAAO,oBAAoB,CAAC;AAE1D;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE;IAAE,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAAE,GAAG,OAAO,CAErF;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,0EAA0E;IAC1E,GAAG,EAAE,QAAQ,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,eAAe,EAAE,CAAC;IACtC,sFAAsF;IACtF,mBAAmB,CAAC,EAAE,eAAe,EAAE,CAAC;IACxC,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,YAAY,GAAG,gBAAgB,CAmBjE;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAC1C,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAC5C,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAE1C;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,GAAG,eAAe,GAAG,UAAU,CAAC;AAEhF,6DAA6D;AAC7D,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AASF,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Change feed
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* How a server advertises the feed, and the frames it streams.
|
|
5
|
+
* See docs/spec/change-feed.md.
|
|
6
|
+
*/
|
|
7
|
+
import { serializeChangeActor, serializeRecord, } from './records.js';
|
|
8
|
+
/** Server→client streaming over `fetch`. The only transport in this version. */
|
|
9
|
+
export const CHANGE_TRANSPORT_SSE = 'sse';
|
|
10
|
+
/**
|
|
11
|
+
* Whether a server offers a change feed this client can consume. A client
|
|
12
|
+
* checks this and fails locally rather than learning it as a 404 partway
|
|
13
|
+
* through a connection — the same reason `auth.methods` exists.
|
|
14
|
+
*/
|
|
15
|
+
export function supportsChangeFeed(discovery) {
|
|
16
|
+
return discovery.changes?.transports?.includes(CHANGE_TRANSPORT_SSE) ?? false;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A change as a server frames it. A purge carries neither the record nor
|
|
20
|
+
* its parent, whatever was asked for: purge is the erasure primitive, and
|
|
21
|
+
* the rule lives here because a server still holds the purged record at
|
|
22
|
+
* emission. See docs/spec/events.md § Purged records carry nothing.
|
|
23
|
+
*/
|
|
24
|
+
export function serializeChange(c) {
|
|
25
|
+
const w = {
|
|
26
|
+
kind: c.kind,
|
|
27
|
+
// Copied, not aliased: a frame is serialized once and delivered to
|
|
28
|
+
// every subscriber, and the array it came from belongs to the emission.
|
|
29
|
+
ops: [...c.ops],
|
|
30
|
+
recordId: c.recordId,
|
|
31
|
+
typeId: c.typeId,
|
|
32
|
+
version: c.version,
|
|
33
|
+
updatedAt: c.updatedAt.toISOString(),
|
|
34
|
+
};
|
|
35
|
+
if (c.actor !== undefined)
|
|
36
|
+
w.actor = serializeChangeActor(c.actor);
|
|
37
|
+
if (c.cursor !== undefined)
|
|
38
|
+
w.cursor = c.cursor;
|
|
39
|
+
if (c.kind === 'purged')
|
|
40
|
+
return w;
|
|
41
|
+
if (c.parentId !== undefined)
|
|
42
|
+
w.parentId = c.parentId;
|
|
43
|
+
if (c.associationsAdded !== undefined)
|
|
44
|
+
w.associationsAdded = c.associationsAdded;
|
|
45
|
+
if (c.associationsRemoved !== undefined)
|
|
46
|
+
w.associationsRemoved = c.associationsRemoved;
|
|
47
|
+
if (c.record !== undefined)
|
|
48
|
+
w.record = serializeRecord(c.record);
|
|
49
|
+
return w;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Frame names. Every frame carries one, and a client MUST ignore a name it
|
|
53
|
+
* does not recognize — which is what makes a new frame an additive, minor
|
|
54
|
+
* change rather than a break. See docs/spec/change-feed.md.
|
|
55
|
+
*/
|
|
56
|
+
export const CHANGE_FRAME_READY = 'ready';
|
|
57
|
+
export const CHANGE_FRAME_RECORD = 'record';
|
|
58
|
+
export const CHANGE_FRAME_RESET = 'reset';
|
|
59
|
+
/**
|
|
60
|
+
* A cursor travels in an SSE `id:` field, so a value spanning a line would
|
|
61
|
+
* truncate the frame carrying it. Same charset and same reason as the auth
|
|
62
|
+
* nonce — see docs/spec/wire-format.md § The handshake.
|
|
63
|
+
*/
|
|
64
|
+
const CURSOR_FORMAT = /^[A-Za-z0-9_-]+$/;
|
|
65
|
+
/** Whether a cursor is framable: unreserved base64url characters only. */
|
|
66
|
+
export function isValidCursor(cursor) {
|
|
67
|
+
return CURSOR_FORMAT.test(cursor);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=change-feed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"change-feed.js","sourceRoot":"","sources":["../src/change-feed.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,oBAAoB,EACpB,eAAe,GAGhB,MAAM,cAAc,CAAC;AAkBtB,gFAAgF;AAChF,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAI1C;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAyC;IAC1E,OAAO,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC;AAChF,CAAC;AA0BD;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,CAAe;IAC7C,MAAM,CAAC,GAAqB;QAC1B,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,mEAAmE;QACnE,wEAAwE;QACxE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;QACf,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE;KACrC,CAAC;IACF,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS;QAAE,CAAC,CAAC,KAAK,GAAG,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACnE,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;QAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;QAAE,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;IACtD,IAAI,CAAC,CAAC,iBAAiB,KAAK,SAAS;QAAE,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,iBAAiB,CAAC;IACjF,IAAI,CAAC,CAAC,mBAAmB,KAAK,SAAS;QAAE,CAAC,CAAC,mBAAmB,GAAG,CAAC,CAAC,mBAAmB,CAAC;IACvF,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;QAAE,CAAC,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACjE,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAC1C,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CAAC;AAC5C,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAsB1C;;;;GAIG;AACH,MAAM,aAAa,GAAG,kBAAkB,CAAC;AAEzC,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* `GET /.well-known/stack` and the protocol version it negotiates. Each
|
|
5
|
+
* optional surface's advertisement lives with that surface — `auth`,
|
|
6
|
+
* `changes`, `installs` — and is only assembled here.
|
|
7
|
+
* See docs/spec/wire-format.md § Discovery.
|
|
8
|
+
*/
|
|
9
|
+
import type { StackCapabilities } from '@haverstack/core';
|
|
10
|
+
import type { DiscoveryAuth } from './auth.js';
|
|
11
|
+
import type { DiscoveryChanges } from './change-feed.js';
|
|
12
|
+
import type { DiscoveryInstalls } from './installs.js';
|
|
13
|
+
/**
|
|
14
|
+
* The wire protocol this package describes. Bump the major when a change
|
|
15
|
+
* would make an older client read a response wrongly; bump the minor for
|
|
16
|
+
* additions an older client can ignore. See docs/spec/wire-format.md
|
|
17
|
+
* § Version negotiation.
|
|
18
|
+
*/
|
|
19
|
+
export declare const WIRE_PROTOCOL_VERSION = "1.0";
|
|
20
|
+
/** GET /.well-known/stack. See docs/spec/wire-format.md § Discovery. */
|
|
21
|
+
export type DiscoveryResponse = {
|
|
22
|
+
version: string;
|
|
23
|
+
entityId: string;
|
|
24
|
+
timezone?: string;
|
|
25
|
+
capabilities?: DiscoveryCapabilities;
|
|
26
|
+
auth?: DiscoveryAuth;
|
|
27
|
+
changes?: DiscoveryChanges;
|
|
28
|
+
installs?: DiscoveryInstalls;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* `capabilities` as it arrives: a foreign server may omit any part, or name
|
|
32
|
+
* a reach or sort field this client has never heard of. Typed loosely on
|
|
33
|
+
* exactly those fields, so the checks normalizeCapabilities() makes read as
|
|
34
|
+
* checks rather than casts. See docs/spec/wire-format.md § Discovery.
|
|
35
|
+
*/
|
|
36
|
+
export type DiscoveryCapabilities = {
|
|
37
|
+
filter?: {
|
|
38
|
+
content?: string;
|
|
39
|
+
contentPresent?: boolean;
|
|
40
|
+
contentByType?: number;
|
|
41
|
+
search?: boolean;
|
|
42
|
+
};
|
|
43
|
+
sort?: {
|
|
44
|
+
fields?: string[];
|
|
45
|
+
contentField?: boolean;
|
|
46
|
+
contentFieldByType?: number;
|
|
47
|
+
};
|
|
48
|
+
limits?: {
|
|
49
|
+
attachmentBytes?: number | null;
|
|
50
|
+
contentBytes?: number | null;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Resolves anything absent, malformed or unrecognized to the least capable
|
|
55
|
+
* value it could stand for — one rule, applied once, rather than a default
|
|
56
|
+
* per key at each call site. A `null` limit is the one permissive reading,
|
|
57
|
+
* since the server's own ceiling still answers 413. See
|
|
58
|
+
* docs/spec/adapters.md § Adapter capabilities.
|
|
59
|
+
*/
|
|
60
|
+
export declare function normalizeCapabilities(capabilities: DiscoveryCapabilities | undefined): StackCapabilities;
|
|
61
|
+
/** Splits a MAJOR.MINOR protocol version. Returns null if it isn't one. */
|
|
62
|
+
export declare function parseProtocolVersion(version: string): {
|
|
63
|
+
major: number;
|
|
64
|
+
minor: number;
|
|
65
|
+
} | null;
|
|
66
|
+
/**
|
|
67
|
+
* Majors must match; minors never have to. A higher server minor is additive
|
|
68
|
+
* fields this client ignores, and a higher client minor is optional fields
|
|
69
|
+
* the server may omit — neither can make a response read wrongly, which is
|
|
70
|
+
* the only thing a major bump signals.
|
|
71
|
+
*/
|
|
72
|
+
export declare function isProtocolCompatible(version: string, against?: string): boolean;
|
|
73
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAuC,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAE3C,wEAAwE;AACxE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAClG,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClF,MAAM,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC5E,CAAC;AAKF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,qBAAqB,GAAG,SAAS,GAC9C,iBAAiB,CA2BnB;AAUD,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAG7F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,SAAwB,GAAG,OAAO,CAI9F"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* `GET /.well-known/stack` and the protocol version it negotiates. Each
|
|
5
|
+
* optional surface's advertisement lives with that surface — `auth`,
|
|
6
|
+
* `changes`, `installs` — and is only assembled here.
|
|
7
|
+
* See docs/spec/wire-format.md § Discovery.
|
|
8
|
+
*/
|
|
9
|
+
import { NATIVE_SORT_FIELDS } from '@haverstack/core';
|
|
10
|
+
/**
|
|
11
|
+
* The wire protocol this package describes. Bump the major when a change
|
|
12
|
+
* would make an older client read a response wrongly; bump the minor for
|
|
13
|
+
* additions an older client can ignore. See docs/spec/wire-format.md
|
|
14
|
+
* § Version negotiation.
|
|
15
|
+
*/
|
|
16
|
+
export const WIRE_PROTOCOL_VERSION = '1.0';
|
|
17
|
+
const CONTENT_FILTER_REACHES = new Set(['none', 'field', 'path']);
|
|
18
|
+
const SORT_FIELDS = new Set(NATIVE_SORT_FIELDS);
|
|
19
|
+
/**
|
|
20
|
+
* Resolves anything absent, malformed or unrecognized to the least capable
|
|
21
|
+
* value it could stand for — one rule, applied once, rather than a default
|
|
22
|
+
* per key at each call site. A `null` limit is the one permissive reading,
|
|
23
|
+
* since the server's own ceiling still answers 413. See
|
|
24
|
+
* docs/spec/adapters.md § Adapter capabilities.
|
|
25
|
+
*/
|
|
26
|
+
export function normalizeCapabilities(capabilities) {
|
|
27
|
+
const filter = capabilities?.filter;
|
|
28
|
+
const sort = capabilities?.sort;
|
|
29
|
+
const limits = capabilities?.limits;
|
|
30
|
+
const reach = CONTENT_FILTER_REACHES.has(filter?.content)
|
|
31
|
+
? filter?.content
|
|
32
|
+
: 'none';
|
|
33
|
+
// The per-Type shapes travel in the POST /records/query body, which a
|
|
34
|
+
// server reaching no content does not serve.
|
|
35
|
+
const cap = (value) => (reach === 'none' ? 0 : capOrZero(value));
|
|
36
|
+
return {
|
|
37
|
+
filter: {
|
|
38
|
+
content: reach,
|
|
39
|
+
contentPresent: filter?.contentPresent === true,
|
|
40
|
+
contentByType: cap(filter?.contentByType),
|
|
41
|
+
search: filter?.search === true,
|
|
42
|
+
},
|
|
43
|
+
sort: {
|
|
44
|
+
fields: (sort?.fields ?? []).filter((f) => SORT_FIELDS.has(f)),
|
|
45
|
+
contentField: sort?.contentField === true,
|
|
46
|
+
contentFieldByType: cap(sort?.contentFieldByType),
|
|
47
|
+
},
|
|
48
|
+
limits: {
|
|
49
|
+
attachmentBytes: finiteOrNull(limits?.attachmentBytes),
|
|
50
|
+
contentBytes: finiteOrNull(limits?.contentBytes),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** A cap on keys, or 0 — declined — for anything but a non-negative integer. */
|
|
55
|
+
const capOrZero = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value > 0 ? value : 0;
|
|
56
|
+
/** A ceiling this client can compare against, or null for "cannot pre-check". */
|
|
57
|
+
const finiteOrNull = (value) => typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
58
|
+
/** Splits a MAJOR.MINOR protocol version. Returns null if it isn't one. */
|
|
59
|
+
export function parseProtocolVersion(version) {
|
|
60
|
+
const match = /^(\d+)\.(\d+)$/.exec(version);
|
|
61
|
+
return match ? { major: Number(match[1]), minor: Number(match[2]) } : null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Majors must match; minors never have to. A higher server minor is additive
|
|
65
|
+
* fields this client ignores, and a higher client minor is optional fields
|
|
66
|
+
* the server may omit — neither can make a response read wrongly, which is
|
|
67
|
+
* the only thing a major bump signals.
|
|
68
|
+
*/
|
|
69
|
+
export function isProtocolCompatible(version, against = WIRE_PROTOCOL_VERSION) {
|
|
70
|
+
const server = parseProtocolVersion(version);
|
|
71
|
+
const client = parseProtocolVersion(against);
|
|
72
|
+
return server !== null && client !== null && server.major === client.major;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error responses
|
|
3
|
+
* -------------------------------------------------------
|
|
4
|
+
* The round-trip contract for core's typed error taxonomy: a server
|
|
5
|
+
* serializes a caught core error via serializeError(), and APIAdapter
|
|
6
|
+
* reconstructs the same class via deserializeError(). `code` is the
|
|
7
|
+
* authoritative discriminator; status is a transport hint. See
|
|
8
|
+
* docs/spec/wire-format.md § Error responses.
|
|
9
|
+
*/
|
|
10
|
+
import type { SchemaDriftViolation, StackErrorCode, ValidationError } from '@haverstack/core';
|
|
11
|
+
/**
|
|
12
|
+
* Alias of core's StackErrorCode: the vocabulary belongs with the classes
|
|
13
|
+
* that carry it, and StackError.code is typed by it, so re-declaring the
|
|
14
|
+
* union here would be a second copy to drift.
|
|
15
|
+
*/
|
|
16
|
+
export type WireErrorCode = StackErrorCode;
|
|
17
|
+
export type WireError = {
|
|
18
|
+
error: {
|
|
19
|
+
code: WireErrorCode;
|
|
20
|
+
message: string;
|
|
21
|
+
/** Field-level validation failures. Only present for code: 'validation'. */
|
|
22
|
+
details?: ValidationError[];
|
|
23
|
+
/** ifVersion/If-Match precondition state. Only present for code: 'version_conflict'. */
|
|
24
|
+
versionConflict?: {
|
|
25
|
+
recordId: string;
|
|
26
|
+
expectedVersion: number;
|
|
27
|
+
actualVersion: number;
|
|
28
|
+
};
|
|
29
|
+
/** The rejected defineType() call's target and violations. Only present for code: 'schema_drift'. */
|
|
30
|
+
schemaDrift?: {
|
|
31
|
+
typeId: string;
|
|
32
|
+
violations: SchemaDriftViolation[];
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/** Canonical HTTP status for each wire error code. */
|
|
37
|
+
export declare const WIRE_ERROR_STATUS: Record<WireErrorCode, number>;
|
|
38
|
+
/**
|
|
39
|
+
* Statuses that unambiguously imply a wire error code, for reconstructing
|
|
40
|
+
* an error from status alone when a response has no parseable wire error
|
|
41
|
+
* body. 500 is deliberately excluded — it would misclassify ordinary
|
|
42
|
+
* server bugs as StackMigrationError. See docs/spec/wire-format.md
|
|
43
|
+
* § Wire error body.
|
|
44
|
+
*/
|
|
45
|
+
export declare const STATUS_TO_CODE: Partial<Record<number, WireErrorCode>>;
|
|
46
|
+
/** Whether `body` is `{ error: { code, message } }` with a code from `codes`. */
|
|
47
|
+
export declare function hasErrorBody(body: unknown, codes: ReadonlySet<string>): boolean;
|
|
48
|
+
/** Type guard: does this parsed JSON body look like a WireError? */
|
|
49
|
+
export declare function isWireError(body: unknown): body is WireError;
|
|
50
|
+
/**
|
|
51
|
+
* Convert a thrown core error into its wire response. Used by server
|
|
52
|
+
* implementations. Returns null for anything that isn't a StackError —
|
|
53
|
+
* callers fall back to their own generic error handling, so an ordinary bug
|
|
54
|
+
* stays a bare 500 rather than being dressed as a protocol error.
|
|
55
|
+
*/
|
|
56
|
+
export declare function serializeError(err: unknown): {
|
|
57
|
+
status: number;
|
|
58
|
+
body: WireError;
|
|
59
|
+
} | null;
|
|
60
|
+
/** Reconstruct the core error a WireError body describes. */
|
|
61
|
+
export declare function deserializeError(body: WireError): Error;
|
|
62
|
+
/**
|
|
63
|
+
* Reconstruct a core error from an HTTP status alone (no usable wire error
|
|
64
|
+
* body). Returns null for statuses with no unambiguous code — callers
|
|
65
|
+
* should fall back to a generic adapter-level error.
|
|
66
|
+
*/
|
|
67
|
+
export declare function errorForStatus(status: number, message: string): Error | null;
|
|
68
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAeH,OAAO,KAAK,EAAE,oBAAoB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE9F;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC;AAE3C,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE;QACL,IAAI,EAAE,aAAa,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,4EAA4E;QAC5E,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;QAC5B,wFAAwF;QACxF,eAAe,CAAC,EAAE;YAChB,QAAQ,EAAE,MAAM,CAAC;YACjB,eAAe,EAAE,MAAM,CAAC;YACxB,aAAa,EAAE,MAAM,CAAC;SACvB,CAAC;QACF,qGAAqG;QACrG,WAAW,CAAC,EAAE;YACZ,MAAM,EAAE,MAAM,CAAC;YACf,UAAU,EAAE,oBAAoB,EAAE,CAAC;SACpC,CAAC;KACH,CAAC;CACH,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAoC3D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAajE,CAAC;AAIF,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAO/E;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,SAAS,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG,IAAI,CAkBvF;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,KAAK,CA+BvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAG5E"}
|