@effect-app/infra 2.73.4 → 2.74.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.
@@ -0,0 +1,154 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { Array, Context, Effect, type Layer, Option, type S } from "effect-app"
3
+ import { type GetEffectContext, type RPCContextMap } from "effect-app/client"
4
+ import { type Tag } from "effect-app/Context"
5
+ import { typedValuesOf } from "effect-app/utils"
6
+ import { InfraLogger } from "../../logger.js"
7
+ import { sort } from "./tsort.js"
8
+
9
+ export type ContextWithLayer<
10
+ Config,
11
+ Id,
12
+ Service,
13
+ E,
14
+ R,
15
+ MakeE,
16
+ MakeR,
17
+ Tag extends string,
18
+ Args extends [config: Config, headers: Record<string, string>],
19
+ Dependencies extends any[]
20
+ > =
21
+ & Context.Tag<
22
+ Id,
23
+ { handle: (...args: Args) => Effect<Option<Context<Service>>, E, R>; _tag: Tag }
24
+ >
25
+ & {
26
+ Default: Layer.Layer<Id, MakeE, MakeR>
27
+ dependsOn?: Dependencies
28
+ }
29
+
30
+ export type AnyContextWithLayer<Config, Service, Error> =
31
+ | ContextWithLayer<
32
+ Config,
33
+ any,
34
+ Service,
35
+ Error,
36
+ any,
37
+ any,
38
+ any,
39
+ string,
40
+ any,
41
+ any
42
+ >
43
+ | ContextWithLayer<
44
+ Config,
45
+ any,
46
+ Service,
47
+ Error,
48
+ never,
49
+ any,
50
+ never,
51
+ any,
52
+ any,
53
+ any
54
+ >
55
+ | ContextWithLayer<
56
+ Config,
57
+ any,
58
+ Service,
59
+ Error,
60
+ any,
61
+ any,
62
+ never,
63
+ any,
64
+ any,
65
+ any
66
+ >
67
+ | ContextWithLayer<
68
+ Config,
69
+ any,
70
+ Service,
71
+ Error,
72
+ never,
73
+ any,
74
+ any,
75
+ any,
76
+ any,
77
+ any
78
+ >
79
+
80
+ export const mergeContexts = Effect.fnUntraced(
81
+ function*<T extends readonly { maker: any; handle: Effect<Context<any>> }[]>(makers: T) {
82
+ let context = Context.empty()
83
+ for (const mw of makers) {
84
+ yield* InfraLogger.logDebug("Building context for middleware", mw.maker.key ?? mw.maker)
85
+ const moreContext = yield* mw.handle.pipe(Effect.provide(context))
86
+ yield* InfraLogger.logDebug(
87
+ "Built context for middleware",
88
+ mw.maker.key ?? mw.maker,
89
+ (moreContext as any).toJSON().services
90
+ )
91
+ context = Context.merge(context, moreContext)
92
+ }
93
+ return context as Context.Context<Effect.Success<T[number]["handle"]>>
94
+ }
95
+ )
96
+
97
+ export const mergeOptionContexts = Effect.fnUntraced(
98
+ function*<T extends readonly { maker: any; handle: Effect<Option<Context<any>>> }[]>(makers: T) {
99
+ let context = Context.empty()
100
+ for (const mw of makers) {
101
+ yield* InfraLogger.logDebug("Building context for middleware", mw.maker.key ?? mw.maker)
102
+ const moreContext = yield* mw.handle.pipe(Effect.provide(context))
103
+ yield* InfraLogger.logDebug(
104
+ "Built context for middleware",
105
+ mw.maker.key ?? mw.maker,
106
+ Option.map(moreContext, (c) => (c as any).toJSON().services)
107
+ )
108
+ if (moreContext.value) {
109
+ context = Context.merge(context, moreContext.value)
110
+ }
111
+ }
112
+ return context
113
+ }
114
+ )
115
+
116
+ export const implementMiddleware = <T extends Record<string, RPCContextMap.Any>>() =>
117
+ <
118
+ TI extends {
119
+ [K in keyof T]: AnyContextWithLayer<
120
+ { [K in keyof T]?: T[K]["contextActivation"] },
121
+ T[K]["service"],
122
+ S.Schema.Type<T[K]["error"]>
123
+ >
124
+ }
125
+ >(implementations: TI) => ({
126
+ dependencies: typedValuesOf(implementations).map((_) => _.Default) as {
127
+ [K in keyof TI]: TI[K]["Default"]
128
+ }[keyof TI][],
129
+ effect: Effect.gen(function*() {
130
+ const sorted = sort(typedValuesOf(implementations))
131
+
132
+ const makers = yield* Effect.all(sorted)
133
+ return Effect.fnUntraced(
134
+ function*(config: { [K in keyof T]?: T[K]["contextActivation"] }, headers: Record<string, string>) {
135
+ const ctx = yield* mergeOptionContexts(
136
+ Array.map(
137
+ makers,
138
+ (_, i) => ({ maker: sorted[i], handle: (_ as any).handle(config, headers) as any }) as any
139
+ )
140
+ )
141
+ return ctx as Context.Context<
142
+ GetEffectContext<T, typeof config>
143
+ >
144
+ }
145
+ ) as (
146
+ config: { [K in keyof T]?: T[K]["contextActivation"] },
147
+ headers: Record<string, string>
148
+ ) => Effect.Effect<
149
+ Context.Context<GetEffectContext<T, typeof config>>,
150
+ Effect.Error<ReturnType<Tag.Service<TI[keyof TI]>["handle"]>>,
151
+ Effect.Context<ReturnType<Tag.Service<TI[keyof TI]>["handle"]>>
152
+ >
153
+ })
154
+ })
@@ -0,0 +1,56 @@
1
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
+ // @ts-nocheck
3
+ export function tsort(edges) {
4
+ const nodes = new Map(), sorted = [], visited = new Map()
5
+
6
+ const Node = function(id) {
7
+ this.id = id
8
+ this.afters = []
9
+ }
10
+
11
+ edges.forEach((v) => {
12
+ const from = v[0], to = v[1]
13
+ if (!nodes.get(from)) nodes.set(from, new Node(from))
14
+ if (!nodes.get(to)) nodes.set(to, new Node(to))
15
+ nodes.get(from).afters.push(to)
16
+ })
17
+ ;[...nodes.keys()].forEach(function visit(idstr, ancestors) {
18
+ const node = nodes.get(idstr), id = node.id
19
+
20
+ if (visited.get(idstr)) return
21
+ if (!Array.isArray(ancestors)) ancestors = []
22
+
23
+ ancestors.push(id)
24
+ visited.set(idstr, true)
25
+ node.afters.forEach(function(afterID) {
26
+ if (ancestors.indexOf(afterID) >= 0) {
27
+ throw new Error("closed chain : " + afterID + " is in " + id)
28
+ }
29
+ visit(
30
+ afterID,
31
+ ancestors.map(function(v) {
32
+ return v
33
+ })
34
+ )
35
+ })
36
+ sorted.unshift(id)
37
+ })
38
+
39
+ return sorted
40
+ }
41
+
42
+ export const createEdges = <T extends { dependsOn?: any[] }>(dep: readonly T[]) => {
43
+ const result = []
44
+ dep.forEach((key) => {
45
+ key.dependsOn?.forEach((n) => {
46
+ result.push([n, key])
47
+ })
48
+ })
49
+ return result
50
+ }
51
+
52
+ export const sort = <T>(dep: readonly (T & { dependsOn?: any[] })[]): readonly T[] => {
53
+ const edges = createEdges(dep)
54
+ const result = tsort(edges)
55
+ return result.concat(dep.filter((v) => !result.includes(v)))
56
+ }
@@ -3,16 +3,14 @@
3
3
  /* eslint-disable @typescript-eslint/no-empty-object-type */
