@effect-app/infra 1.45.0 → 1.46.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 (91) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/_cjs/RequestContext.cjs +16 -38
  3. package/_cjs/RequestContext.cjs.map +1 -1
  4. package/_cjs/api/internal/RequestContextMiddleware.cjs +9 -24
  5. package/_cjs/api/internal/RequestContextMiddleware.cjs.map +1 -1
  6. package/_cjs/api/internal/events.cjs +1 -1
  7. package/_cjs/api/internal/events.cjs.map +1 -1
  8. package/_cjs/api/setupRequest.cjs +28 -39
  9. package/_cjs/api/setupRequest.cjs.map +1 -1
  10. package/_cjs/errorReporter.cjs +3 -5
  11. package/_cjs/errorReporter.cjs.map +1 -1
  12. package/_cjs/logger/jsonLogger.cjs +2 -2
  13. package/_cjs/logger/jsonLogger.cjs.map +1 -1
  14. package/_cjs/logger/logFmtLogger.cjs +1 -2
  15. package/_cjs/logger/logFmtLogger.cjs.map +1 -1
  16. package/_cjs/logger/shared.cjs +15 -12
  17. package/_cjs/logger/shared.cjs.map +1 -1
  18. package/_cjs/services/QueueMaker/SQLQueue.cjs +3 -17
  19. package/_cjs/services/QueueMaker/SQLQueue.cjs.map +1 -1
  20. package/_cjs/services/QueueMaker/memQueue.cjs +3 -16
  21. package/_cjs/services/QueueMaker/memQueue.cjs.map +1 -1
  22. package/_cjs/services/QueueMaker/sbqueue.cjs +3 -16
  23. package/_cjs/services/QueueMaker/sbqueue.cjs.map +1 -1
  24. package/_cjs/services/QueueMaker/service.cjs +1 -9
  25. package/_cjs/services/QueueMaker/service.cjs.map +1 -1
  26. package/_cjs/services/RepositoryBase.cjs +3 -2
  27. package/_cjs/services/RepositoryBase.cjs.map +1 -1
  28. package/_cjs/services/Store/Memory.cjs +4 -7
  29. package/_cjs/services/Store/Memory.cjs.map +1 -1
  30. package/dist/RequestContext.d.ts +20 -63
  31. package/dist/RequestContext.d.ts.map +1 -1
  32. package/dist/RequestContext.js +16 -38
  33. package/dist/api/internal/RequestContextMiddleware.d.ts +1 -2
  34. package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
  35. package/dist/api/internal/RequestContextMiddleware.js +11 -30
  36. package/dist/api/internal/events.d.ts +1 -1
  37. package/dist/api/internal/events.d.ts.map +1 -1
  38. package/dist/api/internal/events.js +3 -3
  39. package/dist/api/setupRequest.d.ts +3 -7
  40. package/dist/api/setupRequest.d.ts.map +1 -1
  41. package/dist/api/setupRequest.js +28 -47
  42. package/dist/errorReporter.d.ts.map +1 -1
  43. package/dist/errorReporter.js +5 -7
  44. package/dist/logger/jsonLogger.d.ts.map +1 -1
  45. package/dist/logger/jsonLogger.js +4 -4
  46. package/dist/logger/logFmtLogger.d.ts.map +1 -1
  47. package/dist/logger/logFmtLogger.js +3 -4
  48. package/dist/logger/shared.d.ts +2 -2
  49. package/dist/logger/shared.d.ts.map +1 -1
  50. package/dist/logger/shared.js +13 -10
  51. package/dist/services/QueueMaker/SQLQueue.d.ts +3 -4
  52. package/dist/services/QueueMaker/SQLQueue.d.ts.map +1 -1
  53. package/dist/services/QueueMaker/SQLQueue.js +5 -18
  54. package/dist/services/QueueMaker/memQueue.d.ts +2 -3
  55. package/dist/services/QueueMaker/memQueue.d.ts.map +1 -1
  56. package/dist/services/QueueMaker/memQueue.js +6 -16
  57. package/dist/services/QueueMaker/sbqueue.d.ts +2 -3
  58. package/dist/services/QueueMaker/sbqueue.d.ts.map +1 -1
  59. package/dist/services/QueueMaker/sbqueue.js +6 -16
  60. package/dist/services/QueueMaker/service.d.ts +2 -13
  61. package/dist/services/QueueMaker/service.d.ts.map +1 -1
  62. package/dist/services/QueueMaker/service.js +2 -10
  63. package/dist/services/Repository/ext.d.ts +11 -11
  64. package/dist/services/RepositoryBase.d.ts +6 -6
  65. package/dist/services/RepositoryBase.d.ts.map +1 -1
  66. package/dist/services/RepositoryBase.js +3 -3
  67. package/dist/services/RequestFiberSet.d.ts +1 -1
  68. package/dist/services/Store/Memory.d.ts +2 -6
  69. package/dist/services/Store/Memory.d.ts.map +1 -1
  70. package/dist/services/Store/Memory.js +4 -6
  71. package/package.json +4 -14
  72. package/src/RequestContext.ts +15 -46
  73. package/src/api/internal/RequestContextMiddleware.ts +10 -31
  74. package/src/api/internal/events.ts +2 -2
  75. package/src/api/setupRequest.ts +38 -72
  76. package/src/errorReporter.ts +4 -6
  77. package/src/logger/jsonLogger.ts +3 -3
  78. package/src/logger/logFmtLogger.ts +2 -3
  79. package/src/logger/shared.ts +15 -9
  80. package/src/services/QueueMaker/SQLQueue.ts +5 -19
  81. package/src/services/QueueMaker/memQueue.ts +5 -15
  82. package/src/services/QueueMaker/sbqueue.ts +5 -15
  83. package/src/services/QueueMaker/service.ts +2 -11
  84. package/src/services/RepositoryBase.ts +1 -2
  85. package/src/services/Store/Memory.ts +3 -7
  86. package/_cjs/services/RequestContextContainer.cjs +0 -36
  87. package/_cjs/services/RequestContextContainer.cjs.map +0 -1
  88. package/dist/services/RequestContextContainer.d.ts +0 -42
  89. package/dist/services/RequestContextContainer.d.ts.map +0 -1
  90. package/dist/services/RequestContextContainer.js +0 -31
  91. package/src/services/RequestContextContainer.ts +0 -53
