@effect-app/infra 0.48.0 → 0.49.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/_cjs/_ext/Array.cjs.map +1 -1
- package/_cjs/api/defaultErrorHandler.cjs.map +1 -1
- package/_cjs/api/express/makeJsonSchema.cjs +2 -2
- package/_cjs/api/express/makeJsonSchema.cjs.map +1 -1
- package/_cjs/api/express/schema/jwt.cjs.map +1 -1
- package/_cjs/api/express/schema/requestHandler.cjs.map +1 -1
- package/_cjs/api/express/schema/routing.cjs.map +1 -1
- package/_cjs/api/reportError.cjs.map +1 -1
- package/_cjs/api/routing.cjs.map +1 -1
- package/_cjs/api/setupRequest.cjs.map +1 -1
- package/_cjs/api/writeDocs.cjs.map +1 -1
- package/_cjs/rateLimit.cjs.map +1 -1
- package/_cjs/services/Emailer/Sendgrid.cjs.map +1 -1
- package/_cjs/services/Emailer/fake.cjs.map +1 -1
- package/_cjs/services/Operations/live.cjs.map +1 -1
- package/_cjs/services/Operations/service.cjs.map +1 -1
- package/_cjs/services/QueueMaker/errors.cjs.map +1 -1
- package/_cjs/services/QueueMaker/memQueue.cjs.map +1 -1
- package/_cjs/services/QueueMaker/sbqueue.cjs.map +1 -1
- package/_cjs/services/Repository.cjs +8 -8
- package/_cjs/services/Repository.cjs.map +1 -1
- package/_cjs/services/RepositoryBase.cjs +13 -13
- package/_cjs/services/RepositoryBase.cjs.map +1 -1
- package/_cjs/services/RequestContextContainer.cjs.map +1 -1
- package/_cjs/services/Store/Cosmos.cjs +9 -9
- package/_cjs/services/Store/Cosmos.cjs.map +1 -1
- package/_cjs/services/Store/Cosmos.test.cjs.map +1 -1
- package/_cjs/services/Store/Disk.cjs.map +1 -1
- package/_cjs/services/Store/Memory.cjs +42 -42
- package/_cjs/services/Store/Memory.cjs.map +1 -1
- package/_cjs/services/Store/Redis.cjs +13 -13
- package/_cjs/services/Store/Redis.cjs.map +1 -1
- package/_cjs/services/Store/codeFilter.test.cjs.map +1 -1
- package/_cjs/services/Store/index.cjs.map +1 -1
- package/_cjs/services/Store/service.cjs.map +1 -1
- package/_cjs/services/Store/utils.cjs +2 -3
- package/_cjs/services/Store/utils.cjs.map +1 -1
- package/_cjs/services/simpledb/cosmosdb.cjs +12 -4
- package/_cjs/services/simpledb/cosmosdb.cjs.map +1 -1
- package/_cjs/services/simpledb/diskdb.cjs.map +1 -1
- package/_cjs/services/simpledb/memdb.cjs.map +1 -1
- package/_cjs/services/simpledb/mongodb.cjs +15 -5
- package/_cjs/services/simpledb/mongodb.cjs.map +1 -1
- package/_cjs/services/simpledb/redisdb.cjs +13 -7
- package/_cjs/services/simpledb/redisdb.cjs.map +1 -1
- package/_cjs/services/simpledb/simpledb.cjs.map +1 -1
- package/_src/_ext/Array.ts +3 -2
- package/_src/api/defaultErrorHandler.ts +14 -12
- package/_src/api/express/makeJsonSchema.ts +6 -5
- package/_src/api/express/schema/jwt.ts +1 -1
- package/_src/api/express/schema/requestHandler.ts +112 -100
- package/_src/api/express/schema/routing.ts +61 -55
- package/_src/api/reportError.ts +16 -12
- package/_src/api/routing.ts +157 -135
- package/_src/api/setupRequest.ts +3 -1
- package/_src/api/writeDocs.ts +4 -3
- package/_src/rateLimit.ts +21 -14
- package/_src/services/Emailer/Sendgrid.ts +11 -10
- package/_src/services/Emailer/fake.ts +2 -1
- package/_src/services/Operations/live.ts +18 -12
- package/_src/services/Operations/service.ts +26 -17
- package/_src/services/QueueMaker/errors.ts +7 -6
- package/_src/services/QueueMaker/memQueue.ts +13 -11
- package/_src/services/QueueMaker/sbqueue.ts +16 -14
- package/_src/services/Repository.ts +53 -51
- package/_src/services/RepositoryBase.ts +33 -28
- package/_src/services/RequestContextContainer.ts +4 -3
- package/_src/services/Store/Cosmos.test.ts +31 -29
- package/_src/services/Store/Cosmos.ts +203 -180
- package/_src/services/Store/Disk.ts +19 -18
- package/_src/services/Store/Memory.ts +37 -32
- package/_src/services/Store/Redis.ts +31 -27
- package/_src/services/Store/codeFilter.test.ts +26 -16
- package/_src/services/Store/index.ts +26 -24
- package/_src/services/Store/service.ts +5 -5
- package/_src/services/Store/utils.ts +27 -24
- package/_src/services/simpledb/cosmosdb.ts +61 -51
- package/_src/services/simpledb/diskdb.ts +38 -31
- package/_src/services/simpledb/memdb.ts +25 -21
- package/_src/services/simpledb/mongodb.ts +40 -35
- package/_src/services/simpledb/redisdb.ts +66 -55
- package/_src/services/simpledb/simpledb.ts +32 -30
- package/dist/_ext/Array.d.ts.map +1 -1
- package/dist/_ext/Array.js +2 -2
- package/dist/api/defaultErrorHandler.d.ts.map +1 -1
- package/dist/api/defaultErrorHandler.js +5 -5
- package/dist/api/express/makeJsonSchema.d.ts +0 -1
- package/dist/api/express/makeJsonSchema.d.ts.map +1 -1
- package/dist/api/express/makeJsonSchema.js +4 -4
- package/dist/api/express/schema/jwt.js +2 -2
- package/dist/api/express/schema/requestHandler.d.ts.map +1 -1
- package/dist/api/express/schema/requestHandler.js +17 -17
- package/dist/api/express/schema/routing.d.ts.map +1 -1
- package/dist/api/express/schema/routing.js +13 -11
- package/dist/api/reportError.d.ts.map +1 -1
- package/dist/api/reportError.js +6 -6
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +29 -25
- package/dist/api/setupRequest.d.ts.map +1 -1
- package/dist/api/setupRequest.js +2 -2
- package/dist/api/writeDocs.d.ts.map +1 -1
- package/dist/api/writeDocs.js +5 -4
- package/dist/rateLimit.d.ts +4 -4
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/rateLimit.js +5 -4
- package/dist/services/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/services/Emailer/Sendgrid.js +9 -9
- package/dist/services/Emailer/fake.d.ts.map +1 -1
- package/dist/services/Emailer/fake.js +1 -1
- package/dist/services/Operations/live.d.ts.map +1 -1
- package/dist/services/Operations/live.js +11 -8
- package/dist/services/Operations/service.d.ts.map +1 -1
- package/dist/services/Operations/service.js +10 -4
- package/dist/services/QueueMaker/errors.d.ts.map +1 -1
- package/dist/services/QueueMaker/errors.js +5 -5
- package/dist/services/QueueMaker/memQueue.d.ts +1 -1
- package/dist/services/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/services/QueueMaker/memQueue.js +5 -4
- package/dist/services/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/services/QueueMaker/sbqueue.js +5 -5
- package/dist/services/Repository.d.ts +34 -35
- package/dist/services/Repository.d.ts.map +1 -1
- package/dist/services/Repository.js +16 -16
- package/dist/services/RepositoryBase.d.ts +4 -4
- package/dist/services/RepositoryBase.d.ts.map +1 -1
- package/dist/services/RepositoryBase.js +25 -22
- package/dist/services/RequestContextContainer.d.ts.map +1 -1
- package/dist/services/RequestContextContainer.js +3 -3
- package/dist/services/Store/Cosmos.d.ts +3 -3
- package/dist/services/Store/Cosmos.d.ts.map +1 -1
- package/dist/services/Store/Cosmos.js +53 -39
- package/dist/services/Store/Disk.d.ts.map +1 -1
- package/dist/services/Store/Disk.js +18 -18
- package/dist/services/Store/Memory.d.ts +2 -3
- package/dist/services/Store/Memory.d.ts.map +1 -1
- package/dist/services/Store/Memory.js +44 -44
- package/dist/services/Store/Redis.d.ts +4 -4
- package/dist/services/Store/Redis.d.ts.map +1 -1
- package/dist/services/Store/Redis.js +19 -17
- package/dist/services/Store/index.d.ts.map +1 -1
- package/dist/services/Store/index.js +4 -4
- package/dist/services/Store/service.d.ts +4 -5
- package/dist/services/Store/service.d.ts.map +1 -1
- package/dist/services/Store/service.js +3 -3
- package/dist/services/Store/utils.d.ts +2 -2
- package/dist/services/Store/utils.d.ts.map +1 -1
- package/dist/services/Store/utils.js +16 -14
- package/dist/services/simpledb/cosmosdb.d.ts.map +1 -1
- package/dist/services/simpledb/cosmosdb.js +16 -12
- package/dist/services/simpledb/diskdb.d.ts.map +1 -1
- package/dist/services/simpledb/diskdb.js +15 -15
- package/dist/services/simpledb/memdb.d.ts.map +1 -1
- package/dist/services/simpledb/memdb.js +6 -6
- package/dist/services/simpledb/mongodb.d.ts +5 -5
- package/dist/services/simpledb/mongodb.d.ts.map +1 -1
- package/dist/services/simpledb/mongodb.js +9 -9
- package/dist/services/simpledb/redisdb.d.ts +4 -4
- package/dist/services/simpledb/redisdb.d.ts.map +1 -1
- package/dist/services/simpledb/redisdb.js +18 -18
- package/dist/services/simpledb/simpledb.d.ts.map +1 -1
- package/dist/services/simpledb/simpledb.js +9 -9
- package/package.json +7 -7
package/_src/api/routing.ts
CHANGED
|
@@ -47,44 +47,49 @@ export function makeRequestParsers<
|
|
|
47
47
|
>["Request"]
|
|
48
48
|
): RequestParsers<PathA, CookieA, QueryA, BodyA, HeaderA> {
|
|
49
49
|
const ph = Effect(
|
|
50
|
-
Option
|
|
51
|
-
.
|
|
50
|
+
Option
|
|
51
|
+
.fromNullable(Request.Headers)
|
|
52
|
+
.map((s) => s)
|
|
52
53
|
.map(Parser.for)
|
|
53
54
|
.map(MO.condemnFail)
|
|
54
55
|
)
|
|
55
|
-
const parseHeaders = (u: unknown) => ph.flatMapOpt(d => d(u))
|
|
56
|
+
const parseHeaders = (u: unknown) => ph.flatMapOpt((d) => d(u))
|
|
56
57
|
|
|
57
58
|
const pq = Effect(
|
|
58
|
-
Option
|
|
59
|
-
.
|
|
59
|
+
Option
|
|
60
|
+
.fromNullable(Request.Query)
|
|
61
|
+
.map((s) => s)
|
|
60
62
|
.map(Parser.for)
|
|
61
63
|
.map(MO.condemnFail)
|
|
62
64
|
)
|
|
63
|
-
const parseQuery = (u: unknown) => pq.flatMapOpt(d => d(u))
|
|
65
|
+
const parseQuery = (u: unknown) => pq.flatMapOpt((d) => d(u))
|
|
64
66
|
|
|
65
67
|
const pb = Effect(
|
|
66
|
-
Option
|
|
67
|
-
.
|
|
68
|
+
Option
|
|
69
|
+
.fromNullable(Request.Body)
|
|
70
|
+
.map((s) => s)
|
|
68
71
|
.map(Parser.for)
|
|
69
72
|
.map(MO.condemnFail)
|
|
70
73
|
)
|
|
71
|
-
const parseBody = (u: unknown) => pb.flatMapOpt(d => d(u))
|
|
74
|
+
const parseBody = (u: unknown) => pb.flatMapOpt((d) => d(u))
|
|
72
75
|
|
|
73
76
|
const pp = Effect(
|
|
74
|
-
Option
|
|
75
|
-
.
|
|
77
|
+
Option
|
|
78
|
+
.fromNullable(Request.Path)
|
|
79
|
+
.map((s) => s)
|
|
76
80
|
.map(Parser.for)
|
|
77
81
|
.map(MO.condemnFail)
|
|
78
82
|
)
|
|
79
|
-
const parsePath = (u: unknown) => pp.flatMapOpt(d => d(u))
|
|
83
|
+
const parsePath = (u: unknown) => pp.flatMapOpt((d) => d(u))
|
|
80
84
|
|
|
81
85
|
const pc = Effect(
|
|
82
|
-
Option
|
|
83
|
-
.
|
|
86
|
+
Option
|
|
87
|
+
.fromNullable(Request.Cookie)
|
|
88
|
+
.map((s) => s)
|
|
84
89
|
.map(Parser.for)
|
|
85
90
|
.map(MO.condemnFail)
|
|
86
91
|
)
|
|
87
|
-
const parseCookie = (u: unknown) => pc.flatMapOpt(d => d(u))
|
|
92
|
+
const parseCookie = (u: unknown) => pc.flatMapOpt((d) => d(u))
|
|
88
93
|
|
|
89
94
|
return {
|
|
90
95
|
parseBody,
|
|
@@ -169,22 +174,24 @@ export function match<
|
|
|
169
174
|
requestHandler = handler
|
|
170
175
|
makeMiddlewareContext = makeContext
|
|
171
176
|
}
|
|
172
|
-
return Ex
|
|
173
|
-
requestHandler.Request.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
177
|
+
return Ex
|
|
178
|
+
.match(requestHandler.Request.method.toLowerCase() as any)(
|
|
179
|
+
requestHandler.Request.path.split("?")[0],
|
|
180
|
+
makeRequestHandler<R, E, PathA, CookieA, QueryA, BodyA, HeaderA, ReqA, ResA, R2, PR, RErr>(
|
|
181
|
+
requestHandler,
|
|
182
|
+
errorHandler,
|
|
183
|
+
makeMiddlewareContext
|
|
184
|
+
)
|
|
178
185
|
)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
.zipRight(
|
|
187
|
+
Effect(
|
|
188
|
+
makeRouteDescriptor(
|
|
189
|
+
requestHandler.Request.path,
|
|
190
|
+
requestHandler.Request.method,
|
|
191
|
+
requestHandler
|
|
192
|
+
)
|
|
185
193
|
)
|
|
186
194
|
)
|
|
187
|
-
)
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
export function respondSuccess<ReqA, A, E>(
|
|
@@ -192,11 +199,12 @@ export function respondSuccess<ReqA, A, E>(
|
|
|
192
199
|
) {
|
|
193
200
|
return (req: ReqA, res: express.Response, a: A) =>
|
|
194
201
|
Effect(encodeResponse(req)(a))
|
|
195
|
-
.flatMap(r =>
|
|
202
|
+
.flatMap((r) =>
|
|
196
203
|
Effect.sync(() => {
|
|
197
204
|
r === undefined
|
|
198
205
|
? res.status(204).send()
|
|
199
|
-
: res
|
|
206
|
+
: res
|
|
207
|
+
.status(200)
|
|
200
208
|
.send(JSON.stringify(r))
|
|
201
209
|
})
|
|
202
210
|
)
|
|
@@ -300,122 +308,136 @@ export function makeRequestHandler<
|
|
|
300
308
|
}
|
|
301
309
|
|
|
302
310
|
return (req: express.Request, res: express.Response) => {
|
|
303
|
-
return Debug.untraced(restore =>
|
|
304
|
-
Effect
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
311
|
+
return Debug.untraced((restore) =>
|
|
312
|
+
Effect
|
|
313
|
+
.all({
|
|
314
|
+
requestContext: Effect.sync(() => {
|
|
315
|
+
const requestContext = makeContext(req)
|
|
316
|
+
if (req.method === "GET") {
|
|
317
|
+
res.setHeader("Cache-Control", "no-store")
|
|
318
|
+
}
|
|
319
|
+
res.setHeader("Content-Language", requestContext.locale)
|
|
320
|
+
return requestContext
|
|
321
|
+
}),
|
|
322
|
+
pars: getParams(req)
|
|
323
|
+
})
|
|
315
324
|
.flatMap(({ pars, requestContext }) =>
|
|
316
|
-
RequestSettings
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
).zipRight(
|
|
334
|
-
Effect.suspend(() => {
|
|
335
|
-
const handleRequest = parseRequest(req)
|
|
336
|
-
.map(({ body, path, query }) => {
|
|
337
|
-
const hn = {
|
|
338
|
-
...body.value,
|
|
339
|
-
...query.value,
|
|
340
|
-
...path.value
|
|
341
|
-
} as unknown as ReqA
|
|
342
|
-
return hn
|
|
325
|
+
RequestSettings
|
|
326
|
+
.get
|
|
327
|
+
.flatMap((s) =>
|
|
328
|
+
// TODO: we don;t have access to user id here cause context is not yet created
|
|
329
|
+
Effect.logInfo("Incoming request").apply(
|
|
330
|
+
Effect.logAnnotates({
|
|
331
|
+
method: req.method,
|
|
332
|
+
path: req.originalUrl,
|
|
333
|
+
...s.verbose
|
|
334
|
+
? {
|
|
335
|
+
reqPath: pars.path.$$.pretty,
|
|
336
|
+
reqQuery: pars.query.$$.pretty,
|
|
337
|
+
reqBody: pretty(pars.body),
|
|
338
|
+
reqCookies: pretty(pars.cookies),
|
|
339
|
+
reqHeaders: pars.headers.$$.pretty
|
|
340
|
+
}
|
|
341
|
+
: undefined
|
|
343
342
|
})
|
|
344
|
-
.flatMap(parsedReq =>
|
|
345
|
-
restore(() => handle(parsedReq as any))()
|
|
346
|
-
.flatMap(r => respond(parsedReq, res, r))
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
// Commands should not be interruptable.
|
|
350
|
-
const r = req.method !== "GET" ? handleRequest.uninterruptible : handleRequest // .instrument("Performance.RequestResponse")
|
|
351
|
-
// the first log entry should be of the request start.
|
|
352
|
-
const r2 = makeMiddlewareContext
|
|
353
|
-
? restoreFromRequestContext
|
|
354
|
-
.zipRight(r.setupRequestFrom
|
|
355
|
-
// the db namespace must be restored, before calling provide here
|
|
356
|
-
.provideSomeContextEffect(makeMiddlewareContext(req, res)))
|
|
357
|
-
: restoreFromRequestContext
|
|
358
|
-
// PR is not relevant here
|
|
359
|
-
.zipRight(r) as Effect<R, E | ValidationError, void>
|
|
360
|
-
return errorHandler(
|
|
361
|
-
req,
|
|
362
|
-
res,
|
|
363
|
-
r2
|
|
364
343
|
)
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
344
|
+
)
|
|
345
|
+
.zipRight(
|
|
346
|
+
Effect.suspend(() => {
|
|
347
|
+
const handleRequest = parseRequest(req)
|
|
348
|
+
.map(({ body, path, query }) => {
|
|
349
|
+
const hn = {
|
|
350
|
+
...body.value,
|
|
351
|
+
...query.value,
|
|
352
|
+
...path.value
|
|
353
|
+
} as unknown as ReqA
|
|
354
|
+
return hn
|
|
355
|
+
})
|
|
356
|
+
.flatMap((parsedReq) =>
|
|
357
|
+
restore(() => handle(parsedReq as any))()
|
|
358
|
+
.flatMap((r) => respond(parsedReq, res, r))
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
// Commands should not be interruptable.
|
|
362
|
+
const r = req.method !== "GET" ? handleRequest.uninterruptible : handleRequest // .instrument("Performance.RequestResponse")
|
|
363
|
+
// the first log entry should be of the request start.
|
|
364
|
+
const r2 = makeMiddlewareContext
|
|
365
|
+
? restoreFromRequestContext
|
|
366
|
+
.zipRight(r
|
|
367
|
+
.setupRequestFrom
|
|
368
|
+
// the db namespace must be restored, before calling provide here
|
|
369
|
+
.provideSomeContextEffect(makeMiddlewareContext(req, res)))
|
|
370
|
+
: restoreFromRequestContext
|
|
371
|
+
// PR is not relevant here
|
|
372
|
+
.zipRight(r) as Effect<R, E | ValidationError, void>
|
|
373
|
+
return errorHandler(
|
|
374
|
+
req,
|
|
375
|
+
res,
|
|
376
|
+
r2
|
|
377
|
+
)
|
|
378
|
+
})
|
|
379
|
+
)
|
|
380
|
+
.tapErrorCause((cause) =>
|
|
381
|
+
Effect
|
|
382
|
+
.allPar(
|
|
383
|
+
Effect(res.status(500).send()),
|
|
384
|
+
RequestContextContainer.get.flatMap((requestContext) =>
|
|
385
|
+
reportRequestError(cause, {
|
|
386
|
+
requestContext,
|
|
387
|
+
path: req.originalUrl,
|
|
388
|
+
method: req.method
|
|
389
|
+
})
|
|
390
|
+
),
|
|
391
|
+
Effect.suspend(() => {
|
|
392
|
+
const headers = res.getHeaders()
|
|
393
|
+
return Effect
|
|
394
|
+
.logErrorCauseMessage(
|
|
395
|
+
"Finished request",
|
|
396
|
+
cause
|
|
397
|
+
)
|
|
398
|
+
.apply(Effect.logAnnotates({
|
|
399
|
+
method: req.method,
|
|
400
|
+
path: req.originalUrl,
|
|
401
|
+
statusCode: res.statusCode.toString(),
|
|
402
|
+
|
|
403
|
+
reqPath: pars.path.$$.pretty,
|
|
404
|
+
reqQuery: pars.query.$$.pretty,
|
|
405
|
+
reqBody: pretty(pars.body),
|
|
406
|
+
reqCookies: pretty(pars.cookies),
|
|
407
|
+
reqHeaders: pars.headers.$$.pretty,
|
|
408
|
+
|
|
409
|
+
resHeaders: Object
|
|
410
|
+
.entries(headers)
|
|
411
|
+
.reduce((prev, [key, value]) => {
|
|
412
|
+
prev[key] = value && typeof value === "string" ? snipString(value) : value
|
|
413
|
+
return prev
|
|
414
|
+
}, {} as Record<string, any>)
|
|
415
|
+
.$$
|
|
416
|
+
.pretty
|
|
417
|
+
}))
|
|
375
418
|
})
|
|
376
|
-
)
|
|
377
|
-
|
|
419
|
+
)
|
|
420
|
+
.tapErrorCause((cause) => Effect(console.error("Error occurred while reporting error", cause)))
|
|
421
|
+
.setupRequestFrom
|
|
422
|
+
)
|
|
423
|
+
.tap(() =>
|
|
424
|
+
RequestSettings
|
|
425
|
+
.get
|
|
426
|
+
.flatMap((s) => {
|
|
378
427
|
const headers = res.getHeaders()
|
|
379
|
-
return Effect.
|
|
380
|
-
"Finished request",
|
|
381
|
-
cause
|
|
382
|
-
).apply(Effect.logAnnotates({
|
|
428
|
+
return Effect.logInfo("Finished request").apply(Effect.logAnnotates({
|
|
383
429
|
method: req.method,
|
|
384
430
|
path: req.originalUrl,
|
|
385
431
|
statusCode: res.statusCode.toString(),
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
reqHeaders: pars.headers.$$.pretty,
|
|
392
|
-
|
|
393
|
-
resHeaders: Object.entries(headers).reduce((prev, [key, value]) => {
|
|
394
|
-
prev[key] = value && typeof value === "string" ? snipString(value) : value
|
|
395
|
-
return prev
|
|
396
|
-
}, {} as Record<string, any>)
|
|
397
|
-
.$$.pretty
|
|
432
|
+
...s.verbose
|
|
433
|
+
? {
|
|
434
|
+
resHeaders: headers.$$.pretty
|
|
435
|
+
}
|
|
436
|
+
: undefined
|
|
398
437
|
}))
|
|
399
438
|
})
|
|
400
|
-
)
|
|
401
|
-
.tapErrorCause(cause => Effect(console.error("Error occurred while reporting error", cause)))
|
|
402
439
|
.setupRequestFrom
|
|
403
440
|
)
|
|
404
|
-
.tap(() =>
|
|
405
|
-
RequestSettings.get.flatMap(s => {
|
|
406
|
-
const headers = res.getHeaders()
|
|
407
|
-
return Effect.logInfo("Finished request").apply(Effect.logAnnotates({
|
|
408
|
-
method: req.method,
|
|
409
|
-
path: req.originalUrl,
|
|
410
|
-
statusCode: res.statusCode.toString(),
|
|
411
|
-
...s.verbose
|
|
412
|
-
? {
|
|
413
|
-
resHeaders: headers.$$.pretty
|
|
414
|
-
} :
|
|
415
|
-
undefined
|
|
416
|
-
}))
|
|
417
|
-
}).setupRequestFrom
|
|
418
|
-
)
|
|
419
441
|
.setupRequestFrom
|
|
420
442
|
.provideService(RequestContextContainer, new RequestContextContainerImpl(requestContext)) // otherwise external error reporter breaks.
|
|
421
443
|
)
|
|
@@ -484,7 +506,7 @@ export function matchAll<T extends RequestHandlers>(handlers: T) {
|
|
|
484
506
|
export function matchAllAlt<T extends RequestHandlersTest>(handlers: T) {
|
|
485
507
|
const mapped = handlers.$$.keys.reduce((prev, cur) => {
|
|
486
508
|
const matches = matchAll(handlers[cur])
|
|
487
|
-
matches.$$.keys.forEach(key => prev[`${cur as string}.${key as string}`] = matches[key])
|
|
509
|
+
matches.$$.keys.forEach((key) => prev[`${cur as string}.${key as string}`] = matches[key])
|
|
488
510
|
return prev
|
|
489
511
|
}, {} as any) as Flatten<RouteAllTest<typeof handlers>>
|
|
490
512
|
|
package/_src/api/setupRequest.ts
CHANGED
|
@@ -22,7 +22,9 @@ export function setupRequest<R, E, A>(self: Effect<R, E, A>, requestContext: Req
|
|
|
22
22
|
* @tsplus getter effect/io/Effect setupRequestFrom
|
|
23
23
|
*/
|
|
24
24
|
export function setupRequestFrom<R, E, A>(self: Effect<R, E, A>) {
|
|
25
|
-
return Debug.untraced(() =>
|
|
25
|
+
return Debug.untraced(() =>
|
|
26
|
+
RequestContextContainer.get.flatMap((requestContext) => self.setupRequest(requestContext))
|
|
27
|
+
)
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
/**
|
package/_src/api/writeDocs.ts
CHANGED
|
@@ -6,7 +6,8 @@ import type { RouteDescriptorAny } from "./express/schema/routing.js"
|
|
|
6
6
|
|
|
7
7
|
export function writeOpenapiDocs(rdescs: Record<string, Record<string, RouteDescriptorAny>>) {
|
|
8
8
|
return makeOpenApiSpecs(
|
|
9
|
-
typedValuesOf(rdescs)
|
|
9
|
+
typedValuesOf(rdescs)
|
|
10
|
+
.reduce((prev, cur) => prev.concat(typedValuesOf(cur)), [] as readonly RouteDescriptorAny[])
|
|
10
11
|
.sortWith(Order.string.contramap((a: RouteDescriptorAny) => a.path)),
|
|
11
12
|
Plutus.info({
|
|
12
13
|
title: "api",
|
|
@@ -14,12 +15,12 @@ export function writeOpenapiDocs(rdescs: Record<string, Record<string, RouteDesc
|
|
|
14
15
|
pageTitle: "api"
|
|
15
16
|
})
|
|
16
17
|
)
|
|
17
|
-
.map(_ => ({
|
|
18
|
+
.map((_) => ({
|
|
18
19
|
..._,
|
|
19
20
|
tags: [
|
|
20
21
|
// add the tags here
|
|
21
22
|
]
|
|
22
23
|
}))
|
|
23
|
-
.flatMap(_ => writeTextFile("./openapi.json", JSON.stringify(_, undefined, 2)).orDie)
|
|
24
|
+
.flatMap((_) => writeTextFile("./openapi.json", JSON.stringify(_, undefined, 2)).orDie)
|
|
24
25
|
.flatMap(() => Effect.logInfo("OpenAPI spec written to './openapi.json'"))
|
|
25
26
|
}
|
package/_src/rateLimit.ts
CHANGED
|
@@ -34,13 +34,14 @@
|
|
|
34
34
|
*/
|
|
35
35
|
export function SEM_withPermitsDuration(permits: number, duration: Duration) {
|
|
36
36
|
return (self: Semaphore): <R, E, A>(effect: Effect<R, E, A>) => Effect<R, E, A> => {
|
|
37
|
-
return effect =>
|
|
37
|
+
return (effect) =>
|
|
38
38
|
Effect.uninterruptibleMask(
|
|
39
|
-
restore =>
|
|
39
|
+
(restore) =>
|
|
40
40
|
restore(self.take(permits))
|
|
41
41
|
> restore(effect)
|
|
42
42
|
.ensuring(
|
|
43
|
-
self
|
|
43
|
+
self
|
|
44
|
+
.release(permits)
|
|
44
45
|
.delay(duration)
|
|
45
46
|
)
|
|
46
47
|
)
|
|
@@ -54,13 +55,15 @@ export function SEM_withPermitsDuration(permits: number, duration: Duration) {
|
|
|
54
55
|
export function batchPar<R, E, A, R2, E2, A2, T>(
|
|
55
56
|
n: number,
|
|
56
57
|
forEachItem: (item: T, iWithinBatch: number, batchI: number) => Effect<R, E, A>,
|
|
57
|
-
forEachBatch: (a:
|
|
58
|
+
forEachBatch: (a: NonEmptyArray<A>, i: number) => Effect<R2, E2, A2>
|
|
58
59
|
) {
|
|
59
60
|
return (items: Iterable<T>) =>
|
|
60
|
-
items
|
|
61
|
+
items
|
|
62
|
+
.chunk(n)
|
|
61
63
|
.forEachEffectParWithIndex((_, i) =>
|
|
62
|
-
_
|
|
63
|
-
.
|
|
64
|
+
_
|
|
65
|
+
.forEachParWithIndex((_, j) => forEachItem(_, j, i))
|
|
66
|
+
.flatMap((_) => forEachBatch(_ as NonEmptyArray<A>, i))
|
|
64
67
|
)
|
|
65
68
|
}
|
|
66
69
|
|
|
@@ -71,13 +74,15 @@ export function batchPar<R, E, A, R2, E2, A2, T>(
|
|
|
71
74
|
export function batch<R, E, A, R2, E2, A2, T>(
|
|
72
75
|
n: number,
|
|
73
76
|
forEachItem: (item: T, iWithinBatch: number, batchI: number) => Effect<R, E, A>,
|
|
74
|
-
forEachBatch: (a:
|
|
77
|
+
forEachBatch: (a: NonEmptyArray<A>, i: number) => Effect<R2, E2, A2>
|
|
75
78
|
) {
|
|
76
79
|
return (items: Iterable<T>) =>
|
|
77
|
-
items
|
|
80
|
+
items
|
|
81
|
+
.chunk(n)
|
|
78
82
|
.forEachEffectWithIndex((_, i) =>
|
|
79
|
-
_
|
|
80
|
-
.
|
|
83
|
+
_
|
|
84
|
+
.forEachParWithIndex((_, j) => forEachItem(_, j, i))
|
|
85
|
+
.flatMap((_) => forEachBatch(_ as NonEmptyArray<A>, i))
|
|
81
86
|
)
|
|
82
87
|
}
|
|
83
88
|
|
|
@@ -112,13 +117,15 @@ export function naiveRateLimit(
|
|
|
112
117
|
) {
|
|
113
118
|
return <T>(items: Iterable<T>) => (<R, E, A, R2, E2, A2>(
|
|
114
119
|
forEachItem: (i: T) => Effect<R, E, A>,
|
|
115
|
-
forEachBatch: (a:
|
|
120
|
+
forEachBatch: (a: A[]) => Effect<R2, E2, A2>
|
|
116
121
|
) =>
|
|
117
|
-
items
|
|
122
|
+
items
|
|
123
|
+
.chunk(n)
|
|
118
124
|
.forEachEffectWithIndex((batch, i) =>
|
|
119
125
|
((i === 0) ? Effect.unit : Effect.sleep(d))
|
|
120
126
|
.zipRight(
|
|
121
|
-
batch
|
|
127
|
+
batch
|
|
128
|
+
.forEachEffectPar(forEachItem)
|
|
122
129
|
.withParallelism(n)
|
|
123
130
|
.flatMap(forEachBatch)
|
|
124
131
|
)
|
|
@@ -28,11 +28,11 @@ const makeLiveSendgrid = ({ apiKey, defaultFrom, defaultReplyTo, realMail, subje
|
|
|
28
28
|
Error | sgMail.ResponseError,
|
|
29
29
|
[sgMail.ClientResponse, Record<string, unknown>]
|
|
30
30
|
>(
|
|
31
|
-
cb =>
|
|
31
|
+
(cb) =>
|
|
32
32
|
void sgMail.send(renderedMsg, false, (err, result) =>
|
|
33
|
-
err
|
|
34
|
-
cb(Effect.fail(err))
|
|
35
|
-
cb(Effect(result)))
|
|
33
|
+
err
|
|
34
|
+
? cb(Effect.fail(err))
|
|
35
|
+
: cb(Effect(result)))
|
|
36
36
|
)
|
|
37
37
|
)
|
|
38
38
|
|
|
@@ -55,7 +55,8 @@ const makeLiveSendgrid = ({ apiKey, defaultFrom, defaultReplyTo, realMail, subje
|
|
|
55
55
|
* @tsplus static Emailer.Ops LiveSendgrid
|
|
56
56
|
*/
|
|
57
57
|
export function LiveSendgrid(config: Config<SendgridConfig>) {
|
|
58
|
-
return config
|
|
58
|
+
return config
|
|
59
|
+
.config
|
|
59
60
|
.flatMap(makeLiveSendgrid)
|
|
60
61
|
.toLayer(Emailer)
|
|
61
62
|
}
|
|
@@ -86,10 +87,10 @@ export function renderMessage(forceFake: boolean) {
|
|
|
86
87
|
*/
|
|
87
88
|
export function isTestAddress(to: EmailData) {
|
|
88
89
|
return (
|
|
89
|
-
(typeof to === "string" && to.toLowerCase().endsWith(".test"))
|
|
90
|
-
(typeof to === "object"
|
|
91
|
-
"email" in to
|
|
92
|
-
to.email.toLowerCase().endsWith(".test"))
|
|
90
|
+
(typeof to === "string" && to.toLowerCase().endsWith(".test"))
|
|
91
|
+
|| (typeof to === "object"
|
|
92
|
+
&& "email" in to
|
|
93
|
+
&& to.email.toLowerCase().endsWith(".test"))
|
|
93
94
|
)
|
|
94
95
|
}
|
|
95
96
|
|
|
@@ -108,7 +109,7 @@ const eq = Equivalence.string.contramap((to: { name?: string; email: string } |
|
|
|
108
109
|
function renderFakeIfTest(addr: EmailData | EmailData[], makeId: () => number) {
|
|
109
110
|
return Array.isArray(addr)
|
|
110
111
|
? addr
|
|
111
|
-
.map(x => (isTestAddress(x) ? renderFake(x, makeId) : x))
|
|
112
|
+
.map((x) => (isTestAddress(x) ? renderFake(x, makeId) : x))
|
|
112
113
|
.uniq(eq)
|
|
113
114
|
.toArray
|
|
114
115
|
: isTestAddress(addr)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { pretty } from "@effect-app/prelude/utils"
|
|
2
2
|
import { Emailer } from "./service.js"
|
|
3
3
|
|
|
4
|
-
const makeFake = Effect
|
|
4
|
+
const makeFake = Effect
|
|
5
|
+
.logDebug("FAKE Emailer Service enabled")
|
|
5
6
|
.map((): Emailer => ({
|
|
6
7
|
sendMail(msg) {
|
|
7
8
|
return Effect.logDebug(`Fake send mail`).logAnnotate("msg", pretty(msg))
|
|
@@ -4,7 +4,7 @@ import type { OperationProgress } from "@effect-app/prelude/Operations"
|
|
|
4
4
|
import { Failure, Operation, OperationId, Success } from "@effect-app/prelude/Operations"
|
|
5
5
|
import { Operations } from "./service.js"
|
|
6
6
|
|
|
7
|
-
const reportAppError = reportError(cause => new RequestException(cause))
|
|
7
|
+
const reportAppError = reportError((cause) => new RequestException(cause))
|
|
8
8
|
|
|
9
9
|
const make = Effect.sync(() => {
|
|
10
10
|
const ops = new Map<OperationId, Operation>()
|
|
@@ -12,7 +12,8 @@ const make = Effect.sync(() => {
|
|
|
12
12
|
|
|
13
13
|
const cleanup = Effect.sync(() => {
|
|
14
14
|
const before = new Date().subHours(1)
|
|
15
|
-
ops
|
|
15
|
+
ops
|
|
16
|
+
.entries()
|
|
16
17
|
.toChunk
|
|
17
18
|
.forEach(([id, op]) => {
|
|
18
19
|
const lastChanged = Option.fromNullable(op.updatedAt).getOrElse(() => op.createdAt)
|
|
@@ -31,7 +32,7 @@ const make = Effect.sync(() => {
|
|
|
31
32
|
return Effect(Option.fromNullable(ops.get(id)))
|
|
32
33
|
}
|
|
33
34
|
function finishOp(id: OperationId, exit: Exit<unknown, unknown>) {
|
|
34
|
-
return findOp(id).flatMap(_ =>
|
|
35
|
+
return findOp(id).flatMap((_) =>
|
|
35
36
|
Effect.sync(() => {
|
|
36
37
|
if (_.isNone()) {
|
|
37
38
|
throw new Error("Not found")
|
|
@@ -46,18 +47,22 @@ const make = Effect.sync(() => {
|
|
|
46
47
|
? LongString("Interrupted")
|
|
47
48
|
: exit.cause.isDie()
|
|
48
49
|
? LongString("Unknown error")
|
|
49
|
-
: exit
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
: exit
|
|
51
|
+
.cause
|
|
52
|
+
.failureOption
|
|
53
|
+
.flatMap((_) =>
|
|
54
|
+
typeof _ === "object" && _ !== null && "message" in _ && LongString.Guard(_.message)
|
|
55
|
+
? Option(_.message)
|
|
56
|
+
: Option.none
|
|
57
|
+
)
|
|
58
|
+
.value ?? null
|
|
54
59
|
})
|
|
55
60
|
})
|
|
56
61
|
})
|
|
57
62
|
)
|
|
58
63
|
}
|
|
59
64
|
function update(id: OperationId, progress: OperationProgress) {
|
|
60
|
-
return findOp(id).flatMap(_ =>
|
|
65
|
+
return findOp(id).flatMap((_) =>
|
|
61
66
|
Effect.sync(() => {
|
|
62
67
|
if (_.isNone()) {
|
|
63
68
|
throw new Error("Not found")
|
|
@@ -69,7 +74,7 @@ const make = Effect.sync(() => {
|
|
|
69
74
|
return Operations.make({
|
|
70
75
|
cleanup,
|
|
71
76
|
register: makeOp
|
|
72
|
-
.tap(id =>
|
|
77
|
+
.tap((id) =>
|
|
73
78
|
Effect.logAnnotateScoped("operationId", id)
|
|
74
79
|
> addOp(id).acquireRelease(
|
|
75
80
|
(_, exit) => finishOp(id, exit)
|
|
@@ -81,9 +86,10 @@ const make = Effect.sync(() => {
|
|
|
81
86
|
})
|
|
82
87
|
})
|
|
83
88
|
|
|
84
|
-
const cleanupLoop = Operations
|
|
89
|
+
const cleanupLoop = Operations
|
|
90
|
+
.flatMap((_) => _.cleanup)
|
|
85
91
|
.exit
|
|
86
|
-
.flatMap(_ => {
|
|
92
|
+
.flatMap((_) => {
|
|
87
93
|
if (_.isSuccess()) {
|
|
88
94
|
return Effect.unit
|
|
89
95
|
} else {
|