4
4
  /* eslint-disable @typescript-eslint/no-explicit-any */
5
5
  import { determineMethod, isCommand } from "@effect-app/infra/api/routing/utils"
6
- import { logError, reportError } from "@effect-app/infra/errorReporter"
7
- import { InfraLogger } from "@effect-app/infra/logger"
8
6
  import { Rpc, RpcGroup, RpcServer } from "@effect/rpc"
9
- import { Array, Cause, Duration, Effect, Layer, type NonEmptyArray, type NonEmptyReadonlyArray, ParseResult, Predicate, Request, S, Schedule, Schema } from "effect-app"
7
+ import { type Array, Duration, Effect, Layer, type NonEmptyArray, type NonEmptyReadonlyArray, Predicate, Request, S, Schedule, Schema } from "effect-app"
10
8
  import type { GetEffectContext, GetEffectError, RPCContextMap } from "effect-app/client/req"
11
9
  import { type HttpHeaders, HttpRouter } from "effect-app/http"
12
- import { pretty, typedKeysOf, typedValuesOf } from "effect-app/utils"
10
+ import { typedKeysOf, typedValuesOf } from "effect-app/utils"
13
11
  import type { Contravariant } from "effect/Types"
14
12
  import { type YieldWrap } from "effect/Utils"
15
- import { type Middleware } from "./routing/DynamicMiddleware.js"
13
+ import { DevMode, type Middleware } from "./routing/DynamicMiddleware.js"
16
14
 
