@effect-app/infra 4.0.0-beta.2 → 4.0.0-beta.21

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 (62) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/dist/Emailer/Sendgrid.js +1 -1
  3. package/dist/Emailer/service.d.ts +1 -1
  4. package/dist/Model/query/dsl.d.ts +9 -9
  5. package/dist/Model/query/new-kid-interpreter.d.ts +1 -1
  6. package/dist/QueueMaker/SQLQueue.d.ts +1 -1
  7. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  8. package/dist/QueueMaker/SQLQueue.js +2 -2
  9. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  10. package/dist/QueueMaker/memQueue.js +10 -9
  11. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  12. package/dist/QueueMaker/sbqueue.js +11 -9
  13. package/dist/RequestContext.d.ts +5 -5
  14. package/dist/RequestFiberSet.d.ts.map +1 -1
  15. package/dist/RequestFiberSet.js +4 -4
  16. package/dist/Store/ContextMapContainer.d.ts +1 -1
  17. package/dist/Store/Cosmos.js +1 -1
  18. package/dist/Store/Memory.d.ts.map +1 -1
  19. package/dist/Store/Memory.js +1 -1
  20. package/dist/adapters/SQL/Model.d.ts +2 -5
  21. package/dist/adapters/SQL/Model.d.ts.map +1 -1
  22. package/dist/adapters/SQL/Model.js +21 -13
  23. package/dist/adapters/ServiceBus.js +3 -3
  24. package/dist/adapters/redis-client.d.ts +1 -1
  25. package/dist/api/internal/auth.d.ts +1 -1
  26. package/dist/api/internal/events.d.ts.map +1 -1
  27. package/dist/api/internal/events.js +6 -4
  28. package/dist/api/routing/schema/jwt.d.ts +1 -1
  29. package/dist/api/routing/schema/jwt.d.ts.map +1 -1
  30. package/dist/api/routing/schema/jwt.js +1 -1
  31. package/dist/api/routing.d.ts +13 -15
  32. package/dist/api/routing.d.ts.map +1 -1
  33. package/dist/api/routing.js +3 -3
  34. package/dist/api/setupRequest.js +3 -3
  35. package/dist/errorReporter.d.ts +1 -1
  36. package/dist/errorReporter.d.ts.map +1 -1
  37. package/dist/errorReporter.js +1 -1
  38. package/dist/fileUtil.d.ts.map +1 -1
  39. package/dist/fileUtil.js +3 -2
  40. package/dist/rateLimit.js +1 -1
  41. package/package.json +9 -9
  42. package/src/Emailer/Sendgrid.ts +1 -1
  43. package/src/QueueMaker/SQLQueue.ts +2 -3
  44. package/src/QueueMaker/memQueue.ts +41 -42
  45. package/src/QueueMaker/sbqueue.ts +65 -62
  46. package/src/RequestFiberSet.ts +3 -3
  47. package/src/Store/Cosmos.ts +10 -10
  48. package/src/Store/Memory.ts +2 -4
  49. package/src/adapters/SQL/Model.ts +76 -71
  50. package/src/adapters/ServiceBus.ts +2 -2
  51. package/src/api/internal/events.ts +4 -3
  52. package/src/api/routing/schema/jwt.ts +2 -3
  53. package/src/api/routing.ts +14 -19
  54. package/src/api/setupRequest.ts +2 -2
  55. package/src/errorReporter.ts +1 -1
  56. package/src/fileUtil.ts +2 -1
  57. package/src/rateLimit.ts +2 -2
  58. package/test/controller.test.ts +10 -6
  59. package/test/dist/controller.test.d.ts.map +1 -1
  60. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  61. package/test/query.test.ts +0 -2
  62. package/test/rpc-multi-middleware.test.ts +1 -1
@@ -1,12 +1,11 @@
1
1
  import { Tracer } from "effect"
2
- import { Cause, Effect, flow, S } from "effect-app"
2
+ import { Cause, Effect, flow, type NonEmptyReadonlyArray, S } from "effect-app"
3
3
  import type { StringId } from "effect-app/Schema"
4
4
  import { pretty } from "effect-app/utils"
5
5
  import { Receiver, Sender } from "../adapters/ServiceBus.js"
6
6
  import { getRequestContext, setupRequestContextWithCustomSpan } from "../api/setupRequest.js"
7
7
  import { InfraLogger } from "../logger.js"