@@ -1,91 +1,57 @@
1
1
  import { NonEmptyString255 } from "@effect-app/schema"
2
- import { Effect, Layer, pipe } from "effect-app"
3
- import { RequestId } from "effect-app/ids"
4
- import { RequestContext, spanAttributes } from "../RequestContext.js"
5
- import { RequestContextContainer } from "../services/RequestContextContainer.js"
2
+ import { Effect, FiberRef, Layer } from "effect-app"
3
+ import { LocaleRef, RequestContext, spanAttributes } from "../RequestContext.js"
6
4
  import { ContextMapContainer } from "../services/Store/ContextMapContainer.js"
5
+ import { storeId } from "../services/Store/Memory.js"
7
6
 
8
- function makeInternalRequestContext(name: string) {
9
- return Effect.sync(() => {
10
- const id = RequestId.make()
11
- return new RequestContext({
12
- id,
13
- rootId: id,
14
- locale: "en",
15
- name: NonEmptyString255(name)
16
- })
7
+ export const getRequestContext = Effect
8
+ .all({
9
+ span: Effect.currentSpan.pipe(Effect.orDie),
10
+ locale: FiberRef.get(LocaleRef),
11
+ namespace: FiberRef.get(storeId)
17
12
  })
18
- }
19
-
20
- const withRequestSpan = <R, E, A>(f: Effect<A, E, R>) =>
21
- Effect.andThen(
22
- RequestContextContainer
23
- .get,
24
- (ctx) =>
25
- f.pipe(
26
- Effect.withSpan("request " + ctx.name, { attributes: spanAttributes(ctx), captureStackTrace: false }),
27
- // request context info is picked up directly in the logger for annotations.
28
- Effect.withLogSpan("request")
29
- )
13
+ .pipe(
14
+ Effect.map(({ locale, namespace, span }) =>
15
+ new RequestContext({
16
+ span,
17
+ locale,
18
+ namespace,
19
+ // TODO: get through span context, or don't care at all.
20
+ name: NonEmptyString255("_root_")
21
+ })
22
+ )
30
23
  )
31
24
 
32
- const withExistingRequestSpan = <R, E, A>(f: Effect<A, E, R>) =>
25
+ const withRequestSpan = (name = "request") => <R, E, A>(f: Effect<A, E, R>) =>
33
26
  Effect.andThen(
34
- RequestContextContainer.get,
27
+ getRequestContext,
35
28
  (ctx) =>
36
- Effect.annotateCurrentSpan(spanAttributes(ctx)).pipe(
37
- Effect.andThen(f),
29
+ f.pipe(
30
+ Effect.withSpan(name, { attributes: spanAttributes(ctx), captureStackTrace: false }),
31
+ // TODO: false
38
32
  // request context info is picked up directly in the logger for annotations.
39
- Effect.withLogSpan("request")
33
+ Effect.withLogSpan(name)
40
34
  )
41
35
  )
42
36
 
43
37
  const setupContextMap = Effect.andThen(ContextMapContainer, (_) => _.start).pipe(Layer.effectDiscard)
44
38
 
45
- // const RequestContextLiveFromRequestContext = (requestContext: RequestContext) =>
46
- // RequestContext.Tag.makeLayer(requestContext)
47
- // memoization problem
48
- // const RequestContextLive = RequestContextContainer.get.toLayer(RequestContext.Tag)
49
- const RequestContextStartLiveFromRequestContext = (requestContext: RequestContext) =>
50
- Layer.provideMerge(
51
- setupContextMap,
52
- // .provideMerge(RequestContextLiveFromRequestContext(requestContext))
53
- Effect
54
- .andThen(RequestContextContainer, (_) => _.start(requestContext))
55
- .pipe(Layer.effectDiscard)
56
- )
57
-
58
- const RequestContextStartLive = (requestContext: RequestContext | string) =>
59
- typeof requestContext === "string"
60
- ? pipe(
61
- makeInternalRequestContext(requestContext),
62
- Effect.andThen(RequestContextStartLiveFromRequestContext),
63
- Layer.unwrapEffect
64
- )
65
- : RequestContextStartLiveFromRequestContext(requestContext)
66
-
67
- export function setupRequestContext<R, E, A>(self: Effect<A, E, R>, requestContext: RequestContext | string) {
68
- return self
69
- .pipe(
70
- withRequestSpan,
71
- Effect.provide(RequestContextStartLive(requestContext))
72
- )
73
- }
74
-
75
- export function setupExistingRequestContext<R, E, A>(self: Effect<A, E, R>, requestContext: RequestContext | string) {
76
- return self
39
+ export const setupRequestContextFromCurrent = (name = "request") => <R, E, A>(self: Effect<A, E, R>) =>
40
+ self
77
41
  .pipe(
78
- withExistingRequestSpan,
79
- Effect.provide(RequestContextStartLive(requestContext))
42
+ withRequestSpan(name),
43
+ Effect.provide(setupContextMap)
80
44
  )
81
- }
82
45
 
83
- const UpdateRequestContextLive = (f: (rc: RequestContext) => RequestContext) =>
84
- Effect.andThen(RequestContextContainer, (rcc) => rcc.update(f)).pipe(Layer.effectDiscard)
46
+ export function setupRequestContext<R, E, A>(self: Effect<A, E, R>, requestContext: RequestContext) {
47
+ return Effect.gen(function*() {
48
+ yield* FiberRef.set(LocaleRef, requestContext.locale)
49
+ yield* FiberRef.set(storeId, requestContext.namespace)
85
50
 
86
- /**
87
- * @tsplus fluent effect/io/Effect updateRequestContext
88
- */
89
- export function updateRequestContext<R, E, A>(self: Effect<A, E, R>, f: (rc: RequestContext) => RequestContext) {
90
- return Effect.provide(self, UpdateRequestContextLive(f))
51
+ return yield* self
52
+ .pipe(
53
+ withRequestSpan(requestContext.name),
54
+ Effect.provide(setupContextMap)
55
+ )
56
+ })
91
57
  }
@@ -1,9 +1,9 @@
1
1
  import { dropUndefined } from "@effect-app/core/utils"
2
2
  import * as Sentry from "@sentry/node"
3
- import { Cause, Effect, Option } from "effect-app"
3
+ import { Cause, Effect } from "effect-app"
4
+ import { getRequestContext } from "./api/setupRequest.js"
4
5
  import { CauseException, ErrorReported, tryToJson } from "./errors.js"
5
6
  import { InfraLogger } from "./logger.js"
6
- import { RequestContextContainer } from "./services/RequestContextContainer.js"
7
7
 
8
8
  export function reportError(
9
9
  name: string
@@ -38,8 +38,7 @@ function reportSentry(
38
38
  error: CauseException<unknown>,
39
39
  extras: Record<string, unknown> | undefined
40
40
  ) {
41
- return RequestContextContainer.getOption.pipe(Effect.map((ctx) => {
42
- const context = Option.getOrUndefined(ctx)
41
+ return getRequestContext.pipe(Effect.map((context) => {
43
42
  const scope = new Sentry.Scope()
44
43
  if (context) scope.setContext("context", context as unknown as Record<string, unknown>)
45
44
  if (extras) scope.setContext("extras", extras)
@@ -78,8 +77,7 @@ export function captureException(error: unknown) {
78
77
  }
79
78
 
80
79
  export function reportMessage(message: string, extras?: Record<string, unknown>) {
81
- return RequestContextContainer.getOption.pipe(Effect.map((ctx) => {
82
- const context = Option.getOrUndefined(ctx)
80
+ return getRequestContext.pipe(Effect.map((context) => {
83
81
  const scope = new Sentry.Scope()
84
82
  if (context) scope.setContext("context", context as unknown as Record<string, unknown>)
85
83
  if (extras) scope.setContext("extras", extras)
@@ -1,4 +1,4 @@
1
- import { Cause, FiberId, HashMap, List, Logger, Option } from "effect-app"
1
+ import { Cause, FiberId, HashMap, List, Logger } from "effect-app"
2
2
  import { getRequestContext } from "./shared.js"
3
3
 
4
4
  export const jsonLogger = Logger.make<unknown, void>(
@@ -6,14 +6,14 @@ export const jsonLogger = Logger.make<unknown, void>(
6
6
  const now = new Date()
7
7
  const nowMillis = now.getTime()
8
8
 
9
- const c = getRequestContext(context)
9
+ const request = getRequestContext(context)
10
10
 
11
11
  const data = {
12
12
  timestamp: now,
13
13
  level: logLevel.label,
14
14
  fiber: FiberId.threadName(fiberId),
15
15
  message,
16
- request: Option.getOrUndefined(c),
16
+ request,
17
17
  cause: cause !== null && cause !== Cause.empty ? Cause.pretty(cause, { renderErrorCause: true }) : undefined,
18
18
  spans: List.map(spans, (_) => ({ label: _.label, timing: nowMillis - _.startTime })).pipe(List.toArray),
19
19
  annotations: HashMap.size(annotations) > 0
@@ -1,12 +1,11 @@
1
- import { HashMap, Logger, Option } from "effect-app"
1
+ import { HashMap, Logger } from "effect-app"
2
2
  import { spanAttributes } from "../RequestContext.js"
3
3
  import { getRequestContext } from "./shared.js"
4
4
 
5
5
  export const logfmtLogger = Logger.make<unknown, void>(
6
6
  (_) => {
7
7
  let { annotations } = _
8
- const c = getRequestContext(_.context)
9
- const requestContext = Option.getOrUndefined(c)
8
+ const requestContext = getRequestContext(_.context)
10
9
  if (requestContext && requestContext.name !== "_root_") {
11
10
  annotations = HashMap.make(...[
12
11
  ...annotations,
@@ -1,15 +1,21 @@
1
- import { RuntimeFlags } from "effect"
2
- import { Context, FiberRef, Option, Runtime } from "effect-app"
1
+ import { NonEmptyString255 } from "@effect-app/schema"
2
+ import { Context, FiberRef, Option, Tracer } from "effect-app"
3
3
  import * as FiberRefs from "effect/FiberRefs"
4
- import { RequestContextContainer } from "../services/RequestContextContainer.js"
4
+ import { LocaleRef, RequestContext } from "../RequestContext.js"
5
+ import { storeId } from "../services/Store/Memory.js"
5
6
 
6
7
  export function getRequestContext(fiberRefs: FiberRefs.FiberRefs) {
7
8
  const context = FiberRefs.getOrDefault(fiberRefs, FiberRef.currentContext)
8
- const a = Context.getOption(context, RequestContextContainer)
9
- const c = Option.map(a, (_) => {
10
- // TODO: perhaps a litle expensive?
11
- const rt = Runtime.make({ context, fiberRefs, runtimeFlags: RuntimeFlags.none })
12
- return Runtime.runSync(rt)(_.requestContext)
9
+ const span = Context.getOption(context, Tracer.ParentSpan)
10
+ const locale = FiberRefs.getOrDefault(fiberRefs, LocaleRef)
11
+ const namespace = FiberRefs.getOrDefault(fiberRefs, storeId)
12
+ return new RequestContext({
13
+ span: Option.getOrElse(
14
+ span,
15
+ () => ({ spanId: "bogus", sampled: true, traceId: "bogus" })
16
+ ),
17
+ name: NonEmptyString255("_"),
18
+ locale,
19
+ namespace
13
20
  })
14
- return c
15
21
  }
@@ -1,16 +1,13 @@
1
1
  import { Model } from "@effect-app/infra-adapters/SQL"
2
- import { setupRequestContext } from "@effect-app/infra/api/setupRequest"
3
- import { RequestContext } from "@effect-app/infra/RequestContext"
2
+ import { getRequestContext, setupRequestContext } from "@effect-app/infra/api/setupRequest"
4
3
  import { reportNonInterruptedFailure } from "@effect-app/infra/services/QueueMaker/errors"
5
4
  import type { QueueBase } from "@effect-app/infra/services/QueueMaker/service"
6
5
  import { QueueMeta } from "@effect-app/infra/services/QueueMaker/service"
7
- import { RequestContextContainer } from "@effect-app/infra/services/RequestContextContainer"
8
6
  import { SqlClient } from "@effect/sql"
9
7
  import { randomUUID } from "crypto"
10
8
  import { subMinutes } from "date-fns"
11
9
  import { Effect, Fiber, Option, S, Tracer } from "effect-app"
12
- import { RequestId } from "effect-app/ids"
13
- import { NonEmptyString255 } from "effect-app/schema"
10
+ import type { NonEmptyString255 } from "effect-app/schema"
14
11
  import { pretty } from "effect-app/utils"
15
12
  import { InfraLogger } from "../../logger.js"
16
13
 
@@ -112,22 +109,15 @@ export function makeSQLQueue<
112
109
  finish: ({ createdAt, updatedAt, ...q }: Drain) =>
113
110
  drainRepo.updateVoid(Drain.update.make({ ...q, finishedAt: Option.some(new Date()) })) // auto in lib , etag: randomUUID()
114
111
  }
115
- const rcc = yield* RequestContextContainer
116
-
117
112
  return {
118
113
  publish: (...messages) =>
119
114
  Effect
120
115
  .gen(function*() {
121
- const requestContext = yield* rcc.requestContext
122
- const span = yield* Effect.serviceOption(Tracer.ParentSpan)
116
+ const requestContext = yield* getRequestContext
123
117
  return yield* Effect
124
118
  .forEach(
125
119
  messages,
126
- (m) =>
127
- q.offer(m, {
128
- requestContext: new RequestContext(requestContext), // workaround Schema expecting exact class
129
- span: Option.getOrUndefined(span)
130
- }),
120
+ (m) => q.offer(m, requestContext),
131
121
  {
132
122
  discard: true
133
123
  }
@@ -160,11 +150,7 @@ export function makeSQLQueue<
160
150
  (_) =>
161
151
  setupRequestContext(
162
152
  _,
163
- RequestContext.inherit(meta.requestContext, {
164
- id: RequestId(body.id),
165
- locale: "en" as const,
166
- name: NonEmptyString255(`${queueDrainName}.${body._tag}`)
167
- })
153
+ meta
168
154
  ),
169
155
  Effect
170
156
  .withSpan(`queue.drain: ${queueDrainName}.${body._tag}`, {
@@ -1,13 +1,9 @@
1
1
  import { MemQueue } from "@effect-app/infra-adapters/memQueue"
2
- import { RequestContext } from "@effect-app/infra/RequestContext"
3
- import { NonEmptyString255 } from "@effect-app/schema"
4
2
  import { Tracer } from "effect"
5
- import { Effect, Fiber, flow, Option, S } from "effect-app"
6
- import { RequestId } from "effect-app/ids"
3
+ import { Effect, Fiber, flow, S } from "effect-app"
7
4
  import { pretty } from "effect-app/utils"
8
- import { setupRequestContext } from "../../api/setupRequest.js"
5
+ import { getRequestContext, setupRequestContext } from "../../api/setupRequest.js"
9
6
  import { InfraLogger } from "../../logger.js"
10
- import { RequestContextContainer } from "../RequestContextContainer.js"
11
7
  import { reportNonInterruptedFailure } from "./errors.js"
12
8
  import { type QueueBase, QueueMeta } from "./service.js"
13
9
 
@@ -29,7 +25,6 @@ export function makeMemQueue<
29
25
  const mem = yield* MemQueue
30
26
  const q = yield* mem.getOrCreateQueue(queueName)
31
27
  const qDrain = yield* mem.getOrCreateQueue(queueDrainName)
32
- const rcc = yield* RequestContextContainer
33
28
 
34
29
  const wireSchema = S.Struct({ body: schema, meta: QueueMeta })
35
30
  const drainW = S.Struct({ body: drainSchema, meta: QueueMeta })
@@ -39,12 +34,11 @@ export function makeMemQueue<
39
34
  publish: (...messages) =>
40
35
  Effect
41
36
  .gen(function*() {
42
- const requestContext = yield* rcc.requestContext
43
- const span = yield* Effect.serviceOption(Tracer.ParentSpan)
37
+ const requestContext = yield* getRequestContext
44
38
  return yield* Effect
45
39
  .forEach(messages, (m) =>
46
40
  // we JSON encode, because that is what the wire also does, and it reveals holes in e.g unknown encoders (Date->String)
47
- S.encode(wireSchema)({ body: m, meta: { requestContext, span: Option.getOrUndefined(span) } }).pipe(
41
+ S.encode(wireSchema)({ body: m, meta: requestContext }).pipe(
48
42
  Effect.orDie,
49
43
  Effect
50
44
  .andThen(JSON.stringify),
@@ -83,11 +77,7 @@ export function makeMemQueue<
83
77
  (_) =>
84
78
  setupRequestContext(
85
79
  _,
86
- RequestContext.inherit(meta.requestContext, {
87
- id: RequestId(body.id),
88
- locale: "en" as const,
89
- name: NonEmptyString255(`${queueDrainName}.${body._tag}`)
90
- })
80
+ meta
91
81
  ),
92
82
  Effect
93
83
  .withSpan(`queue.drain: ${queueDrainName}.${body._tag}`, {
@@ -6,16 +6,12 @@ import {
6
6
  ServiceBusReceiverFactory,
7
7
  subscribe
8
8
  } from "@effect-app/infra-adapters/ServiceBus"
9
- import { RequestContext } from "@effect-app/infra/RequestContext"
10
9
  import { Tracer } from "effect"
11
- import { Cause, Effect, flow, Layer, Option, S } from "effect-app"
12
- import { RequestId } from "effect-app/ids"
10
+ import { Cause, Effect, flow, Layer, S } from "effect-app"
13
11
  import type { StringId } from "effect-app/schema"
14
- import { NonEmptyString255 } from "effect-app/schema"
15
12
  import { pretty } from "effect-app/utils"
16
- import { setupRequestContext } from "../../api/setupRequest.js"
13
+ import { getRequestContext, setupRequestContext } from "../../api/setupRequest.js"
17
14
  import { InfraLogger } from "../../logger.js"
18
- import { RequestContextContainer } from "../RequestContextContainer.js"
19
15
  import { reportNonInterruptedFailure, reportNonInterruptedFailureCause, reportQueueError } from "./errors.js"
20
16
  import { type QueueBase, QueueMeta } from "./service.js"
21
17
 
@@ -45,7 +41,6 @@ export function makeServiceBusQueue<
45
41
  const receiver = yield* ServiceBusReceiverFactory
46
42
  const silenceAndReportError = reportNonInterruptedFailure({ name: "ServiceBusQueue.drain." + queueDrainName })
47
43
  const reportError = reportNonInterruptedFailureCause({ name: "ServiceBusQueue.drain." + queueDrainName })
48
- const rcc = yield* RequestContextContainer
49
44
 
50
45
  // TODO: or do async?
51
46
  // This will make sure that the host receives the error (MainFiberSet.join), who will then interrupt everything and commence a shutdown and restart of app
@@ -83,11 +78,7 @@ export function makeServiceBusQueue<
83
78
  (_) =>
84
79
  setupRequestContext(
85
80
  _,
86
- RequestContext.inherit(meta.requestContext, {
87
- id: RequestId(body.id),
88
- locale: "en" as const,
89
- name: NonEmptyString255(`${queueDrainName}.${body._tag}`)
90
- })
81
+ meta
91
82
  ),
92
83
  Effect
93
84
  .withSpan(
@@ -133,8 +124,7 @@ export function makeServiceBusQueue<
133
124
  publish: (...messages) =>
134
125
  Effect
135
126
  .gen(function*() {
136
- const requestContext = yield* rcc.requestContext
137
- const span = yield* Effect.serviceOption(Tracer.ParentSpan)
127
+ const requestContext = yield* getRequestContext
138
128
  return yield* Effect
139
129
  .promise((abortSignal) =>
140
130
  s.sendMessages(
@@ -142,7 +132,7 @@ export function makeServiceBusQueue<
142
132
  body: JSON.stringify(
143
133
  S.encodeSync(wireSchema)({
144
134
  body: m,
145
- meta: { requestContext, span: Option.getOrUndefined(span) }
135
+ meta: requestContext
146
136
  })
147
137
  ),
148
138
  messageId: m.id, /* correllationid: requestId */
@@ -1,14 +1,12 @@
1
- import { S } from "effect-app"
2
1
  import type { Effect, NonEmptyReadonlyArray, Scope } from "effect-app"
3
2
  import { RequestContext } from "../../RequestContext.js"
4
- import type { RequestContextContainer } from "../RequestContextContainer.js"
5
3
  import type { ContextMapContainer } from "../Store/ContextMapContainer.js"
6
4
 
7
5
  export interface QueueBase<Evt, DrainEvt> {
8
6
  drain: <DrainE, DrainR>(
9
7
  makeHandleEvent: (ks: DrainEvt) => Effect<void, DrainE, DrainR>,
10
8
  sessionId?: string
11
- ) => Effect<never, never, Scope | RequestContextContainer | ContextMapContainer | DrainR>
9
+ ) => Effect<never, never, Scope | ContextMapContainer | DrainR>
12
10
  publish: (
13
11
  ...messages: NonEmptyReadonlyArray<Evt>
14
12
  ) => Effect<void>
@@ -20,11 +18,4 @@ export interface QueueBase<Evt, DrainEvt> {
20
18
  export interface QueueMakerOps {}
21
19
  export const QueueMaker: QueueMakerOps = {}
22
20
 
23
- export const QueueMeta = S.Struct({
24
- requestContext: RequestContext,
25
- span: S.optional(S.Struct({
26
- spanId: S.String,
27
- traceId: S.String,
28
- sampled: S.Boolean
29
- }))
30
- })
21
+ export const QueueMeta = RequestContext
@@ -450,12 +450,11 @@ export function makeRepo<
450
450
  })
451
451
  )
452
452
  }
453
- // TODO: deal with idKey <-> "id" in encoded
454
453
  function findE(id: T[IdKey]) {
455
454
  return pipe(
456
455
  encodeId({ [idKey]: id } as any),
457
456
  Effect.orDie,
458
- Effect.map((_) => (_ as any).id),
457
+ Effect.map((_) => (_ as any)[idKey]), // we will have idKey because the transform is undone again by the encode schema mumbo jumbo above
459
458
  Effect.flatMap(findEId)
460
459
  )
461
460
  }
@@ -1,10 +1,10 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
 
3
+ import { NonEmptyString255 } from "@effect-app/schema"
3
4
  import { Array, Effect, FiberRef, flow, Option, Order, pipe, Ref, Struct } from "effect-app"
4
5
  import type { NonEmptyReadonlyArray } from "effect-app"
5
6
  import { get } from "effect-app/utils"
6
7
  import { InfraLogger } from "../../logger.js"
7
- import type { RequestContext } from "../../RequestContext.js"
8
8
  import type { FilterArgs, PersistenceModelType, Store, StoreConfig } from "./service.js"
9
9
  import { StoreMaker } from "./service.js"
10
10
  import { codeFilter, makeUpdateETag } from "./utils.js"
@@ -55,12 +55,8 @@ export function memFilter<T extends { id: string }, U extends keyof T = never>(f
55
55
  })
56
56
  }
57
57
 
58
- export const storeId = FiberRef.unsafeMake("primary")
59
-
60
- /**
61
- * @tsplus getter RequestContext restoreStoreId
62
- */
63
- export const restoreFromRequestContext = (ctx: RequestContext) => FiberRef.set(storeId, ctx.namespace ?? "primary")
58
+ const defaultNs = NonEmptyString255("primary")
59
+ export const storeId = FiberRef.unsafeMake<NonEmptyString255>(defaultNs)
64
60
 
65
61
  function logQuery(f: FilterArgs<any, any>, defaultValues?: any) {
66
62
  return InfraLogger
@@ -1,36 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.RequestContextContainer = exports.RCTag = void 0;
7
- var _schema = require("@effect-app/schema");
8
- var _effectApp = require("effect-app");
9
- var _ids = require("effect-app/ids");
10
- var _RequestContext = require("../RequestContext.cjs");
11
- var _Memory = require("./Store/Memory.cjs");
12
- /**
13
- * @tsplus type RequestContextContainer
14
- * @tsplus companion RequestContextContainer.Ops
15
- */
16
- class RequestContextContainer extends _effectApp.Context.TagId("effect-app/RequestContextContainer")() {
17
- static get get() {
18
- return _effectApp.Effect.flatMap(RequestContextContainer, _ => _.requestContext);
19
- }
20
- static get getOption() {
21
- return _effectApp.Effect.flatMap(_effectApp.Effect.contextWith(_ => _effectApp.Context.getOption(_, RequestContextContainer)), requestContext => _effectApp.Option.isSome(requestContext) ? _effectApp.Effect.map(requestContext.value.requestContext, _effectApp.Option.some) : _effectApp.Effect.sync(() => _effectApp.Option.none()));
22
- }
23
- static live = _effectApp.Effect.andThen(_effectApp.Effect.sync(() => new _RequestContext.RequestContext({
24
- name: (0, _schema.NonEmptyString255)("_root_"),
25
- rootId: (0, _ids.RequestId)("_root_"),
26
- locale: "en"
27
- })), _effectApp.FiberRef.make).pipe(_effectApp.Effect.map(ref => RequestContextContainer.of({
28
- requestContext: _effectApp.FiberRef.get(ref),
29
- update: f => _effectApp.Effect.tap(_effectApp.FiberRef.updateAndGet(ref, f), rc => _effectApp.Effect.annotateCurrentSpan((0, _RequestContext.spanAttributes)(rc))),
30
- start: a => _effectApp.Effect.zipRight(_effectApp.FiberRef.set(ref, a), (0, _Memory.restoreFromRequestContext)(a))
31
- })), _effectApp.Layer.scoped(this));
32
- }
33
- /** @tsplus static RequestContext.Ops Tag */
34
- exports.RequestContextContainer = RequestContextContainer;
35
- const RCTag = exports.RCTag = _effectApp.Context.GenericTag("@services/RCTag");
36
- //# sourceMappingURL=RequestContextContainer.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RequestContextContainer.cjs","names":["_schema","require","_effectApp","_ids","_RequestContext","_Memory","RequestContextContainer","Context","TagId","get","Effect","flatMap","_","requestContext","getOption","contextWith","Option","isSome","map","value","some","sync","none","live","andThen","RequestContext","name","NonEmptyString255","rootId","RequestId","locale","FiberRef","make","pipe","ref","of","update","f","tap","updateAndGet","rc","annotateCurrentSpan","spanAttributes","start","a","zipRight","set","restoreFromRequestContext","Layer","scoped","exports","RCTag","GenericTag"],"sources":["../../src/services/RequestContextContainer.ts"],"sourcesContent":[null],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,UAAA,GAAAD,OAAA;AACA,IAAAE,IAAA,GAAAF,OAAA;AACA,IAAAG,eAAA,GAAAH,OAAA;AACA,IAAAI,OAAA,GAAAJ,OAAA;AAEA;;;;AAIM,MAAgBK,uBACpB,SAAQC,kBAAO,CAACC,KAAK,CAAC,oCAAoC,CAAC,EAIvD;EAEJ,WAAWC,GAAGA,CAAA;IACZ,OAAOC,iBAAM,CAACC,OAAO,CAACL,uBAAuB,EAAGM,CAAC,IAAKA,CAAC,CAACC,cAAc,CAAC;EACzE;EACA,WAAWC,SAASA,CAAA;IAClB,OAAOJ,iBAAM,CAACC,OAAO,CACnBD,iBAAM,CACHK,WAAW,CAAEH,CAAiB,IAAKL,kBAAO,CAACO,SAAS,CAACF,CAAC,EAAEN,uBAAuB,CAAC,CAAC,EACnFO,cAAc,IACbG,iBAAM,CAACC,MAAM,CAACJ,cAAc,CAAC,GACzBH,iBAAM,CAACQ,GAAG,CAACL,cAAc,CAACM,KAAK,CAACN,cAAc,EAAEG,iBAAM,CAACI,IAAI,CAAC,GAC5DV,iBAAM,CAACW,IAAI,CAAC,MAAML,iBAAM,CAACM,IAAI,EAAE,CAAC,CACvC;EACH;EACA,OAAgBC,IAAI,GAAGb,iBAAM,CAC1Bc,OAAO,CACNd,iBAAM,CACHW,IAAI,CAAC,MACJ,IAAII,8BAAc,CAAC;IAAEC,IAAI,EAAE,IAAAC,yBAAiB,EAAC,QAAQ,CAAC;IAAEC,MAAM,EAAE,IAAAC,cAAS,EAAC,QAAQ,CAAC;IAAEC,MAAM,EAAE;EAAI,CAAE,CAAC,CACrG,EACHC,mBAAQ,CAACC,IAAoB,CAC9B,CACAC,IAAI,CACHvB,iBAAM,CAACQ,GAAG,CAAEgB,GAAG,IACb5B,uBAAuB,CAAC6B,EAAE,CAAC;IACzBtB,cAAc,EAAEkB,mBAAQ,CAACtB,GAAG,CAACyB,GAAG,CAAC;IACjCE,MAAM,EAAGC,CAAwC,IAC/C3B,iBAAM,CAAC4B,GAAG,CAACP,mBAAQ,CAACQ,YAAY,CAACL,GAAG,EAAEG,CAAC,CAAC,EAAGG,EAAE,IAAK9B,iBAAM,CAAC+B,mBAAmB,CAAC,IAAAC,8BAAc,EAACF,EAAE,CAAC,CAAC,CAAC;IACnGG,KAAK,EAAGC,CAAiB,IAAKlC,iBAAM,CAACmC,QAAQ,CAACd,mBAAQ,CAACe,GAAG,CAACZ,GAAG,EAAEU,CAAC,CAAC,EAAE,IAAAG,iCAAyB,EAACH,CAAC,CAAC;GACjG,CAAC,CACH,EACDI,gBAAK,CAACC,MAAM,CAAC,IAAI,CAAC,CACnB;;AAGL;AAAAC,OAAA,CAAA5C,uBAAA,GAAAA,uBAAA;AACO,MAAM6C,KAAK,GAAAD,OAAA,CAAAC,KAAA,GAAG5C,kBAAO,CAAC6C,UAAU,CAAiB,iBAAiB,CAAC","ignoreList":[]}
@@ -1,42 +0,0 @@
1
- import { Context, Effect, Layer, Option } from "effect-app";
2
- import { RequestContext } from "../RequestContext.js";
3
- declare const RequestContextContainer_base: (abstract new (service: {
4
- requestContext: Effect<RequestContext>;
5
- update: (f: (rc: RequestContext) => RequestContext) => Effect<RequestContext>;
6
- start: (f: RequestContext) => Effect<void>;
7
- }) => Readonly<{
8
- requestContext: Effect<RequestContext>;
9
- update: (f: (rc: RequestContext) => RequestContext) => Effect<RequestContext>;
10
- start: (f: RequestContext) => Effect<void>;
11
- }> & Context.TagClassShape<"effect-app/RequestContextContainer", {
12
- requestContext: Effect<RequestContext>;
13
- update: (f: (rc: RequestContext) => RequestContext) => Effect<RequestContext>;
14
- start: (f: RequestContext) => Effect<void>;
15
- }>) & {
16
- toLayer: <E, R>(eff: Effect<Omit<RequestContextContainer, keyof Context.TagClassShape<any, any>>, E, R>) => Layer<RequestContextContainer, E, R>;
17
- toLayerScoped: <E, R_1>(eff: Effect<Omit<RequestContextContainer, keyof Context.TagClassShape<any, any>>, E, R_1>) => Layer<RequestContextContainer, E, Exclude<R_1, import("effect/Scope").Scope>>;
18
- of: (service: Omit<RequestContextContainer, keyof Context.TagClassShape<any, any>>) => RequestContextContainer;
19
- } & Context.Tag<RequestContextContainer, RequestContextContainer> & {
20
- requestContext: Effect<RequestContext, never, RequestContextContainer>;
21
- update: (f: (rc: RequestContext) => RequestContext) => Effect<RequestContext, never, RequestContextContainer>;
22
- start: (f: RequestContext) => Effect<void, never, RequestContextContainer>;
23
- } & {
24
- use: <X>(body: (_: {
25
- requestContext: Effect<RequestContext>;
26
- update: (f: (rc: RequestContext) => RequestContext) => Effect<RequestContext>;
27
- start: (f: RequestContext) => Effect<void>;
28
- }) => X) => X extends Effect<infer A_1, infer E_1, infer R_3> ? Effect<A_1, E_1, R_3 | RequestContextContainer> : Effect<X, never, RequestContextContainer>;
29
- };
30
- /**
31
- * @tsplus type RequestContextContainer
32
- * @tsplus companion RequestContextContainer.Ops
33
- */
34
- export declare abstract class RequestContextContainer extends RequestContextContainer_base {
35
- static get get(): Effect<RequestContext, never, RequestContextContainer>;
36
- static get getOption(): Effect.Effect<Option.Option<RequestContext>, never, never>;
37
- static readonly live: Layer.Layer<RequestContextContainer, never, never>;
38
- }
39
- /** @tsplus static RequestContext.Ops Tag */
40
- export declare const RCTag: Context.Tag<RequestContext, RequestContext>;
41
- export {};
42
- //# sourceMappingURL=RequestContextContainer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RequestContextContainer.d.ts","sourceRoot":"","sources":["../../src/services/RequestContextContainer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAY,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAErE,OAAO,EAAE,cAAc,EAAkB,MAAM,sBAAsB,CAAA;;oBASjD,MAAM,CAAC,cAAc,CAAC;YAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,cAAc,KAAK,cAAc,KAAK,MAAM,CAAC,cAAc,CAAC;WACtE,CAAC,CAAC,EAAE,cAAc,KAAK,MAAM,CAAC,IAAI,CAAC;;oBAF1B,MAAM,CAAC,cAAc,CAAC;YAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,cAAc,KAAK,cAAc,KAAK,MAAM,CAAC,cAAc,CAAC;WACtE,CAAC,CAAC,EAAE,cAAc,KAAK,MAAM,CAAC,IAAI,CAAC;;oBAF1B,MAAM,CAAC,cAAc,CAAC;YAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,cAAc,KAAK,cAAc,KAAK,MAAM,CAAC,cAAc,CAAC;WACtE,CAAC,CAAC,EAAE,cAAc,KAAK,MAAM,CAAC,IAAI,CAAC;;;;;;;qBADzB,cAAc,KAAK,cAAc;;;;wBADlC,MAAM,CAAC,cAAc,CAAC;gBAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,cAAc,KAAK,cAAc,KAAK,MAAM,CAAC,cAAc,CAAC;eACtE,CAAC,CAAC,EAAE,cAAc,KAAK,MAAM,CAAC,IAAI,CAAC;;;AAR9C;;;GAGG;AACH,8BAAsB,uBACpB,SAAQ,4BAIJ;IAEJ,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,cAAc,EAAE,KAAK,EAAE,uBAAuB,CAAC,CAEvE;IACD,MAAM,KAAK,SAAS,+DASnB;IACD,MAAM,CAAC,QAAQ,CAAC,IAAI,qDAkBjB;CACJ;AAED,4CAA4C;AAC5C,eAAO,MAAM,KAAK,6CAAwD,CAAA"}
@@ -1,31 +0,0 @@
1
- import { NonEmptyString255 } from "@effect-app/schema";
2
- import { Context, Effect, FiberRef, Layer, Option } from "effect-app";
3
- import { RequestId } from "effect-app/ids";
4
- import { RequestContext, spanAttributes } from "../RequestContext.js";
5
- import { restoreFromRequestContext } from "./Store/Memory.js";
6
- /**
7
- * @tsplus type RequestContextContainer
8
- * @tsplus companion RequestContextContainer.Ops
9
- */
10
- export class RequestContextContainer extends Context.TagId("effect-app/RequestContextContainer")() {
11
- static get get() {
12
- return Effect.flatMap(RequestContextContainer, (_) => _.requestContext);
13
- }
14
- static get getOption() {
15
- return Effect.flatMap(Effect
16
- .contextWith((_) => Context.getOption(_, RequestContextContainer)), (requestContext) => Option.isSome(requestContext)
17
- ? Effect.map(requestContext.value.requestContext, Option.some)
18
- : Effect.sync(() => Option.none()));
19
- }
20
- static live = Effect
21
- .andThen(Effect
22
- .sync(() => new RequestContext({ name: NonEmptyString255("_root_"), rootId: RequestId("_root_"), locale: "en" })), (FiberRef.make))
23
- .pipe(Effect.map((ref) => RequestContextContainer.of({
24
- requestContext: FiberRef.get(ref),
25
- update: (f) => Effect.tap(FiberRef.updateAndGet(ref, f), (rc) => Effect.annotateCurrentSpan(spanAttributes(rc))),
26
- start: (a) => Effect.zipRight(FiberRef.set(ref, a), restoreFromRequestContext(a))
27
- })), Layer.scoped(this));
28
- }
29
- /** @tsplus static RequestContext.Ops Tag */
30
- export const RCTag = Context.GenericTag("@services/RCTag");
31
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVxdWVzdENvbnRleHRDb250YWluZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvUmVxdWVzdENvbnRleHRDb250YWluZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFDdEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDckUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBQzFDLE9BQU8sRUFBRSxjQUFjLEVBQUUsY0FBYyxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDckUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFN0Q7OztHQUdHO0FBQ0gsTUFBTSxPQUFnQix1QkFDcEIsU0FBUSxPQUFPLENBQUMsS0FBSyxDQUFDLG9DQUFvQyxDQUFDLEVBSXZEO0lBRUosTUFBTSxLQUFLLEdBQUc7UUFDWixPQUFPLE1BQU0sQ0FBQyxPQUFPLENBQUMsdUJBQXVCLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUMsQ0FBQTtJQUN6RSxDQUFDO0lBQ0QsTUFBTSxLQUFLLFNBQVM7UUFDbEIsT0FBTyxNQUFNLENBQUMsT0FBTyxDQUNuQixNQUFNO2FBQ0gsV0FBVyxDQUFDLENBQUMsQ0FBaUIsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsdUJBQXVCLENBQUMsQ0FBQyxFQUNwRixDQUFDLGNBQWMsRUFBRSxFQUFFLENBQ2pCLE1BQU0sQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDO1lBQzNCLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsY0FBYyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUM7WUFDOUQsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLENBQ3ZDLENBQUE7SUFDSCxDQUFDO0lBQ0QsTUFBTSxDQUFVLElBQUksR0FBRyxNQUFNO1NBQzFCLE9BQU8sQ0FDTixNQUFNO1NBQ0gsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUNULElBQUksY0FBYyxDQUFDLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsUUFBUSxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQ3JHLEVBQ0gsQ0FBQSxRQUFRLENBQUMsSUFBb0IsQ0FBQSxDQUM5QjtTQUNBLElBQUksQ0FDSCxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FDakIsdUJBQXVCLENBQUMsRUFBRSxDQUFDO1FBQ3pCLGNBQWMsRUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztRQUNqQyxNQUFNLEVBQUUsQ0FBQyxDQUF3QyxFQUFFLEVBQUUsQ0FDbkQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ25HLEtBQUssRUFBRSxDQUFDLENBQWlCLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUseUJBQXlCLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDbEcsQ0FBQyxDQUNILEVBQ0QsS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FDbkIsQ0FBQTs7QUFHTCw0Q0FBNEM7QUFDNUMsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQWlCLGlCQUFpQixDQUFDLENBQUEifQ==