17
15
  export * from "./routing/DynamicMiddleware.js"
18
16
 
@@ -36,9 +34,6 @@ export namespace LayersUtils {
36
34
  : never
37
35
  }
38
36
 
39
- const logRequestError = logError("Request")
40
- const reportRequestError = reportError("Request")
41
-
42
37
  // retry just once on optimistic concurrency exceptions
43
38
  const optimisticConcurrencySchedule = Schedule.once.pipe(
44
39
  Schedule.intersect(Schedule.recurWhile<any>((a) => a?._tag === "OptimisticConcurrencyException"))
@@ -423,64 +418,17 @@ export const makeRouter = <
423
418
  }
424
419
  } as any
425
420
  : resource,
426
- rpc.effect(resource, (input: any, headers: HttpHeaders.Headers) =>
427
- // TODO: render more data... similar to console?
428
- Effect
429
- .annotateCurrentSpan(
430
- "requestInput",
431
- Object.entries(input).reduce((prev, [key, value]: [string, unknown]) => {
432
- prev[key] = key === "password"
433
- ? "<redacted>"
434
- : typeof value === "string" || typeof value === "number" || typeof value === "boolean"
435
- ? typeof value === "string" && value.length > 256
436
- ? (value.substring(0, 253) + "...")
437
- : value
438
- : Array.isArray(value)
439
- ? `Array[${value.length}]`
440
- : value === null || value === undefined
441
- ? `${value}`
442
- : typeof value === "object" && value
443
- ? `Object[${Object.keys(value).length}]`
444
- : typeof value
445
- return prev
446
- }, {} as Record<string, string | number | boolean>)
447
- )
448
- .pipe(
449
- // can't use andThen due to some being a function and effect
450
- Effect.zipRight(handle(input, headers)),
451
- // TODO: support ParseResult if the error channel of the request allows it.. but who would want that?
452
- Effect.catchAll((_) => ParseResult.isParseError(_) ? Effect.die(_) : Effect.fail(_)),
453
- Effect.tapErrorCause((cause) => Cause.isFailure(cause) ? logRequestError(cause) : Effect.void),
454
- Effect.tapDefect((cause) =>
455
- Effect
456
- .all([
457
- reportRequestError(cause, {
458
- action: `${meta.moduleName}.${resource._tag}`
459
- }),
460
- InfraLogger
461
- .logError("Finished request", cause)
462
- .pipe(Effect.annotateLogs({
463
- action: `${meta.moduleName}.${resource._tag}`,
464
- req: pretty(resource),
465
- headers: pretty(headers)
466
- // resHeaders: pretty(
467
- // Object
468
- // .entries(headers)
469
- // .reduce((prev, [key, value]) => {
470
- // prev[key] = value && typeof value === "string" ? snipString(value) : value
471
- // return prev
472
- // }, {} as Record<string, any>)
473
- // )
474
- }))
475
- ])
476
- ),
477
- // NOTE: this does not catch errors from the middlewares..
478
- // we should re-evalute this in any case..
479
- devMode ? (_) => _ : Effect.catchAllDefect(() => Effect.die("Internal Server Error")),
421
+ rpc.effect(
422
+ resource,
423
+ (req, headers) =>
424
+ handle(req, headers).pipe(
480
425
  Effect.withSpan("Request." + meta.moduleName + "." + resource._tag, {
481
426
  captureStackTrace: () => handler.stack
482
- })
483
- ), meta.moduleName),
427
+ }),
428
+ Effect.provideService(DevMode, devMode)
429
+ ),
430
+ meta.moduleName
431
+ ),
484
432
  meta.moduleName