8
8
  import { reportNonInterruptedFailure, reportNonInterruptedFailureCause, reportQueueError } from "./errors.js"
9
- import type { NonEmptyReadonlyArray } from "effect-app"
10
9
  import { type QueueBase, QueueMeta } from "./service.js"
11
10
 
12
11
  export function makeServiceBusQueue<
@@ -22,8 +21,11 @@ export function makeServiceBusQueue<
22
21
  body: schema,
23
22
  meta: QueueMeta
24
23
  })
24
+ const wireSchemaJson = S.fromJsonString(wireSchema)
25
+ const encodePublish = S.encodeEffect(wireSchemaJson)
25
26
  const drainW = S.Struct({ body: drainSchema, meta: QueueMeta })
26
- const parseDrain = flow(S.decodeUnknownEffect(drainW), Effect.orDie)
27
+ const drainWJson = S.fromJsonString(drainW)
28
+ const parseDrain = flow(S.decodeUnknownEffect(drainWJson), Effect.orDie)
27
29
 
28
30
  return Effect.gen(function*() {
29
31
  const sender = yield* Sender
@@ -40,55 +42,51 @@ export function makeServiceBusQueue<
40
42
  handleEvent: (ks: DrainEvt) => Effect.Effect<void, DrainE, DrainR>,
41
43
  sessionId?: string
42
44
  ) => {
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- function processMessage(messageBody: any) {
45
- return Effect
46
- .sync(() => JSON.parse(messageBody))
47
- .pipe(
48
- Effect.flatMap((x) => parseDrain(x)),
49
- Effect.orDie,
50
- Effect
51
- .flatMap(({ body, meta }) => {
52
- let effect = InfraLogger
53
- .logDebug(`[${receiver.name}] Processing incoming message`)
54
- .pipe(
55
- Effect.annotateLogs({
56
- body: pretty(body),
57
- meta: pretty(meta)
58
- }),
59
- Effect.andThen(handleEvent(body)),
60
- Effect.orDie
61
- )
62
- // we silenceAndReportError here, so that the error is reported, and moves into the Exit.
63
- .pipe(
64
- silenceAndReportError,
65
- (_) =>
66
- setupRequestContextWithCustomSpan(
67
- _,
68
- meta,
69
- `queue.drain: ${receiver.name}${sessionId ? `#${sessionId}` : ""}.${body._tag}`,
70
- {
71
- captureStackTrace: false,
72
- kind: "consumer",
73
- attributes: {
74
- "queue.name": receiver.name,
75
- "queue.sessionId": sessionId,
76
- "queue.input": body
77
- }
45
+ function processMessage(messageBody: unknown) {
46
+ return parseDrain(messageBody).pipe(
47
+ Effect.orDie,
48
+ Effect
49
+ .flatMap(({ body, meta }) => {
50
+ let effect = InfraLogger
51
+ .logDebug(`[${receiver.name}] Processing incoming message`)
52
+ .pipe(
53
+ Effect.annotateLogs({
54
+ body: pretty(body),
55
+ meta: pretty(meta)
56
+ }),
57
+ Effect.andThen(handleEvent(body)),
58
+ Effect.orDie
59
+ )
60
+ // we silenceAndReportError here, so that the error is reported, and moves into the Exit.
61
+ .pipe(
62
+ silenceAndReportError,
63
+ (_) =>
64
+ setupRequestContextWithCustomSpan(
65
+ _,
66
+ meta,
67
+ `queue.drain: ${receiver.name}${sessionId ? `#${sessionId}` : ""}.${body._tag}`,
68
+ {
69
+ captureStackTrace: false,
70
+ kind: "consumer",
71
+ attributes: {
72
+ "queue.name": receiver.name,
73
+ "queue.sessionId": sessionId,
74
+ "queue.input": body
78
75
  }
79
- )
80
- )
81
- if (meta.span) {
82
- effect = Effect.withParentSpan(effect, Tracer.externalSpan(meta.span))
83
- }
84
- return effect
85
- }),
86
- Effect
87
- // we reportError here, so that we report the error only, and keep flowing
88
- .tapCause(reportError),
89
- // we still need to flatten the Exit.
90
- Effect.flatMap((_) => _)
91
- )
76
+ }
77
+ )
78
+ )
79
+ if (meta.span) {
80
+ effect = Effect.withParentSpan(effect, Tracer.externalSpan(meta.span))
81
+ }
82
+ return effect
83
+ }),
84
+ Effect
85
+ // we reportError here, so that we report the error only, and keep flowing
86
+ .tapCause(reportError),
87
+ // we still need to flatten the Exit.
88
+ Effect.flatMap((_) => _)
89
+ )
92
90
  }
93
91
 
94
92
  return receiver
@@ -111,17 +109,22 @@ export function makeServiceBusQueue<
111
109
  getRequestContext
112
110
  .pipe(
113
111
  Effect.flatMap((requestContext) =>
114
- Effect.forEach(messages, (m) =>
115
- S.encodeEffect(wireSchema)({
116
- body: m,
117
- meta: requestContext
118
- }).pipe(Effect.orDie, Effect.map((encoded) => ({
119
- body: JSON.stringify(encoded),
120
- messageId: m.id, /* correllationid: requestId */
121
- contentType: "application/json",
122
- sessionId: "sessionId" in m ? m.sessionId as string : undefined as unknown as string // TODO: optional
123
- }))))
124
- .pipe(Effect.flatMap((msgs) => sender.sendMessages(msgs)))
112
+ Effect
113
+ .forEach(messages, (m) =>
114
+ encodePublish({
115
+ body: m,
116
+ meta: requestContext
117
+ })
118
+ .pipe(
119
+ Effect.orDie,
120
+ Effect.map((body) => ({
121
+ body,
122
+ messageId: m.id, /* correllationid: requestId */
123
+ contentType: "application/json",
124
+ sessionId: "sessionId" in m ? m.sessionId as string : undefined as unknown as string // TODO: optional
125
+ }))
126
+ ))
127
+ .pipe(Effect.flatMap((msgs) => sender.sendMessages(msgs)))
125
128
  ),
126
129
  Effect.withSpan("queue.publish: " + sender.name, {
127
130
  kind: "producer",
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Effect, Fiber, FiberSet, Layer, ServiceMap, type Tracer } from "effect-app"
2
+ import { Effect, Fiber, FiberSet, Layer, Option, ServiceMap, type Tracer } from "effect-app"
3
3
  import { reportRequestError, reportUnknownRequestError } from "./api/reportError.js"
4
4
  import { InfraLogger } from "./logger.js"
5
5
 
@@ -8,8 +8,8 @@ const getRootParentSpan = Effect.gen(function*() {
8
8
  Effect.catchTag("NoSuchElementError", () => Effect.succeed(null))
9
9
  )
10
10
  if (!span) return span
11
- while (span._tag === "Span" && span.parent !== undefined) {
12
- span = span.parent
11
+ while (span._tag === "Span" && Option.isSome(span.parent)) {
12
+ span = span.parent.value
13
13
  }
14
14
  return span
15
15
  })
@@ -328,15 +328,13 @@ function makeCosmosStore({ prefix }: StorageConfig) {
328
328
  .query<M>(q, { partitionKey: mainPartitionKey })
329
329
  .fetchAll()
330
330
  .then(({ resources }) =>
331
- resources.map((_) =>
332
- ({
333
- ...pipe(
334
- defaultValues,
335
- Struct.pick(f.select!.filter((_) => typeof _ === "string"))
336
- ),
337
- ...mapReverseId(_ as any)
338
- }) as any
339
- )
331
+ resources.map((_) => ({
332
+ ...pipe(
333
+ defaultValues,
334
+ Struct.pick(f.select!.filter((_) => typeof _ === "string") as never[])
335
+ ),
336
+ ...mapReverseId(_ as any)
337
+ }))
340
338
  )
341
339
  : container
342
340
  .items
@@ -404,7 +402,9 @@ function makeCosmosStore({ prefix }: StorageConfig) {
404
402
  Effect
405
403
  .flatMap((x) => {
406
404
  if (x.statusCode === 412 || x.statusCode === 404 || x.statusCode === 409) {
407
- return Effect.fail(new OptimisticConcurrencyException({ type: name, id: e[idKey], code: x.statusCode }))
405
+ return Effect.fail(
406
+ new OptimisticConcurrencyException({ type: name, id: e[idKey], code: x.statusCode })
407
+ )
408
408
  }
409
409
  if (x.statusCode > 299 || x.statusCode < 200) {
410
410
  return Effect.die(
@@ -24,7 +24,7 @@ export function memFilter<T extends FieldValues, U extends keyof T = never>(f: F
24
24
  )
25
25
  const n = Struct.pick(i, keys)
26
26
  subKeys.forEach((subKey) => {
27
- n[subKey.key] = i[subKey.key]!.map(Struct.pick(subKey.subKeys))
27
+ n[subKey.key] = i[subKey.key]!.map(Struct.pick(subKey.subKeys as never[]))
28
28
  })
29
29
  return n as M
30
30
  }) as any
@@ -72,9 +72,7 @@ export function memFilter<T extends FieldValues, U extends keyof T = never>(f: F
72
72
  }
73
73
 
74
74
  const defaultNs: NonEmptyString255 = NonEmptyString255("primary")
75
- export class storeId
76
- extends ServiceMap.Reference("StoreId", { defaultValue: (): NonEmptyString255 => defaultNs })
77
- {}
75
+ export class storeId extends ServiceMap.Reference("StoreId", { defaultValue: (): NonEmptyString255 => defaultNs }) {}
78
76
 
79
77
  function logQuery(f: FilterArgs<any, any>, defaultValues?: any) {
80
78
  return InfraLogger
@@ -7,10 +7,6 @@
7
7
  /**
8
8
  * @since 1.0.0
9
9
  */
10
- import * as VariantSchema from "effect/unstable/schema/VariantSchema"
11
- import { SqlClient } from "effect/unstable/sql/SqlClient"
12
- import * as SqlResolver from "effect/unstable/sql/SqlResolver"
13
- import * as SqlSchema from "effect/unstable/sql/SqlSchema"
14
10
  import crypto from "crypto" // TODO
15
11
  import type { Brand } from "effect/Brand"
16
12
  import * as DateTime from "effect/DateTime"
@@ -24,6 +20,10 @@ import * as Schema from "effect/Schema"
24
20
  import * as Getter from "effect/SchemaGetter"
25
21
  import * as Transformation from "effect/SchemaTransformation"
26
22
  import type { Scope } from "effect/Scope"
23
+ import * as VariantSchema from "effect/unstable/schema/VariantSchema"
24
+ import { SqlClient } from "effect/unstable/sql/SqlClient"
25
+ import * as SqlResolver from "effect/unstable/sql/SqlResolver"
26
+ import * as SqlSchema from "effect/unstable/sql/SqlSchema"
27
27
 
28
28
  const {
29
29
  Class,
@@ -190,14 +190,13 @@ export const Generated = <S extends Schema.Top>(
190
190
  * @since 1.0.0
191
191
  * @category generated
192
192
  */
193
- export interface GeneratedByApp<S extends Schema.Top>
194
- extends
195
- VariantSchema.Field<{
196
- readonly select: S
197
- readonly insert: S
198
- readonly update: S
199
- readonly json: S
200
- }>
193
+ export interface GeneratedByApp<S extends Schema.Top> extends
194
+ VariantSchema.Field<{
195
+ readonly select: S
196
+ readonly insert: S
197
+ readonly update: S
198
+ readonly json: S
199
+ }>
201
200
  {}
202
201
 
203
202
  /**
@@ -303,8 +302,7 @@ export const FieldOption: <Field extends VariantSchema.Field<any> | Schema.Top>(
303
302
  ) => Field extends Schema.Top ? FieldOption<Field>
304
303
  : Field extends VariantSchema.Field<infer S> ? VariantSchema.Field<
305
304
  {
306
- readonly [K in keyof S]: S[K] extends Schema.Top
307
- ? K extends VariantsDatabase ? Schema.OptionFromNullOr<S[K]>
305
+ readonly [K in keyof S]: S[K] extends Schema.Top ? K extends VariantsDatabase ? Schema.OptionFromNullOr<S[K]>
308
306
  : optionalOption<S[K]>
309
307
  : never
310
308
  }
@@ -545,16 +543,15 @@ export const DateTimeUpdateFromNumber: DateTimeUpdateFromNumber = Field({
545
543
  * @since 1.0.0
546
544
  * @category json
547
545
  */
548
- export interface JsonFromString<S extends Schema.Top>
549
- extends
550
- VariantSchema.Field<{
551
- readonly select: Schema.fromJsonString<S>
552
- readonly insert: Schema.fromJsonString<S>
553
- readonly update: Schema.fromJsonString<S>
554
- readonly json: S
555
- readonly jsonCreate: S
556
- readonly jsonUpdate: S
557
- }>
546
+ export interface JsonFromString<S extends Schema.Top> extends
547
+ VariantSchema.Field<{
548
+ readonly select: Schema.fromJsonString<S>
549
+ readonly insert: Schema.fromJsonString<S>
550
+ readonly update: Schema.fromJsonString<S>
551
+ readonly json: S
552
+ readonly jsonCreate: S
553
+ readonly jsonUpdate: S
554
+ }>
558
555
  {}
559
556
 
560
557
  /**
@@ -825,26 +822,28 @@ export const makeDataLoaders = <
825
822
  const idColumn = options.idColumn as string
826
823
  const setMaxBatchSize = options.maxBatchSize ? RequestResolver.batchN(options.maxBatchSize) : identity
827
824
 
828
- const insertResolver = SqlResolver.ordered({
829
- Request: Model.insert,
830
- Result: Model,
831
- execute: (request: any) =>
832
- sql.onDialectOrElse({
833
- mysql: () =>
834
- Effect.forEach(request, (request: any) =>
835
- sql`insert into ${sql(options.tableName)} ${sql.insert(request)};
825
+ const insertResolver = SqlResolver
826
+ .ordered({
827
+ Request: Model.insert,
828
+ Result: Model,
829
+ execute: (request: any) =>
830
+ sql.onDialectOrElse({
831
+ mysql: () =>
832
+ Effect.forEach(request, (request: any) =>
833
+ sql`insert into ${sql(options.tableName)} ${sql.insert(request)};
836
834
  select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID();`
837
- .unprepared
838
- .pipe(
839
- Effect.map(([, results]) => results![0] as any)
840
- ), { concurrency: 10 }),
841
- orElse: () => sql`insert into ${sql(options.tableName)} ${sql.insert(request).returning("*")}`
842
- })
843
- }).pipe(
844
- RequestResolver.setDelay(options.window),
845
- setMaxBatchSize,
846
- RequestResolver.withSpan(`${options.spanPrefix}.insertResolver`)
847
- )
835
+ .unprepared
836
+ .pipe(
837
+ Effect.map(([, results]) => results![0] as any)
838
+ ), { concurrency: 10 }),
839
+ orElse: () => sql`insert into ${sql(options.tableName)} ${sql.insert(request).returning("*")}`
840
+ })
841
+ })
842
+ .pipe(
843
+ RequestResolver.setDelay(options.window),
844
+ setMaxBatchSize,
845
+ RequestResolver.withSpan(`${options.spanPrefix}.insertResolver`)
846
+ )
848
847
  const insertExecute = SqlResolver.request(insertResolver)
849
848
  const insert = (
850
849
  insert: S["insert"]["Type"]
@@ -860,14 +859,16 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
860
859
  })
861
860
  ) as any
862
861
 
863
- const insertVoidResolver = SqlResolver.void({
864
- Request: Model.insert,
865
- execute: (request: any) => sql`insert into ${sql(options.tableName)} ${sql.insert(request)}`
866
- }).pipe(
867
- RequestResolver.setDelay(options.window),
868
- setMaxBatchSize,
869
- RequestResolver.withSpan(`${options.spanPrefix}.insertVoidResolver`)
870
- )
862
+ const insertVoidResolver = SqlResolver
863
+ .void({
864
+ Request: Model.insert,
865
+ execute: (request: any) => sql`insert into ${sql(options.tableName)} ${sql.insert(request)}`
866
+ })
867
+ .pipe(
868
+ RequestResolver.setDelay(options.window),
869
+ setMaxBatchSize,
870
+ RequestResolver.withSpan(`${options.spanPrefix}.insertVoidResolver`)
871
+ )
871
872
  const insertVoidExecute = SqlResolver.request(insertVoidResolver)
872
873
  const insertVoid = (
873
874
  insert: S["insert"]["Type"]
@@ -878,18 +879,20 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
878
879
  })
879
880
  ) as any
880
881
 
881
- const findByIdResolver = SqlResolver.findById({
882
- Id: idSchema,
883
- Result: Model,
884
- ResultId(request: any) {
885
- return request[idColumn]
886
- },
887
- execute: (ids: any) => sql`select * from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}`
888
- }).pipe(
889
- RequestResolver.setDelay(options.window),
890
- setMaxBatchSize,
891
- RequestResolver.withSpan(`${options.spanPrefix}.findByIdResolver`)
892
- )
882
+ const findByIdResolver = SqlResolver
883
+ .findById({
884
+ Id: idSchema,
885
+ Result: Model,
886
+ ResultId(request: any) {
887
+ return request[idColumn]
888
+ },
889
+ execute: (ids: any) => sql`select * from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}`
890
+ })
891
+ .pipe(
892
+ RequestResolver.setDelay(options.window),
893
+ setMaxBatchSize,
894
+ RequestResolver.withSpan(`${options.spanPrefix}.findByIdResolver`)
895
+ )
893
896
  const findByIdExecute = SqlResolver.request(findByIdResolver)
894
897
  const findById = (
895
898
  id: S["fields"][Id]["Type"]
@@ -904,14 +907,16 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
904
907
  })
905
908
  ) as any
906
909
 
907
- const deleteResolver = SqlResolver.void({
908
- Request: idSchema,
909
- execute: (ids: any) => sql`delete from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}`
910
- }).pipe(
911
- RequestResolver.setDelay(options.window),
912
- setMaxBatchSize,
913
- RequestResolver.withSpan(`${options.spanPrefix}.deleteResolver`)
914
- )
910
+ const deleteResolver = SqlResolver
911
+ .void({
912
+ Request: idSchema,
913
+ execute: (ids: any) => sql`delete from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}`
914
+ })
915
+ .pipe(
916
+ RequestResolver.setDelay(options.window),
917
+ setMaxBatchSize,
918
+ RequestResolver.withSpan(`${options.spanPrefix}.deleteResolver`)
919
+ )
915
920
  const deleteExecute = SqlResolver.request(deleteResolver)
916
921
  const delete_ = (
917
922
  id: S["fields"][Id]["Type"]
@@ -66,7 +66,7 @@ export const SenderTag = <Id>() => <Key extends string>(queueName: Key) => {
66
66
  return Object.assign(tag, {
67
67
  layer: Layer.effect(
68
68
  tag,
69
- Sender.make(queueName).pipe(Effect.map((_) => Sender.of(_)))
69
+ Sender.make(queueName).pipe(Effect.map(Sender.of))
70
70
  )
71
71
  })
72
72
  }
@@ -185,7 +185,7 @@ export const ReceiverTag = <Id>() => <Key extends string>(queueName: Key) => {
185
185
  return Object.assign(tag, {
186
186
  layer: Layer.effect(
187
187
  tag,
188
- makeReceiver(queueName).pipe(Effect.map((_) => Receiver.of(_)))
188
+ makeReceiver(queueName).pipe(Effect.map(Receiver.of))
189
189
  )
190
190
  })
191
191
  }
@@ -28,19 +28,20 @@ export const makeSSE = <A extends { id: any }, SI, SR>(
28
28
 
29
29
  const enc = new TextEncoder()
30
30
 
31
- const encode = S.encodeEffect(schema)
31
+ const encode = S.encodeEffect(S.fromJsonString(schema))
32
32
 
33
33
  const eventStream = Stream.mapEffect(
34
34
  events,
35
35
  (_) =>
36
36
  encode(_.evt)
37
- .pipe(Effect.map((evt) => `id: ${_.evt.id}\ndata: ${JSON.stringify(evt)}`))
37
+ .pipe(Effect.map((data) => `id: ${_.evt.id}\ndata: ${data}`))
38
38
  )
39
39
 
40
40
  const stream = pipe(
41
41
  setRetry,
42
42
  Stream.merge(keepAlive),
43
- Stream.merge(eventStream, { haltStrategy: "either" }),
43
+ // Keep this unary so pipe receives a function, not a Stream value.
44
+ (self) => Stream.merge(self, eventStream, { haltStrategy: "either" }),
44
45
  Stream.tapCause((cause) => Effect.logError("SSE error", cause)),
45
46
  Stream.map((_) => enc.encode(_ + "\n\n"))
46
47
  )
@@ -15,8 +15,7 @@ export const parseJwt = <Sch extends S.Top>(
15
15
  (s, _options) =>
16
16
  Effect.try({
17
17
  try: () => jwtDecode(s, options),
18
- catch: (e: any) =>
19
- new S.SchemaIssue.InvalidValue(Option.some(s), { message: e?.message })
18
+ catch: (e: any) => new S.SchemaIssue.InvalidValue(Option.some(s), { message: e?.message })
20
19
  })
21
20
  )
22
- .pipe(S.decodeTo(schema) as any) as any as S.decodeTo<Sch, S.String>
21
+ .pipe(S.decodeTo(schema) as any)
@@ -16,11 +16,11 @@ export * from "./routing/middleware.js"
16
16
 
17
17
  // it's the result of extending S.Req setting success, config
18
18
  // it's a schema plus some metadata
19
- export type AnyRequestModule = S.Any & {
19
+ export type AnyRequestModule = S.Top & {
20
20
  _tag: string // unique identifier for the request module
21
21
  config: any // ?
22
- success: S.Any // validates the success response
23
- error: S.Any // validates the failure response
22
+ success: S.Top // validates the success response
23
+ error: S.Top // validates the failure response
24
24
  }
25
25
 
26
26
  // builder pattern for adding actions to a router until all actions are added
@@ -53,10 +53,10 @@ namespace RequestTypes {
53
53
  }
54
54
  type RequestType = typeof RequestTypes[keyof typeof RequestTypes]
55
55
 
56
- type GetSuccess<T> = T extends { success: S.Any } ? T["success"] : typeof S.Void
57
- type GetFailure<T extends { error?: S.Any }> = T["error"] extends never ? typeof S.Never : T["error"]
56
+ type GetSuccess<T> = T extends { success: S.Top } ? T["success"] : typeof S.Void
57
+ type GetFailure<T extends { error?: S.Top }> = T["error"] extends never ? typeof S.Never : T["error"]
58
58
 
59
- type GetSuccessShape<Action extends { success?: S.Any }, RT extends RequestType> = {
59
+ type GetSuccessShape<Action extends { success?: S.Top }, RT extends RequestType> = {
60
60
  d: S.Schema.Type<GetSuccess<Action>>
61
61
  raw: S.Codec.Encoded<GetSuccess<Action>>
62
62
  }[RT]
@@ -141,7 +141,7 @@ export type RouteMatcher<
141
141
  & {
142
142
  success: Resource[Key]["success"]
143
143
  successRaw: S.Codec<S.Codec.Encoded<Resource[Key]["success"]>>
144
- error: Resource[Key]["failure"]
144
+ error: Resource[Key]["error"]
145
145
  /**
146
146
  * Requires the Encoded shape (e.g directly undecoded from DB, so that we don't do multiple Decode/Encode)
147
147
  */
@@ -194,7 +194,8 @@ export const makeRouter = <
194
194
  > = (
195
195
  req: S.Schema.Type<Action>
196
196
  ) => Generator<
197
- Effect.Effect<
197
+ Yieldable<
198
+ any,
198
199
  any,
199
200
  S.Schema.Type<GetFailure<Action>> | S.SchemaError,
200
201
  // the actual implementation of the handler may just require the dynamic context provided by the middleware
@@ -247,7 +248,7 @@ export const makeRouter = <
247
248
 
248
249
  type RequestModules = FilterRequestModules<Resource>
249
250
  const requestModules = typedKeysOf(rsc).reduce((acc, cur) => {
250
- if (Predicate.isObject(rsc[cur]) && rsc[cur]["success"]) {
251
+ if (Predicate.isObjectKeyword(rsc[cur]) && rsc[cur]["success"]) {
251
252
  acc[cur as keyof RequestModules] = rsc[cur] as RequestModules[keyof RequestModules]
252
253
  }
253
254
  return acc
@@ -319,7 +320,7 @@ export const makeRouter = <
319
320
  ? Impl[K]["raw"] extends (...args: any[]) => Effect.Effect<any, any, infer R> ? R
320
321
  : Impl[K]["raw"] extends Effect.Effect<any, any, infer R> ? R
321
322
  : Impl[K]["raw"] extends (...args: any[]) => Generator<
322
- Effect.Effect<any, any, infer R>,
323
+ Yieldable<any, any, any, infer R>,
323
324
  any,
324
325
  any
325
326
  > ? R
@@ -327,7 +328,7 @@ export const makeRouter = <
327
328
  : Impl[K] extends (...args: any[]) => Effect.Effect<any, any, infer R> ? R
328
329
  : Impl[K] extends Effect.Effect<any, any, infer R> ? R
329
330
  : Impl[K] extends (...args: any[]) => Generator<
330
- Effect.Effect<any, any, infer R>,
331
+ Yieldable<any, any, any, infer R>,
331
332
  any,
332
333
  any
333
334
  > ? R
@@ -415,7 +416,7 @@ export const makeRouter = <
415
416
  .make(
416
417
  ...typedValuesOf(mapped).map(([resource]) => {
417
418
  return Rpc
418
- .make(resource._tag, { payload: resource, success: resource.success, error: resource.failure })
419
+ .make(resource._tag, { payload: resource, success: resource.success, error: resource.error })
419
420
  .annotate(middleware.requestContext, resource.config ?? {})
420
421
  })
421
422
  )
@@ -509,13 +510,7 @@ export const makeRouter = <
509
510
  dependencies?: ReadonlyArray<Layer.Any>
510
511
  // v4: generators yield Yieldable with asEffect()
511
512
  effect: (match: typeof router3) => Generator<
512
- {
513
- asEffect(): Effect.Effect<
514
- any,
515
- any,
516
- any
517
- >
518
- },
513
+ Yieldable<any, any, any, any>,
519
514
  { [K in keyof FilterRequestModules<Resource>]: AnyHandler<Resource[K]> },
520
515
  any
521
516
  >
@@ -56,7 +56,7 @@ export function setupRequestContext<R, E, A>(self: Effect.Effect<A, E, R>, reque
56
56
  const layer = Layer.mergeAll(
57
57
  ContextMapContainer.layer,
58
58
  Layer.succeed(LocaleRef, requestContext.locale),
59
- Layer.succeed(storeId, NonEmptyString255(requestContext.namespace))
59
+ Layer.succeed(storeId, requestContext.namespace)
60
60
  )
61
61
  return self
62
62
  .pipe(
@@ -74,7 +74,7 @@ export function setupRequestContextWithCustomSpan<R, E, A>(
74
74
  const layer = Layer.mergeAll(
75
75
  ContextMapContainer.layer,
76
76
  Layer.succeed(LocaleRef, requestContext.locale),
77
- Layer.succeed(storeId, NonEmptyString255(requestContext.namespace))
77
+ Layer.succeed(storeId, requestContext.namespace)
78
78
  )
79
79
  return self
80
80
  .pipe(
@@ -1,5 +1,5 @@
1
1
  import * as Sentry from "@sentry/node"
2
- import { Cause, Effect, LogLevel } from "effect-app"
2
+ import { Cause, Effect, type LogLevel } from "effect-app"
3
3
  import { dropUndefined, LogLevelToSentry } from "effect-app/utils"
4
4
  import { getRC } from "./api/setupRequest.js"
5
5
  import { CauseException, tryToJson, tryToReport } from "./errors.js"
package/src/fileUtil.ts CHANGED
@@ -119,7 +119,8 @@ export function withFileLock<A, E, R>(
119
119
  // ensure lock is released
120
120
  yield* Effect.addFinalizer(() =>
121
121
  Effect
122
- .tryPromise(release)
122
+ // we have to make sure we use a thunk, or the library will cause problems because effect passes abortsignal as first argument
123
+ .tryPromise(() => release())
123
124
  .pipe(Effect.orDie)
124
125
  )
125
126
 
package/src/rateLimit.ts CHANGED
@@ -56,7 +56,7 @@ export function batchPar<R, E, A, R2, E2, A2, T>(
56
56
  (_, i) =>
57
57
  Effect
58
58
  .forEach(_, (_, j) => forEachItem(_, j, i), { concurrency: "inherit" })
59
- .pipe(Effect.flatMap((_) => forEachBatch(_ as NonEmptyArray<A>, i))),
59
+ .pipe(Effect.flatMap((_) => forEachBatch(_, i))),
60
60
  { concurrency: "inherit" }
61
61
  )
62
62
  }
@@ -72,7 +72,7 @@ export function batch<R, E, A, R2, E2, A2, T>(
72
72
  (_, i) =>
73
73
  Effect
74
74
  .forEach(_, (_, j) => forEachItem(_, j, i), { concurrency: "inherit" })
75
- .pipe(Effect.flatMap((_) => forEachBatch(_ as NonEmptyArray<A>, i)))
75
+ .pipe(Effect.flatMap((_) => forEachBatch(_, i)))
76
76
  )
77
77
  }
78
78