@emseepea/feedback 0.5.3 → 0.7.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/README.md +226 -7
- package/dist/collections.d.ts +47 -0
- package/dist/collections.d.ts.map +1 -0
- package/dist/collections.js +141 -0
- package/dist/collections.js.map +1 -0
- package/dist/index.d.ts +127 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +405 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp-events.d.ts +38 -0
- package/dist/mcp-events.d.ts.map +1 -0
- package/dist/mcp-events.js +161 -0
- package/dist/mcp-events.js.map +1 -0
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -5,8 +5,6 @@ defines the limits of that label.
|
|
|
5
5
|
|
|
6
6
|
Add detailed feedback or a durable support conversation to any Em See Pea
|
|
7
7
|
server. The package is optional. Generated applications do not configure it.
|
|
8
|
-
Their semantic tests install it only as a development dependency so successful
|
|
9
|
-
example journeys can prove that the AI did not record negative feedback.
|
|
10
8
|
|
|
11
9
|
Use a submission when the team only needs one useful observation. Use a
|
|
12
10
|
conversation when the team must reply and the AI must bring that reply back to
|
|
@@ -59,6 +57,199 @@ or expected number of steps is not feedback-worthy.
|
|
|
59
57
|
These are instructions for the AI, not server-enforced guarantees. Qualify the
|
|
60
58
|
behaviour with a native semantic test for every AI client you support.
|
|
61
59
|
|
|
60
|
+
## Separate Customer and Internal Feedback
|
|
61
|
+
|
|
62
|
+
A collection is a deployment-configured authorization partition, such as
|
|
63
|
+
`customer` or `internal`. It identifies the feedback destination, not an
|
|
64
|
+
account or person. Declare submission, monitoring, and operator roles
|
|
65
|
+
separately; declaring a collection grants none of those roles automatically.
|
|
66
|
+
|
|
67
|
+
| Deployment | Submission destination | Monitoring and retrieval |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| Customer-facing MCP | `customer` only | None |
|
|
70
|
+
| Internal MCP | Explicitly `internal` | Protected access to `internal`, `customer`, or both authorized collections |
|
|
71
|
+
|
|
72
|
+
The support backend owns the authoritative record, assignment, status,
|
|
73
|
+
replies, notifications, and private notes. Em See Pea reads and writes exact
|
|
74
|
+
records there; it does not create a second support inbox.
|
|
75
|
+
|
|
76
|
+
Use the same stable account scope for submission and operator adapters and
|
|
77
|
+
the MCP Events `ownerKey`. Resolve it from verified authentication. Do not use
|
|
78
|
+
an access token or assume an OAuth client ID identifies an account. Two
|
|
79
|
+
accounts using the same collection remain separate.
|
|
80
|
+
|
|
81
|
+
### Configure customer submission only
|
|
82
|
+
|
|
83
|
+
The imports from `./feedback-integration.js` are application code you provide.
|
|
84
|
+
`feedbackBackend` implements `FeedbackCollectionSubmissionBackend` over your
|
|
85
|
+
durable support storage. It enforces `context.scope` on every write, list,
|
|
86
|
+
lookup, and cursor.
|
|
87
|
+
|
|
88
|
+
`accountScopeForPrincipal` resolves the authenticated account. `authentication`
|
|
89
|
+
supplies your checked OAuth verifier and metadata.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import {
|
|
93
|
+
defineFeedbackCollections,
|
|
94
|
+
defineFeedbackCollectionSubmissions,
|
|
95
|
+
} from "@emseepea/feedback";
|
|
96
|
+
import { createEmseepea } from "@emseepea/server";
|
|
97
|
+
import {
|
|
98
|
+
authentication, feedbackBackend, accountScopeForPrincipal,
|
|
99
|
+
} from "./feedback-integration.js";
|
|
100
|
+
|
|
101
|
+
const customer = defineFeedbackCollections({
|
|
102
|
+
collections: ["customer"],
|
|
103
|
+
submissions: [{
|
|
104
|
+
collection: "customer", access: "protected",
|
|
105
|
+
requiredScopes: ["feedback:submit"],
|
|
106
|
+
}],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const app = createEmseepea({
|
|
110
|
+
name: "customer-feedback", version: "1.0.0", authentication,
|
|
111
|
+
tools: defineFeedbackCollectionSubmissions({
|
|
112
|
+
definition: customer,
|
|
113
|
+
scope: accountScopeForPrincipal,
|
|
114
|
+
backend: feedbackBackend,
|
|
115
|
+
}),
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
This exposes `submit-customer-feedback` with a fixed destination. The caller
|
|
120
|
+
cannot select a collection. It exposes no operator tools or MCP Events.
|
|
121
|
+
If anonymous submission is intentional, declare `access: "public"` without
|
|
122
|
+
`requiredScopes` and provide a fixed, application-owned storage scope.
|
|
123
|
+
|
|
124
|
+
### Configure internal submission and protected operators
|
|
125
|
+
|
|
126
|
+
The application module below also supplies a durable `eventStore`, its
|
|
127
|
+
`eventSystemHealthy` check, and `accountScopeForAuth` using the same account
|
|
128
|
+
projection as `accountScopeForPrincipal`. `canMonitorCollection` checks the
|
|
129
|
+
owner's current permission for the collection and requested lifecycle phase.
|
|
130
|
+
|
|
131
|
+
Enforce the declared monitor scopes in that callback; the helper does not
|
|
132
|
+
infer grants from the role declaration.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import {
|
|
136
|
+
defineFeedbackCollections,
|
|
137
|
+
defineFeedbackCollectionSubmissions,
|
|
138
|
+
defineFeedbackCollectionOperators,
|
|
139
|
+
} from "@emseepea/feedback";
|
|
140
|
+
import {
|
|
141
|
+
createFeedbackSubmittedEventsOptions,
|
|
142
|
+
publishFeedbackSubmittedEvent,
|
|
143
|
+
} from "@emseepea/feedback/mcp-events";
|
|
144
|
+
import { createEmseepea } from "@emseepea/server";
|
|
145
|
+
import {
|
|
146
|
+
authentication, feedbackBackend, accountScopeForPrincipal,
|
|
147
|
+
accountScopeForAuth, canMonitorCollection, eventStore, eventSystemHealthy,
|
|
148
|
+
} from "./feedback-integration.js";
|
|
149
|
+
|
|
150
|
+
const internal = defineFeedbackCollections({
|
|
151
|
+
collections: ["customer", "internal"],
|
|
152
|
+
submissions: [{
|
|
153
|
+
collection: "internal", access: "protected",
|
|
154
|
+
requiredScopes: ["feedback:submit:internal"],
|
|
155
|
+
}],
|
|
156
|
+
operators: [
|
|
157
|
+
{ collection: "internal", access: "protected",
|
|
158
|
+
requiredScopes: ["feedback:operator", "feedback:read:internal"] },
|
|
159
|
+
{ collection: "customer", access: "protected",
|
|
160
|
+
requiredScopes: ["feedback:operator", "feedback:read:customer"] },
|
|
161
|
+
],
|
|
162
|
+
monitors: [
|
|
163
|
+
{ collection: "internal", access: "protected",
|
|
164
|
+
requiredScopes: ["feedback:monitor:internal"] },
|
|
165
|
+
{ collection: "customer", access: "protected",
|
|
166
|
+
requiredScopes: ["feedback:monitor:customer"] },
|
|
167
|
+
],
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const events = createFeedbackSubmittedEventsOptions({
|
|
171
|
+
definition: internal,
|
|
172
|
+
ownerKey: accountScopeForAuth,
|
|
173
|
+
canMonitorCollection,
|
|
174
|
+
health: eventSystemHealthy,
|
|
175
|
+
store: eventStore,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
let app: ReturnType<typeof createEmseepea>;
|
|
179
|
+
app = createEmseepea({
|
|
180
|
+
name: "internal-feedback", version: "1.0.0", authentication, events,
|
|
181
|
+
tools: [
|
|
182
|
+
...defineFeedbackCollectionSubmissions({
|
|
183
|
+
definition: internal,
|
|
184
|
+
scope: accountScopeForPrincipal,
|
|
185
|
+
backend: feedbackBackend,
|
|
186
|
+
hooks: [(event, context) => publishFeedbackSubmittedEvent(app, event, context)
|
|
187
|
+
.then(() => undefined)],
|
|
188
|
+
}),
|
|
189
|
+
...defineFeedbackCollectionOperators({
|
|
190
|
+
definition: internal,
|
|
191
|
+
scope: accountScopeForPrincipal,
|
|
192
|
+
backend: feedbackBackend,
|
|
193
|
+
}),
|
|
194
|
+
],
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The internal submission tool is `submit-internal-feedback`. Operator roles
|
|
199
|
+
must share a tool-entry scope, here `feedback:operator`. Each call also checks
|
|
200
|
+
every scope for its selected collection before accessing the backend.
|
|
201
|
+
Use protected tool discovery when operator names and schemas must be hidden.
|
|
202
|
+
|
|
203
|
+
Hooks run after persistence and are best-effort. For reliable notification,
|
|
204
|
+
save the recorded event and its account scope in a transactional outbox and
|
|
205
|
+
call `publishFeedbackSubmittedEvent(app, event, { scope })` from your worker.
|
|
206
|
+
The publisher targets only subscriptions whose `ownerKey` equals that scope.
|
|
207
|
+
Keep the scope in trusted storage, outside the delivered payload.
|
|
208
|
+
|
|
209
|
+
### Read and monitor exact submissions
|
|
210
|
+
|
|
211
|
+
`list-feedback-submissions` accepts `{ collection, cursor?, limit? }`.
|
|
212
|
+
The limit defaults to 20 and cannot exceed 50. Pass the returned `nextCursor`
|
|
213
|
+
unchanged for the next page in the same collection and account scope.
|
|
214
|
+
`get-feedback-submission` accepts the exact `{ collection, submissionId }`.
|
|
215
|
+
Unknown, unauthorized, and mismatched records return the same public error.
|
|
216
|
+
|
|
217
|
+
Results contain `collection`, `submissionId`, `observation`, `detail`, and
|
|
218
|
+
`recordedAt`. Supply `contextSchema` to both tool builders to accept and return
|
|
219
|
+
validated application context. Backend `source` and authorization `scope`
|
|
220
|
+
are excluded; results cannot exceed 256 KiB.
|
|
221
|
+
|
|
222
|
+
Discover `feedback.submitted` with `events/list`, then subscribe using one of
|
|
223
|
+
these argument sets:
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{ "collections": ["internal"] }
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{ "collections": ["customer"] }
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
{ "collections": ["customer", "internal"] }
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Use only currently authorized collections. The selection must be non-empty,
|
|
238
|
+
unique, and no larger than 32 configured monitor collections. It is sorted
|
|
239
|
+
before subscription identity is calculated. Discovery, subscription, refresh,
|
|
240
|
+
and delivery each recheck authorization; delivery also rechecks queued work.
|
|
241
|
+
|
|
242
|
+
The payload is exactly `{ collection, submissionId, sourceEventId }`.
|
|
243
|
+
Retrieve the authoritative record with `get-feedback-submission` before
|
|
244
|
+
acting on it. Use `sourceEventId` to recognize repeated publication. Configure
|
|
245
|
+
callback verification and a durable delivery store as described in the
|
|
246
|
+
[MCP Events guide](https://emseepea.github.io/emseepea/mcp-events/).
|
|
247
|
+
|
|
248
|
+
`createFeedbackSubmittedEventsOptions` returns `undefined` when no monitor
|
|
249
|
+
role exists. The included `createInMemoryFeedbackCollectionBackend` is
|
|
250
|
+
process-local reference storage; supply a durable collection backend for
|
|
251
|
+
deployment. Existing conversation adapters retain their conversation APIs.
|
|
252
|
+
|
|
62
253
|
## Add a Protected Support Conversation
|
|
63
254
|
|
|
64
255
|
```ts
|
|
@@ -209,11 +400,8 @@ Configure Zendesk's webhook body to match the documented `eventId`, `subdomain`,
|
|
|
209
400
|
`ticketId`, `scopeTag`, `occurredAt`, and `change` shape exported by the
|
|
210
401
|
TypeScript API.
|
|
211
402
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
categorisation, milestone, status, notification, and email behavior remains the
|
|
215
|
-
provider's responsibility and must be qualified in the account where you deploy
|
|
216
|
-
the adapter.
|
|
403
|
+
Configure assignment, categories, milestones, status, notifications, and email
|
|
404
|
+
in the provider account where you deploy the adapter.
|
|
217
405
|
|
|
218
406
|
## Handle Feedback Events
|
|
219
407
|
|
|
@@ -241,6 +429,37 @@ and cannot change the MCP result. Hook code must honor that signal and deadline.
|
|
|
241
429
|
For reliable delivery, use the PostgreSQL or Firestore outbox, or GitHub and
|
|
242
430
|
Zendesk native automation.
|
|
243
431
|
|
|
432
|
+
### Notify an AI client about a team reply
|
|
433
|
+
|
|
434
|
+
A protected conversation can optionally use MCP Events to tell a subscribed AI
|
|
435
|
+
client that a team reply is ready. The event carries only the account or client
|
|
436
|
+
scope and stable thread, message, and source-event IDs. It does not carry the
|
|
437
|
+
reply text. The client should call `get-feedback-thread` and present the reply
|
|
438
|
+
to the person.
|
|
439
|
+
|
|
440
|
+
1. Configure `createFeedbackReplyEventsOptions` from
|
|
441
|
+
`@emseepea/feedback/mcp-events` as the server's `events` option. Use the same
|
|
442
|
+
stable account or client scope for its `ownerKey` as for
|
|
443
|
+
`defineFeedbackConversation({ scope })`.
|
|
444
|
+
2. Supply `canReadThread(ownerKey, threadId)` to check access to the exact
|
|
445
|
+
thread. The check runs when subscribing and again before delivery. Supply
|
|
446
|
+
your durable MCP Events store and health check as described in the
|
|
447
|
+
[MCP Events guide](https://emseepea.github.io/emseepea/mcp-events/).
|
|
448
|
+
3. After saving a team reply, pass its typed feedback event to
|
|
449
|
+
`publishFeedbackTeamReplyEvent(app, event)`. For PostgreSQL or Firestore,
|
|
450
|
+
publish from the transactional outbox: a saved queue that can be retried
|
|
451
|
+
after failures. For GitHub or Zendesk, use the checked provider webhook.
|
|
452
|
+
The helper ignores non-team events and publishes only a reference to a team
|
|
453
|
+
message.
|
|
454
|
+
|
|
455
|
+
An outbox retry can publish the same reply more than once. Use the stable
|
|
456
|
+
`sourceEventId` in the event payload to recognise duplicates.
|
|
457
|
+
|
|
458
|
+
The Markdown destination is one-way and has no team reply to announce. An
|
|
459
|
+
event delivery, or a reply being offered to an AI client, does not prove a
|
|
460
|
+
person saw it. Test the complete reply journey in your own client and
|
|
461
|
+
deployment before relying on it.
|
|
462
|
+
|
|
244
463
|
## Effect and Retry Limits
|
|
245
464
|
|
|
246
465
|
Creating a thread, submitting feedback, and appending a message are
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const feedbackCollectionSchema: z.ZodString;
|
|
3
|
+
export type FeedbackCollection = z.output<typeof feedbackCollectionSchema>;
|
|
4
|
+
export type FeedbackCollectionRole = "submission" | "operator" | "monitor";
|
|
5
|
+
export type FeedbackSubmissionRoleDeclaration = Readonly<{
|
|
6
|
+
collection: FeedbackCollection;
|
|
7
|
+
access: "public";
|
|
8
|
+
requiredScopes?: never;
|
|
9
|
+
}> | Readonly<{
|
|
10
|
+
collection: FeedbackCollection;
|
|
11
|
+
access: "protected";
|
|
12
|
+
requiredScopes: readonly string[];
|
|
13
|
+
}>;
|
|
14
|
+
export interface FeedbackProtectedRoleDeclaration {
|
|
15
|
+
readonly collection: FeedbackCollection;
|
|
16
|
+
readonly access: "protected";
|
|
17
|
+
readonly requiredScopes: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export interface FeedbackCollectionsOptions {
|
|
20
|
+
readonly collections: readonly FeedbackCollection[];
|
|
21
|
+
readonly submissions?: readonly FeedbackSubmissionRoleDeclaration[];
|
|
22
|
+
readonly operators?: readonly FeedbackProtectedRoleDeclaration[];
|
|
23
|
+
readonly monitors?: readonly FeedbackProtectedRoleDeclaration[];
|
|
24
|
+
}
|
|
25
|
+
export interface FeedbackCollectionCatalogueEntry {
|
|
26
|
+
readonly id: FeedbackCollection;
|
|
27
|
+
readonly roles: readonly FeedbackCollectionRole[];
|
|
28
|
+
}
|
|
29
|
+
export interface FeedbackSubmissionRoleProjection {
|
|
30
|
+
readonly collection: FeedbackCollection;
|
|
31
|
+
readonly toolName: `submit-${string}-feedback`;
|
|
32
|
+
readonly access: "public" | "protected";
|
|
33
|
+
readonly requiredScopes: readonly string[];
|
|
34
|
+
}
|
|
35
|
+
export interface FeedbackProtectedRoleProjection {
|
|
36
|
+
readonly collection: FeedbackCollection;
|
|
37
|
+
readonly access: "protected";
|
|
38
|
+
readonly requiredScopes: readonly string[];
|
|
39
|
+
}
|
|
40
|
+
export interface FeedbackCollectionsDefinition {
|
|
41
|
+
readonly catalogue: readonly FeedbackCollectionCatalogueEntry[];
|
|
42
|
+
readonly submissions: readonly FeedbackSubmissionRoleProjection[];
|
|
43
|
+
readonly operators: readonly FeedbackProtectedRoleProjection[];
|
|
44
|
+
readonly monitors: readonly FeedbackProtectedRoleProjection[];
|
|
45
|
+
}
|
|
46
|
+
export declare function defineFeedbackCollections(options: FeedbackCollectionsOptions): FeedbackCollectionsDefinition;
|
|
47
|
+
//# sourceMappingURL=collections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../src/collections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,wBAAwB,aAE2B,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC3E,MAAM,MAAM,sBAAsB,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;AAE3E,MAAM,MAAM,iCAAiC,GACzC,QAAQ,CAAC;IACT,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,QAAQ,CAAC;IACjB,cAAc,CAAC,EAAE,KAAK,CAAC;CACxB,CAAC,GACA,QAAQ,CAAC;IACT,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC,CAAC;AAEL,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,WAAW,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpD,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,iCAAiC,EAAE,CAAC;IACpE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,gCAAgC,EAAE,CAAC;IACjE,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,gCAAgC,EAAE,CAAC;CACjE;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,EAAE,EAAE,kBAAkB,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,SAAS,sBAAsB,EAAE,CAAC;CACnD;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,UAAU,MAAM,WAAW,CAAC;IAC/C,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAC;IACxC,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,SAAS,EAAE,SAAS,gCAAgC,EAAE,CAAC;IAChE,QAAQ,CAAC,WAAW,EAAE,SAAS,gCAAgC,EAAE,CAAC;IAClE,QAAQ,CAAC,SAAS,EAAE,SAAS,+BAA+B,EAAE,CAAC;IAC/D,QAAQ,CAAC,QAAQ,EAAE,SAAS,+BAA+B,EAAE,CAAC;CAC/D;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,6BAA6B,CAuC/B"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const feedbackCollectionSchema = z.string()
|
|
3
|
+
.regex(/^[a-z][a-z0-9._-]{0,63}$/)
|
|
4
|
+
.describe("Deployment-static feedback collection identifier.");
|
|
5
|
+
export function defineFeedbackCollections(options) {
|
|
6
|
+
const raw = requireRecord(options, "Feedback collections configuration");
|
|
7
|
+
rejectUnknownKeys(raw, ["collections", "submissions", "operators", "monitors"], "Feedback collections configuration");
|
|
8
|
+
if (!Array.isArray(raw.collections) || raw.collections.length === 0) {
|
|
9
|
+
throw new TypeError("Feedback collections configuration requires at least one collection");
|
|
10
|
+
}
|
|
11
|
+
const declared = new Set();
|
|
12
|
+
for (const value of raw.collections) {
|
|
13
|
+
const checked = feedbackCollectionSchema.safeParse(value);
|
|
14
|
+
if (!checked.success)
|
|
15
|
+
throw new TypeError("Invalid feedback collection identifier");
|
|
16
|
+
if (declared.has(checked.data)) {
|
|
17
|
+
throw new TypeError(`Duplicate collection: ${checked.data}`);
|
|
18
|
+
}
|
|
19
|
+
declared.add(checked.data);
|
|
20
|
+
}
|
|
21
|
+
const submissions = compileSubmissionRoles(raw.submissions, declared);
|
|
22
|
+
const operators = compileProtectedRoles("operator", raw.operators, declared);
|
|
23
|
+
const monitors = compileProtectedRoles("monitor", raw.monitors, declared);
|
|
24
|
+
const submissionCollections = new Set(submissions.map(({ collection }) => collection));
|
|
25
|
+
const operatorCollections = new Set(operators.map(({ collection }) => collection));
|
|
26
|
+
const monitorCollections = new Set(monitors.map(({ collection }) => collection));
|
|
27
|
+
const catalogue = [...declared].sort().map((id) => Object.freeze({
|
|
28
|
+
id,
|
|
29
|
+
roles: Object.freeze([
|
|
30
|
+
...(submissionCollections.has(id) ? ["submission"] : []),
|
|
31
|
+
...(operatorCollections.has(id) ? ["operator"] : []),
|
|
32
|
+
...(monitorCollections.has(id) ? ["monitor"] : []),
|
|
33
|
+
]),
|
|
34
|
+
}));
|
|
35
|
+
return Object.freeze({
|
|
36
|
+
catalogue: Object.freeze(catalogue),
|
|
37
|
+
submissions: Object.freeze(submissions),
|
|
38
|
+
operators: Object.freeze(operators),
|
|
39
|
+
monitors: Object.freeze(monitors),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function compileSubmissionRoles(value, declared) {
|
|
43
|
+
const entries = optionalArray(value, "Submission roles");
|
|
44
|
+
const toolNames = new Set();
|
|
45
|
+
const projections = entries.map((entry) => {
|
|
46
|
+
const role = requireRecord(entry, "Submission role");
|
|
47
|
+
if (Object.keys(role).some((key) => !["collection", "access", "requiredScopes"].includes(key))) {
|
|
48
|
+
throw new TypeError("Submission destination must be fixed by deployment configuration");
|
|
49
|
+
}
|
|
50
|
+
const collection = collectionReference(role.collection, declared);
|
|
51
|
+
const toolName = submissionToolName(collection);
|
|
52
|
+
if (toolNames.has(toolName))
|
|
53
|
+
throw new TypeError(`Duplicate submission tool name: ${toolName}`);
|
|
54
|
+
toolNames.add(toolName);
|
|
55
|
+
if (role.access !== "public" && role.access !== "protected") {
|
|
56
|
+
throw new TypeError("Submission access must be public or protected");
|
|
57
|
+
}
|
|
58
|
+
const requiredScopes = role.access === "protected"
|
|
59
|
+
? protectedScopes("Submission", role.requiredScopes)
|
|
60
|
+
: publicScopes(role.requiredScopes);
|
|
61
|
+
return Object.freeze({ collection, toolName, access: role.access, requiredScopes });
|
|
62
|
+
});
|
|
63
|
+
return projections.sort(compareCollection);
|
|
64
|
+
}
|
|
65
|
+
function compileProtectedRoles(roleName, value, declared) {
|
|
66
|
+
const entries = optionalArray(value, `${roleName} roles`);
|
|
67
|
+
const collections = new Set();
|
|
68
|
+
const projections = entries.map((entry) => {
|
|
69
|
+
const role = requireRecord(entry, `${capitalize(roleName)} role`);
|
|
70
|
+
rejectUnknownKeys(role, ["collection", "access", "requiredScopes"], `${capitalize(roleName)} role`);
|
|
71
|
+
const collection = collectionReference(role.collection, declared);
|
|
72
|
+
if (collections.has(collection))
|
|
73
|
+
throw new TypeError(`Duplicate ${roleName} role for collection: ${collection}`);
|
|
74
|
+
collections.add(collection);
|
|
75
|
+
if (role.access !== "protected") {
|
|
76
|
+
throw new TypeError(`${capitalize(roleName)} roles must use protected access`);
|
|
77
|
+
}
|
|
78
|
+
return Object.freeze({
|
|
79
|
+
collection,
|
|
80
|
+
access: "protected",
|
|
81
|
+
requiredScopes: protectedScopes(capitalize(roleName), role.requiredScopes),
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
return projections.sort(compareCollection);
|
|
85
|
+
}
|
|
86
|
+
function collectionReference(value, declared) {
|
|
87
|
+
const checked = feedbackCollectionSchema.safeParse(value);
|
|
88
|
+
if (!checked.success || !declared.has(checked.data)) {
|
|
89
|
+
throw new TypeError(`Role references undeclared collection: ${String(value)}`);
|
|
90
|
+
}
|
|
91
|
+
return checked.data;
|
|
92
|
+
}
|
|
93
|
+
function submissionToolName(collection) {
|
|
94
|
+
const slug = collection.replace(/[._]+/g, "-");
|
|
95
|
+
return `submit-${slug}-feedback`;
|
|
96
|
+
}
|
|
97
|
+
function protectedScopes(roleName, value) {
|
|
98
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
99
|
+
throw new TypeError(`${roleName} role requires at least one scope`);
|
|
100
|
+
}
|
|
101
|
+
const scopes = value.map((scope) => {
|
|
102
|
+
if (typeof scope !== "string" || scope.length > 240 || !/^[\x21\x23-\x5B\x5D-\x7E]+$/.test(scope)) {
|
|
103
|
+
throw new TypeError(`${roleName} role contains an invalid scope`);
|
|
104
|
+
}
|
|
105
|
+
return scope;
|
|
106
|
+
});
|
|
107
|
+
if (new Set(scopes).size !== scopes.length) {
|
|
108
|
+
throw new TypeError(`${roleName} role contains duplicate scopes`);
|
|
109
|
+
}
|
|
110
|
+
return Object.freeze(scopes);
|
|
111
|
+
}
|
|
112
|
+
function publicScopes(value) {
|
|
113
|
+
if (value !== undefined)
|
|
114
|
+
throw new TypeError("Public submission roles cannot declare scopes");
|
|
115
|
+
return Object.freeze([]);
|
|
116
|
+
}
|
|
117
|
+
function optionalArray(value, label) {
|
|
118
|
+
if (value === undefined)
|
|
119
|
+
return [];
|
|
120
|
+
if (!Array.isArray(value))
|
|
121
|
+
throw new TypeError(`${label} must be an array`);
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
function requireRecord(value, label) {
|
|
125
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
126
|
+
throw new TypeError(`${label} must be an object`);
|
|
127
|
+
}
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
function rejectUnknownKeys(value, allowed, label) {
|
|
131
|
+
if (Object.keys(value).some((key) => !allowed.includes(key))) {
|
|
132
|
+
throw new TypeError(`${label} contains an unsupported field`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function compareCollection(a, b) {
|
|
136
|
+
return a.collection < b.collection ? -1 : a.collection > b.collection ? 1 : 0;
|
|
137
|
+
}
|
|
138
|
+
function capitalize(value) {
|
|
139
|
+
return `${value[0]?.toUpperCase()}${value.slice(1)}`;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=collections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.js","sourceRoot":"","sources":["../src/collections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,EAAE;KAC/C,KAAK,CAAC,0BAA0B,CAAC;KACjC,QAAQ,CAAC,mDAAmD,CAAC,CAAC;AAuDjE,MAAM,UAAU,yBAAyB,CACvC,OAAmC;IAEnC,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,EAAE,oCAAoC,CAAC,CAAC;IACzE,iBAAiB,CAAC,GAAG,EAAE,CAAC,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,CAAC,EAC5E,oCAAoC,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,SAAS,CAAC,qEAAqE,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC/C,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,wBAAwB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,SAAS,CAAC,wCAAwC,CAAC,CAAC;QACpF,IAAI,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,SAAS,CAAC,yBAAyB,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,WAAW,GAAG,sBAAsB,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,qBAAqB,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC7E,MAAM,QAAQ,GAAG,qBAAqB,CAAC,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1E,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACvF,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACnF,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACjF,MAAM,SAAS,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;QAC/D,EAAE;QACF,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;YACnB,GAAG,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,YAAqB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,GAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5D,CAAC;KACH,CAAC,CAAC,CAAC;IAEJ,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;QACnC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;QACvC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;QACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;KAClC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAc,EACd,QAAyC;IAEzC,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACxC,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;QACrD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC/F,MAAM,IAAI,SAAS,CAAC,kEAAkE,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAChD,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;QAChG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxB,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC5D,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,KAAK,WAAW;YAChD,CAAC,CAAC,eAAe,CAAC,YAAY,EAAE,IAAI,CAAC,cAAc,CAAC;YACpD,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IACH,OAAO,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,qBAAqB,CAC5B,QAAgC,EAChC,KAAc,EACd,QAAyC;IAEzC,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,QAAQ,QAAQ,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;IAClD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACxC,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClE,iBAAiB,CAAC,IAAI,EAAE,CAAC,YAAY,EAAE,QAAQ,EAAE,gBAAgB,CAAC,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACpG,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAClE,IAAI,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,aAAa,QAAQ,yBAAyB,UAAU,EAAE,CAAC,CAAC;QACjH,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAChC,MAAM,IAAI,SAAS,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,kCAAkC,CAAC,CAAC;QACjF,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,UAAU;YACV,MAAM,EAAE,WAAoB;YAC5B,cAAc,EAAE,eAAe,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC;SAC3E,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,mBAAmB,CAC1B,KAAc,EACd,QAAyC;IAEzC,MAAM,OAAO,GAAG,wBAAwB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1D,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,SAAS,CAAC,0CAA0C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC;AAED,SAAS,kBAAkB,CAAC,UAA8B;IACxD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,UAAU,IAAI,WAAW,CAAC;AACnC,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB,EAAE,KAAc;IACvD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,SAAS,CAAC,GAAG,QAAQ,mCAAmC,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACjC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAClG,MAAM,IAAI,SAAS,CAAC,GAAG,QAAQ,iCAAiC,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IACH,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC3C,MAAM,IAAI,SAAS,CAAC,GAAG,QAAQ,iCAAiC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;IAC9F,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,KAAa;IAClD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,mBAAmB,CAAC,CAAC;IAC5E,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,KAAa;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,oBAAoB,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,KAA0C,CAAC;AACpD,CAAC;AAED,SAAS,iBAAiB,CACxB,KAAwC,EACxC,OAA0B,EAC1B,KAAa;IAEb,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,gCAAgC,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAyD,CAAI,EAAE,CAAI;IAC3F,OAAO,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACvD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type EmseepeaTool, type Principal } from "@emseepea/server";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { type FeedbackCollection, type FeedbackCollectionsDefinition } from "./collections.js";
|
|
4
|
+
export * from "./collections.js";
|
|
3
5
|
export declare const feedbackObservationSchema: z.ZodEnum<{
|
|
4
6
|
error: "error";
|
|
5
7
|
friction: "friction";
|
|
@@ -72,6 +74,131 @@ export interface FeedbackAdapterContext {
|
|
|
72
74
|
readonly signal: AbortSignal;
|
|
73
75
|
readonly deadlineMs: number;
|
|
74
76
|
}
|
|
77
|
+
export declare const feedbackSubmissionSourceReferenceSchema: z.ZodObject<{
|
|
78
|
+
system: z.ZodString;
|
|
79
|
+
id: z.ZodString;
|
|
80
|
+
}, z.core.$strict>;
|
|
81
|
+
export declare const feedbackSubmissionRecordSchema: z.ZodObject<{
|
|
82
|
+
collection: z.ZodString;
|
|
83
|
+
submissionId: z.ZodString;
|
|
84
|
+
scope: z.ZodString;
|
|
85
|
+
observation: z.ZodEnum<{
|
|
86
|
+
error: "error";
|
|
87
|
+
friction: "friction";
|
|
88
|
+
annoyance: "annoyance";
|
|
89
|
+
unnecessary_difficulty: "unnecessary_difficulty";
|
|
90
|
+
confusion: "confusion";
|
|
91
|
+
repetition: "repetition";
|
|
92
|
+
unexpected_good_result: "unexpected_good_result";
|
|
93
|
+
unexpected_bad_result: "unexpected_bad_result";
|
|
94
|
+
capability_mismatch: "capability_mismatch";
|
|
95
|
+
suggestion: "suggestion";
|
|
96
|
+
notable_success: "notable_success";
|
|
97
|
+
}>;
|
|
98
|
+
detail: z.ZodString;
|
|
99
|
+
context: z.ZodOptional<z.ZodUnknown>;
|
|
100
|
+
recordedAt: z.ZodISODateTime;
|
|
101
|
+
source: z.ZodObject<{
|
|
102
|
+
system: z.ZodString;
|
|
103
|
+
id: z.ZodString;
|
|
104
|
+
}, z.core.$strict>;
|
|
105
|
+
}, z.core.$strip>;
|
|
106
|
+
export declare const feedbackSubmissionReferenceSchema: z.ZodObject<{
|
|
107
|
+
collection: z.ZodString;
|
|
108
|
+
submissionId: z.ZodString;
|
|
109
|
+
}, z.core.$strict>;
|
|
110
|
+
export declare const feedbackSubmissionRecordedEventSchema: z.ZodObject<{
|
|
111
|
+
id: z.ZodString;
|
|
112
|
+
type: z.ZodLiteral<"feedback.submission.recorded">;
|
|
113
|
+
occurredAt: z.ZodISODateTime;
|
|
114
|
+
record: z.ZodObject<{
|
|
115
|
+
collection: z.ZodString;
|
|
116
|
+
submissionId: z.ZodString;
|
|
117
|
+
}, z.core.$strict>;
|
|
118
|
+
source: z.ZodObject<{
|
|
119
|
+
system: z.ZodString;
|
|
120
|
+
id: z.ZodString;
|
|
121
|
+
}, z.core.$strict>;
|
|
122
|
+
}, z.core.$strict>;
|
|
123
|
+
export declare const getFeedbackSubmissionQuerySchema: z.ZodObject<{
|
|
124
|
+
collection: z.ZodString;
|
|
125
|
+
submissionId: z.ZodString;
|
|
126
|
+
}, z.core.$strict>;
|
|
127
|
+
export declare const listFeedbackSubmissionsQuerySchema: z.ZodObject<{
|
|
128
|
+
collection: z.ZodString;
|
|
129
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
130
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
131
|
+
}, z.core.$strict>;
|
|
132
|
+
export declare const feedbackSubmissionPageSchema: z.ZodObject<{
|
|
133
|
+
submissions: z.ZodArray<z.ZodObject<{
|
|
134
|
+
collection: z.ZodString;
|
|
135
|
+
submissionId: z.ZodString;
|
|
136
|
+
scope: z.ZodString;
|
|
137
|
+
observation: z.ZodEnum<{
|
|
138
|
+
error: "error";
|
|
139
|
+
friction: "friction";
|
|
140
|
+
annoyance: "annoyance";
|
|
141
|
+
unnecessary_difficulty: "unnecessary_difficulty";
|
|
142
|
+
confusion: "confusion";
|
|
143
|
+
repetition: "repetition";
|
|
144
|
+
unexpected_good_result: "unexpected_good_result";
|
|
145
|
+
unexpected_bad_result: "unexpected_bad_result";
|
|
146
|
+
capability_mismatch: "capability_mismatch";
|
|
147
|
+
suggestion: "suggestion";
|
|
148
|
+
notable_success: "notable_success";
|
|
149
|
+
}>;
|
|
150
|
+
detail: z.ZodString;
|
|
151
|
+
context: z.ZodOptional<z.ZodUnknown>;
|
|
152
|
+
recordedAt: z.ZodISODateTime;
|
|
153
|
+
source: z.ZodObject<{
|
|
154
|
+
system: z.ZodString;
|
|
155
|
+
id: z.ZodString;
|
|
156
|
+
}, z.core.$strict>;
|
|
157
|
+
}, z.core.$strip>>;
|
|
158
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
159
|
+
}, z.core.$strip>;
|
|
160
|
+
export type FeedbackSubmissionSourceReference = z.output<typeof feedbackSubmissionSourceReferenceSchema>;
|
|
161
|
+
export type FeedbackSubmissionRecord = z.output<typeof feedbackSubmissionRecordSchema>;
|
|
162
|
+
export type FeedbackSubmissionReference = z.output<typeof feedbackSubmissionReferenceSchema>;
|
|
163
|
+
export type FeedbackSubmissionRecordedEvent = z.output<typeof feedbackSubmissionRecordedEventSchema>;
|
|
164
|
+
export type GetFeedbackSubmissionQuery = z.output<typeof getFeedbackSubmissionQuerySchema>;
|
|
165
|
+
export type ListFeedbackSubmissionsQuery = z.output<typeof listFeedbackSubmissionsQuerySchema>;
|
|
166
|
+
export type FeedbackSubmissionPage = z.output<typeof feedbackSubmissionPageSchema>;
|
|
167
|
+
export interface FeedbackCollectionBackend {
|
|
168
|
+
getSubmission(query: GetFeedbackSubmissionQuery, context: FeedbackAdapterContext): FeedbackSubmissionRecord | undefined | Promise<FeedbackSubmissionRecord | undefined>;
|
|
169
|
+
listSubmissions(query: ListFeedbackSubmissionsQuery, context: FeedbackAdapterContext): FeedbackSubmissionPage | Promise<FeedbackSubmissionPage>;
|
|
170
|
+
}
|
|
171
|
+
export interface FeedbackCollectionSubmissionBackend<Context = undefined> extends FeedbackCollectionBackend {
|
|
172
|
+
recordSubmission(command: Readonly<{
|
|
173
|
+
collection: FeedbackCollection;
|
|
174
|
+
observation: FeedbackObservation;
|
|
175
|
+
detail: string;
|
|
176
|
+
context: Context;
|
|
177
|
+
}>, context: FeedbackAdapterContext): FeedbackSubmissionRecord | Promise<FeedbackSubmissionRecord>;
|
|
178
|
+
}
|
|
179
|
+
export type FeedbackSubmissionRecordedHook = (event: Readonly<FeedbackSubmissionRecordedEvent>, context: FeedbackAdapterContext) => void | Promise<void>;
|
|
180
|
+
export interface InMemoryFeedbackCollectionOptions {
|
|
181
|
+
readonly sourceSystem?: string;
|
|
182
|
+
readonly initialRecords?: readonly unknown[];
|
|
183
|
+
readonly createSubmissionId?: () => string;
|
|
184
|
+
readonly now?: () => string;
|
|
185
|
+
}
|
|
186
|
+
export declare function createInMemoryFeedbackCollectionBackend<Context = undefined>(options?: InMemoryFeedbackCollectionOptions): FeedbackCollectionSubmissionBackend<Context>;
|
|
187
|
+
export interface FeedbackCollectionSubmissionOptions<ContextSchema extends z.ZodType = z.ZodUndefined> {
|
|
188
|
+
readonly definition: FeedbackCollectionsDefinition;
|
|
189
|
+
readonly scope?: string | ((principal: Principal | undefined) => string);
|
|
190
|
+
readonly contextSchema?: ContextSchema;
|
|
191
|
+
readonly backend: FeedbackCollectionSubmissionBackend<z.output<ContextSchema>>;
|
|
192
|
+
readonly hooks?: readonly FeedbackSubmissionRecordedHook[];
|
|
193
|
+
}
|
|
194
|
+
export declare function defineFeedbackCollectionSubmissions<ContextSchema extends z.ZodType = z.ZodUndefined>(options: FeedbackCollectionSubmissionOptions<ContextSchema>): readonly EmseepeaTool[];
|
|
195
|
+
export interface FeedbackCollectionOperatorOptions<ContextSchema extends z.ZodType = z.ZodNever> {
|
|
196
|
+
readonly definition: FeedbackCollectionsDefinition;
|
|
197
|
+
readonly scope?: string | ((principal: Principal | undefined) => string);
|
|
198
|
+
readonly contextSchema?: ContextSchema;
|
|
199
|
+
readonly backend: FeedbackCollectionBackend;
|
|
200
|
+
}
|
|
201
|
+
export declare function defineFeedbackCollectionOperators<ContextSchema extends z.ZodType = z.ZodNever>(options: FeedbackCollectionOperatorOptions<ContextSchema>): readonly EmseepeaTool[];
|
|
75
202
|
export declare const feedbackEventSchema: z.ZodObject<{
|
|
76
203
|
id: z.ZodString;
|
|
77
204
|
type: z.ZodEnum<{
|
|
@@ -316,5 +443,4 @@ export interface FeedbackConversationOptions {
|
|
|
316
443
|
readonly hooks?: readonly FeedbackEventHook[];
|
|
317
444
|
}
|
|
318
445
|
export declare function defineFeedbackConversation(options: FeedbackConversationOptions): readonly EmseepeaTool[];
|
|
319
|
-
export {};
|
|
320
446
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,6BAA6B,EACnC,MAAM,kBAAkB,CAAC;AAE1B,cAAc,kBAAkB,CAAC;AAMjC,eAAO,MAAM,yBAAyB;;;;;;;;;;;;EAYuB,CAAC;AAe9D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;iBAWhC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;iBAM/B,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;iBAIrC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC7E,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACrE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACnE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE/E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,uCAAuC;;;kBAGlD,CAAC;AAEH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;iBASzC,CAAC;AAEH,eAAO,MAAM,iCAAiC;;;kBAG5C,CAAC;AAEH,eAAO,MAAM,qCAAqC;;;;;;;;;;;;kBAMhD,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;kBAAoC,CAAC;AAClF,eAAO,MAAM,kCAAkC;;;;kBAI7C,CAAC;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGvC,CAAC;AAEH,MAAM,MAAM,iCAAiC,GAAG,CAAC,CAAC,MAAM,CACtD,OAAO,uCAAuC,CAC/C,CAAC;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,8BAA8B,CAAC,CAAC;AACvF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAC7F,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,CACpD,OAAO,qCAAqC,CAC7C,CAAC;AACF,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAC3F,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAC/F,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAEnF,MAAM,WAAW,yBAAyB;IACxC,aAAa,CACX,KAAK,EAAE,0BAA0B,EACjC,OAAO,EAAE,sBAAsB,GAC9B,wBAAwB,GAAG,SAAS,GAAG,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAAC;IACxF,eAAe,CACb,KAAK,EAAE,4BAA4B,EACnC,OAAO,EAAE,sBAAsB,GAC9B,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC7D;AAED,MAAM,WAAW,mCAAmC,CAAC,OAAO,GAAG,SAAS,CACtE,SAAQ,yBAAyB;IACjC,gBAAgB,CACd,OAAO,EAAE,QAAQ,CAAC;QAChB,UAAU,EAAE,kBAAkB,CAAC;QAC/B,WAAW,EAAE,mBAAmB,CAAC;QACjC,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC,EACF,OAAO,EAAE,sBAAsB,GAC9B,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACjE;AAED,MAAM,MAAM,8BAA8B,GAAG,CAC3C,KAAK,EAAE,QAAQ,CAAC,+BAA+B,CAAC,EAChD,OAAO,EAAE,sBAAsB,KAC5B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED,wBAAgB,uCAAuC,CAAC,OAAO,GAAG,SAAS,EACzE,OAAO,GAAE,iCAAsC,GAC9C,mCAAmC,CAAC,OAAO,CAAC,CAyE9C;AAED,MAAM,WAAW,mCAAmC,CAAC,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,YAAY;IACnG,QAAQ,CAAC,UAAU,EAAE,6BAA6B,CAAC;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,KAAK,MAAM,CAAC,CAAC;IACzE,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,mCAAmC,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,8BAA8B,EAAE,CAAC;CAC5D;AAED,wBAAgB,mCAAmC,CAAC,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,YAAY,EAClG,OAAO,EAAE,mCAAmC,CAAC,aAAa,CAAC,GAC1D,SAAS,YAAY,EAAE,CAwEzB;AAED,MAAM,WAAW,iCAAiC,CAAC,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ;IAC7F,QAAQ,CAAC,UAAU,EAAE,6BAA6B,CAAC;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,KAAK,MAAM,CAAC,CAAC;IACzE,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;CAC7C;AAOD,wBAAgB,iCAAiC,CAAC,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,EAC5F,OAAO,EAAE,iCAAiC,CAAC,aAAa,CAAC,GACxD,SAAS,YAAY,EAAE,CAqHzB;AAQD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;kBAQ9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACjE,MAAM,MAAM,iBAAiB,GAAG,CAC9B,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,EAC9B,OAAO,EAAE,QAAQ,CAAC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,KAC3D,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,MAAM,WAAW,yBAAyB,CAAC,OAAO,GAAG,SAAS;IAC5D,MAAM,CACJ,OAAO,EAAE,QAAQ,CAAC;QAChB,WAAW,EAAE,mBAAmB,CAAC;QACjC,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC,EACF,OAAO,EAAE,sBAAsB,GAC9B,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACjE;AAED,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;kBAA4C,CAAC;AACrE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAwBtE,QAAA,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;iBAI1B,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE9E,MAAM,WAAW,yBAAyB,CAAC,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,YAAY;IACzF,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAC;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,KAAK,MAAM,CAAC,CAAC;IACzE,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC/C;AAED,wBAAgB,wBAAwB,CAAC,aAAa,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,YAAY,EACvF,OAAO,EAAE,yBAAyB,CAAC,aAAa,CAAC,GAChD,YAAY,CAkEd;AAED,QAAA,MAAM,yBAAyB;;;kBAG7B,CAAC;AACH,QAAA,MAAM,0BAA0B;;;kBAG9B,CAAC;AACH,QAAA,MAAM,sBAAsB;;;kBAG1B,CAAC;AACH,QAAA,MAAM,oBAAoB;;kBAExB,CAAC;AAMH,QAAA,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAG5B,CAAC;AACH,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAG7B,CAAC;AACH,QAAA,MAAM,uBAAuB;;;;;;;;;;;kBAE3B,CAAC;AACH,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAGzB,CAAC;AAEH,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACrF,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACvF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAClF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACpF,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAChF,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE5E,MAAM,WAAW,2BAA2B;IAC1C,YAAY,CACV,OAAO,EAAE,2BAA2B,EACpC,OAAO,EAAE,sBAAsB,GAC9B,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAC;IACpE,aAAa,CACX,OAAO,EAAE,4BAA4B,EACrC,OAAO,EAAE,sBAAsB,GAC9B,2BAA2B,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACtE,WAAW,CACT,KAAK,EAAE,wBAAwB,EAC/B,OAAO,EAAE,sBAAsB,GAC9B,yBAAyB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAClE,SAAS,CACP,KAAK,EAAE,sBAAsB,EAC7B,OAAO,EAAE,sBAAsB,GAC9B,uBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,KAAK,MAAM,CAAC;IAC9D,QAAQ,CAAC,OAAO,EAAE,2BAA2B,CAAC;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC/C;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,SAAS,YAAY,EAAE,CAkFxG"}
|