485
433
  ] as const
486
434
  return acc
@@ -1,18 +1,20 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
- import { type MakeContext, type MakeErrors, makeRouter } from "@effect-app/infra/api/routing"
3
+ import { type MakeContext, type MakeErrors, makeRouter, RequestCacheLayers } from "@effect-app/infra/api/routing"
4
4
  import type { RequestContext } from "@effect-app/infra/RequestContext"
5
- import { expectTypeOf } from "@effect/vitest"
6
- import { Context, Effect, Layer, S } from "effect-app"
7
- import { type GetEffectContext, InvalidStateError, makeRpcClient, type RPCContextMap, UnauthorizedError } from "effect-app/client"
5
+ import { expect, expectTypeOf, it } from "@effect/vitest"
6
+ import { type Array, Context, Effect, Layer, Option, S } from "effect-app"
7
+ import { InvalidStateError, makeRpcClient, type RPCContextMap, UnauthorizedError } from "effect-app/client"
8
8
  import { HttpServerRequest } from "effect-app/http"
9
9
  import { Class, TaggedError } from "effect-app/Schema"
10
10
  import { ContextProvider, makeMiddleware, mergeContextProviders, MergedContextProvider } from "../src/api/routing/DynamicMiddleware.js"
11
+ import { sort } from "../src/api/routing/tsort.js"
11
12
  import { SomeService } from "./query.test.js"
12
13
 
13
14
  class UserProfile extends Context.assignTag<UserProfile, UserProfile>("UserProfile")(
14
15
  Class<UserProfile>("UserProfile")({
15
- id: S.String
16
+ id: S.String,
17
+ roles: S.Array(S.String)
16
18
  })
17
19
  ) {
18
20
  }
@@ -32,7 +34,7 @@ export class Some extends Context.TagMakeId("Some", Effect.succeed({ a: 1 }))<So
32
34
  export class SomeElse extends Context.TagMakeId("SomeElse", Effect.succeed({ b: 2 }))<SomeElse>() {}
33
35
 
34
36
  // @effect-diagnostics-next-line missingEffectServiceDependency:off
