@effect-app/infra 4.0.0-beta.16 → 4.0.0-beta.160
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 +1054 -0
- package/dist/CUPS.d.ts +15 -7
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +10 -12
- package/dist/Emailer/Sendgrid.d.ts +14 -14
- package/dist/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/Emailer/Sendgrid.js +16 -15
- package/dist/Emailer/fake.d.ts +1 -1
- package/dist/Emailer/service.d.ts +9 -3
- package/dist/Emailer/service.d.ts.map +1 -1
- package/dist/Emailer/service.js +3 -3
- package/dist/Emailer.d.ts +1 -1
- package/dist/MainFiberSet.d.ts +5 -5
- package/dist/MainFiberSet.d.ts.map +1 -1
- package/dist/MainFiberSet.js +3 -3
- package/dist/Model/Repository/Registry.d.ts +20 -0
- package/dist/Model/Repository/Registry.d.ts.map +1 -0
- package/dist/Model/Repository/Registry.js +17 -0
- package/dist/Model/Repository/ext.d.ts +33 -15
- package/dist/Model/Repository/ext.d.ts.map +1 -1
- package/dist/Model/Repository/ext.js +54 -2
- package/dist/Model/Repository/internal/internal.d.ts +6 -6
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +43 -32
- package/dist/Model/Repository/legacy.d.ts +1 -1
- package/dist/Model/Repository/makeRepo.d.ts +7 -6
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
- package/dist/Model/Repository/makeRepo.js +5 -1
- package/dist/Model/Repository/service.d.ts +28 -23
- package/dist/Model/Repository/service.d.ts.map +1 -1
- package/dist/Model/Repository/validation.d.ts +142 -17
- package/dist/Model/Repository/validation.d.ts.map +1 -1
- package/dist/Model/Repository/validation.js +5 -5
- package/dist/Model/Repository.d.ts +2 -1
- package/dist/Model/Repository.d.ts.map +1 -1
- package/dist/Model/Repository.js +2 -1
- package/dist/Model/dsl.d.ts +4 -4
- package/dist/Model/dsl.d.ts.map +1 -1
- package/dist/Model/filter/filterApi.d.ts +5 -5
- package/dist/Model/filter/filterApi.d.ts.map +1 -1
- package/dist/Model/filter/types/errors.d.ts +1 -1
- package/dist/Model/filter/types/fields.d.ts +1 -1
- package/dist/Model/filter/types/path/common.d.ts +1 -1
- package/dist/Model/filter/types/path/eager.d.ts +1 -1
- package/dist/Model/filter/types/path/eager.d.ts.map +1 -1
- package/dist/Model/filter/types/path/index.d.ts +1 -1
- package/dist/Model/filter/types/utils.d.ts +1 -1
- package/dist/Model/filter/types/validator.d.ts +1 -1
- package/dist/Model/filter/types.d.ts +1 -1
- package/dist/Model/query/dsl.d.ts +1 -1
- package/dist/Model/query/dsl.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.d.ts +6 -6
- package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.js +3 -3
- package/dist/Model/query.d.ts +1 -1
- package/dist/Model.d.ts +2 -1
- package/dist/Model.d.ts.map +1 -1
- package/dist/Model.js +2 -1
- package/dist/Operations.d.ts +6 -6
- package/dist/Operations.d.ts.map +1 -1
- package/dist/Operations.js +56 -59
- package/dist/OperationsRepo.d.ts +11 -29
- package/dist/OperationsRepo.d.ts.map +1 -1
- package/dist/OperationsRepo.js +3 -3
- package/dist/QueueMaker/SQLQueue.d.ts +5 -7
- package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/QueueMaker/SQLQueue.js +105 -114
- package/dist/QueueMaker/errors.d.ts +2 -2
- package/dist/QueueMaker/errors.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.d.ts +7 -4
- package/dist/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.js +51 -62
- package/dist/QueueMaker/sbqueue.d.ts +6 -3
- package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/QueueMaker/sbqueue.js +37 -53
- package/dist/QueueMaker/service.d.ts +1 -1
- package/dist/RequestContext.d.ts +114 -26
- package/dist/RequestContext.d.ts.map +1 -1
- package/dist/RequestContext.js +7 -7
- package/dist/RequestFiberSet.d.ts +7 -7
- package/dist/RequestFiberSet.d.ts.map +1 -1
- package/dist/RequestFiberSet.js +5 -5
- package/dist/Store/ContextMapContainer.d.ts +19 -3
- package/dist/Store/ContextMapContainer.d.ts.map +1 -1
- package/dist/Store/ContextMapContainer.js +13 -3
- package/dist/Store/Cosmos/query.d.ts +1 -1
- package/dist/Store/Cosmos/query.d.ts.map +1 -1
- package/dist/Store/Cosmos/query.js +8 -10
- package/dist/Store/Cosmos.d.ts +1 -1
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +308 -242
- package/dist/Store/Disk.d.ts +2 -2
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +25 -22
- package/dist/Store/Memory.d.ts +4 -4
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +27 -22
- package/dist/Store/SQL/Pg.d.ts +4 -0
- package/dist/Store/SQL/Pg.d.ts.map +1 -0
- package/dist/Store/SQL/Pg.js +189 -0
- package/dist/Store/SQL/query.d.ts +38 -0
- package/dist/Store/SQL/query.d.ts.map +1 -0
- package/dist/Store/SQL/query.js +367 -0
- package/dist/Store/SQL.d.ts +20 -0
- package/dist/Store/SQL.d.ts.map +1 -0
- package/dist/Store/SQL.js +381 -0
- package/dist/Store/codeFilter.d.ts +1 -1
- package/dist/Store/codeFilter.d.ts.map +1 -1
- package/dist/Store/codeFilter.js +2 -1
- package/dist/Store/index.d.ts +5 -2
- package/dist/Store/index.d.ts.map +1 -1
- package/dist/Store/index.js +15 -3
- package/dist/Store/service.d.ts +17 -6
- package/dist/Store/service.d.ts.map +1 -1
- package/dist/Store/service.js +24 -6
- package/dist/Store/utils.d.ts +1 -1
- package/dist/Store/utils.d.ts.map +1 -1
- package/dist/Store/utils.js +3 -4
- package/dist/Store.d.ts +1 -1
- package/dist/adapters/SQL/Model.d.ts +28 -42
- package/dist/adapters/SQL/Model.d.ts.map +1 -1
- package/dist/adapters/SQL/Model.js +2 -2
- package/dist/adapters/SQL.d.ts +1 -1
- package/dist/adapters/ServiceBus.d.ts +9 -9
- package/dist/adapters/ServiceBus.d.ts.map +1 -1
- package/dist/adapters/ServiceBus.js +13 -15
- package/dist/adapters/cosmos-client.d.ts +3 -3
- package/dist/adapters/cosmos-client.d.ts.map +1 -1
- package/dist/adapters/cosmos-client.js +3 -3
- package/dist/adapters/index.d.ts +8 -2
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +8 -2
- package/dist/adapters/logger.d.ts +1 -1
- package/dist/adapters/logger.d.ts.map +1 -1
- package/dist/adapters/memQueue.d.ts +3 -3
- package/dist/adapters/memQueue.d.ts.map +1 -1
- package/dist/adapters/memQueue.js +3 -3
- package/dist/adapters/mongo-client.d.ts +3 -3
- package/dist/adapters/mongo-client.d.ts.map +1 -1
- package/dist/adapters/mongo-client.js +3 -3
- package/dist/adapters/redis-client.d.ts +3 -3
- package/dist/adapters/redis-client.d.ts.map +1 -1
- package/dist/adapters/redis-client.js +3 -3
- package/dist/api/ContextProvider.d.ts +7 -7
- package/dist/api/ContextProvider.d.ts.map +1 -1
- package/dist/api/ContextProvider.js +6 -6
- package/dist/api/codec.d.ts +1 -1
- package/dist/api/internal/RequestContextMiddleware.d.ts +2 -2
- package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
- package/dist/api/internal/RequestContextMiddleware.js +2 -2
- package/dist/api/internal/auth.d.ts +44 -6
- package/dist/api/internal/auth.d.ts.map +1 -1
- package/dist/api/internal/auth.js +160 -29
- package/dist/api/internal/events.d.ts +3 -3
- package/dist/api/internal/events.d.ts.map +1 -1
- package/dist/api/internal/events.js +9 -7
- package/dist/api/internal/health.d.ts +1 -1
- package/dist/api/layerUtils.d.ts +6 -6
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/layerUtils.js +5 -5
- package/dist/api/middlewares.d.ts +1 -1
- package/dist/api/reportError.d.ts +1 -1
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -4
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.d.ts +39 -3
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +45 -14
- package/dist/api/routing/middleware.d.ts +1 -2
- package/dist/api/routing/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware.js +1 -2
- package/dist/api/routing/schema/jwt.d.ts +1 -1
- package/dist/api/routing/schema/jwt.d.ts.map +1 -1
- package/dist/api/routing/tsort.d.ts +1 -1
- package/dist/api/routing/tsort.d.ts.map +1 -1
- package/dist/api/routing/utils.d.ts +3 -3
- package/dist/api/routing/utils.d.ts.map +1 -1
- package/dist/api/routing.d.ts +12 -14
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +17 -6
- package/dist/api/setupRequest.d.ts +8 -5
- package/dist/api/setupRequest.d.ts.map +1 -1
- package/dist/api/setupRequest.js +12 -7
- package/dist/api/util.d.ts +1 -1
- package/dist/arbs.d.ts +1 -1
- package/dist/arbs.d.ts.map +1 -1
- package/dist/arbs.js +5 -3
- package/dist/errorReporter.d.ts +4 -4
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +16 -23
- package/dist/errors.d.ts +1 -1
- package/dist/fileUtil.d.ts +1 -1
- package/dist/fileUtil.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/logger/jsonLogger.d.ts +1 -1
- package/dist/logger/logFmtLogger.d.ts +1 -1
- package/dist/logger/shared.d.ts +1 -1
- package/dist/logger/shared.js +2 -2
- package/dist/logger.d.ts +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/rateLimit.d.ts +9 -3
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/rateLimit.js +5 -11
- package/dist/test.d.ts +1 -1
- package/dist/test.d.ts.map +1 -1
- package/dist/vitest.d.ts +1 -1
- package/eslint.config.mjs +3 -3
- package/examples/query.ts +39 -35
- package/package.json +42 -28
- package/src/CUPS.ts +9 -11
- package/src/Emailer/Sendgrid.ts +17 -14
- package/src/Emailer/service.ts +8 -2
- package/src/MainFiberSet.ts +3 -3
- package/src/Model/Repository/Registry.ts +33 -0
- package/src/Model/Repository/ext.ts +93 -6
- package/src/Model/Repository/internal/internal.ts +97 -88
- package/src/Model/Repository/makeRepo.ts +12 -10
- package/src/Model/Repository/service.ts +31 -22
- package/src/Model/Repository/validation.ts +4 -4
- package/src/Model/Repository.ts +1 -0
- package/src/Model/dsl.ts +3 -3
- package/src/Model/query/new-kid-interpreter.ts +2 -2
- package/src/Model.ts +1 -0
- package/src/Operations.ts +78 -113
- package/src/OperationsRepo.ts +2 -2
- package/src/QueueMaker/SQLQueue.ts +121 -151
- package/src/QueueMaker/memQueue.ts +82 -103
- package/src/QueueMaker/sbqueue.ts +56 -86
- package/src/RequestContext.ts +8 -8
- package/src/RequestFiberSet.ts +4 -4
- package/src/Store/ContextMapContainer.ts +41 -2
- package/src/Store/Cosmos/query.ts +9 -11
- package/src/Store/Cosmos.ts +437 -343
- package/src/Store/Disk.ts +52 -49
- package/src/Store/Memory.ts +54 -48
- package/src/Store/SQL/Pg.ts +318 -0
- package/src/Store/SQL/query.ts +409 -0
- package/src/Store/SQL.ts +668 -0
- package/src/Store/codeFilter.ts +1 -0
- package/src/Store/index.ts +17 -2
- package/src/Store/service.ts +31 -7
- package/src/Store/utils.ts +23 -22
- package/src/adapters/SQL/Model.ts +10 -4
- package/src/adapters/ServiceBus.ts +111 -115
- package/src/adapters/cosmos-client.ts +2 -2
- package/src/adapters/index.ts +7 -0
- package/src/adapters/memQueue.ts +2 -2
- package/src/adapters/mongo-client.ts +2 -2
- package/src/adapters/redis-client.ts +2 -2
- package/src/api/ContextProvider.ts +11 -11
- package/src/api/internal/RequestContextMiddleware.ts +1 -1
- package/src/api/internal/auth.ts +246 -44
- package/src/api/internal/events.ts +12 -8
- package/src/api/layerUtils.ts +8 -8
- package/src/api/routing/middleware/RouterMiddleware.ts +4 -4
- package/src/api/routing/middleware/middleware.ts +52 -12
- package/src/api/routing/middleware.ts +0 -2
- package/src/api/routing.ts +21 -7
- package/src/api/setupRequest.ts +28 -8
- package/src/arbs.ts +4 -2
- package/src/errorReporter.ts +58 -72
- package/src/logger/shared.ts +1 -1
- package/src/rateLimit.ts +30 -22
- package/test/auth.test.ts +101 -0
- package/test/contextProvider.test.ts +11 -11
- package/test/controller.test.ts +18 -14
- package/test/dist/auth.test.d.ts.map +1 -0
- package/test/dist/contextProvider.test.d.ts.map +1 -1
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/date-query.test.d.ts.map +1 -0
- package/test/dist/fixtures.d.ts +26 -12
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +12 -10
- package/test/dist/query.test.d.ts.map +1 -1
- package/test/dist/rawQuery.test.d.ts.map +1 -1
- package/test/dist/repository-ext.test.d.ts.map +1 -0
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/dist/router-generator.test.d.ts.map +1 -0
- package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
- package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
- package/test/dist/sql-store.test.d.ts.map +1 -0
- package/test/fixtures.ts +11 -9
- package/test/query.test.ts +216 -34
- package/test/rawQuery.test.ts +23 -19
- package/test/repository-ext.test.ts +60 -0
- package/test/requires.test.ts +6 -6
- package/test/router-generator.test.ts +180 -0
- package/test/routing-interruptibility.test.ts +63 -0
- package/test/rpc-multi-middleware.test.ts +78 -9
- package/test/sql-store.test.ts +1064 -0
- package/test/validateSample.test.ts +15 -12
- package/tsconfig.examples.json +1 -1
- package/tsconfig.json +0 -1
- package/tsconfig.json.bak +2 -2
- package/tsconfig.src.json +35 -35
- package/tsconfig.test.json +2 -2
package/src/CUPS.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type FileOptions, tempFile } from "@effect-app/infra/fileUtil"
|
|
2
2
|
import cp from "child_process"
|
|
3
|
-
import { Config, Effect, Layer, Option, Predicate, S
|
|
3
|
+
import { Config, Context, Effect, Layer, Option, Predicate, S } from "effect-app"
|
|
4
4
|
import { pretty } from "effect-app/utils"
|
|
5
5
|
import fs from "fs"
|
|
6
6
|
import os from "os"
|
|
@@ -74,15 +74,13 @@ function printBuffer(printer: PrinterConfig, options: string[]) {
|
|
|
74
74
|
)
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
})
|
|
85
|
-
}
|
|
77
|
+
const getAvailablePrinters = Effect.fnUntraced(function*(host?: string) {
|
|
78
|
+
const { stdout } = yield* exec(["lpstat", ...buildListArgs({ host }), "-s"].join(" "))
|
|
79
|
+
return [...stdout.matchAll(/device for (\w+):/g)]
|
|
80
|
+
.map((_) => _[1])
|
|
81
|
+
.filter(Predicate.isNotNullish)
|
|
82
|
+
.map((_) => S.NonEmptyString255(_))
|
|
83
|
+
})
|
|
86
84
|
|
|
87
85
|
function* buildListArgs(config?: { host?: string | undefined }) {
|
|
88
86
|
if (config?.host) {
|
|
@@ -100,7 +98,7 @@ export const CUPSConfig = Config.all({
|
|
|
100
98
|
)
|
|
101
99
|
})
|
|
102
100
|
|
|
103
|
-
export class CUPS extends
|
|
101
|
+
export class CUPS extends Context.Service<CUPS>()("effect-app/CUPS", {
|
|
104
102
|
make: Effect.gen(function*() {
|
|
105
103
|
const config = yield* CUPSConfig
|
|
106
104
|
const serverUrl = Option.getOrUndefined(config.server)
|
package/src/Emailer/Sendgrid.ts
CHANGED
|
@@ -7,7 +7,9 @@ import { inspect } from "util"
|
|
|
7
7
|
import { InfraLogger } from "../logger.js"
|
|
8
8
|
import { Emailer, type EmailMsg, type EmailMsgOptionalFrom, type SendgridConfig, SendMailError } from "./service.js"
|
|
9
9
|
|
|
10
|
-
const makeSendgrid = (
|
|
10
|
+
const makeSendgrid = (
|
|
11
|
+
{ apiKey, defaultFrom, defaultReplyTo, fakeMailAddress, realMail, subjectPrefix }: SendgridConfig
|
|
12
|
+
) =>
|
|
11
13
|
Effect.sync(() => {
|
|
12
14
|
sgMail.setApiKey(Redacted.value(apiKey))
|
|
13
15
|
|
|
@@ -18,7 +20,7 @@ const makeSendgrid = ({ apiKey, defaultFrom, defaultReplyTo, realMail, subjectPr
|
|
|
18
20
|
from: msg_.from ?? defaultFrom,
|
|
19
21
|
replyTo: msg_.replyTo ?? (msg_.from ? undefined : defaultReplyTo)
|
|
20
22
|
})
|
|
21
|
-
const render = renderMessage(!realMail)
|
|
23
|
+
const render = renderMessage(!realMail, fakeMailAddress)
|
|
22
24
|
|
|
23
25
|
const renderedMsg_ = render(msg)
|
|
24
26
|
const renderedMsg = {
|
|
@@ -68,23 +70,24 @@ export function Sendgrid(config: SendgridConfig) {
|
|
|
68
70
|
/**
|
|
69
71
|
* @hidden
|
|
70
72
|
*/
|
|
71
|
-
export function renderMessage(forceFake: boolean) {
|
|
73
|
+
export function renderMessage(forceFake: boolean, fakeMailAddress: string) {
|
|
72
74
|
let i = 0
|
|
73
75
|
const makeId = () => i++
|
|
76
|
+
const makeFakeEmail = () => fakeMailAddress.replace("{i}", String(makeId()))
|
|
74
77
|
return forceFake
|
|
75
78
|
? (msg: EmailMsg) =>
|
|
76
79
|
dropUndefinedT({
|
|
77
80
|
...msg,
|
|
78
|
-
to: msg.to && renderFake(msg.to,
|
|
79
|
-
cc: msg.cc && renderFake(msg.cc,
|
|
80
|
-
bcc: msg.bcc && renderFake(msg.bcc,
|
|
81
|
+
to: msg.to && renderFake(msg.to, makeFakeEmail),
|
|
82
|
+
cc: msg.cc && renderFake(msg.cc, makeFakeEmail),
|
|
83
|
+
bcc: msg.bcc && renderFake(msg.bcc, makeFakeEmail)
|
|
81
84
|
})
|
|
82
85
|
: (msg: EmailMsg) =>
|
|
83
86
|
dropUndefinedT({
|
|
84
87
|
...msg,
|
|
85
|
-
to: msg.to && renderFakeIfTest(msg.to,
|
|
86
|
-
cc: msg.cc && renderFakeIfTest(msg.cc,
|
|
87
|
-
bcc: msg.bcc && renderFakeIfTest(msg.bcc,
|
|
88
|
+
to: msg.to && renderFakeIfTest(msg.to, makeFakeEmail),
|
|
89
|
+
cc: msg.cc && renderFakeIfTest(msg.cc, makeFakeEmail),
|
|
90
|
+
bcc: msg.bcc && renderFakeIfTest(msg.bcc, makeFakeEmail)
|
|
88
91
|
})
|
|
89
92
|
}
|
|
90
93
|
|
|
@@ -100,10 +103,10 @@ export function isTestAddress(to: EmailData) {
|
|
|
100
103
|
)
|
|
101
104
|
}
|
|
102
105
|
|
|
103
|
-
function renderFake(addr: EmailData | readonly EmailData[],
|
|
106
|
+
function renderFake(addr: EmailData | readonly EmailData[], makeEmail: () => string) {
|
|
104
107
|
return {
|
|
105
108
|
name: renderMailData(addr),
|
|
106
|
-
email:
|
|
109
|
+
email: makeEmail()
|
|
107
110
|
}
|
|
108
111
|
}
|
|
109
112
|
const eq = Equivalence.mapInput(
|
|
@@ -117,14 +120,14 @@ function isEmailDataArray(md: EmailData | readonly EmailData[]): md is readonly
|
|
|
117
120
|
|
|
118
121
|
// TODO: should just not add any already added email address
|
|
119
122
|
// https://stackoverflow.com/a/53603076/11595834
|
|
120
|
-
function renderFakeIfTest(addr: EmailData | readonly EmailData[],
|
|
123
|
+
function renderFakeIfTest(addr: EmailData | readonly EmailData[], makeEmail: () => string) {
|
|
121
124
|
if (isEmailDataArray(addr)) {
|
|
122
125
|
return Array.dedupeWith(
|
|
123
|
-
addr.map((x) => (isTestAddress(x) ? renderFake(x,
|
|
126
|
+
addr.map((x) => (isTestAddress(x) ? renderFake(x, makeEmail) : x)),
|
|
124
127
|
eq
|
|
125
128
|
)
|
|
126
129
|
}
|
|
127
|
-
return isTestAddress(addr) ? renderFake(addr,
|
|
130
|
+
return isTestAddress(addr) ? renderFake(addr, makeEmail) : addr
|
|
128
131
|
}
|
|
129
132
|
|
|
130
133
|
function renderMailData(md: EmailData | readonly EmailData[]): string {
|
package/src/Emailer/service.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { MailContent, MailData } from "@sendgrid/helpers/classes/mail.js"
|
|
2
2
|
import type { ResponseError } from "@sendgrid/mail"
|
|
3
|
-
import { Data, type Effect, type NonEmptyReadonlyArray, type Redacted
|
|
3
|
+
import { Context, Data, type Effect, type NonEmptyReadonlyArray, type Redacted } from "effect-app"
|
|
4
4
|
import type { Email } from "effect-app/Schema"
|
|
5
5
|
|
|
6
6
|
export class SendMailError extends Data.TaggedError("SendMailError")<{
|
|
7
7
|
readonly raw: Error | ResponseError
|
|
8
8
|
}> {}
|
|
9
9
|
|
|
10
|
-
export class Emailer extends
|
|
10
|
+
export class Emailer extends Context.Opaque<Emailer, {
|
|
11
11
|
sendMail: (msg: EmailMsgOptionalFrom) => Effect.Effect<void, SendMailError>
|
|
12
12
|
}>()("effect-app/Emailer") {}
|
|
13
13
|
|
|
@@ -22,6 +22,12 @@ export interface SendgridConfig {
|
|
|
22
22
|
realMail: boolean
|
|
23
23
|
defaultFrom: EmailData
|
|
24
24
|
apiKey: Redacted.Redacted<string>
|
|
25
|
+
/**
|
|
26
|
+
* Email address used for fake/test recipients. Use `{i}` as a placeholder for an auto-incrementing index to ensure uniqueness.
|
|
27
|
+
*
|
|
28
|
+
* @example "test+{i}@example.com"
|
|
29
|
+
*/
|
|
30
|
+
fakeMailAddress: string
|
|
25
31
|
}
|
|
26
32
|
export type EmailTemplateMsg = MailData & { templateId: string }
|
|
27
33
|
|
package/src/MainFiberSet.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Effect, Fiber, FiberSet, Layer
|
|
2
|
-
|
|
1
|
+
import { Context, Effect, Fiber, FiberSet, Layer } from "effect-app"
|
|
2
|
+
|
|
3
3
|
import { InfraLogger } from "./logger.js"
|
|
4
4
|
import { reportNonInterruptedFailureCause } from "./QueueMaker/errors.js"
|
|
5
5
|
import { setRootParentSpan } from "./RequestFiberSet.js"
|
|
@@ -62,7 +62,7 @@ const make = Effect.gen(function*() {
|
|
|
62
62
|
* you should register these long running fibers in a FiberSet, and join them at the end of your main program.
|
|
63
63
|
* This way any errors will blow up the main program instead of fibers dying unknowingly.
|
|
64
64
|
*/
|
|
65
|
-
export class MainFiberSet extends
|
|
65
|
+
export class MainFiberSet extends Context.Service<MainFiberSet>()("MainFiberSet", { make }) {
|
|
66
66
|
static readonly Live = Layer.effect(this, this.make)
|
|
67
67
|
static readonly JoinLive = this.asEffect().pipe(
|
|
68
68
|
Effect.andThen((_) => _.join),
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Context, Effect } from "effect-app"
|
|
2
|
+
|
|
3
|
+
export interface RegisteredRepository {
|
|
4
|
+
readonly seedNamespace: (namespace: string) => Effect.Effect<void>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const make = Effect.sync(() => {
|
|
8
|
+
const repos = new Map<string, RegisteredRepository>()
|
|
9
|
+
return {
|
|
10
|
+
register(modelName: string, repo: RegisteredRepository) {
|
|
11
|
+
repos.set(modelName, repo)
|
|
12
|
+
},
|
|
13
|
+
seedNamespace: (namespace: string) =>
|
|
14
|
+
Effect.suspend(() =>
|
|
15
|
+
Effect.forEach(
|
|
16
|
+
repos.values(),
|
|
17
|
+
(r) => r.seedNamespace(namespace),
|
|
18
|
+
{ concurrency: "unbounded", discard: true }
|
|
19
|
+
)
|
|
20
|
+
),
|
|
21
|
+
get entries(): ReadonlyMap<string, RegisteredRepository> {
|
|
22
|
+
return repos
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export class RepositoryRegistry extends Context.Opaque<RepositoryRegistry, {
|
|
28
|
+
readonly register: (modelName: string, repo: RegisteredRepository) => void
|
|
29
|
+
readonly seedNamespace: (namespace: string) => Effect.Effect<void>
|
|
30
|
+
readonly entries: ReadonlyMap<string, RegisteredRepository>
|
|
31
|
+
}>()("effect-app/RepositoryRegistry", { make }) {}
|
|
32
|
+
|
|
33
|
+
export const RepositoryRegistryLive = RepositoryRegistry.toLayer(RepositoryRegistry.make)
|
|
@@ -9,6 +9,22 @@ import type { Query, QueryEnd, QueryWhere } from "../query.js"
|
|
|
9
9
|
import * as Q from "../query.js"
|
|
10
10
|
import type { Repository } from "./service.js"
|
|
11
11
|
|
|
12
|
+
interface BatchOptions {
|
|
13
|
+
readonly batch?: true | number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const asReadonlyArray = <T>(itemOrItems: T | ReadonlyArray<T>): ReadonlyArray<T> =>
|
|
17
|
+
globalThis.Array.isArray(itemOrItems)
|
|
18
|
+
? itemOrItems as ReadonlyArray<T>
|
|
19
|
+
: [itemOrItems as T]
|
|
20
|
+
|
|
21
|
+
const getBatchSize = (batch?: true | number) =>
|
|
22
|
+
batch === true
|
|
23
|
+
? 100
|
|
24
|
+
: typeof batch === "number" && Number.isFinite(batch) && batch > 0
|
|
25
|
+
? Math.floor(batch)
|
|
26
|
+
: undefined
|
|
27
|
+
|
|
12
28
|
export const extendRepo = <
|
|
13
29
|
T,
|
|
14
30
|
Encoded extends FieldValues,
|
|
@@ -16,9 +32,10 @@ export const extendRepo = <
|
|
|
16
32
|
ItemType extends string,
|
|
17
33
|
IdKey extends keyof T & keyof Encoded,
|
|
18
34
|
RSchema,
|
|
19
|
-
RPublish
|
|
35
|
+
RPublish,
|
|
36
|
+
RProvided = never
|
|
20
37
|
>(
|
|
21
|
-
repo: Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish>
|
|
38
|
+
repo: Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish, RProvided>
|
|
22
39
|
) => {
|
|
23
40
|
const get = (id: T[IdKey]) =>
|
|
24
41
|
repo.find(id).pipe(
|
|
@@ -244,8 +261,77 @@ export const extendRepo = <
|
|
|
244
261
|
request: (id: T[IdKey]) => Effect.request(_request({ id }), requestResolver),
|
|
245
262
|
get,
|
|
246
263
|
log: (evt: Evt) => AnyPureDSL.log(evt),
|
|
247
|
-
|
|
264
|
+
/**
|
|
265
|
+
* Enables chunked writes for large batches via `options.batch`.
|
|
266
|
+
* Note: batching breaks transactional properties because chunks are saved independently.
|
|
267
|
+
*/
|
|
268
|
+
save: ((itemOrItems: T | ReadonlyArray<T>, options?: BatchOptions) => {
|
|
269
|
+
const items = asReadonlyArray(itemOrItems)
|
|
270
|
+
if (!Array.isReadonlyArrayNonEmpty(items)) {
|
|
271
|
+
return Effect.void
|
|
272
|
+
}
|
|
273
|
+
const batchSize = getBatchSize(options?.batch)
|
|
274
|
+
if (batchSize === undefined) {
|
|
275
|
+
return repo.saveAndPublish(items)
|
|
276
|
+
}
|
|
277
|
+
return Effect.forEach(
|
|
278
|
+
Array.chunksOf(items, batchSize),
|
|
279
|
+
(batch) => repo.saveAndPublish(batch),
|
|
280
|
+
{ discard: true }
|
|
281
|
+
)
|
|
282
|
+
}) as (
|
|
283
|
+
itemOrItems: T | ReadonlyArray<T>,
|
|
284
|
+
options?: BatchOptions
|
|
285
|
+
) => Effect.Effect<
|
|
286
|
+
void,
|
|
287
|
+
InvalidStateError | OptimisticConcurrencyException,
|
|
288
|
+
RSchema | RPublish
|
|
289
|
+
>,
|
|
248
290
|
saveWithEvents: (events: Iterable<Evt>) => (...items: NonEmptyArray<T>) => repo.saveAndPublish(items, events),
|
|
291
|
+
/**
|
|
292
|
+
* Enables chunked deletes for large batches via `options.batch`.
|
|
293
|
+
* Note: batching breaks transactional properties because chunks are removed independently.
|
|
294
|
+
*/
|
|
295
|
+
remove: ((itemOrItems: T | ReadonlyArray<T>, options?: BatchOptions) => {
|
|
296
|
+
const items = asReadonlyArray(itemOrItems)
|
|
297
|
+
if (!Array.isReadonlyArrayNonEmpty(items)) {
|
|
298
|
+
return Effect.void
|
|
299
|
+
}
|
|
300
|
+
const batchSize = getBatchSize(options?.batch)
|
|
301
|
+
if (batchSize === undefined) {
|
|
302
|
+
return repo.removeAndPublish(items)
|
|
303
|
+
}
|
|
304
|
+
return Effect.forEach(
|
|
305
|
+
Array.chunksOf(items, batchSize),
|
|
306
|
+
(batch) => repo.removeAndPublish(batch),
|
|
307
|
+
{ discard: true }
|
|
308
|
+
)
|
|
309
|
+
}) as (
|
|
310
|
+
itemOrItems: T | ReadonlyArray<T>,
|
|
311
|
+
options?: BatchOptions
|
|
312
|
+
) => Effect.Effect<void, never, RSchema | RPublish>,
|
|
313
|
+
/**
|
|
314
|
+
* Enables chunked deletes for large batches via `options.batch`.
|
|
315
|
+
* Note: batching breaks transactional properties because chunks are removed independently.
|
|
316
|
+
*/
|
|
317
|
+
removeById: ((idOrIds: T[IdKey] | ReadonlyArray<T[IdKey]>, options?: BatchOptions) => {
|
|
318
|
+
const ids = asReadonlyArray(idOrIds)
|
|
319
|
+
if (!Array.isReadonlyArrayNonEmpty(ids)) {
|
|
320
|
+
return Effect.void
|
|
321
|
+
}
|
|
322
|
+
const batchSize = getBatchSize(options?.batch)
|
|
323
|
+
if (batchSize === undefined) {
|
|
324
|
+
return repo.removeById(ids)
|
|
325
|
+
}
|
|
326
|
+
return Effect.forEach(
|
|
327
|
+
Array.chunksOf(ids, batchSize),
|
|
328
|
+
(batch) => repo.removeById(batch),
|
|
329
|
+
{ discard: true }
|
|
330
|
+
)
|
|
331
|
+
}) as (
|
|
332
|
+
idOrIds: T[IdKey] | ReadonlyArray<T[IdKey]>,
|
|
333
|
+
options?: BatchOptions
|
|
334
|
+
) => Effect.Effect<void, never, RSchema>,
|
|
249
335
|
queryAndSavePure,
|
|
250
336
|
saveManyWithPure,
|
|
251
337
|
byIdAndSaveWithPure,
|
|
@@ -268,7 +354,7 @@ export const extendRepo = <
|
|
|
268
354
|
return {
|
|
269
355
|
...repo,
|
|
270
356
|
...exts
|
|
271
|
-
} as Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish> & typeof exts
|
|
357
|
+
} as Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish, RProvided> & typeof exts
|
|
272
358
|
}
|
|
273
359
|
|
|
274
360
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
@@ -279,5 +365,6 @@ export interface ExtendedRepository<
|
|
|
279
365
|
ItemType extends string,
|
|
280
366
|
IdKey extends keyof T & keyof Encoded,
|
|
281
367
|
RSchema,
|
|
282
|
-
RPublish
|
|
283
|
-
|
|
368
|
+
RPublish,
|
|
369
|
+
RProvided = never
|
|
370
|
+
> extends ReturnType<typeof extendRepo<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish, RProvided>> {}
|