@atproto/sync 0.1.40 → 0.2.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 (50) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/events.d.ts +12 -13
  3. package/dist/events.d.ts.map +1 -1
  4. package/dist/events.js.map +1 -1
  5. package/dist/firehose/index.d.ts +8 -8
  6. package/dist/firehose/index.d.ts.map +1 -1
  7. package/dist/firehose/index.js +23 -13
  8. package/dist/firehose/index.js.map +1 -1
  9. package/dist/lexicons/com/atproto/sync/subscribeRepos.d.ts +3 -0
  10. package/dist/lexicons/com/atproto/sync/subscribeRepos.d.ts.map +1 -0
  11. package/dist/lexicons/com/atproto/sync/subscribeRepos.defs.d.ts +152 -0
  12. package/dist/lexicons/com/atproto/sync/subscribeRepos.defs.d.ts.map +1 -0
  13. package/dist/lexicons/com/atproto/sync/subscribeRepos.defs.js +75 -0
  14. package/dist/lexicons/com/atproto/sync/subscribeRepos.defs.js.map +1 -0
  15. package/dist/lexicons/com/atproto/sync/subscribeRepos.js +45 -0
  16. package/dist/lexicons/com/atproto/sync/subscribeRepos.js.map +1 -0
  17. package/dist/lexicons/com/atproto/sync.d.ts +2 -0
  18. package/dist/lexicons/com/atproto/sync.d.ts.map +1 -0
  19. package/dist/lexicons/com/atproto/sync.js +41 -0
  20. package/dist/lexicons/com/atproto/sync.js.map +1 -0
  21. package/dist/lexicons/com/atproto.d.ts +2 -0
  22. package/dist/lexicons/com/atproto.d.ts.map +1 -0
  23. package/dist/lexicons/com/atproto.js +41 -0
  24. package/dist/lexicons/com/atproto.js.map +1 -0
  25. package/dist/lexicons/com.d.ts +2 -0
  26. package/dist/lexicons/com.d.ts.map +1 -0
  27. package/dist/lexicons/com.js +41 -0
  28. package/dist/lexicons/com.js.map +1 -0
  29. package/dist/lexicons/index.d.ts +2 -0
  30. package/dist/lexicons/index.d.ts.map +1 -0
  31. package/dist/lexicons/index.js +41 -0
  32. package/dist/lexicons/index.js.map +1 -0
  33. package/dist/util.d.ts +2 -2
  34. package/dist/util.d.ts.map +1 -1
  35. package/dist/util.js +7 -3
  36. package/dist/util.js.map +1 -1
  37. package/package.json +8 -7
  38. package/src/events.ts +12 -13
  39. package/src/firehose/index.ts +53 -45
  40. package/src/util.ts +10 -10
  41. package/tests/firehose.test.ts +11 -8
  42. package/tests/runner.test.ts +1 -1
  43. package/tsconfig.build.tsbuildinfo +1 -1
  44. package/tsconfig.json +4 -1
  45. package/tsconfig.tests.json +8 -0
  46. package/dist/firehose/lexicons.d.ts +0 -105
  47. package/dist/firehose/lexicons.d.ts.map +0 -1
  48. package/dist/firehose/lexicons.js +0 -299
  49. package/dist/firehose/lexicons.js.map +0 -1
  50. package/src/firehose/lexicons.ts +0 -446
@@ -1,4 +1,3 @@
1
- import { CID } from 'multiformats/cid'
2
1
  import type { ClientOptions } from 'ws'
3
2
  import { Deferrable, createDeferrable, wait } from '@atproto/common'