35
- const contextProvider = ContextProvider({
37
+ export const someContextProvider = ContextProvider({
36
38
  effect: Effect.gen(function*() {
37
39
  yield* SomeService
38
40
  if (Math.random() > 0.5) return yield* new CustomError1()
@@ -59,7 +61,7 @@ class MyContextProvider extends Effect.Service<MyContextProvider>()("MyContextPr
59
61
  if (Math.random() > 0.5) return yield* new CustomError1()
60
62
 
61
63
  return Effect.gen(function*() {
62
- // the only requirements you can have are the one provided by HttpRouter.HttpRouter.Provided
64
+ // the only requiremeno you can have are the one provided by HttpRouter.HttpRouter.Provided
63
65
  yield* HttpServerRequest.HttpServerRequest
64
66
 
65
67
  // this is allowed here but mergeContextProviders/MergedContextProvider will trigger an error
@@ -74,62 +76,118 @@ class MyContextProvider extends Effect.Service<MyContextProvider>()("MyContextPr
74
76
  })
75
77
  }) {}
76
78
 
79
+ class RequestCacheContext extends Effect.Service<RequestCacheContext>()("RequestCacheContext", {
80
+ effect: Effect.gen(function*() {
81
+ return Effect.gen(function*() {
82
+ const ctx = yield* Layer.build(RequestCacheLayers)
83
+ return ctx as Context.Context<any> // todo: ugh.
84
+ })
85
+ })
86
+ }) {}
87
+
77
88
  const merged = mergeContextProviders(MyContextProvider)
78
89
  export const contextProvider2 = ContextProvider(merged)
79
90
  export const contextProvider3 = MergedContextProvider(MyContextProvider)
80
-
81
- expectTypeOf(contextProvider2).toEqualTypeOf<typeof contextProvider>()
91
+ expectTypeOf(contextProvider2).toEqualTypeOf<typeof someContextProvider>()
82
92
  expectTypeOf(contextProvider3).toEqualTypeOf<typeof contextProvider2>()
93
+ const merged2 = mergeContextProviders(MyContextProvider, RequestCacheContext)
94
+ export const contextProvider22 = ContextProvider(merged2)
95
+ export const contextProvider23 = MergedContextProvider(MyContextProvider, RequestCacheContext)
96
+ expectTypeOf(contextProvider23).toEqualTypeOf<typeof contextProvider22>()
83
97
 
84
98
  export type RequestContextMap = {
85
- allowAnonymous: RPCContextMap.Inverted<"userProfile", UserProfile, typeof NotLoggedInError>
86
- // TODO: not boolean but `string[]`
87
- requireRoles: RPCContextMap.Custom<"", never, typeof UnauthorizedError, Array<string>>
99
+ allowAnonymous: RPCContextMap.Inverted<UserProfile, typeof NotLoggedInError>
100
+ requireRoles: RPCContextMap.Custom<never, typeof UnauthorizedError, Array<string>>
101
+ test: RPCContextMap<never, typeof S.Never>
88
102
  }
89
103
 
90
104
  const Str = Context.GenericTag<"str", "str">("str")
91
105
  const Str2 = Context.GenericTag<"str2", "str">("str2")
92
106
 
107
+ class AllowAnonymous extends Effect.Service<AllowAnonymous>()("AllowAnonymous", {
108
+ effect: Effect.gen(function*() {
109
+ return {
110
+ handle: Effect.fn(function*(opts: { allowAnonymous?: false }, headers: Record<string, string>) {
111
+ const isLoggedIn = !!headers["x-user"]
112
+ if (!isLoggedIn) {
113
+ if (!opts.allowAnonymous) {
114
+ return yield* new NotLoggedInError({ message: "Not logged in" })
115
+ }
116
+ return Option.none()
117
+ }
118
+ return Option.some(Context.make(
119
+ UserProfile,
120
+ { id: "whatever", roles: ["user", "manager"] }
121
+ ))
122
+ })
123
+ }
124
+ })
125
+ }) {}
126
+
127
+ class RequireRoles extends Effect.Service<RequireRoles>()("RequireRoles", {
128
+ effect: Effect.gen(function*() {
129
+ return {
130
+ handle: Effect.fn(
131
+ function*(cfg: { requireRoles?: readonly string[] }) {
132
+ // we don't know if the service will be provided or not, so we use option..
133
+ const userProfile = yield* Effect.serviceOption(UserProfile)
134
+ const { requireRoles } = cfg
135
+ if (requireRoles && !userProfile.value?.roles?.some((role) => requireRoles.includes(role))) {
136
+ return yield* new UnauthorizedError({ message: "don't have the right roles" })
137
+ }
138
+ return Option.none<Context<never>>()
139
+ }
140
+ )
141
+ }
142
+ })
143
+ }) {
144
+ static dependsOn = [AllowAnonymous]
145
+ }
146
+
147
+ class Test extends Effect.Service<Test>()("Test", {
148
+ effect: Effect.gen(function*() {
149
+ return {
150
+ handle: Effect.fn(function*() {
151
+ return Option.none<Context<never>>()
152
+ })
153
+ }
154
+ })
155
+ }) {}
156
+
157
+ // TODO: eventually it might be nice if we have total control over order somehow..
158
+ // [ AddRequestNameToSpanContext, RequestCacheContext, UninterruptibleMiddleware, Dynamic(or individual, AllowAnonymous, RequireRoles, Test - or whichever order) ]
93
159
  const middleware = makeMiddleware<RequestContextMap>()({
94
160
  dependencies: [Layer.effect(Str2, Str)],
95
- contextProvider,
161
+ // TODO: I guess it makes sense to support just passing array of context providers too, like dynamicMiddlewares?
162
+ contextProvider: MergedContextProvider(RequestCacheContext, MyContextProvider),
163
+ // or is the better api to use constructors outside, like how contextProvider is used now?
164
+ dynamicMiddlewares: {
165
+ requireRoles: RequireRoles,
166
+ allowAnonymous: AllowAnonymous,
167
+ test: Test
168
+ },
169
+ // TODO: 0..n of these generic middlewares?
96
170
  execute: (maker) =>
97
171
  Effect.gen(function*() {
98
- return maker((_schema, handler, moduleName) => (req, headers) => {
99
- return Effect
100
- .gen(function*() {
101
- // const headers = yield* Rpc.currentHeaders
102
- const ctx = Context.empty().pipe(
103
- Context.add(UserProfile, { id: "whatever" })
104
- )
105
-
106
- // you can use only HttpRouter.HttpRouter.Provided here as additional context
107
- // and what ContextMaker provides too
108
- // const someElse = yield* SomeElse
109
-
110
- yield* Some // provided by ContextMaker
111
- yield* HttpServerRequest.HttpServerRequest // provided by HttpRouter.HttpRouter.Provided
112
-
113
- return yield* handler(req, headers).pipe(
114
- Effect.provide(ctx as Context.Context<GetEffectContext<RequestContextMap, (typeof _schema)["config"]>>)
115
- // I do expect the ContextMaker to provide this
116
- // Effect.provideService(Some, new Some({ a: 1 }))
117
- )
118
- })
119
- .pipe(
120
- Effect.provide(
121
- Effect
122
- .gen(function*() {
123
- yield* Effect.annotateCurrentSpan("request.name", moduleName ? `${moduleName}.${req._tag}` : req._tag)
124
-
125
- // const httpReq = yield* HttpServerRequest.HttpServerRequest
126
-
127
- //
128
- })
129
- .pipe(Layer.effectDiscard)
130
- )
131
- )
132
- })
172
+ return maker(
173
+ (_schema, handler) => (req, headers) =>
174
+ // contextProvider and dynamicMiddlewares are already provided here.
175
+ // aka this runs "last"
176
+ Effect
177
+ .gen(function*() {
178
+ // you can use only HttpRouter.HttpRouter.Provided here as additional context
179
+ // and what ContextMaker provides too
180
+ // const someElse = yield* SomeElse
181
+ yield* Some // provided by ContextMaker
182
+ yield* HttpServerRequest.HttpServerRequest // provided by HttpRouter.HttpRouter.Provided
183
+
184
+ return yield* handler(req, headers)
185
+ .pipe(
186
+ // TODO: make this depend on query/command, and consider if middleware also should be affected. right now it's not.
187
+ Effect.uninterruptible
188
+ )
189
+ })
190
+ )
133
191
  })
134
192
  })
135
193
 
@@ -141,7 +199,8 @@ export type RequestConfig = {
141
199
  }
142
200
  export const { TaggedRequest: Req } = makeRpcClient<RequestConfig, RequestContextMap>({
143
201
  allowAnonymous: NotLoggedInError,
144
- requireRoles: UnauthorizedError
202
+ requireRoles: UnauthorizedError,
203
+ test: S.Never
145
204
  })
146
205
 
147
206
  export class Eff extends Req<Eff>()("Eff", {}, { success: S.Void }) {}
@@ -269,6 +328,13 @@ const router = Router(Something)({
269
328
  }
270
329
  })
271
330
 
331
+ it("sorts based on requirements", () => {
332
+ const input = [RequireRoles, AllowAnonymous, Test]
333
+ const sorted = sort(input)
334
+ console.dir({ input, sorted }, { depth: 10 })
335
+ expect(sorted).toEqual([AllowAnonymous, RequireRoles, Test])
336
+ })
337
+
272
338
  // eslint-disable-next-line unused-imports/no-unused-vars
273
339
  const matched = matchAll({ router })
274
340
  expectTypeOf({} as Layer.Context<typeof matched>).toEqualTypeOf<SomeService | "str">()
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.legacy2.test.d.ts","sourceRoot":"","sources":["../controller.legacy2.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.legacy3.test.d.ts","sourceRoot":"","sources":["../controller.legacy3.test.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEjC,OAAO,EAAW,MAAM,EAAY,KAAK,EAAE,CAAC,EAAY,MAAM,YAAY,CAAA;AAC1E,OAAO,EAAwC,KAAK,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC/G,OAAO,EAAe,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAOhE,MAAM,WAAW,GAAG;IAClB,OAAO,EAAE,cAAc,CAAA;CACxB;AAED,MAAM,MAAM,MAAM,GAAG;IAGnB,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,iBAAiB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;CACvF,CAAA;AAmGD,eAAO,MAAQ,QAAQ;;;;;gBA0EgwD,MAAO,KAAK;;;;;;GA1E1wD,QAAQ;;;;;;iDA0Eq0F,MAAM,KAAK,CAAC,GAAG;;;;;;;;;;;;iDAAg1D,MAAM,KAAK,CAAC,GAAG;;;;;;;;;;;;iDAAg1D,MAAM,KAAK,CAAC,GAAG;;;;;;;;;;;;iDAAg1D,MAAM,KAAK,CAAC,GAAG;;;;;;;;;;;;iDAA2yD,MAAM,KAAK,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CA1E1oU,CAAA;AAElE,MAAM,MAAM,aAAa,GAAG;IAC1B,yCAAyC;IACzC,cAAc,CAAC,EAAE,IAAI,CAAA;IACrB,iEAAiE;IACjE,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC/B,CAAA;AACD,eAAO,MAAuB,GAAG;yCAxEL,EAAG,MAAM,CAAC,MAAM;iBAgClC,EA/BK,MACb,CA8BQ,GA9BJ,GA8BI,EA9BC,MAEV,CA4BS,MA5BF;iBAAuB,EAAE,MAC9B,CA2BO,GA3BH,GA2BG,EA3BG,MAAK,CAAC,MAAM;;;;;;2CASkB,EAAG,MAAM,CAAC,MAAM;iBAkBjD,EAAA,MAjBA,CAAC,GAAG,GAAE,EAAG,MAAM,CAAC,MAAM;;;;;;2CAiBtB,EAPO,MAAC,CAAC,MAAM;iBACA,EAAG,MAAM,CAAC,GAAG,GAAE,EAAG,MAAM,CAAC,MAAM;;;;;;2CAc1C,EAAA,MAAL,CAAK,MAAE;;;;;2CAMqC,EAAG,MAAM,CAAC,MAAM;;;;;CA6BnE,CAAA;;;;;;;;;;AAEF,qBAAa,YAAa,SAAQ,iBAEX;CAAG;;;;;;;;;;AAE1B,qBAAa,gBAAiB,SAAQ,qBAEb;CAAG;;;;;AAI5B,qBAAa,gBAAiB,SAAQ,qBAKpC;CAAG;;;;;AASL,qBAAa,aAAc,SAAQ,kBAOjC;CAAG;;;;;AAEL,qBAAa,iBAAkB,SAAQ,sBAKrC;CAAG"}