@effect-app/infra 4.0.0-beta.26 → 4.0.0-beta.260
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 +1966 -0
- package/_check.sh +1 -1
- package/dist/CUPS.d.ts +30 -11
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +35 -14
- package/dist/ClusterCosmos.d.ts +64 -0
- package/dist/ClusterCosmos.d.ts.map +1 -0
- package/dist/ClusterCosmos.js +487 -0
- package/dist/ClusterServiceBus.d.ts +67 -0
- package/dist/ClusterServiceBus.d.ts.map +1 -0
- package/dist/ClusterServiceBus.js +82 -0
- package/dist/ContextProvider.d.ts +34 -0
- package/dist/ContextProvider.d.ts.map +1 -0
- package/dist/ContextProvider.js +40 -0
- package/dist/Emailer/Sendgrid.d.ts +111 -147
- package/dist/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/Emailer/Sendgrid.js +24 -19
- package/dist/Emailer/fake.d.ts +2 -2
- package/dist/Emailer/fake.d.ts.map +1 -1
- package/dist/Emailer/fake.js +4 -4
- package/dist/MainFiberSet.d.ts +12 -9
- package/dist/MainFiberSet.d.ts.map +1 -1
- package/dist/MainFiberSet.js +10 -6
- package/dist/QueueMaker/SQLQueue.d.ts +8 -9
- package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/QueueMaker/SQLQueue.js +138 -120
- package/dist/QueueMaker/errors.d.ts +5 -3
- package/dist/QueueMaker/errors.d.ts.map +1 -1
- package/dist/QueueMaker/errors.js +4 -2
- package/dist/QueueMaker/memQueue.d.ts +10 -6
- package/dist/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.js +84 -68
- package/dist/QueueMaker/sbqueue.d.ts +9 -5
- package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/QueueMaker/sbqueue.js +60 -58
- package/dist/RequestFiberSet.d.ts +10 -7
- package/dist/RequestFiberSet.d.ts.map +1 -1
- package/dist/RequestFiberSet.js +13 -8
- package/dist/SQL/Model.d.ts +468 -0
- package/dist/SQL/Model.d.ts.map +1 -0
- package/dist/SQL/Model.js +469 -0
- package/dist/SQL.d.ts +2 -0
- package/dist/SQL.d.ts.map +1 -0
- package/dist/{adapters/SQL.js → SQL.js} +1 -1
- package/dist/ServiceBus.d.ts +61 -0
- package/dist/ServiceBus.d.ts.map +1 -0
- package/dist/ServiceBus.js +108 -0
- package/dist/Store/Cosmos/query.d.ts +15 -4
- package/dist/Store/Cosmos/query.d.ts.map +1 -1
- package/dist/Store/Cosmos/query.js +179 -41
- package/dist/Store/Cosmos.d.ts +3 -3
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +344 -246
- package/dist/Store/Disk.d.ts +5 -5
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +78 -38
- package/dist/Store/Memory.d.ts +7 -10
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +326 -66
- 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 +232 -0
- package/dist/Store/SQL/query.d.ts +49 -0
- package/dist/Store/SQL/query.d.ts.map +1 -0
- package/dist/Store/SQL/query.js +527 -0
- package/dist/Store/SQL.d.ts +21 -0
- package/dist/Store/SQL.d.ts.map +1 -0
- package/dist/Store/SQL.js +449 -0
- package/dist/Store/codeFilter.d.ts +5 -5
- package/dist/Store/codeFilter.d.ts.map +1 -1
- package/dist/Store/codeFilter.js +6 -3
- package/dist/Store/index.d.ts +7 -5
- package/dist/Store/index.d.ts.map +1 -1
- package/dist/Store/index.js +18 -5
- package/dist/Store/utils.d.ts +4 -3
- package/dist/Store/utils.d.ts.map +1 -1
- package/dist/Store/utils.js +5 -5
- package/dist/WorkflowEngineCosmos.d.ts +29 -0
- package/dist/WorkflowEngineCosmos.d.ts.map +1 -0
- package/dist/WorkflowEngineCosmos.js +521 -0
- package/dist/WorkflowEngineSqlite.d.ts +24 -0
- package/dist/WorkflowEngineSqlite.d.ts.map +1 -0
- package/dist/WorkflowEngineSqlite.js +550 -0
- package/dist/arbs.d.ts +2 -2
- package/dist/arbs.d.ts.map +1 -1
- package/dist/arbs.js +5 -3
- package/dist/codec.d.ts +5 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +5 -0
- package/dist/cosmos-client.d.ts +16 -0
- package/dist/cosmos-client.d.ts.map +1 -0
- package/dist/cosmos-client.js +11 -0
- package/dist/errorReporter.d.ts +7 -5
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +23 -27
- package/dist/errors.d.ts +1 -1
- package/dist/fileUtil.d.ts +2 -2
- package/dist/fileUtil.d.ts.map +1 -1
- package/dist/fileUtil.js +2 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/internal/RequestContextMiddleware.d.ts +5 -0
- package/dist/internal/RequestContextMiddleware.d.ts.map +1 -0
- package/dist/internal/RequestContextMiddleware.js +45 -0
- package/dist/internal/auth.d.ts +53 -0
- package/dist/internal/auth.d.ts.map +1 -0
- package/dist/internal/auth.js +180 -0
- package/dist/internal/events.d.ts +11 -0
- package/dist/internal/events.d.ts.map +1 -0
- package/dist/internal/events.js +49 -0
- package/dist/internal/health.d.ts +3 -0
- package/dist/internal/health.d.ts.map +1 -0
- package/dist/internal/health.js +5 -0
- package/dist/layerUtils.d.ts +32 -0
- package/dist/layerUtils.d.ts.map +1 -0
- package/dist/layerUtils.js +17 -0
- package/dist/logger/jsonLogger.d.ts +2 -2
- package/dist/logger/jsonLogger.d.ts.map +1 -1
- package/dist/logger/jsonLogger.js +5 -3
- package/dist/logger/logFmtLogger.d.ts +2 -2
- package/dist/logger/logFmtLogger.d.ts.map +1 -1
- package/dist/logger/logFmtLogger.js +3 -3
- package/dist/logger/shared.d.ts +3 -3
- package/dist/logger/shared.d.ts.map +1 -1
- package/dist/logger/shared.js +5 -5
- package/dist/logger.d.ts +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/memQueue.d.ts +15 -0
- package/dist/memQueue.d.ts.map +1 -0
- package/dist/memQueue.js +21 -0
- package/dist/middlewares.d.ts +10 -0
- package/dist/middlewares.d.ts.map +1 -0
- package/dist/{api/middlewares.js → middlewares.js} +1 -1
- package/dist/mongo-client.d.ts +11 -0
- package/dist/mongo-client.d.ts.map +1 -0
- package/dist/mongo-client.js +15 -0
- package/dist/otel.d.ts +75 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +65 -0
- package/dist/rateLimit.d.ts +12 -4
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/rateLimit.js +7 -12
- package/dist/redis-client.d.ts +42 -0
- package/dist/redis-client.d.ts.map +1 -0
- package/dist/redis-client.js +98 -0
- package/dist/reportError.d.ts +4 -0
- package/dist/reportError.d.ts.map +1 -0
- package/dist/reportError.js +28 -0
- package/dist/routing/middleware/RouterMiddleware.d.ts +16 -0
- package/dist/routing/middleware/RouterMiddleware.d.ts.map +1 -0
- package/dist/{api/routing → routing}/middleware/RouterMiddleware.js +1 -1
- package/dist/routing/middleware/middleware.d.ts +48 -0
- package/dist/routing/middleware/middleware.d.ts.map +1 -0
- package/dist/routing/middleware/middleware.js +128 -0
- package/dist/routing/middleware.d.ts +3 -0
- package/dist/routing/middleware.d.ts.map +1 -0
- package/dist/{api/routing → routing}/middleware.js +1 -2
- package/dist/routing/schema/jwt.d.ts +4 -0
- package/dist/routing/schema/jwt.d.ts.map +1 -0
- package/dist/routing/schema/jwt.js +13 -0
- package/dist/routing/tsort.d.ts +8 -0
- package/dist/routing/tsort.d.ts.map +1 -0
- package/dist/routing/tsort.js +51 -0
- package/dist/routing/utils.d.ts +19 -0
- package/dist/routing/utils.d.ts.map +1 -0
- package/dist/routing/utils.js +45 -0
- package/dist/routing.d.ts +184 -0
- package/dist/routing.d.ts.map +1 -0
- package/dist/routing.js +236 -0
- package/dist/test.d.ts +3 -3
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +2 -2
- package/dist/util.d.ts +3 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +14 -0
- package/dist/vitest.d.ts +1 -1
- package/docs/cluster-storage.md +26 -0
- package/docs/workflow-engine.md +262 -0
- package/examples/query.ts +47 -39
- package/package.json +31 -345
- package/run.sh +1 -0
- package/src/CUPS.ts +52 -13
- package/src/ClusterCosmos.ts +954 -0
- package/src/ClusterServiceBus.ts +242 -0
- package/src/{api/ContextProvider.ts → ContextProvider.ts} +19 -16
- package/src/Emailer/Sendgrid.ts +82 -59
- package/src/Emailer/fake.ts +3 -3
- package/src/MainFiberSet.ts +12 -10
- package/src/QueueMaker/SQLQueue.ts +153 -156
- package/src/QueueMaker/errors.ts +3 -1
- package/src/QueueMaker/memQueue.ts +113 -107
- package/src/QueueMaker/sbqueue.ts +78 -90
- package/src/RequestFiberSet.ts +13 -8
- package/src/{adapters/SQL → SQL}/Model.ts +42 -41
- package/src/ServiceBus.ts +219 -0
- package/src/Store/Cosmos/query.ts +216 -52
- package/src/Store/Cosmos.ts +493 -353
- package/src/Store/Disk.ts +109 -69
- package/src/Store/Memory.ts +365 -96
- package/src/Store/SQL/Pg.ts +363 -0
- package/src/Store/SQL/query.ts +603 -0
- package/src/Store/SQL.ts +735 -0
- package/src/Store/codeFilter.ts +8 -5
- package/src/Store/index.ts +21 -6
- package/src/Store/utils.ts +26 -24
- package/src/WorkflowEngineCosmos.ts +719 -0
- package/src/WorkflowEngineSqlite.ts +813 -0
- package/src/arbs.ts +5 -3
- package/src/{adapters/cosmos-client.ts → cosmos-client.ts} +5 -3
- package/src/errorReporter.ts +66 -76
- package/src/fileUtil.ts +1 -1
- package/src/index.ts +2 -1
- package/src/{api/internal → internal}/RequestContextMiddleware.ts +23 -6
- package/src/internal/auth.ts +272 -0
- package/src/{api/internal → internal}/events.ts +22 -13
- package/src/{api/layerUtils.ts → layerUtils.ts} +14 -10
- package/src/logger/jsonLogger.ts +4 -2
- package/src/logger/logFmtLogger.ts +2 -2
- package/src/logger/shared.ts +5 -4
- package/src/{adapters/memQueue.ts → memQueue.ts} +5 -4
- package/src/{adapters/mongo-client.ts → mongo-client.ts} +4 -2
- package/src/otel.ts +152 -0
- package/src/rateLimit.ts +34 -23
- package/src/{adapters/redis-client.ts → redis-client.ts} +7 -3
- package/src/{api/reportError.ts → reportError.ts} +3 -2
- package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +5 -4
- package/src/{api/routing → routing}/middleware/middleware.ts +62 -17
- package/src/routing/middleware.ts +4 -0
- package/src/{api/routing → routing}/schema/jwt.ts +2 -1
- package/src/{api/routing → routing}/utils.ts +2 -1
- package/src/routing.ts +768 -0
- package/src/test.ts +2 -2
- package/test/auth.test.ts +101 -0
- package/test/cluster-cosmos.test.ts +503 -0
- package/test/cluster-servicebus.test.ts +180 -0
- package/test/contextProvider.test.ts +15 -12
- package/test/controller.test.ts +28 -32
- package/test/cosmos-query.test.ts +159 -0
- package/test/dist/_check-agg-infer.test-d.d.ts +2 -0
- package/test/dist/_check-agg-infer.test-d.d.ts.map +1 -0
- package/test/dist/_check-agg-infer.test-d.js +19 -0
- package/test/dist/_check-proj-infer.test-d.d.ts +2 -0
- package/test/dist/_check-proj-infer.test-d.d.ts.map +1 -0
- package/test/dist/_check-proj-infer.test-d.js +16 -0
- package/test/dist/_check-tighten.test-d.d.ts +2 -0
- package/test/dist/_check-tighten.test-d.d.ts.map +1 -0
- package/test/dist/_check-tighten.test-d.js +21 -0
- package/test/dist/auth.test.d.ts.map +1 -0
- package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
- package/test/dist/cluster-servicebus.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/cosmos-query.test.d.ts.map +1 -0
- package/test/dist/date-query.test.d.ts.map +1 -0
- package/test/dist/fixtures.d.ts +30 -12
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +17 -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-context-map-streaming.test.d.ts.map +1 -0
- package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
- package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
- package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
- package/test/dist/sql-store.test.d.ts.map +1 -0
- package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
- package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
- package/test/fixtures.ts +16 -9
- package/test/layerUtils.test.ts +2 -2
- package/test/query.test.ts +905 -40
- package/test/rawQuery.test.ts +340 -22
- package/test/repository-ext.test.ts +62 -0
- package/test/requires.test.ts +10 -5
- package/test/router-generator.test.ts +187 -0
- package/test/routing-interruptibility.test.ts +66 -0
- package/test/rpc-context-map-streaming.test.ts +262 -0
- package/test/rpc-e2e-invalidation.test.ts +256 -0
- package/test/rpc-multi-middleware.test.ts +85 -10
- package/test/rpc-stream-fullstack.test.ts +304 -0
- package/test/sql-store.test.ts +1711 -0
- package/test/validateSample.test.ts +26 -14
- package/test/workflow-engine-cosmos.test.ts +354 -0
- package/test/workflow-engine-sqlite.test.ts +299 -0
- package/tsconfig.examples.json +1 -1
- package/tsconfig.json +2 -1
- package/tsconfig.json.bak +2 -2
- package/tsconfig.src.json +35 -35
- package/tsconfig.test.json +2 -2
- package/dist/Emailer/service.d.ts +0 -55
- package/dist/Emailer/service.d.ts.map +0 -1
- package/dist/Emailer/service.js +0 -6
- package/dist/Emailer.d.ts +0 -2
- package/dist/Emailer.d.ts.map +0 -1
- package/dist/Emailer.js +0 -2
- package/dist/Model/Repository/ext.d.ts +0 -41
- package/dist/Model/Repository/ext.d.ts.map +0 -1
- package/dist/Model/Repository/ext.js +0 -65
- package/dist/Model/Repository/internal/internal.d.ts +0 -59
- package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
- package/dist/Model/Repository/internal/internal.js +0 -316
- package/dist/Model/Repository/legacy.d.ts +0 -19
- package/dist/Model/Repository/legacy.d.ts.map +0 -1
- package/dist/Model/Repository/legacy.js +0 -2
- package/dist/Model/Repository/makeRepo.d.ts +0 -49
- package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
- package/dist/Model/Repository/makeRepo.js +0 -24
- package/dist/Model/Repository/service.d.ts +0 -89
- package/dist/Model/Repository/service.d.ts.map +0 -1
- package/dist/Model/Repository/service.js +0 -2
- package/dist/Model/Repository/validation.d.ts +0 -42
- package/dist/Model/Repository/validation.d.ts.map +0 -1
- package/dist/Model/Repository/validation.js +0 -32
- package/dist/Model/Repository.d.ts +0 -6
- package/dist/Model/Repository.d.ts.map +0 -1
- package/dist/Model/Repository.js +0 -6
- package/dist/Model/dsl.d.ts +0 -32
- package/dist/Model/dsl.d.ts.map +0 -1
- package/dist/Model/dsl.js +0 -44
- package/dist/Model/filter/filterApi.d.ts +0 -30
- package/dist/Model/filter/filterApi.d.ts.map +0 -1
- package/dist/Model/filter/filterApi.js +0 -2
- package/dist/Model/filter/types/errors.d.ts +0 -29
- package/dist/Model/filter/types/errors.d.ts.map +0 -1
- package/dist/Model/filter/types/errors.js +0 -2
- package/dist/Model/filter/types/fields.d.ts +0 -15
- package/dist/Model/filter/types/fields.d.ts.map +0 -1
- package/dist/Model/filter/types/fields.js +0 -2
- package/dist/Model/filter/types/path/common.d.ts +0 -316
- package/dist/Model/filter/types/path/common.d.ts.map +0 -1
- package/dist/Model/filter/types/path/common.js +0 -2
- package/dist/Model/filter/types/path/eager.d.ts +0 -95
- package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
- package/dist/Model/filter/types/path/eager.js +0 -31
- package/dist/Model/filter/types/path/index.d.ts +0 -4
- package/dist/Model/filter/types/path/index.d.ts.map +0 -1
- package/dist/Model/filter/types/path/index.js +0 -3
- package/dist/Model/filter/types/utils.d.ts +0 -79
- package/dist/Model/filter/types/utils.d.ts.map +0 -1
- package/dist/Model/filter/types/utils.js +0 -2
- package/dist/Model/filter/types/validator.d.ts +0 -30
- package/dist/Model/filter/types/validator.d.ts.map +0 -1
- package/dist/Model/filter/types/validator.js +0 -2
- package/dist/Model/filter/types.d.ts +0 -5
- package/dist/Model/filter/types.d.ts.map +0 -1
- package/dist/Model/filter/types.js +0 -7
- package/dist/Model/query/dsl.d.ts +0 -248
- package/dist/Model/query/dsl.d.ts.map +0 -1
- package/dist/Model/query/dsl.js +0 -104
- package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
- package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
- package/dist/Model/query/new-kid-interpreter.js +0 -165
- package/dist/Model/query.d.ts +0 -15
- package/dist/Model/query.d.ts.map +0 -1
- package/dist/Model/query.js +0 -3
- package/dist/Model.d.ts +0 -4
- package/dist/Model.d.ts.map +0 -1
- package/dist/Model.js +0 -4
- package/dist/Operations.d.ts +0 -55
- package/dist/Operations.d.ts.map +0 -1
- package/dist/Operations.js +0 -102
- package/dist/OperationsRepo.d.ts +0 -41
- package/dist/OperationsRepo.d.ts.map +0 -1
- package/dist/OperationsRepo.js +0 -14
- package/dist/QueueMaker/service.d.ts +0 -11
- package/dist/QueueMaker/service.d.ts.map +0 -1
- package/dist/QueueMaker/service.js +0 -4
- package/dist/RequestContext.d.ts +0 -63
- package/dist/RequestContext.d.ts.map +0 -1
- package/dist/RequestContext.js +0 -49
- package/dist/Store/ContextMapContainer.d.ts +0 -14
- package/dist/Store/ContextMapContainer.d.ts.map +0 -1
- package/dist/Store/ContextMapContainer.js +0 -16
- package/dist/Store/service.d.ts +0 -108
- package/dist/Store/service.d.ts.map +0 -1
- package/dist/Store/service.js +0 -71
- package/dist/Store.d.ts +0 -2
- package/dist/Store.d.ts.map +0 -1
- package/dist/Store.js +0 -2
- package/dist/adapters/SQL/Model.d.ts +0 -479
- package/dist/adapters/SQL/Model.d.ts.map +0 -1
- package/dist/adapters/SQL/Model.js +0 -478
- package/dist/adapters/SQL.d.ts +0 -2
- package/dist/adapters/SQL.d.ts.map +0 -1
- package/dist/adapters/ServiceBus.d.ts +0 -58
- package/dist/adapters/ServiceBus.d.ts.map +0 -1
- package/dist/adapters/ServiceBus.js +0 -99
- package/dist/adapters/cosmos-client.d.ts +0 -14
- package/dist/adapters/cosmos-client.d.ts.map +0 -1
- package/dist/adapters/cosmos-client.js +0 -9
- package/dist/adapters/index.d.ts +0 -2
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -2
- package/dist/adapters/logger.d.ts +0 -9
- package/dist/adapters/logger.d.ts.map +0 -1
- package/dist/adapters/logger.js +0 -3
- package/dist/adapters/memQueue.d.ts +0 -13
- package/dist/adapters/memQueue.d.ts.map +0 -1
- package/dist/adapters/memQueue.js +0 -20
- package/dist/adapters/mongo-client.d.ts +0 -10
- package/dist/adapters/mongo-client.d.ts.map +0 -1
- package/dist/adapters/mongo-client.js +0 -13
- package/dist/adapters/redis-client.d.ts +0 -39
- package/dist/adapters/redis-client.d.ts.map +0 -1
- package/dist/adapters/redis-client.js +0 -94
- package/dist/api/ContextProvider.d.ts +0 -31
- package/dist/api/ContextProvider.d.ts.map +0 -1
- package/dist/api/ContextProvider.js +0 -38
- package/dist/api/codec.d.ts +0 -5
- package/dist/api/codec.d.ts.map +0 -1
- package/dist/api/codec.js +0 -5
- package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
- package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
- package/dist/api/internal/RequestContextMiddleware.js +0 -35
- package/dist/api/internal/auth.d.ts +0 -15
- package/dist/api/internal/auth.d.ts.map +0 -1
- package/dist/api/internal/auth.js +0 -47
- package/dist/api/internal/events.d.ts +0 -9
- package/dist/api/internal/events.d.ts.map +0 -1
- package/dist/api/internal/events.js +0 -42
- package/dist/api/internal/health.d.ts +0 -3
- package/dist/api/internal/health.d.ts.map +0 -1
- package/dist/api/internal/health.js +0 -5
- package/dist/api/layerUtils.d.ts +0 -24
- package/dist/api/layerUtils.d.ts.map +0 -1
- package/dist/api/layerUtils.js +0 -16
- package/dist/api/middlewares.d.ts +0 -10
- package/dist/api/middlewares.d.ts.map +0 -1
- package/dist/api/reportError.d.ts +0 -4
- package/dist/api/reportError.d.ts.map +0 -1
- package/dist/api/reportError.js +0 -27
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +0 -15
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/middleware.d.ts +0 -9
- package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/middleware.js +0 -92
- package/dist/api/routing/middleware.d.ts +0 -4
- package/dist/api/routing/middleware.d.ts.map +0 -1
- package/dist/api/routing/schema/jwt.d.ts +0 -4
- package/dist/api/routing/schema/jwt.d.ts.map +0 -1
- package/dist/api/routing/schema/jwt.js +0 -12
- package/dist/api/routing/tsort.d.ts +0 -8
- package/dist/api/routing/tsort.d.ts.map +0 -1
- package/dist/api/routing/tsort.js +0 -51
- package/dist/api/routing/utils.d.ts +0 -19
- package/dist/api/routing/utils.d.ts.map +0 -1
- package/dist/api/routing/utils.js +0 -44
- package/dist/api/routing.d.ts +0 -138
- package/dist/api/routing.d.ts.map +0 -1
- package/dist/api/routing.js +0 -166
- package/dist/api/setupRequest.d.ts +0 -12
- package/dist/api/setupRequest.d.ts.map +0 -1
- package/dist/api/setupRequest.js +0 -44
- package/dist/api/util.d.ts +0 -3
- package/dist/api/util.d.ts.map +0 -1
- package/dist/api/util.js +0 -14
- package/eslint.config.mjs +0 -24
- package/src/Emailer/service.ts +0 -52
- package/src/Emailer.ts +0 -1
- package/src/Model/Repository/ext.ts +0 -283
- package/src/Model/Repository/internal/internal.ts +0 -577
- package/src/Model/Repository/legacy.ts +0 -27
- package/src/Model/Repository/makeRepo.ts +0 -139
- package/src/Model/Repository/service.ts +0 -627
- package/src/Model/Repository/validation.ts +0 -31
- package/src/Model/Repository.ts +0 -5
- package/src/Model/dsl.ts +0 -128
- package/src/Model/filter/filterApi.ts +0 -60
- package/src/Model/filter/types/errors.ts +0 -47
- package/src/Model/filter/types/fields.ts +0 -50
- package/src/Model/filter/types/path/common.ts +0 -404
- package/src/Model/filter/types/path/eager.ts +0 -298
- package/src/Model/filter/types/path/index.ts +0 -4
- package/src/Model/filter/types/utils.ts +0 -128
- package/src/Model/filter/types/validator.ts +0 -46
- package/src/Model/filter/types.ts +0 -6
- package/src/Model/query/dsl.ts +0 -2110
- package/src/Model/query/new-kid-interpreter.ts +0 -210
- package/src/Model/query.ts +0 -13
- package/src/Model.ts +0 -3
- package/src/Operations.ts +0 -235
- package/src/OperationsRepo.ts +0 -16
- package/src/QueueMaker/service.ts +0 -17
- package/src/RequestContext.ts +0 -63
- package/src/Store/ContextMapContainer.ts +0 -20
- package/src/Store/service.ts +0 -184
- package/src/Store.ts +0 -1
- package/src/adapters/ServiceBus.ts +0 -209
- package/src/adapters/index.ts +0 -0
- package/src/adapters/logger.ts +0 -3
- package/src/api/internal/auth.ts +0 -68
- package/src/api/routing/middleware.ts +0 -6
- package/src/api/routing.ts +0 -598
- package/src/api/setupRequest.ts +0 -84
- /package/src/{adapters/SQL.ts → SQL.ts} +0 -0
- /package/src/{api/codec.ts → codec.ts} +0 -0
- /package/src/{api/internal → internal}/health.ts +0 -0
- /package/src/{api/middlewares.ts → middlewares.ts} +0 -0
- /package/src/{api/routing → routing}/tsort.ts +0 -0
- /package/src/{api/util.ts → util.ts} +0 -0
package/src/arbs.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
// Do not import to frontend
|
|
2
2
|
|
|
3
3
|
import { faker } from "@faker-js/faker"
|
|
4
|
-
import { type S } from "effect-app"
|
|
5
4
|
import { setFaker } from "effect-app/faker"
|
|
5
|
+
import type * as S from "effect-app/Schema"
|
|
6
6
|
import * as FastCheck from "effect/testing/FastCheck"
|
|
7
7
|
import { Random } from "fast-check"
|
|
8
|
-
import
|
|
8
|
+
import { congruential32 } from "pure-rand/generator/congruential32"
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const seed = 5
|
|
11
|
+
const rng = congruential32(seed)
|
|
12
|
+
const rnd = new Random(rng)
|
|
11
13
|
|
|
12
14
|
setFaker(faker)
|
|
13
15
|
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { CosmosClient as ComosClient_ } from "@azure/cosmos"
|
|
2
|
-
import
|
|
2
|
+
import * as Context from "effect-app/Context"
|
|
3
|
+
import * as Effect from "effect-app/Effect"
|
|
4
|
+
import * as Layer from "effect-app/Layer"
|
|
3
5
|
|
|
4
6
|
const withClient = (url: string) => Effect.sync(() => new ComosClient_(url))
|
|
5
7
|
|
|
6
8
|
export const makeCosmosClient = (url: string, dbName: string) =>
|
|
7
9
|
Effect.map(withClient(url), (x) => ({ db: x.database(dbName) }))
|
|
8
10
|
|
|
9
|
-
export class CosmosClient extends
|
|
11
|
+
export class CosmosClient extends Context.Service<CosmosClient, {
|
|
10
12
|
readonly db: ReturnType<InstanceType<typeof ComosClient_>["database"]>
|
|
11
13
|
}>()("@services/CosmosClient") {}
|
|
12
14
|
|
|
13
|
-
export const db = CosmosClient.
|
|
15
|
+
export const db = CosmosClient.pipe(Effect.map((_) => _.db))
|
|
14
16
|
|
|
15
17
|
export const CosmosClientLayer = (cosmosUrl: string, dbName: string) =>
|
|
16
18
|
Layer.effect(CosmosClient, makeCosmosClient(cosmosUrl, dbName))
|
package/src/errorReporter.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as Sentry from "@sentry/node"
|
|
2
|
-
import
|
|
2
|
+
import * as Effect from "effect-app/Effect"
|
|
3
|
+
import { getRC } from "effect-app/setupRequest"
|
|
3
4
|
import { dropUndefined, LogLevelToSentry } from "effect-app/utils"
|
|
4
|
-
import
|
|
5
|
+
import * as Cause from "effect/Cause"
|
|
6
|
+
import type * as LogLevel from "effect/LogLevel"
|
|
5
7
|
import { CauseException, tryToJson, tryToReport } from "./errors.js"
|
|
6
8
|
import { InfraLogger } from "./logger.js"
|
|
7
9
|
|
|
@@ -13,47 +15,41 @@ const tryCauseException = <E>(cause: Cause.Cause<E>, name: string): CauseExcepti
|
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
export function reportError(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
const error = tryCauseException(cause, name)
|
|
31
|
-
|
|
32
|
-
yield* reportSentry(error, extras, LogLevelToSentry(level))
|
|
33
|
-
yield* InfraLogger
|
|
34
|
-
.logWithLevel(level, "Reporting error", cause)
|
|
35
|
-
.pipe(
|
|
36
|
-
Effect.annotateLogs(dropUndefined({
|
|
37
|
-
extras,
|
|
38
|
-
error: tryToReport(error),
|
|
39
|
-
cause: tryToJson(cause),
|
|
40
|
-
__error_name__: name
|
|
41
|
-
}))
|
|
42
|
-
)
|
|
43
|
-
.pipe(
|
|
44
|
-
Effect.catchCause((cause) => InfraLogger.logWarning("Failed to log error", cause)),
|
|
45
|
-
Effect.catchCause(() => InfraLogger.logFatal("Failed to log error cause"))
|
|
46
|
-
)
|
|
18
|
+
export function reportError(name: string) {
|
|
19
|
+
return Effect.fnUntraced(
|
|
20
|
+
function*(
|
|
21
|
+
cause: Cause.Cause<unknown>,
|
|
22
|
+
extras?: Record<string, unknown>,
|
|
23
|
+
level: LogLevel.Severity = "Error"
|
|
24
|
+
) {
|
|
25
|
+
if (Cause.hasInterruptsOnly(cause)) {
|
|
26
|
+
yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs("extras", JSON.stringify(extras ?? {})))
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
const error = tryCauseException(cause, name)
|
|
47
30
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
31
|
+
yield* reportSentry(error, extras, LogLevelToSentry(level))
|
|
32
|
+
yield* InfraLogger
|
|
33
|
+
.logWithLevel(level, "Reporting error", cause)
|
|
34
|
+
.pipe(
|
|
35
|
+
Effect.annotateLogs(dropUndefined({
|
|
36
|
+
extras,
|
|
37
|
+
error: tryToReport(error),
|
|
38
|
+
cause: tryToJson(cause),
|
|
39
|
+
__error_name__: name
|
|
40
|
+
})),
|
|
41
|
+
Effect.catchCause((cause) => InfraLogger.logWarning("Failed to log error", cause)),
|
|
42
|
+
Effect.catchCause(() => InfraLogger.logFatal("Failed to log error cause"))
|
|
55
43
|
)
|
|
56
|
-
|
|
44
|
+
|
|
45
|
+
return error
|
|
46
|
+
},
|
|
47
|
+
(effect) =>
|
|
48
|
+
Effect.tapCause(effect, (cause) =>
|
|
49
|
+
InfraLogger.logError("Failed to report error", cause).pipe(
|
|
50
|
+
Effect.tapCause(() => InfraLogger.logFatal("Failed to log error cause"))
|
|
51
|
+
))
|
|
52
|
+
)
|
|
57
53
|
}
|
|
58
54
|
|
|
59
55
|
function reportSentry(
|
|
@@ -66,45 +62,39 @@ function reportSentry(
|
|
|
66
62
|
scope.setLevel(level)
|
|
67
63
|
if (context) scope.setContext("context", { ...context })
|
|
68
64
|
if (extras) scope.setContext("extras", extras)
|
|
69
|
-
|
|
70
|
-
scope.setContext("
|
|
65
|
+
const squashed = Cause.squash(error.originalCause)
|
|
66
|
+
scope.setContext("mainError", tryToJson(squashed))
|
|
67
|
+
scope.setContext("error", tryToReport(error))
|
|
68
|
+
scope.setContext("cause", tryToJson(error.originalCause))
|
|
71
69
|
Sentry.captureException(error, scope)
|
|
72
70
|
}))
|
|
73
71
|
}
|
|
74
72
|
|
|
75
|
-
export function logError<E>(
|
|
76
|
-
|
|
77
|
-
) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}))
|
|
93
|
-
)
|
|
94
|
-
})
|
|
95
|
-
.pipe(
|
|
96
|
-
Effect.tapCause(() => InfraLogger.logFatal("Failed to log error cause"))
|
|
97
|
-
)
|
|
73
|
+
export function logError<E>(name: string) {
|
|
74
|
+
return Effect.fnUntraced(
|
|
75
|
+
function*(cause: Cause.Cause<E>, extras?: Record<string, unknown>) {
|
|
76
|
+
if (Cause.hasInterruptsOnly(cause)) {
|
|
77
|
+
yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs(dropUndefined({ extras })))
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
yield* InfraLogger
|
|
81
|
+
.logWarning("Logging error", cause)
|
|
82
|
+
.pipe(Effect.annotateLogs(dropUndefined({
|
|
83
|
+
extras,
|
|
84
|
+
cause: tryToJson(cause),
|
|
85
|
+
__error_name__: name
|
|
86
|
+
})))
|
|
87
|
+
},
|
|
88
|
+
(effect) => Effect.tapCause(effect, () => InfraLogger.logFatal("Failed to log error cause"))
|
|
89
|
+
)
|
|
98
90
|
}
|
|
99
91
|
|
|
100
|
-
export
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
Sentry.captureMessage(message, scope)
|
|
92
|
+
export const reportMessage = Effect.fnUntraced(function*(message: string, extras?: Record<string, unknown>) {
|
|
93
|
+
const context = yield* getRC
|
|
94
|
+
const scope = new Sentry.Scope()
|
|
95
|
+
if (context) scope.setContext("context", { ...context })
|
|
96
|
+
if (extras) scope.setContext("extras", extras)
|
|
97
|
+
Sentry.captureMessage(message, scope)
|
|
107
98
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
99
|
+
console.warn(message, extras)
|
|
100
|
+
})
|
package/src/fileUtil.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export *
|
|
1
|
+
export * from "./logger.js"
|
|
2
|
+
export * from "./Store/index.js"
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Effect from "effect-app/Effect"
|
|
2
2
|
import { HttpMiddleware, HttpServerRequest, HttpServerResponse } from "effect-app/http"
|
|
3
|
+
import * as Layer from "effect-app/Layer"
|
|
4
|
+
import { Locale, LocaleRef, RequestContext, spanAttributes } from "effect-app/RequestContext"
|
|
3
5
|
import { NonEmptyString255 } from "effect-app/Schema"
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
+
import { provideOnRequestScope } from "effect-app/setupRequest"
|
|
7
|
+
import { ContextMapContainer, storeId } from "effect-app/Store"
|
|
6
8
|
|
|
7
9
|
export const RequestContextMiddleware = (defaultLocale: Locale = "en") =>
|
|
8
10
|
HttpMiddleware.make((app) =>
|
|
@@ -21,18 +23,33 @@ export const RequestContextMiddleware = (defaultLocale: Locale = "en") =>
|
|
|
21
23
|
const namespace = NonEmptyString255((ns && (Array.isArray(ns) ? ns[0] : ns)) || "primary")
|
|
22
24
|
const deviceId = req.headers["x-fe-device-id"]
|
|
23
25
|
|
|
24
|
-
const requestContext =
|
|
26
|
+
const requestContext = RequestContext.make({
|
|
25
27
|
span: {
|
|
26
28
|
traceId: currentSpan.traceId,
|
|
27
29
|
spanId: currentSpan.spanId,
|
|
28
30
|
sampled: currentSpan.sampled
|
|
29
31
|
},
|
|
30
|
-
name: NonEmptyString255(req.originalUrl), // set more detailed elsewhere
|
|
32
|
+
name: NonEmptyString255(`HTTP ${req.method} ${req.originalUrl.split("?")[0]}`), // set more detailed elsewhere
|
|
31
33
|
locale,
|
|
32
34
|
namespace,
|
|
33
35
|
sourceId: deviceId ? NonEmptyString255(deviceId) : undefined
|
|
34
36
|
})
|
|
35
|
-
|
|
37
|
+
yield* Effect.annotateCurrentSpan(spanAttributes(requestContext))
|
|
38
|
+
const layer = Layer.mergeAll(
|
|
39
|
+
ContextMapContainer.layer,
|
|
40
|
+
Layer.succeed(LocaleRef, requestContext.locale),
|
|
41
|
+
Layer.succeed(storeId, requestContext.namespace)
|
|
42
|
+
)
|
|
43
|
+
// Bind layer to the request scope so ContextMap's finalizer (clear()) runs only
|
|
44
|
+
// after the response body is fully drained — not when `app` returns its
|
|
45
|
+
// HttpServerResponse value. Streaming RPC responses keep producing chunks (and
|
|
46
|
+
// using ContextMap-cached etags) after `app` returns; a sub-scope from
|
|
47
|
+
// `Effect.provide(layer)` would close too early and wipe etags mid-stream,
|
|
48
|
+
// causing spurious OptimisticConcurrencyException on later writes.
|
|
49
|
+
const res = yield* app.pipe(
|
|
50
|
+
Effect.withLogSpan(requestContext.name),
|
|
51
|
+
provideOnRequestScope(layer)
|
|
52
|
+
)
|
|
36
53
|
|
|
37
54
|
// TODO: how to set also on errors?
|
|
38
55
|
return HttpServerResponse.setHeaders(res, {
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import * as Effect from "effect-app/Effect"
|
|
2
|
+
import { HttpHeaders, HttpMiddleware, HttpServerRequest, HttpServerResponse } from "effect-app/http"
|
|
3
|
+
import * as Option from "effect-app/Option"
|
|
4
|
+
import * as Data from "effect/Data"
|
|
5
|
+
import { createRemoteJWKSet, jwtVerify } from "jose"
|
|
6
|
+
|
|
7
|
+
const getHeaders = (error: string, description: string, scopes?: ReadonlyArray<string>) => ({
|
|
8
|
+
"WWW-Authenticate": `Bearer realm="api", error="${error}", error_description="${description.replace(/"/g, "'")}"${
|
|
9
|
+
scopes ? `, scope="${scopes.join(" ")}"` : ""
|
|
10
|
+
}`
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export class UnauthorizedError extends Error {
|
|
14
|
+
readonly status: number = 401
|
|
15
|
+
readonly statusCode: number = 401
|
|
16
|
+
headers = { "WWW-Authenticate": "Bearer realm=\"api\"" }
|
|
17
|
+
|
|
18
|
+
constructor(message = "Unauthorized") {
|
|
19
|
+
super(message)
|
|
20
|
+
this.name = this.constructor.name
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class InvalidRequestError extends UnauthorizedError {
|
|
25
|
+
readonly code: string
|
|
26
|
+
override readonly status = 400
|
|
27
|
+
override readonly statusCode = 400
|
|
28
|
+
|
|
29
|
+
constructor(message = "Invalid Request", useErrorCode = true) {
|
|
30
|
+
super(message)
|
|
31
|
+
this.code = useErrorCode ? "invalid_request" : ""
|
|
32
|
+
if (useErrorCode) {
|
|
33
|
+
this.headers = getHeaders(this.code, this.message)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class InvalidTokenError extends UnauthorizedError {
|
|
39
|
+
readonly code = "invalid_token"
|
|
40
|
+
|
|
41
|
+
constructor(message = "Invalid Token") {
|
|
42
|
+
super(message)
|
|
43
|
+
this.headers = getHeaders(this.code, this.message)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class InsufficientScopeError extends UnauthorizedError {
|
|
48
|
+
readonly code = "insufficient_scope"
|
|
49
|
+
override readonly status = 403
|
|
50
|
+
override readonly statusCode = 403
|
|
51
|
+
|
|
52
|
+
constructor(scopes?: ReadonlyArray<string>, message = "Insufficient Scope") {
|
|
53
|
+
super(message)
|
|
54
|
+
this.headers = getHeaders(this.code, this.message, scopes)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface JwtVerifierOptions {
|
|
59
|
+
readonly audience?: string | Array<string> | ReadonlyArray<string>
|
|
60
|
+
readonly clockTolerance?: number
|
|
61
|
+
readonly issuer?: string
|
|
62
|
+
readonly issuerBaseURL?: string
|
|
63
|
+
readonly jwksUri?: string
|
|
64
|
+
readonly maxTokenAge?: number
|
|
65
|
+
readonly secret?: string
|
|
66
|
+
readonly strict?: boolean
|
|
67
|
+
readonly tokenSigningAlg?: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface AuthOptions extends JwtVerifierOptions {
|
|
71
|
+
readonly authRequired?: boolean
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
type Config = AuthOptions
|
|
75
|
+
|
|
76
|
+
type JwtError = InsufficientScopeError | InvalidRequestError | InvalidTokenError | UnauthorizedError
|
|
77
|
+
|
|
78
|
+
type ResolvedConfigBase = {
|
|
79
|
+
readonly audience: string | Array<string> | undefined
|
|
80
|
+
readonly clockTolerance: number
|
|
81
|
+
readonly issuer: string | undefined
|
|
82
|
+
readonly maxTokenAge: number | undefined
|
|
83
|
+
readonly strict: boolean
|
|
84
|
+
readonly tokenSigningAlg: string | undefined
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type ResolvedConfig =
|
|
88
|
+
& ResolvedConfigBase
|
|
89
|
+
& (
|
|
90
|
+
| {
|
|
91
|
+
readonly key: ReturnType<typeof createRemoteJWKSet>
|
|
92
|
+
readonly keyType: "jwks"
|
|
93
|
+
}
|
|
94
|
+
| {
|
|
95
|
+
readonly key: Uint8Array
|
|
96
|
+
readonly keyType: "secret"
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null
|
|
101
|
+
|
|
102
|
+
const getErrorMessage = (error: unknown) => error instanceof Error ? error.message : String(error)
|
|
103
|
+
|
|
104
|
+
const normalizeAudience = (audience: Config["audience"]): string | Array<string> | undefined =>
|
|
105
|
+
Array.isArray(audience) ? Array.from(audience) : audience as string | undefined
|
|
106
|
+
|
|
107
|
+
const buildDiscoveryUrl = (issuerBaseURL: string) => {
|
|
108
|
+
const url = new URL(issuerBaseURL)
|
|
109
|
+
if (!url.pathname.includes("/.well-known/")) {
|
|
110
|
+
url.pathname = url.pathname.endsWith("/")
|
|
111
|
+
? `${url.pathname}.well-known/openid-configuration`
|
|
112
|
+
: `${url.pathname}/.well-known/openid-configuration`
|
|
113
|
+
}
|
|
114
|
+
url.search = ""
|
|
115
|
+
url.hash = ""
|
|
116
|
+
return url
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const fetchDiscoveryDocumentPromise = async (issuerBaseURL: string) => {
|
|
120
|
+
const response = await fetch(buildDiscoveryUrl(issuerBaseURL))
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
throw new Error(`Failed to fetch authorization server metadata: ${response.status}`)
|
|
123
|
+
}
|
|
124
|
+
const json = await response.json()
|
|
125
|
+
if (!isRecord(json) || typeof json["issuer"] !== "string" || typeof json["jwks_uri"] !== "string") {
|
|
126
|
+
throw new Error("Invalid authorization server metadata")
|
|
127
|
+
}
|
|
128
|
+
return { issuer: json["issuer"], jwksUri: json["jwks_uri"] }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const getAuthorizationToken = (headers: HttpHeaders.Headers, authRequired: boolean) => {
|
|
132
|
+
const authorization = HttpHeaders.get(headers, "authorization")
|
|
133
|
+
if (Option.isNone(authorization)) {
|
|
134
|
+
return authRequired ? Effect.fail(new UnauthorizedError()) : Effect.succeed(Option.none<string>())
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const [scheme, token] = authorization.value.split(" ")
|
|
138
|
+
if (!scheme || !token || scheme.toLowerCase() !== "bearer") {
|
|
139
|
+
return Effect.fail(new InvalidRequestError("", false))
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return Effect.succeed(Option.some(token))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const makeResolveConfig = (config: Config) => {
|
|
146
|
+
let cached: Promise<ResolvedConfig> | undefined
|
|
147
|
+
|
|
148
|
+
return Effect.tryPromise({
|
|
149
|
+
try: () => {
|
|
150
|
+
if (!cached) {
|
|
151
|
+
cached = (async (): Promise<ResolvedConfig> => {
|
|
152
|
+
const discovery = config.issuerBaseURL
|
|
153
|
+
? await fetchDiscoveryDocumentPromise(config.issuerBaseURL)
|
|
154
|
+
: undefined
|
|
155
|
+
|
|
156
|
+
const issuer = config.issuer ?? discovery?.issuer
|
|
157
|
+
const jwksUri = config.jwksUri ?? discovery?.jwksUri
|
|
158
|
+
const secret = config.secret
|
|
159
|
+
const base = {
|
|
160
|
+
audience: normalizeAudience(config.audience),
|
|
161
|
+
clockTolerance: config.clockTolerance ?? 5,
|
|
162
|
+
issuer,
|
|
163
|
+
maxTokenAge: config.maxTokenAge,
|
|
164
|
+
strict: config.strict ?? false,
|
|
165
|
+
tokenSigningAlg: config.tokenSigningAlg
|
|
166
|
+
} satisfies ResolvedConfigBase
|
|
167
|
+
|
|
168
|
+
if (!issuer && !secret) {
|
|
169
|
+
throw new InvalidRequestError("JWT config requires 'issuer', 'issuerBaseURL', or 'secret'")
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!secret) {
|
|
173
|
+
if (!jwksUri) {
|
|
174
|
+
throw new InvalidRequestError("JWT config requires 'jwksUri', 'issuerBaseURL', or 'secret'")
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
...base,
|
|
179
|
+
key: createRemoteJWKSet(new URL(jwksUri)),
|
|
180
|
+
keyType: "jwks"
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
...base,
|
|
186
|
+
key: new TextEncoder().encode(secret),
|
|
187
|
+
keyType: "secret"
|
|
188
|
+
}
|
|
189
|
+
})()
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return cached
|
|
193
|
+
},
|
|
194
|
+
catch: (error) =>
|
|
195
|
+
error instanceof InvalidRequestError || error instanceof InvalidTokenError
|
|
196
|
+
? error
|
|
197
|
+
: new InvalidTokenError(getErrorMessage(error))
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const verifyToken =
|
|
202
|
+
(resolveConfig: Effect.Effect<ResolvedConfig, InvalidRequestError | InvalidTokenError>) => (token: string) =>
|
|
203
|
+
resolveConfig.pipe(
|
|
204
|
+
Effect.flatMap((config) => {
|
|
205
|
+
const options = {
|
|
206
|
+
clockTolerance: config.clockTolerance,
|
|
207
|
+
...(config.tokenSigningAlg ? { algorithms: [config.tokenSigningAlg] } : {}),
|
|
208
|
+
...(config.audience !== undefined ? { audience: config.audience } : {}),
|
|
209
|
+
...(config.issuer !== undefined ? { issuer: config.issuer } : {}),
|
|
210
|
+
...(config.maxTokenAge !== undefined ? { maxTokenAge: config.maxTokenAge } : {})
|
|
211
|
+
}
|
|
212
|
+
const verified = config.keyType === "jwks"
|
|
213
|
+
? Effect.tryPromise({
|
|
214
|
+
try: () => jwtVerify(token, config.key, options).then(({ protectedHeader }) => ({ protectedHeader })),
|
|
215
|
+
catch: (error) => new InvalidTokenError(getErrorMessage(error))
|
|
216
|
+
})
|
|
217
|
+
: Effect.tryPromise({
|
|
218
|
+
try: () => jwtVerify(token, config.key, options).then(({ protectedHeader }) => ({ protectedHeader })),
|
|
219
|
+
catch: (error) => new InvalidTokenError(getErrorMessage(error))
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
return verified.pipe(
|
|
223
|
+
Effect.flatMap(({ protectedHeader }) => {
|
|
224
|
+
const typ = protectedHeader.typ?.toLowerCase().replace(/^application\//, "")
|
|
225
|
+
return config.strict && typ !== "at+jwt"
|
|
226
|
+
? Effect.fail(new InvalidTokenError("Unexpected 'typ' value"))
|
|
227
|
+
: Effect.void
|
|
228
|
+
})
|
|
229
|
+
)
|
|
230
|
+
})
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
export const checkJWTI = (config: Config) => {
|
|
234
|
+
const resolveConfig = makeResolveConfig(config)
|
|
235
|
+
const verify = verifyToken(resolveConfig)
|
|
236
|
+
|
|
237
|
+
return Effect.fnUntraced(function*(headers: HttpHeaders.Headers) {
|
|
238
|
+
const token = yield* getAuthorizationToken(headers, config.authRequired !== false)
|
|
239
|
+
if (Option.isNone(token)) {
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
yield* verify(token.value)
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export const checkJwt = (config: Config) => {
|
|
248
|
+
const check = checkJWTI(config)
|
|
249
|
+
return HttpMiddleware.make((app) =>
|
|
250
|
+
Effect.gen(function*() {
|
|
251
|
+
const req = yield* HttpServerRequest.HttpServerRequest
|
|
252
|
+
const response = yield* check(req.headers).pipe(
|
|
253
|
+
Effect.catch((error: JwtError) =>
|
|
254
|
+
HttpServerResponse.json({ message: error.message }, {
|
|
255
|
+
status: error.status,
|
|
256
|
+
headers: HttpHeaders.fromInput(error.headers)
|
|
257
|
+
})
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
if (response) {
|
|
262
|
+
return response
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return yield* app
|
|
266
|
+
})
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export class JWTError extends Data.TaggedClass("JWTError")<{
|
|
271
|
+
error: JwtError
|
|
272
|
+
}> {}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Effect from "effect-app/Effect"
|
|
2
2
|
import { HttpHeaders, HttpServerResponse } from "effect-app/http"
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import * as S from "effect-app/Schema"
|
|
4
|
+
import { setupStreamingRequestContextFromCurrent } from "effect-app/setupRequest"
|
|
5
|
+
import { storeId } from "effect-app/Store"
|
|
6
|
+
import * as Duration from "effect/Duration"
|
|
7
|
+
import { pipe } from "effect/Function"
|
|
8
|
+
import * as Schedule from "effect/Schedule"
|
|
9
|
+
import * as Stream from "effect/Stream"
|
|
10
|
+
import { reportError } from "../errorReporter.js"
|
|
5
11
|
|
|
6
12
|
// Tell the client to retry every 10 seconds if connectivity is lost
|
|
7
13
|
const setRetry = Stream.succeed("retry: 10000")
|
|
@@ -9,29 +15,32 @@ const keepAlive = Stream.fromEffectSchedule(Effect.succeed(":keep-alive"), Sched
|
|
|
9
15
|
|
|
10
16
|
let connId = BigInt(0)
|
|
11
17
|
|
|
12
|
-
export const makeSSE = <A extends { id: any }, SI,
|
|
13
|
-
schema: S.Codec<A, SI,
|
|
18
|
+
export const makeSSE = <A extends { id: any }, SI, SRD, SRE>(
|
|
19
|
+
schema: S.Codec<A, SI, SRD, SRE>
|
|
14
20
|
) =>
|
|
15
21
|
<E, R>(events: Stream.Stream<{ evt: A; namespace: string }, E, R>) =>
|
|
16
22
|
Effect
|
|
17
23
|
.gen(function*() {
|
|
18
24
|
const id = connId++
|
|
19
|
-
const ctx = yield* Effect.
|
|
25
|
+
const ctx = yield* Effect.context<R | SRD | SRE>()
|
|
20
26
|
const res = HttpServerResponse.stream(
|
|
21
27
|
// workaround for different scoped behaviour for streams in Bun
|
|
22
28
|
// https://discord.com/channels/795981131316985866/1098177242598756412/1389646879675125861
|
|
23
29
|
Effect
|
|
24
30
|
.gen(function*() {
|
|
25
|
-
|
|
26
|
-
yield* Effect.
|
|
27
|
-
yield* Effect.
|
|
31
|
+
const ns = yield* storeId
|
|
32
|
+
yield* Effect.annotateCurrentSpan({ "network.connection.id": id.toString() })
|
|
33
|
+
yield* Effect.logInfo("$ start listening to events, id: " + id.toString() + ", ns: " + ns)
|
|
34
|
+
yield* Effect.addFinalizer(() =>
|
|
35
|
+
Effect.logInfo("$ end listening to events, id: " + id.toString() + ", ns: " + ns)
|
|
36
|
+
)
|
|
28
37
|
|
|
29
38
|
const enc = new TextEncoder()
|
|
30
39
|
|
|
31
|
-
const encode = S.encodeEffect(S.fromJsonString(schema))
|
|
40
|
+
const encode = S.encodeEffect(S.fromJsonString(S.toCodecJson(schema)))
|
|
32
41
|
|
|
33
42
|
const eventStream = Stream.mapEffect(
|
|
34
|
-
events,
|
|
43
|
+
Stream.filter(events, (_) => _.namespace === ns),
|
|
35
44
|
(_) =>
|
|
36
45
|
encode(_.evt)
|
|
37
46
|
.pipe(Effect.map((data) => `id: ${_.evt.id}\ndata: ${data}`))
|
|
@@ -42,7 +51,7 @@ export const makeSSE = <A extends { id: any }, SI, SR>(
|
|
|
42
51
|
Stream.merge(keepAlive),
|
|
43
52
|
// Keep this unary so pipe receives a function, not a Stream value.
|
|
44
53
|
(self) => Stream.merge(self, eventStream, { haltStrategy: "either" }),
|
|
45
|
-
Stream.tapCause((cause) => Effect.logError("SSE error", cause)),
|
|
54
|
+
Stream.tapCause((cause) => Effect.logError("SSE error, id: " + id.toString() + ", ns: " + ns, cause)),
|
|
46
55
|
Stream.map((_) => enc.encode(_ + "\n\n"))
|
|
47
56
|
)
|
|
48
57
|
|
|
@@ -65,4 +74,4 @@ export const makeSSE = <A extends { id: any }, SI, SR>(
|
|
|
65
74
|
)
|
|
66
75
|
return res
|
|
67
76
|
})
|
|
68
|
-
.pipe(Effect.tapCause(reportError("Request")),
|
|
77
|
+
.pipe(Effect.tapCause(reportError("Request")), setupStreamingRequestContextFromCurrent("events"))
|