4
3
  import {
@@ -6,6 +5,7 @@ import {
6
5
  IdResolver,
7
6
  parseToAtprotoDocument,
8
7
  } from '@atproto/identity'
8
+ import { Cid } from '@atproto/lex'
9
9
  import {
10
10
  RepoVerificationError,
11
11
  cborToLexRecord,
@@ -26,21 +26,9 @@ import {
26
26
  IdentityEvt,
27
27
  SyncEvt,
28
28
  } from '../events'
29
+ import { com } from '../lexicons/index.js'
29
30
  import { EventRunner } from '../runner'
30
31
  import { didAndSeqForEvt } from '../util'
31
- import {
32
- type Account,
33
- type Commit,
34
- type Identity,
35
- type RepoEvent,
36
- RepoOp,
37
- type Sync,
38
- isAccount,
39
- isCommit,
40
- isIdentity,
41
- isSync,
42
- isValidRepoEvent,
43
- } from './lexicons'
44
32
 
45
33
  export type FirehoseOptions = ClientOptions & {
46
34
  idResolver: IdResolver
@@ -65,7 +53,7 @@ export type FirehoseOptions = ClientOptions & {
65
53
  }
66
54
 
67
55
  export class Firehose {
68
- private sub: Subscription<RepoEvent>
56
+ private sub: Subscription<com.atproto.sync.subscribeRepos.$Message>
69
57
  private abortController: AbortController
70
58
  private destoryDefer: Deferrable
71
59
  private matchCollection: ((col: string) => boolean) | null = null
@@ -98,7 +86,7 @@ export class Firehose {
98
86
  this.sub = new Subscription({
99
87
  ...opts,
100
88
  service: opts.service ?? 'wss://bsky.network',
101
- method: 'com.atproto.sync.subscribeRepos',
89
+ method: com.atproto.sync.subscribeRepos.$lxm,
102
90
  signal: this.abortController.signal,
103
91
  getParams: async () => {
104
92
  const getCursorFn = () =>
@@ -110,10 +98,11 @@ export class Firehose {
110
98
  return { cursor }
111
99
  },
112
100
  validate: (value: unknown) => {
113
- try {
114
- return isValidRepoEvent(value)
115
- } catch (err) {
116
- this.opts.onError(new FirehoseValidationError(err, value))
101
+ const result = com.atproto.sync.subscribeRepos.$message.safeParse(value)
102
+ if (result.success) {
103
+ return result.value
104
+ } else {
105
+ this.opts.onError(new FirehoseValidationError(result.reason, value))
117
106
  }
118
107
  },
119
108
  })
@@ -152,9 +141,13 @@ export class Firehose {
152
141
  }
153
142
  }
154
143
 
155
- private async parseEvt(evt: RepoEvent): Promise<Event[]> {
144
+ private async parseEvt(
145
+ evt: com.atproto.sync.subscribeRepos.$Message,
146
+ ): Promise<Event[]> {
156
147
  try {
157
- if (isCommit(evt) && !this.opts.excludeCommit) {
148
+ if (com.atproto.sync.subscribeRepos.commit.$isTypeOf(evt)) {
149
+ if (this.opts.excludeCommit) return []
150
+
158
151
  return this.opts.unauthenticatedCommits
159
152
  ? await parseCommitUnauthenticated(evt, this.matchCollection)
160
153
  : await parseCommitAuthenticated(
@@ -162,17 +155,23 @@ export class Firehose {
162
155
  evt,
163
156
  this.matchCollection,
164
157
  )
165
- } else if (isAccount(evt) && !this.opts.excludeAccount) {
158
+ } else if (com.atproto.sync.subscribeRepos.account.$isTypeOf(evt)) {
159
+ if (this.opts.excludeAccount) return []
160
+
166
161
  const parsed = parseAccount(evt)
167
162
  return parsed ? [parsed] : []
168
- } else if (isIdentity(evt) && !this.opts.excludeIdentity) {
163
+ } else if (com.atproto.sync.subscribeRepos.identity.$isTypeOf(evt)) {
164
+ if (this.opts.excludeIdentity) return []
165
+
169
166
  const parsed = await parseIdentity(
170
167
  this.opts.idResolver,
171
168
  evt,
172
169
  this.opts.unauthenticatedHandles,
173
170
  )
174
171
  return parsed ? [parsed] : []
175
- } else if (isSync(evt) && !this.opts.excludeSync) {
172
+ } else if (com.atproto.sync.subscribeRepos.sync.$isTypeOf(evt)) {
173
+ if (this.opts.excludeSync) return []
174
+
176
175
  const parsed = await parseSync(evt)
177
176
  return parsed ? [parsed] : []
178
177
  } else {
@@ -184,7 +183,7 @@ export class Firehose {
184
183
  }
185
184
  }
186
185
 
187
- private async processEvt(evt: RepoEvent) {
186
+ private async processEvt(evt: com.atproto.sync.subscribeRepos.$Message) {
188
187
  const parsed = await this.parseEvt(evt)
189
188
  for (const write of parsed) {
190
189
  try {
@@ -203,7 +202,7 @@ export class Firehose {
203
202
 
204
203
  export const parseCommitAuthenticated = async (
205
204
  idResolver: IdResolver,
206
- evt: Commit,
205
+ evt: com.atproto.sync.subscribeRepos.Commit,
207
206
  matchCollection?: ((col: string) => boolean) | null,
208
207
  forceKeyRefresh = false,
209
208
  ): Promise<CommitEvt[]> => {
@@ -221,7 +220,7 @@ export const parseCommitAuthenticated = async (
221
220
  }
222
221
  })
223
222
  const key = await idResolver.did.resolveAtprotoKey(did, forceKeyRefresh)
224
- const verifiedCids: Record<string, CID | null> = {}
223
+ const verifiedCids: Record<string, Cid | null> = {}
225
224
  try {
226
225
  const results = await verifyProofs(evt.blocks, claims, did, key)
227
226
  results.verified.forEach((op) => {
@@ -234,20 +233,25 @@ export const parseCommitAuthenticated = async (
234
233
  }
235
234
  throw err
236
235
  }
237
- const verifiedOps: RepoOp[] = ops.filter((op) => {
238
- if (op.action === 'delete') {
239
- return verifiedCids[op.path] === null
240
- } else {
241
- return op.cid !== null && op.cid.equals(verifiedCids[op.path])
242
- }
243
- })
236
+ const verifiedOps: com.atproto.sync.subscribeRepos.RepoOp[] = ops.filter(
237
+ (op) => {
238
+ const verifiedCid = verifiedCids[op.path]
239
+ if (op.action === 'delete') {
240
+ return verifiedCid === null
241
+ } else {
242
+ return (
243
+ op.cid != null && verifiedCid != null && verifiedCid.equals(op.cid)
244
+ )
245
+ }
246
+ },
247
+ )
244
248
  return formatCommitOps(evt, verifiedOps, {
245
249
  skipCidVerification: true, // already checked via verifyProofs()
246
250
  })
247
251
  }
248
252
 
249
253
  export const parseCommitUnauthenticated = async (
250
- evt: Commit,
254
+ evt: com.atproto.sync.subscribeRepos.Commit,
251
255
  matchCollection?: ((col: string) => boolean) | null,
252
256
  ): Promise<CommitEvt[]> => {
253
257
  const ops = maybeFilterOps(evt.ops, matchCollection)
@@ -255,9 +259,9 @@ export const parseCommitUnauthenticated = async (
255
259
  }
256
260
 
257
261
  const maybeFilterOps = (
258
- ops: RepoOp[],
262
+ ops: com.atproto.sync.subscribeRepos.RepoOp[],
259
263
  matchCollection?: ((col: string) => boolean) | null,
260
- ): RepoOp[] => {
264
+ ): com.atproto.sync.subscribeRepos.RepoOp[] => {
261
265
  if (!matchCollection) return ops
262
266
  return ops.filter((op) => {
263
267
  const { collection } = parseDataKey(op.path)
@@ -266,8 +270,8 @@ const maybeFilterOps = (
266
270
  }
267
271
 
268
272
  const formatCommitOps = async (
269
- evt: Commit,
270
- ops: RepoOp[],
273
+ evt: com.atproto.sync.subscribeRepos.Commit,
274
+ ops: com.atproto.sync.subscribeRepos.RepoOp[],
271
275
  options?: { skipCidVerification: boolean },
272
276
  ) => {
273
277
  const car = await readCar(evt.blocks, options)
@@ -284,7 +288,7 @@ const formatCommitOps = async (
284
288
  blocks: car.blocks,
285
289
  rev: evt.rev,
286
290
  uri,
287
- did: uri.host,
291
+ did: uri.did,
288
292
  collection: uri.collection,
289
293
  rkey: uri.rkey,
290
294
  }
@@ -313,7 +317,9 @@ const formatCommitOps = async (
313
317
  return evts
314
318
  }
315
319
 
316
- export const parseSync = async (evt: Sync): Promise<SyncEvt | null> => {
320
+ export const parseSync = async (
321
+ evt: com.atproto.sync.subscribeRepos.Sync,
322
+ ): Promise<SyncEvt | null> => {
317
323
  const car = await readCarWithRoot(evt.blocks)
318
324
 
319
325
  return {
@@ -329,7 +335,7 @@ export const parseSync = async (evt: Sync): Promise<SyncEvt | null> => {
329
335
 
330
336
  export const parseIdentity = async (
331
337
  idResolver: IdResolver,
332
- evt: Identity,
338
+ evt: com.atproto.sync.subscribeRepos.Identity,
333
339
  unauthenticated = false,
334
340
  ): Promise<IdentityEvt | null> => {
335
341
  const res = await idResolver.did.resolve(evt.did)
@@ -361,7 +367,9 @@ const verifyHandle = async (
361
367
  return res === did ? handle : undefined
362
368
  }
363
369
 
364
- export const parseAccount = (evt: Account): AccountEvt | undefined => {
370
+ export const parseAccount = (
371
+ evt: com.atproto.sync.subscribeRepos.Account,
372
+ ): AccountEvt | undefined => {
365
373
  if (evt.status && !isValidStatus(evt.status)) return
366
374
  return {
367
375
  event: 'account',
@@ -389,7 +397,7 @@ export class FirehoseValidationError extends Error {
389
397
  export class FirehoseParseError extends Error {
390
398
  constructor(
391
399
  err: unknown,
392
- public event: RepoEvent,
400
+ public event: com.atproto.sync.subscribeRepos.$Message,
393
401
  ) {
394
402
  super('error in parsing and authenticating firehose event', { cause: err })
395
403
  }
package/src/util.ts CHANGED
@@ -1,16 +1,16 @@
1
- import {
2
- RepoEvent,
3
- isAccount,
4
- isCommit,
5
- isIdentity,
6
- isSync,
7
- } from './firehose/lexicons'
1
+ import { com } from './lexicons/index.js'
8
2
 
9
3
  export const didAndSeqForEvt = (
10
- evt: RepoEvent,
4
+ evt: com.atproto.sync.subscribeRepos.$Message,
11
5
  ): { did: string; seq: number } | undefined => {
12
- if (isCommit(evt)) return { seq: evt.seq, did: evt.repo }
13
- else if (isAccount(evt) || isIdentity(evt) || isSync(evt))
6
+ if (com.atproto.sync.subscribeRepos.commit.$isTypeOf(evt)) {
7
+ return { seq: evt.seq, did: evt.repo }
8
+ } else if (
9
+ com.atproto.sync.subscribeRepos.account.$isTypeOf(evt) ||
10
+ com.atproto.sync.subscribeRepos.identity.$isTypeOf(evt) ||
11
+ com.atproto.sync.subscribeRepos.sync.$isTypeOf(evt)
12
+ ) {
14
13
  return { seq: evt.seq, did: evt.did }
14
+ }
15
15
  return undefined
16
16
  }
@@ -5,8 +5,8 @@ import {
5
5
  mockResolvers,
6
6
  } from '@atproto/dev-env'
7
7
  import { IdResolver } from '@atproto/identity'
8
- import { Firehose, FirehoseOptions, MemoryRunner } from '../src'
9
- import { Create, Event } from '../src/events'
8
+ import { DidString } from '@atproto/syntax'
9
+ import { Create, Event, Firehose, FirehoseOptions, MemoryRunner } from '..'
10
10
 
11
11
  describe('firehose', () => {
12
12
  let network: TestNetworkNoAppView
@@ -47,17 +47,20 @@ describe('firehose', () => {
47
47
  }
48
48
  },
49
49
  onError: (err) => {
50
- throw err
50
+ defer.reject(err)
51
51
  },
52
52
  ...opts,
53
53
  })
54
- firehose.start()
55
- await defer.complete
56
- await firehose.destroy()
57
- return evts
54
+ try {
55
+ firehose.start()
56
+ await defer.complete
57
+ return evts
58
+ } finally {
59
+ await firehose.destroy()
60
+ }
58
61
  }
59
62
 
60
- let alice: string
63
+ let alice: DidString
61
64
 
62
65
  it('reads events from firehose', async () => {
63
66
  const evtsPromise = createAndReadFirehose(6)
@@ -1,5 +1,5 @@
1
1
  import { wait } from '@atproto/common'
2
- import { ConsecutiveList, MemoryRunner } from '../src/runner'
2
+ import { ConsecutiveList, MemoryRunner } from '..'
3
3
 
4
4
  describe('EventRunner utils', () => {
5
5
  describe('ConsecutiveList', () => {
@@ -1 +1 @@
1
- {"root":["./src/events.ts","./src/index.ts","./src/util.ts","./src/firehose/index.ts","./src/firehose/lexicons.ts","./src/runner/consecutive-list.ts","./src/runner/index.ts","./src/runner/memory-runner.ts","./src/runner/types.ts"],"version":"5.8.2"}
1
+ {"root":["./src/events.ts","./src/index.ts","./src/util.ts","./src/firehose/index.ts","./src/lexicons/com.ts","./src/lexicons/index.ts","./src/lexicons/com/atproto.ts","./src/lexicons/com/atproto/sync.ts","./src/lexicons/com/atproto/sync/subscribeRepos.defs.ts","./src/lexicons/com/atproto/sync/subscribeRepos.ts","./src/runner/consecutive-list.ts","./src/runner/index.ts","./src/runner/memory-runner.ts","./src/runner/types.ts"],"version":"5.8.2"}
package/tsconfig.json CHANGED
@@ -1,4 +1,7 @@
1
1
  {
2
2
  "include": [],
3
- "references": [{ "path": "./tsconfig.build.json" }]
3
+ "references": [
4
+ { "path": "./tsconfig.build.json" },
5
+ { "path": "./tsconfig.tests.json" }
6
+ ]
4
7
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig/tests.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./tests",
5
+ "noUnusedLocals": false
6
+ },
7
+ "include": ["./tests"]
8
+ }
@@ -1,105 +0,0 @@
1
- import type { IncomingMessage } from 'node:http';
2
- import type { CID } from 'multiformats/cid';
3
- import { type LexiconDoc } from '@atproto/lexicon';
4
- import type { Auth, ErrorFrame } from '@atproto/xrpc-server';
5
- export declare function isObj(v: unknown): v is Record<string, unknown>;
6
- export declare function hasProp<K extends PropertyKey>(data: object, prop: K): data is Record<K, unknown>;
7
- export interface QueryParams {
8
- /** The last known event seq number to backfill from. */
9
- cursor?: number;
10
- }
11
- export type RepoEvent = Commit | Identity | Account | Sync | Info | {
12
- $type: string;
13
- [k: string]: unknown;
14
- };
15
- export type HandlerError = ErrorFrame<'FutureCursor' | 'ConsumerTooSlow'>;
16
- export type HandlerOutput = HandlerError | RepoEvent;
17
- export type HandlerReqCtx<HA extends Auth = never> = {
18
- auth: HA;
19
- params: QueryParams;
20
- req: IncomingMessage;
21
- signal: AbortSignal;
22
- };
23
- export type Handler<HA extends Auth = never> = (ctx: HandlerReqCtx<HA>) => AsyncIterable<HandlerOutput>;
24
- /** Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature. */
25
- export interface Commit {
26
- /** The stream sequence number of this message. */
27
- seq: number;
28
- /** DEPRECATED -- unused */
29
- rebase: boolean;
30
- /** Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data. */
31
- tooBig: boolean;
32
- /** The repo this event comes from. */
33
- repo: string;
34
- /** Repo commit object CID. */
35
- commit: CID;
36
- /** DEPRECATED -- unused. WARNING -- nullable and optional; stick with optional to ensure golang interoperability. */
37
- prev?: CID | null;
38
- /** The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event. */
39
- rev: string;
40
- /** The rev of the last emitted commit from this repo (if any). */
41
- since: string | null;
42
- /** CAR file containing relevant blocks, as a diff since the previous repo state. */
43
- blocks: Uint8Array;
44
- ops: RepoOp[];
45
- blobs: CID[];
46
- /** Timestamp of when this message was originally broadcast. */
47
- time: string;
48
- [k: string]: unknown;
49
- }
50
- export declare function isCommit(v: unknown): v is Commit;
51
- /** Updates the repo to a new state, without necessarily including that state on the firehose. Used to recover from broken commit streams, data loss incidents, or in situations where upstream host does not know recent state of the repository. */
52
- export interface Sync {
53
- $type?: 'com.atproto.sync.subscribeRepos#sync';
54
- /** The stream sequence number of this message. */
55
- seq: number;
56
- /** The account this repo event corresponds to. Must match that in the commit object. */
57
- did: string;
58
- /** CAR file containing the commit, as a block. The CAR header must include the commit block CID as the first 'root'. */
59
- blocks: Uint8Array;
60
- /** The rev of the commit. This value must match that in the commit object. */
61
- rev: string;
62
- /** Timestamp of when this message was originally broadcast. */
63
- time: string;
64
- }
65
- export declare function isSync(v: unknown): v is Sync;
66
- /** Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache. */
67
- export interface Identity {
68
- seq: number;
69
- did: string;
70
- time: string;
71
- /** The current handle for the account, or 'handle.invalid' if validation fails. This field is optional, might have been validated or passed-through from an upstream source. Semantics and behaviors for PDS vs Relay may evolve in the future; see atproto specs for more details. */
72
- handle?: string;
73
- [k: string]: unknown;
74
- }
75
- export declare function isIdentity(v: unknown): v is Identity;
76
- /** Represents a change to an account's status on a host (eg, PDS or Relay). The semantics of this event are that the status is at the host which emitted the event, not necessarily that at the currently active PDS. Eg, a Relay takedown would emit a takedown with active=false, even if the PDS is still active. */
77
- export interface Account {
78
- seq: number;
79
- did: string;
80
- time: string;
81
- /** Indicates that the account has a repository which can be fetched from the host that emitted this event. */
82
- active: boolean;
83
- /** If active=false, this optional field indicates a reason for why the account is not active. */
84
- status?: 'takendown' | 'suspended' | 'deleted' | 'deactivated' | string;
85
- [k: string]: unknown;
86
- }
87
- export declare function isAccount(v: unknown): v is Account;
88
- export interface Info {
89
- name: 'OutdatedCursor' | string;
90
- message?: string;
91
- [k: string]: unknown;
92
- }
93
- export declare function isInfo(v: unknown): v is Info;
94
- /** A repo operation, ie a mutation of a single record. */
95
- export interface RepoOp {
96
- action: 'create' | 'update' | 'delete' | string;
97
- path: string;
98
- /** For creates and updates, the new record CID. For deletions, null. */
99
- cid: CID | null;
100
- [k: string]: unknown;
101
- }
102
- export declare function isRepoOp(v: unknown): v is RepoOp;
103
- export declare const ComAtprotoSyncSubscribeRepos: LexiconDoc;
104
- export declare const isValidRepoEvent: (evt: unknown) => RepoEvent;
105
- //# sourceMappingURL=lexicons.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lexicons.d.ts","sourceRoot":"","sources":["../../src/firehose/lexicons.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,kBAAkB,CAAA;AAC5D,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAI5D,wBAAgB,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9D;AAED,wBAAgB,OAAO,CAAC,CAAC,SAAS,WAAW,EAC3C,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,GACN,IAAI,IAAI,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAE5B;AAED,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,QAAQ,GACR,OAAO,GACP,IAAI,GACJ,IAAI,GACJ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAA;AAC3C,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,cAAc,GAAG,iBAAiB,CAAC,CAAA;AACzE,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,SAAS,CAAA;AACpD,MAAM,MAAM,aAAa,CAAC,EAAE,SAAS,IAAI,GAAG,KAAK,IAAI;IACnD,IAAI,EAAE,EAAE,CAAA;IACR,MAAM,EAAE,WAAW,CAAA;IACnB,GAAG,EAAE,eAAe,CAAA;IACpB,MAAM,EAAE,WAAW,CAAA;CACpB,CAAA;AACD,MAAM,MAAM,OAAO,CAAC,EAAE,SAAS,IAAI,GAAG,KAAK,IAAI,CAC7C,GAAG,EAAE,aAAa,CAAC,EAAE,CAAC,KACnB,aAAa,CAAC,aAAa,CAAC,CAAA;AAEjC,6JAA6J;AAC7J,MAAM,WAAW,MAAM;IACrB,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAA;IACX,2BAA2B;IAC3B,MAAM,EAAE,OAAO,CAAA;IACf,yJAAyJ;IACzJ,MAAM,EAAE,OAAO,CAAA;IACf,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,8BAA8B;IAC9B,MAAM,EAAE,GAAG,CAAA;IACX,qHAAqH;IACrH,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;IACjB,gJAAgJ;IAChJ,GAAG,EAAE,MAAM,CAAA;IACX,kEAAkE;IAClE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,oFAAoF;IACpF,MAAM,EAAE,UAAU,CAAA;IAClB,GAAG,EAAE,MAAM,EAAE,CAAA;IACb,KAAK,EAAE,GAAG,EAAE,CAAA;IACZ,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAA;IACZ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAMhD;AAED,qPAAqP;AACrP,MAAM,WAAW,IAAI;IACnB,KAAK,CAAC,EAAE,sCAAsC,CAAA;IAC9C,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAA;IACX,wFAAwF;IACxF,GAAG,EAAE,MAAM,CAAA;IACX,wHAAwH;IACxH,MAAM,EAAE,UAAU,CAAA;IAClB,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAA;CACb;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,IAAI,CAM5C;AAED,mMAAmM;AACnM,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,uRAAuR;IACvR,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,QAAQ,CAMpD;AAED,wTAAwT;AACxT,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,8GAA8G;IAC9G,MAAM,EAAE,OAAO,CAAA;IACf,iGAAiG;IACjG,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,CAAA;IACvE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,OAAO,CAMlD;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAAA;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,IAAI,CAM5C;AAED,0DAA0D;AAC1D,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAA;IAC/C,IAAI,EAAE,MAAM,CAAA;IACZ,wEAAwE;IACxE,GAAG,EAAE,GAAG,GAAG,IAAI,CAAA;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAMhD;AAED,eAAO,MAAM,4BAA4B,EAAE,UA2Q1C,CAAA;AAID,eAAO,MAAM,gBAAgB,GAAI,KAAK,OAAO,cAK5C,CAAA"}