@effect-app/infra 1.21.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @effect-app/infra
2
2
 
3
+ ## 1.23.0
4
+
5
+ ### Minor Changes
6
+
7
+ - feat: add SQLQueue
8
+
9
+ ## 1.22.0
10
+
11
+ ### Minor Changes
12
+
13
+ - be4ff0e: port auth
14
+
3
15
  ## 1.21.0
4
16
 
5
17
  ### Minor Changes
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.checkJwt = exports.checkJWTI = void 0;
7
+ var _effectApp = require("effect-app");
8
+ var _http = require("effect-app/http");
9
+ var _expressOauth2JwtBearer = require("express-oauth2-jwt-bearer");
10
+ /* eslint-disable @typescript-eslint/no-explicit-any */
11
+ /* eslint-disable unused-imports/no-unused-vars */
12
+
13
+ const checkJWTI = config => {
14
+ const mw = (0, _expressOauth2JwtBearer.auth)(config);
15
+ return _effectApp.Effect.gen(function* () {
16
+ const req = yield* _http.HttpServerRequest.HttpServerRequest;
17
+ return yield* _effectApp.Effect.async(cb => {
18
+ const next = err => {
19
+ if (!err) return cb(_effectApp.Effect.void);
20
+ if (err instanceof _expressOauth2JwtBearer.InsufficientScopeError || err instanceof _expressOauth2JwtBearer.InvalidRequestError || err instanceof _expressOauth2JwtBearer.InvalidTokenError || err instanceof _expressOauth2JwtBearer.UnauthorizedError) {
21
+ return cb(_effectApp.Effect.fail(err));
22
+ }
23
+ return _effectApp.Effect.die(err);
24
+ };
25
+ const r = {
26
+ headers: req.headers,
27
+ query: {},
28
+ body: {},
29
+ is: () => false
30
+ }; // is("urlencoded")
31
+ try {
32
+ mw(r, {}, next);
33
+ } catch (e) {
34
+ return cb(_effectApp.Effect.die(e));
35
+ }
36
+ });
37
+ });
38
+ };
39
+ exports.checkJWTI = checkJWTI;
40
+ const checkJwt = config => {
41
+ const check = checkJWTI(config);
42
+ return _http.HttpMiddleware.make(app => _effectApp.Effect.gen(function* () {
43
+ const response = yield* check.pipe(_effectApp.Effect.catchAll(e => _effectApp.Effect.succeed(_http.HttpServerResponse.unsafeJson({
44
+ message: e.message
45
+ }, {
46
+ status: e.status,
47
+ headers: _http.HttpHeaders.fromInput(e.headers)
48
+ }))));
49
+ if (response) {
50
+ return response;
51
+ }
52
+ return yield* app;
53
+ }));
54
+ };
55
+ exports.checkJwt = checkJwt;
56
+ //# sourceMappingURL=auth.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.cjs","names":["_effectApp","require","_http","_expressOauth2JwtBearer","checkJWTI","config","mw","auth","Effect","gen","req","HttpServerRequest","async","cb","next","err","void","InsufficientScopeError","InvalidRequestError","InvalidTokenError","UnauthorizedError","fail","die","r","headers","query","body","is","e","exports","checkJwt","check","HttpMiddleware","make","app","response","pipe","catchAll","succeed","HttpServerResponse","unsafeJson","message","status","HttpHeaders","fromInput"],"sources":["../../../src/api/internal/auth.ts"],"sourcesContent":[null],"mappings":";;;;;;AAEA,IAAAA,UAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAD,OAAA;AACA,IAAAE,uBAAA,GAAAF,OAAA;AAJA;AACA;;AAgBO,MAAMG,SAAS,GAAIC,MAAc,IAAI;EAC1C,MAAMC,EAAE,GAAG,IAAAC,4BAAI,EAACF,MAAM,CAAC;EACvB,OAAOG,iBAAM,CAACC,GAAG,CAAC,aAAS;IACzB,MAAMC,GAAG,GAAG,OAAOC,uBAAiB,CAACA,iBAAiB;IAEtD,OAAO,OAAOH,iBAAM,CAACI,KAAK,CAIvBC,EAAE,IAAI;MACL,MAAMC,IAAI,GAAIC,GAAa,IAAI;QAC7B,IAAI,CAACA,GAAG,EAAE,OAAOF,EAAE,CAACL,iBAAM,CAACQ,IAAI,CAAC;QAChC,IACED,GAAG,YAAYE,8CAAsB,IAClCF,GAAG,YAAYG,2CAAmB,IAClCH,GAAG,YAAYI,yCAAiB,IAChCJ,GAAG,YAAYK,yCAAiB,EACnC;UACA,OAAOP,EAAE,CAACL,iBAAM,CAACa,IAAI,CAACN,GAAG,CAAC,CAAC;QAC7B;QACA,OAAOP,iBAAM,CAACc,GAAG,CAACP,GAAG,CAAC;MACxB,CAAC;MACD,MAAMQ,CAAC,GAAG;QAAEC,OAAO,EAAEd,GAAG,CAACc,OAAO;QAAEC,KAAK,EAAE,EAAE;QAAEC,IAAI,EAAE,EAAE;QAAEC,EAAE,EAAEA,CAAA,KAAM;MAAK,CAAE,EAAC;MACzE,IAAI;QACFrB,EAAE,CAACiB,CAAQ,EAAE,EAAS,EAAET,IAAI,CAAC;MAC/B,CAAC,CAAC,OAAOc,CAAC,EAAE;QACV,OAAOf,EAAE,CAACL,iBAAM,CAACc,GAAG,CAACM,CAAC,CAAC,CAAC;MAC1B;IACF,CAAC,CACF;EACH,CAAC,CAAC;AACJ,CAAC;AAAAC,OAAA,CAAAzB,SAAA,GAAAA,SAAA;AAEM,MAAM0B,QAAQ,GAAIzB,MAAc,IAAI;EACzC,MAAM0B,KAAK,GAAG3B,SAAS,CAACC,MAAM,CAAC;EAC/B,OAAO2B,oBAAc,CAACC,IAAI,CAAEC,GAAG,IAC7B1B,iBAAM,CAACC,GAAG,CAAC,aAAS;IAClB,MAAM0B,QAAQ,GAAG,OAAOJ,KAAK,CAACK,IAAI,CAAC5B,iBAAM,CAAC6B,QAAQ,CAAET,CAAC,IACnDpB,iBAAM,CAAC8B,OAAO,CACZC,wBAAkB,CAACC,UAAU,CAAC;MAAEC,OAAO,EAAEb,CAAC,CAACa;IAAO,CAAE,EAAE;MACpDC,MAAM,EAAEd,CAAC,CAACc,MAAM;MAChBlB,OAAO,EAAEmB,iBAAW,CAACC,SAAS,CAAChB,CAAC,CAACJ,OAAO;KACzC,CAAC,CACH,CACF,CAAC;IACF,IAAIW,QAAQ,EAAE;MACZ,OAAOA,QAAQ;IACjB;IACA,OAAO,OAAOD,GAAG;EACnB,CAAC,CAAC,CACH;AACH,CAAC;AAAAL,OAAA,CAAAC,QAAA,GAAAA,QAAA","ignoreList":[]}
@@ -13,6 +13,18 @@ var _exportNames = {
13
13
  };
14
14
  exports.uuidLogAnnotation = exports.errorLog = exports.endpointCallsMetric = exports.cors = exports.basicAuth = exports.accessLog = void 0;
15
15
  var internal = _interopRequireWildcard(require("./internal/middlewares.cjs"));
16
+ var _auth = require("./internal/auth.cjs");
17
+ Object.keys(_auth).forEach(function (key) {
18
+ if (key === "default" || key === "__esModule") return;
19
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
20
+ if (key in exports && exports[key] === _auth[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _auth[key];
25
+ }
26
+ });
27
+ });
16
28
  var _events = require("./internal/events.cjs");
17
29
  Object.keys(_events).forEach(function (key) {
18
30
  if (key === "default" || key === "__esModule") return;
@@ -1 +1 @@
1
- {"version":3,"file":"middlewares.cjs","names":["internal","_interopRequireWildcard","require","_events","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_health","_RequestContextMiddleware","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","n","__proto__","a","getOwnPropertyDescriptor","u","i","set","accessLog","uuidLogAnnotation","endpointCallsMetric","errorLog","basicAuth","cors"],"sources":["../../src/api/middlewares.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"middlewares.cjs","names":["internal","_interopRequireWildcard","require","_auth","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_events","_health","_RequestContextMiddleware","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","n","__proto__","a","getOwnPropertyDescriptor","u","i","set","accessLog","uuidLogAnnotation","endpointCallsMetric","errorLog","basicAuth","cors"],"sources":["../../src/api/middlewares.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.QueueId = void 0;
7
+ exports.makeSQLQueue = makeSQLQueue;
8
+ var _setupRequest = require("@effect-app/infra/api/setupRequest");
9
+ var _RequestContext = require("@effect-app/infra/RequestContext");
10
+ var _errors = require("@effect-app/infra/services/QueueMaker/errors");
11
+ var _service = require("@effect-app/infra/services/QueueMaker/service");
12
+ var _RequestContextContainer = require("@effect-app/infra/services/RequestContextContainer");
13
+ var _sql = require("@effect/sql");
14
+ var _dateFns = require("date-fns");
15
+ var _effectApp = require("effect-app");
16
+ var _ids = require("effect-app/ids");
17
+ var _schema = require("effect-app/schema");
18
+ var _utils = require("effect-app/utils");
19
+ const QueueId = exports.QueueId = _effectApp.S.Number.pipe(_effectApp.S.brand("QueueId"));
20
+ /**
21
+ * Currently limited to one process draining at a time, due to in-process Semaphore instead of row-level locking.
22
+ */
23
+ function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
24
+ return _effectApp.Effect.gen(function* () {
25
+ const base = {
26
+ id: _sql.Model.Generated(QueueId),
27
+ meta: _sql.Model.JsonFromString(_service.QueueMeta),
28
+ name: _effectApp.S.NonEmptyString255,
29
+ createdAt: _sql.Model.DateTimeInsert,
30
+ updatedAt: _sql.Model.DateTimeUpdate,
31
+ // TODO: at+owner
32
+ processingAt: _sql.Model.FieldOption(_effectApp.S.Date),
33
+ finishedAt: _sql.Model.FieldOption(_effectApp.S.Date)
34
+ // TODO: record locking.. / optimistic locking
35
+ // rowVersion: Model.DateTimeFromNumberWithNow
36
+ };
37
+ class Queue extends _sql.Model.Class("Queue")({
38
+ body: _sql.Model.JsonFromString(schema),
39
+ ...base
40
+ }) {}
41
+ class Drain extends _sql.Model.Class("Drain")({
42
+ body: _sql.Model.JsonFromString(drainSchema),
43
+ ...base
44
+ }) {}
45
+ const sql = yield* _sql.SqlClient.SqlClient;
46
+ const queueRepo = yield* _sql.Model.makeRepository(Queue, {
47
+ tableName: "queue",
48
+ spanPrefix: "QueueRepo",
49
+ idColumn: "id"
50
+ });
51
+ const drainRepo = yield* _sql.Model.makeRepository(Drain, {
52
+ tableName: "queue",
53
+ spanPrefix: "DrainRepo",
54
+ idColumn: "id"
55
+ });
56
+ const decodeDrain = _effectApp.S.decode(Drain);
57
+ const drain = () => {
58
+ const limit = (0, _dateFns.subMinutes)(new Date(), 15);
59
+ return sql`SELECT *
60
+ FROM queue
61
+ WHERE name = ${queueDrainName} AND finishedAt IS NULL AND (processingAt IS NULL OR processingAt < ${limit.getTime()})
62
+ LIMIT 1`;
63
+ };
64
+ // temporary workaround until we have a SQLite rowversion..
65
+ const lock = yield* _effectApp.Effect.makeSemaphore(1);
66
+ const q = {
67
+ offer: (body, meta) => _effectApp.Effect.gen(function* () {
68
+ yield* queueRepo.insert(Queue.insert.make({
69
+ body,
70
+ meta,
71
+ name: queueName,
72
+ processingAt: _effectApp.Option.none(),
73
+ finishedAt: _effectApp.Option.none()
74
+ }));
75
+ }),
76
+ take: _effectApp.Effect.gen(function* () {
77
+ while (true) {
78
+ const first = yield* lock.withPermits(1)(_effectApp.Effect.gen(function* () {
79
+ const [first] = yield* drain();
80
+ if (first) {
81
+ const dec = yield* decodeDrain(first);
82
+ const {
83
+ createdAt,
84
+ updatedAt,
85
+ ...rest
86
+ } = dec;
87
+ yield* drainRepo.update(Drain.update.make({
88
+ ...rest,
89
+ processingAt: _effectApp.Option.some(new Date())
90
+ }));
91
+ return dec;
92
+ }
93
+ return null;
94
+ }));
95
+ if (first) return first;
96
+ yield* _effectApp.Effect.sleep(250);
97
+ }
98
+ }),
99
+ finish: ({
100
+ createdAt,
101
+ updatedAt,
102
+ ...q
103
+ }) => drainRepo.update(Drain.update.make({
104
+ ...q,
105
+ finishedAt: _effectApp.Option.some(new Date())
106
+ }))
107
+ };
108
+ const rcc = yield* _RequestContextContainer.RequestContextContainer;
109
+ return {
110
+ publish: (...messages) => _effectApp.Effect.gen(function* ($) {
111
+ const requestContext = yield* $(rcc.requestContext);
112
+ const span = yield* $(_effectApp.Effect.serviceOption(_effectApp.Tracer.ParentSpan));
113
+ return yield* $(_effectApp.Effect.forEach(messages, m => q.offer(m, {
114
+ requestContext: new _RequestContext.RequestContext(requestContext),
115
+ // workaround Schema expecting exact class
116
+ span: _effectApp.Option.getOrUndefined(span)
117
+ }), {
118
+ discard: true
119
+ }));
120
+ }).pipe(_effectApp.Effect.withSpan("queue.publish: " + queueName, {
121
+ captureStackTrace: false,
122
+ kind: "producer",
123
+ attributes: {
124
+ "message_tags": messages.map(_ => _._tag)
125
+ }
126
+ })),
127
+ drain: (handleEvent, sessionId) => _effectApp.Effect.gen(function* () {
128
+ const silenceAndReportError = (0, _errors.reportNonInterruptedFailure)({
129
+ name: "MemQueue.drain." + queueDrainName
130
+ });
131
+ const processMessage = msg => _effectApp.Effect.succeed(msg).pipe(_effectApp.Effect.flatMap(({
132
+ body,
133
+ meta
134
+ }) => {
135
+ let effect = _effectApp.Effect.logDebug(`[${queueDrainName}] Processing incoming message`).pipe(_effectApp.Effect.annotateLogs({
136
+ body: (0, _utils.pretty)(body),
137
+ meta: (0, _utils.pretty)(meta)
138
+ }), _effectApp.Effect.zipRight(handleEvent(body)), silenceAndReportError, _ => (0, _setupRequest.setupRequestContext)(_, _RequestContext.RequestContext.inherit(meta.requestContext, {
139
+ id: (0, _ids.RequestId)(body.id),
140
+ locale: "en",
141
+ name: (0, _schema.NonEmptyString255)(`${queueDrainName}.${body._tag}`)
142
+ })), _effectApp.Effect.withSpan(`queue.drain: ${queueDrainName}.${body._tag}`, {
143
+ captureStackTrace: false,
144
+ kind: "consumer",
145
+ attributes: {
146
+ "queue.name": queueDrainName,
147
+ "queue.sessionId": sessionId,
148
+ "queue.input": body
149
+ }
150
+ }));
151
+ if (meta.span) {
152
+ effect = _effectApp.Effect.withParentSpan(effect, _effectApp.Tracer.externalSpan(meta.span));
153
+ }
154
+ return effect;
155
+ }));
156
+ return yield* q.take.pipe(_effectApp.Effect.flatMap(x => processMessage(x).pipe(_effectApp.Effect.uninterruptible, _effectApp.Effect.fork, _effectApp.Effect.flatMap(_effectApp.Fiber.join), _effectApp.Effect.tap(q.finish(x)))), silenceAndReportError, _effectApp.Effect.forever);
157
+ })
158
+ };
159
+ });
160
+ }
161
+ //# sourceMappingURL=SQLQueue.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SQLQueue.cjs","names":["_setupRequest","require","_RequestContext","_errors","_service","_RequestContextContainer","_sql","_dateFns","_effectApp","_ids","_schema","_utils","QueueId","exports","S","Number","pipe","brand","makeSQLQueue","queueName","queueDrainName","schema","drainSchema","Effect","gen","base","id","Model","Generated","meta","JsonFromString","QueueMeta","name","NonEmptyString255","createdAt","DateTimeInsert","updatedAt","DateTimeUpdate","processingAt","FieldOption","Date","finishedAt","Queue","Class","body","Drain","sql","SqlClient","queueRepo","makeRepository","tableName","spanPrefix","idColumn","drainRepo","decodeDrain","decode","drain","limit","subMinutes","getTime","lock","makeSemaphore","q","offer","insert","make","Option","none","take","first","withPermits","dec","rest","update","some","sleep","finish","rcc","RequestContextContainer","publish","messages","$","requestContext","span","serviceOption","Tracer","ParentSpan","forEach","m","RequestContext","getOrUndefined","discard","withSpan","captureStackTrace","kind","attributes","map","_","_tag","handleEvent","sessionId","silenceAndReportError","reportNonInterruptedFailure","processMessage","msg","succeed","flatMap","effect","logDebug","annotateLogs","pretty","zipRight","setupRequestContext","inherit","RequestId","locale","withParentSpan","externalSpan","x","uninterruptible","fork","Fiber","join","tap","forever"],"sources":["../../../src/services/QueueMaker/SQLQueue.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,8 @@
1
+ import { Effect } from "effect-app";
2
+ import { HttpServerRequest, HttpServerResponse } from "effect-app/http";
3
+ import { auth, UnauthorizedError } from "express-oauth2-jwt-bearer";
4
+ type Config = Parameters<typeof auth>[0];
5
+ export declare const checkJWTI: (config: Config) => Effect.Effect<void, UnauthorizedError, HttpServerRequest.HttpServerRequest>;
6
+ export declare const checkJwt: (config: Config) => <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<HttpServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
7
+ export {};
8
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/api/internal/auth.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAA+B,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpG,OAAO,EACL,IAAI,EAIJ,iBAAiB,EAClB,MAAM,2BAA2B,CAAA;AAMlC,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;AACxC,eAAO,MAAM,SAAS,WAAY,MAAM,gFA+BvC,CAAA;AAED,eAAO,MAAM,QAAQ,WAAY,MAAM,sKAkBtC,CAAA"}
@@ -0,0 +1,45 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable unused-imports/no-unused-vars */
3
+ import { Effect } from "effect-app";
4
+ import { HttpHeaders, HttpMiddleware, HttpServerRequest, HttpServerResponse } from "effect-app/http";
5
+ import { auth, InsufficientScopeError, InvalidRequestError, InvalidTokenError, UnauthorizedError } from "express-oauth2-jwt-bearer";
6
+ export const checkJWTI = (config) => {
7
+ const mw = auth(config);
8
+ return Effect.gen(function* () {
9
+ const req = yield* HttpServerRequest.HttpServerRequest;
10
+ return yield* Effect.async((cb) => {
11
+ const next = (err) => {
12
+ if (!err)
13
+ return cb(Effect.void);
14
+ if (err instanceof InsufficientScopeError
15
+ || err instanceof InvalidRequestError
16
+ || err instanceof InvalidTokenError
17
+ || err instanceof UnauthorizedError) {
18
+ return cb(Effect.fail(err));
19
+ }
20
+ return Effect.die(err);
21
+ };
22
+ const r = { headers: req.headers, query: {}, body: {}, is: () => false }; // is("urlencoded")
23
+ try {
24
+ mw(r, {}, next);
25
+ }
26
+ catch (e) {
27
+ return cb(Effect.die(e));
28
+ }
29
+ });
30
+ });
31
+ };
32
+ export const checkJwt = (config) => {
33
+ const check = checkJWTI(config);
34
+ return HttpMiddleware.make((app) => Effect.gen(function* () {
35
+ const response = yield* check.pipe(Effect.catchAll((e) => Effect.succeed(HttpServerResponse.unsafeJson({ message: e.message }, {
36
+ status: e.status,
37
+ headers: HttpHeaders.fromInput(e.headers)
38
+ }))));
39
+ if (response) {
40
+ return response;
41
+ }
42
+ return yield* app;
43
+ }));
44
+ };
45
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcGkvaW50ZXJuYWwvYXV0aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx1REFBdUQ7QUFDdkQsa0RBQWtEO0FBQ2xELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDbkMsT0FBTyxFQUFFLFdBQVcsRUFBRSxjQUFjLEVBQUUsaUJBQWlCLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUNwRyxPQUFPLEVBQ0wsSUFBSSxFQUNKLHNCQUFzQixFQUN0QixtQkFBbUIsRUFDbkIsaUJBQWlCLEVBQ2pCLGlCQUFpQixFQUNsQixNQUFNLDJCQUEyQixDQUFBO0FBT2xDLE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxDQUFDLE1BQWMsRUFBRSxFQUFFO0lBQzFDLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUN2QixPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDO1FBQ3pCLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxDQUFDLGlCQUFpQixDQUFDLGlCQUFpQixDQUFBO1FBRXRELE9BQU8sS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FJeEIsQ0FBQyxFQUFFLEVBQUUsRUFBRTtZQUNMLE1BQU0sSUFBSSxHQUFHLENBQUMsR0FBYSxFQUFFLEVBQUU7Z0JBQzdCLElBQUksQ0FBQyxHQUFHO29CQUFFLE9BQU8sRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQTtnQkFDaEMsSUFDRSxHQUFHLFlBQVksc0JBQXNCO3VCQUNsQyxHQUFHLFlBQVksbUJBQW1CO3VCQUNsQyxHQUFHLFlBQVksaUJBQWlCO3VCQUNoQyxHQUFHLFlBQVksaUJBQWlCLEVBQ25DLENBQUM7b0JBQ0QsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFBO2dCQUM3QixDQUFDO2dCQUNELE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtZQUN4QixDQUFDLENBQUE7WUFDRCxNQUFNLENBQUMsR0FBRyxFQUFFLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUEsQ0FBQyxtQkFBbUI7WUFDNUYsSUFBSSxDQUFDO2dCQUNILEVBQUUsQ0FBQyxDQUFRLEVBQUUsRUFBUyxFQUFFLElBQUksQ0FBQyxDQUFBO1lBQy9CLENBQUM7WUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUNYLE9BQU8sRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtZQUMxQixDQUFDO1FBQ0gsQ0FBQyxDQUNGLENBQUE7SUFDSCxDQUFDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQTtBQUVELE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBRyxDQUFDLE1BQWMsRUFBRSxFQUFFO0lBQ3pDLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUMvQixPQUFPLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUNqQyxNQUFNLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQztRQUNsQixNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUN2RCxNQUFNLENBQUMsT0FBTyxDQUNaLGtCQUFrQixDQUFDLFVBQVUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDcEQsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNO1lBQ2hCLE9BQU8sRUFBRSxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7U0FDMUMsQ0FBQyxDQUNILENBQ0YsQ0FBQyxDQUFBO1FBQ0YsSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUNiLE9BQU8sUUFBUSxDQUFBO1FBQ2pCLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQTtJQUNuQixDQUFDLENBQUMsQ0FDSCxDQUFBO0FBQ0gsQ0FBQyxDQUFBIn0=
@@ -6,6 +6,7 @@
6
6
  import type * as App from "@effect/platform/HttpApp";
7
7
  import type { Effect } from "effect-app";
8
8
  import type { NotLoggedInError } from "../errors.js";
9
+ export * from "./internal/auth.js";
9
10
  export * from "./internal/events.js";
10
11
  export * from "./internal/health.js";
11
12
  export * from "./internal/RequestContextMiddleware.js";
@@ -1 +1 @@
1
- {"version":3,"file":"middlewares.d.ts","sourceRoot":"","sources":["../../src/api/middlewares.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,KAAK,GAAG,MAAM,0BAA0B,CAAA;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAGpD,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAA;AACpC,cAAc,wCAAwC,CAAA;AAEtD;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE,CACtB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,KACjC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAsB,CAAA;AAE7E;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,EAAE,CAC9B,gBAAgB,CAAC,EAAE,MAAM,KACtB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAA8B,CAAA;AAErF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAC3C,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KACnB,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAgC,CAAA;AAErD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAqB,CAAA;AAE9F;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,EAC5B,gBAAgB,EAAE,CAChB,WAAW,EAAE,oBAAoB,KAC9B,MAAM,CAAC,CAAC,EAAE,gBAAgB,EAAE,EAAE,CAAC,EACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B,CAAC,KACC,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAsB,CAAA;AAErF;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,OAAO,CAAA;CACrB;AAED;;;;;GAKG;AACH,eAAO,MAAM,IAAI,EAAE,CACjB,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,KAC3B,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAiB,CAAA"}
1
+ {"version":3,"file":"middlewares.d.ts","sourceRoot":"","sources":["../../src/api/middlewares.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,KAAK,GAAG,MAAM,0BAA0B,CAAA;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAGpD,cAAc,oBAAoB,CAAA;AAClC,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAA;AACpC,cAAc,wCAAwC,CAAA;AAEtD;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE,CACtB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,KACjC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAsB,CAAA;AAE7E;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,EAAE,CAC9B,gBAAgB,CAAC,EAAE,MAAM,KACtB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAA8B,CAAA;AAErF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAC3C,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KACnB,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAgC,CAAA;AAErD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAqB,CAAA;AAE9F;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,EAC5B,gBAAgB,EAAE,CAChB,WAAW,EAAE,oBAAoB,KAC9B,MAAM,CAAC,CAAC,EAAE,gBAAgB,EAAE,EAAE,CAAC,EACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B,CAAC,KACC,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAsB,CAAA;AAErF;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,OAAO,CAAA;CACrB;AAED;;;;;GAKG;AACH,eAAO,MAAM,IAAI,EAAE,CACjB,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,KAC3B,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAiB,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import * as internal from "./internal/middlewares.js";
2
+ export * from "./internal/auth.js";
2
3
  export * from "./internal/events.js";
3
4
  export * from "./internal/health.js";
4
5
  export * from "./internal/RequestContextMiddleware.js";
@@ -51,4 +52,4 @@ export const basicAuth = internal.basicAuth;
51
52
  * @since 1.0.0
52
53
  */
53
54
  export const cors = internal.cors;
54
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL21pZGRsZXdhcmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE9BQU8sS0FBSyxRQUFRLE1BQU0sMkJBQTJCLENBQUE7QUFFckQsY0FBYyxzQkFBc0IsQ0FBQTtBQUNwQyxjQUFjLHNCQUFzQixDQUFBO0FBQ3BDLGNBQWMsd0NBQXdDLENBQUE7QUFFdEQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FFcUMsUUFBUSxDQUFDLFNBQVMsQ0FBQTtBQUU3RTs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FFNkIsUUFBUSxDQUFDLGlCQUFpQixDQUFBO0FBRXJGOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUVQLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQTtBQUVyRDs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBd0QsUUFBUSxDQUFDLFFBQVEsQ0FBQTtBQVc5Rjs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FRNkMsUUFBUSxDQUFDLFNBQVMsQ0FBQTtBQWVyRjs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLElBQUksR0FFMEMsUUFBUSxDQUFDLElBQUksQ0FBQSJ9
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL21pZGRsZXdhcmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE9BQU8sS0FBSyxRQUFRLE1BQU0sMkJBQTJCLENBQUE7QUFFckQsY0FBYyxvQkFBb0IsQ0FBQTtBQUNsQyxjQUFjLHNCQUFzQixDQUFBO0FBQ3BDLGNBQWMsc0JBQXNCLENBQUE7QUFDcEMsY0FBYyx3Q0FBd0MsQ0FBQTtBQUV0RDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUVxQyxRQUFRLENBQUMsU0FBUyxDQUFBO0FBRTdFOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUU2QixRQUFRLENBQUMsaUJBQWlCLENBQUE7QUFFckY7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBRVAsUUFBUSxDQUFDLG1CQUFtQixDQUFBO0FBRXJEOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUF3RCxRQUFRLENBQUMsUUFBUSxDQUFBO0FBVzlGOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQVE2QyxRQUFRLENBQUMsU0FBUyxDQUFBO0FBZXJGOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sSUFBSSxHQUUwQyxRQUFRLENBQUMsSUFBSSxDQUFBIn0=
@@ -0,0 +1,22 @@
1
+ import { RequestContextContainer } from "@effect-app/infra/services/RequestContextContainer";
2
+ import { SqlClient } from "@effect/sql";
3
+ import { Effect, S, Tracer } from "effect-app";
4
+ import { NonEmptyString255 } from "effect-app/schema";
5
+ export declare const QueueId: S.brand<typeof import("@effect/schema/Schema").Number & {
6
+ withDefault: S.PropertySignature<":", number, never, ":", number, true, never>;
7
+ }, "QueueId">;
8
+ export type QueueId = typeof QueueId.Type;
9
+ /**
10
+ * Currently limited to one process draining at a time, due to in-process Semaphore instead of row-level locking.
11
+ */
12
+ export declare function makeSQLQueue<Evt extends {
13
+ id: S.StringId;
14
+ _tag: string;
15
+ }, DrainEvt extends {
16
+ id: S.StringId;
17
+ _tag: string;
18
+ }, EvtE, DrainEvtE>(queueName: NonEmptyString255, queueDrainName: NonEmptyString255, schema: S.Schema<Evt, EvtE>, drainSchema: S.Schema<DrainEvt, DrainEvtE>): Effect.Effect<{
19
+ publish: (messages_0: Evt, ...messages: Evt[]) => Effect.Effect<void, never, never>;
20
+ drain: <DrainE, DrainR>(handleEvent: (ks: DrainEvt) => Effect<void, DrainE, DrainR>, sessionId?: string) => Effect.Effect<never, never, RequestContextContainer | import("../Store/ContextMapContainer.js").ContextMapContainer | Exclude<Exclude<Exclude<DrainR, Tracer.ParentSpan>, never>, Tracer.ParentSpan>>;
21
+ }, never, RequestContextContainer | SqlClient.SqlClient>;
22
+ //# sourceMappingURL=SQLQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SQLQueue.d.ts","sourceRoot":"","sources":["../../../src/services/QueueMaker/SQLQueue.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oDAAoD,CAAA;AAC5F,OAAO,EAAS,SAAS,EAAE,MAAM,aAAa,CAAA;AAE9C,OAAO,EAAE,MAAM,EAAiB,CAAC,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAE7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAGrD,eAAO,MAAM,OAAO;;aAAoC,CAAA;AACxD,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAEzC;;GAEG;AACH,wBAAgB,YAAY,CAC1B,GAAG,SAAS;IAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC5C,QAAQ,SAAS;IAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACjD,IAAI,EACJ,SAAS,EAET,SAAS,EAAE,iBAAiB,EAC5B,cAAc,EAAE,iBAAiB,EACjC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,EAC3B,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC;;YAgH9B,MAAM,EAAE,MAAM,eACP,CAAC,EAAE,EAAE,QAAQ,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,cAC/C,MAAM;yDA0DzB"}
@@ -0,0 +1,143 @@
1
+ import { setupRequestContext } from "@effect-app/infra/api/setupRequest";
2
+ import { RequestContext } from "@effect-app/infra/RequestContext";
3
+ import { reportNonInterruptedFailure } from "@effect-app/infra/services/QueueMaker/errors";
4
+ import { QueueMeta } from "@effect-app/infra/services/QueueMaker/service";
5
+ import { RequestContextContainer } from "@effect-app/infra/services/RequestContextContainer";
6
+ import { Model, SqlClient } from "@effect/sql";
7
+ import { subMinutes } from "date-fns";
8
+ import { Effect, Fiber, Option, S, Tracer } from "effect-app";
9
+ import { RequestId } from "effect-app/ids";
10
+ import { NonEmptyString255 } from "effect-app/schema";
11
+ import { pretty } from "effect-app/utils";
12
+ export const QueueId = S.Number.pipe(S.brand("QueueId"));
13
+ /**
14
+ * Currently limited to one process draining at a time, due to in-process Semaphore instead of row-level locking.
15
+ */
16
+ export function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
17
+ return Effect.gen(function* () {
18
+ const base = {
19
+ id: Model.Generated(QueueId),
20
+ meta: Model.JsonFromString(QueueMeta),
21
+ name: S.NonEmptyString255,
22
+ createdAt: Model.DateTimeInsert,
23
+ updatedAt: Model.DateTimeUpdate,
24
+ // TODO: at+owner
25
+ processingAt: Model.FieldOption(S.Date),
26
+ finishedAt: Model.FieldOption(S.Date)
27
+ // TODO: record locking.. / optimistic locking
28
+ // rowVersion: Model.DateTimeFromNumberWithNow
29
+ };
30
+ class Queue extends Model.Class("Queue")({
31
+ body: Model.JsonFromString(schema),
32
+ ...base
33
+ }) {
34
+ }
35
+ class Drain extends Model.Class("Drain")({
36
+ body: Model.JsonFromString(drainSchema),
37
+ ...base
38
+ }) {
39
+ }
40
+ const sql = yield* SqlClient.SqlClient;
41
+ const queueRepo = yield* Model.makeRepository(Queue, {
42
+ tableName: "queue",
43
+ spanPrefix: "QueueRepo",
44
+ idColumn: "id"
45
+ });
46
+ const drainRepo = yield* Model.makeRepository(Drain, {
47
+ tableName: "queue",
48
+ spanPrefix: "DrainRepo",
49
+ idColumn: "id"
50
+ });
51
+ const decodeDrain = S.decode(Drain);
52
+ const drain = () => {
53
+ const limit = subMinutes(new Date(), 15);
54
+ return sql `SELECT *
55
+ FROM queue
56
+ WHERE name = ${queueDrainName} AND finishedAt IS NULL AND (processingAt IS NULL OR processingAt < ${limit.getTime()})
57
+ LIMIT 1`;
58
+ };
59
+ // temporary workaround until we have a SQLite rowversion..
60
+ const lock = yield* Effect.makeSemaphore(1);
61
+ const q = {
62
+ offer: (body, meta) => Effect.gen(function* () {
63
+ yield* queueRepo.insert(Queue.insert.make({
64
+ body,
65
+ meta,
66
+ name: queueName,
67
+ processingAt: Option.none(),
68
+ finishedAt: Option.none()
69
+ }));
70
+ }),
71
+ take: Effect.gen(function* () {
72
+ while (true) {
73
+ const first = yield* lock.withPermits(1)(Effect.gen(function* () {
74
+ const [first] = yield* drain();
75
+ if (first) {
76
+ const dec = yield* decodeDrain(first);
77
+ const { createdAt, updatedAt, ...rest } = dec;
78
+ yield* drainRepo.update(Drain.update.make({ ...rest, processingAt: Option.some(new Date()) }));
79
+ return dec;
80
+ }
81
+ return null;
82
+ }));
83
+ if (first)
84
+ return first;
85
+ yield* Effect.sleep(250);
86
+ }
87
+ }),
88
+ finish: ({ createdAt, updatedAt, ...q }) => drainRepo.update(Drain.update.make({ ...q, finishedAt: Option.some(new Date()) }))
89
+ };
90
+ const rcc = yield* RequestContextContainer;
91
+ return {
92
+ publish: (...messages) => Effect
93
+ .gen(function* ($) {
94
+ const requestContext = yield* $(rcc.requestContext);
95
+ const span = yield* $(Effect.serviceOption(Tracer.ParentSpan));
96
+ return yield* $(Effect
97
+ .forEach(messages, (m) => q.offer(m, {
98
+ requestContext: new RequestContext(requestContext), // workaround Schema expecting exact class
99
+ span: Option.getOrUndefined(span)
100
+ }), {
101
+ discard: true
102
+ }));
103
+ })
104
+ .pipe(Effect.withSpan("queue.publish: " + queueName, {
105
+ captureStackTrace: false,
106
+ kind: "producer",
107
+ attributes: { "message_tags": messages.map((_) => _._tag) }
108
+ })),
109
+ drain: (handleEvent, sessionId) => Effect.gen(function* () {
110
+ const silenceAndReportError = reportNonInterruptedFailure({ name: "MemQueue.drain." + queueDrainName });
111
+ const processMessage = (msg) => Effect
112
+ .succeed(msg)
113
+ .pipe(Effect
114
+ .flatMap(({ body, meta }) => {
115
+ let effect = Effect
116
+ .logDebug(`[${queueDrainName}] Processing incoming message`)
117
+ .pipe(Effect.annotateLogs({ body: pretty(body), meta: pretty(meta) }), Effect.zipRight(handleEvent(body)), silenceAndReportError, (_) => setupRequestContext(_, RequestContext.inherit(meta.requestContext, {
118
+ id: RequestId(body.id),
119
+ locale: "en",
120
+ name: NonEmptyString255(`${queueDrainName}.${body._tag}`)
121
+ })), Effect
122
+ .withSpan(`queue.drain: ${queueDrainName}.${body._tag}`, {
123
+ captureStackTrace: false,
124
+ kind: "consumer",
125
+ attributes: {
126
+ "queue.name": queueDrainName,
127
+ "queue.sessionId": sessionId,
128
+ "queue.input": body
129
+ }
130
+ }));
131
+ if (meta.span) {
132
+ effect = Effect.withParentSpan(effect, Tracer.externalSpan(meta.span));
133
+ }
134
+ return effect;
135
+ }));
136
+ return yield* q
137
+ .take
138
+ .pipe(Effect.flatMap((x) => processMessage(x).pipe(Effect.uninterruptible, Effect.fork, Effect.flatMap(Fiber.join), Effect.tap(q.finish(x)))), silenceAndReportError, Effect.forever);
139
+ })
140
+ };
141
+ });
142
+ }
143
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU1FMUXVldWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvUXVldWVNYWtlci9TUUxRdWV1ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQTtBQUN4RSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0NBQWtDLENBQUE7QUFDakUsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sOENBQThDLENBQUE7QUFFMUYsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLCtDQUErQyxDQUFBO0FBQ3pFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLG9EQUFvRCxDQUFBO0FBQzVGLE9BQU8sRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzlDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxVQUFVLENBQUE7QUFDckMsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDN0QsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBQzFDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ3JELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUV6QyxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFBO0FBR3hEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FNMUIsU0FBNEIsRUFDNUIsY0FBaUMsRUFDakMsTUFBMkIsRUFDM0IsV0FBMEM7SUFFMUMsT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQztRQUN6QixNQUFNLElBQUksR0FBRztZ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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/infra",
3
- "version": "1.21.0",
3
+ "version": "1.23.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -19,8 +19,8 @@
19
19
  "pure-rand": "6.1.0",
20
20
  "redlock": "^4.2.0",
21
21
  "@effect-app/core": "1.10.1",
22
- "@effect-app/infra-adapters": "1.11.3",
23
22
  "effect-app": "1.17.1",
23
+ "@effect-app/infra-adapters": "1.11.3",
24
24
  "@effect-app/schema": "1.12.1"
25
25
  },
26
26
  "devDependencies": {
@@ -44,6 +44,7 @@
44
44
  "express": "^4.21.0",
45
45
  "@effect/platform": "^0.66.2",
46
46
  "@effect/schema": "^0.74.1",
47
+ "@effect/sql": "^0.14.0",
47
48
  "@effect/vitest": "^0.10.5",
48
49
  "effect": "^3.8.4"
49
50
  },
@@ -415,6 +416,16 @@
415
416
  "default": "./_cjs/services/OperationsRepo.cjs"
416
417
  }
417
418
  },
419
+ "./services/QueueMaker/SQLQueue": {
420
+ "import": {
421
+ "types": "./dist/services/QueueMaker/SQLQueue.d.ts",
422
+ "default": "./dist/services/QueueMaker/SQLQueue.js"
423
+ },
424
+ "require": {
425
+ "types": "./dist/services/QueueMaker/SQLQueue.d.ts",
426
+ "default": "./_cjs/services/QueueMaker/SQLQueue.cjs"
427
+ }
428
+ },
418
429
  "./services/QueueMaker/errors": {
419
430
  "import": {
420
431
  "types": "./dist/services/QueueMaker/errors.d.ts",
@@ -0,0 +1,69 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable unused-imports/no-unused-vars */
3
+ import { Effect } from "effect-app"
4
+ import { HttpHeaders, HttpMiddleware, HttpServerRequest, HttpServerResponse } from "effect-app/http"
5
+ import {
6
+ auth,
7
+ InsufficientScopeError,
8
+ InvalidRequestError,
9
+ InvalidTokenError,
10
+ UnauthorizedError
11
+ } from "express-oauth2-jwt-bearer"
12
+
13
+ // // Authorization middleware. When used, the Access Token must
14
+ // // exist and be verified against the Auth0 JSON Web Key Set.
15
+
16
+ // type Errors = InsufficientScopeError | InvalidRequestError | InvalidTokenError | UnauthorizedError
17
+ type Config = Parameters<typeof auth>[0]
18
+ export const checkJWTI = (config: Config) => {
19
+ const mw = auth(config)
20
+ return Effect.gen(function*() {
21
+ const req = yield* HttpServerRequest.HttpServerRequest
22
+
23
+ return yield* Effect.async<
24
+ void,
25
+ InsufficientScopeError | InvalidRequestError | InvalidTokenError | UnauthorizedError
26
+ >(
27
+ (cb) => {
28
+ const next = (err?: unknown) => {
29
+ if (!err) return cb(Effect.void)
30
+ if (
31
+ err instanceof InsufficientScopeError
32
+ || err instanceof InvalidRequestError
33
+ || err instanceof InvalidTokenError
34
+ || err instanceof UnauthorizedError
35
+ ) {
36
+ return cb(Effect.fail(err))
37
+ }
38
+ return Effect.die(err)
39
+ }
40
+ const r = { headers: req.headers, query: {}, body: {}, is: () => false } // is("urlencoded")
41
+ try {
42
+ mw(r as any, {} as any, next)
43
+ } catch (e) {
44
+ return cb(Effect.die(e))
45
+ }
46
+ }
47
+ )
48
+ })
49
+ }
50
+
51
+ export const checkJwt = (config: Config) => {
52
+ const check = checkJWTI(config)
53
+ return HttpMiddleware.make((app) =>
54
+ Effect.gen(function*() {
55
+ const response = yield* check.pipe(Effect.catchAll((e) =>
56
+ Effect.succeed(
57
+ HttpServerResponse.unsafeJson({ message: e.message }, {
58
+ status: e.status,
59
+ headers: HttpHeaders.fromInput(e.headers)
60
+ })
61
+ )
62
+ ))
63
+ if (response) {
64
+ return response
65
+ }
66
+ return yield* app
67
+ })
68
+ )
69
+ }
@@ -8,6 +8,7 @@ import type { Effect } from "effect-app"
8
8
  import type { NotLoggedInError } from "../errors.js"
9
9
  import * as internal from "./internal/middlewares.js"
10
10
 
11
+ export * from "./internal/auth.js"
11
12
  export * from "./internal/events.js"
12
13
  export * from "./internal/health.js"
13
14
  export * from "./internal/RequestContextMiddleware.js"
@@ -0,0 +1,201 @@
1
+ import { setupRequestContext } from "@effect-app/infra/api/setupRequest"
2
+ import { RequestContext } from "@effect-app/infra/RequestContext"
3
+ import { reportNonInterruptedFailure } from "@effect-app/infra/services/QueueMaker/errors"
4
+ import type { QueueBase } from "@effect-app/infra/services/QueueMaker/service"
5
+ import { QueueMeta } from "@effect-app/infra/services/QueueMaker/service"
6
+ import { RequestContextContainer } from "@effect-app/infra/services/RequestContextContainer"
7
+ import { Model, SqlClient } from "@effect/sql"
8
+ import { subMinutes } from "date-fns"
9
+ import { Effect, Fiber, Option, S, Tracer } from "effect-app"
10
+ import { RequestId } from "effect-app/ids"
11
+ import { NonEmptyString255 } from "effect-app/schema"
12
+ import { pretty } from "effect-app/utils"
13
+
14
+ export const QueueId = S.Number.pipe(S.brand("QueueId"))
15
+ export type QueueId = typeof QueueId.Type
16
+
17
+ /**
18
+ * Currently limited to one process draining at a time, due to in-process Semaphore instead of row-level locking.
19
+ */
20
+ export function makeSQLQueue<
21
+ Evt extends { id: S.StringId; _tag: string },
22
+ DrainEvt extends { id: S.StringId; _tag: string },
23
+ EvtE,
24
+ DrainEvtE
25
+ >(
26
+ queueName: NonEmptyString255,
27
+ queueDrainName: NonEmptyString255,
28
+ schema: S.Schema<Evt, EvtE>,
29
+ drainSchema: S.Schema<DrainEvt, DrainEvtE>
30
+ ) {
31
+ return Effect.gen(function*() {
32
+ const base = {
33
+ id: Model.Generated(QueueId),
34
+ meta: Model.JsonFromString(QueueMeta),
35
+ name: S.NonEmptyString255,
36
+ createdAt: Model.DateTimeInsert,
37
+ updatedAt: Model.DateTimeUpdate,
38
+ // TODO: at+owner
39
+ processingAt: Model.FieldOption(S.Date),
40
+ finishedAt: Model.FieldOption(S.Date)
41
+ // TODO: record locking.. / optimistic locking
42
+ // rowVersion: Model.DateTimeFromNumberWithNow
43
+ }
44
+ class Queue extends Model.Class<Queue>("Queue")({
45
+ body: Model.JsonFromString(schema),
46
+ ...base
47
+ }) {}
48
+ class Drain extends Model.Class<Drain>("Drain")({
49
+ body: Model.JsonFromString(drainSchema),
50
+ ...base
51
+ }) {}
52
+ const sql = yield* SqlClient.SqlClient
53
+
54
+ const queueRepo = yield* Model.makeRepository(Queue, {
55
+ tableName: "queue",
56
+ spanPrefix: "QueueRepo",
57
+ idColumn: "id"
58
+ })
59
+
60
+ const drainRepo = yield* Model.makeRepository(Drain, {
61
+ tableName: "queue",
62
+ spanPrefix: "DrainRepo",
63
+ idColumn: "id"
64
+ })
65
+
66
+ const decodeDrain = S.decode(Drain)
67
+
68
+ const drain = () => {
69
+ const limit = subMinutes(new Date(), 15)
70
+ return sql<typeof Drain.Encoded>`SELECT *
71
+ FROM queue
72
+ WHERE name = ${queueDrainName} AND finishedAt IS NULL AND (processingAt IS NULL OR processingAt < ${limit.getTime()})
73
+ LIMIT 1`
74
+ }
75
+
76
+ // temporary workaround until we have a SQLite rowversion..
77
+ const lock = yield* Effect.makeSemaphore(1)
78
+
79
+ const q = {
80
+ offer: (body: Evt, meta: typeof QueueMeta.Type) =>
81
+ Effect.gen(function*() {
82
+ yield* queueRepo.insert(
83
+ Queue.insert.make({
84
+ body,
85
+ meta,
86
+ name: queueName,
87
+ processingAt: Option.none(),
88
+ finishedAt: Option.none()
89
+ })
90
+ )
91
+ }),
92
+ take: Effect.gen(function*() {
93
+ while (true) {
94
+ const first = yield* lock.withPermits(1)(Effect.gen(function*() {
95
+ const [first] = yield* drain()
96
+ if (first) {
97
+ const dec = yield* decodeDrain(first)
98
+ const { createdAt, updatedAt, ...rest } = dec
99
+ yield* drainRepo.update(Drain.update.make({ ...rest, processingAt: Option.some(new Date()) }))
100
+ return dec
101
+ }
102
+ return null
103
+ }))
104
+ if (first) return first
105
+ yield* Effect.sleep(250)
106
+ }
107
+ }),
108
+ finish: ({ createdAt, updatedAt, ...q }: Drain) =>
109
+ drainRepo.update(Drain.update.make({ ...q, finishedAt: Option.some(new Date()) }))
110
+ }
111
+ const rcc = yield* RequestContextContainer
112
+
113
+ return {
114
+ publish: (...messages) =>
115
+ Effect
116
+ .gen(function*($) {
117
+ const requestContext = yield* $(rcc.requestContext)
118
+ const span = yield* $(Effect.serviceOption(Tracer.ParentSpan))
119
+ return yield* $(
120
+ Effect
121
+ .forEach(
122
+ messages,
123
+ (m) =>
124
+ q.offer(m, {
125
+ requestContext: new RequestContext(requestContext), // workaround Schema expecting exact class
126
+ span: Option.getOrUndefined(span)
127
+ }),
128
+ {
129
+ discard: true
130
+ }
131
+ )
132
+ )
133
+ })
134
+ .pipe(
135
+ Effect.withSpan("queue.publish: " + queueName, {
136
+ captureStackTrace: false,
137
+ kind: "producer",
138
+ attributes: { "message_tags": messages.map((_) => _._tag) }
139
+ })
140
+ ),
141
+ drain: <DrainE, DrainR>(
142
+ handleEvent: (ks: DrainEvt) => Effect<void, DrainE, DrainR>,
143
+ sessionId?: string
144
+ ) =>
145
+ Effect.gen(function*() {
146
+ const silenceAndReportError = reportNonInterruptedFailure({ name: "MemQueue.drain." + queueDrainName })
147
+ const processMessage = (msg: Drain) =>
148
+ Effect
149
+ .succeed(msg)
150
+ .pipe(Effect
151
+ .flatMap(({ body, meta }) => {
152
+ let effect = Effect
153
+ .logDebug(`[${queueDrainName}] Processing incoming message`)
154
+ .pipe(
155
+ Effect.annotateLogs({ body: pretty(body), meta: pretty(meta) }),
156
+ Effect.zipRight(handleEvent(body)),
157
+ silenceAndReportError,
158
+ (_) =>
159
+ setupRequestContext(
160
+ _,
161
+ RequestContext.inherit(meta.requestContext, {
162
+ id: RequestId(body.id),
163
+ locale: "en" as const,
164
+ name: NonEmptyString255(`${queueDrainName}.${body._tag}`)
165
+ })
166
+ ),
167
+ Effect
168
+ .withSpan(`queue.drain: ${queueDrainName}.${body._tag}`, {
169
+ captureStackTrace: false,
170
+ kind: "consumer",
171
+ attributes: {
172
+ "queue.name": queueDrainName,
173
+ "queue.sessionId": sessionId,
174
+ "queue.input": body
175
+ }
176
+ })
177
+ )
178
+ if (meta.span) {
179
+ effect = Effect.withParentSpan(effect, Tracer.externalSpan(meta.span))
180
+ }
181
+ return effect
182
+ }))
183
+
184
+ return yield* q
185
+ .take
186
+ .pipe(
187
+ Effect.flatMap((x) =>
188
+ processMessage(x).pipe(
189
+ Effect.uninterruptible,
190
+ Effect.fork,
191
+ Effect.flatMap(Fiber.join),
192
+ Effect.tap(q.finish(x))
193
+ )
194
+ ),
195
+ silenceAndReportError,
196
+ Effect.forever
197
+ )
198
+ })
199
+ } satisfies QueueBase<Evt, DrainEvt>
200
+ })
201
+ }
@@ -1,37 +0,0 @@
1
- // packages/infra/vitest.config.ts
2
- import { defineConfig } from "file:///Users/patrickroza/pj/effect-app/libs/node_modules/.pnpm/vite@5.2.6_@types+node@20.11.30/node_modules/vite/dist/node/index.js";
3
-
4
- // vite.config.base.ts
5
- import path from "path";
6
- import fs from "fs";
7
- var __vite_injected_original_dirname = "/Users/patrickroza/pj/effect-app/libs";
8
- function makeConfig(dirName) {
9
- const prefix = path.resolve(__vite_injected_original_dirname, "packages");
10
- const packages = fs.readdirSync(prefix).map((f) => prefix + "/" + f).filter((f) => fs.lstatSync(f).isDirectory());
11
- const cfg = {
12
- // eslint-disable-next-line @typescript-eslint/no-var-requires
13
- //plugins: [autoImport],
14
- test: {
15
- include: ["./test/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
16
- reporters: "verbose",
17
- globals: true
18
- },
19
- resolve: {
20
- alias: packages.reduce((acc, cur) => {
21
- acc[JSON.parse(fs.readFileSync(cur + "/package.json", "utf-8")).name] = path.resolve(cur, cur.endsWith("core") ? "dist" : "src");
22
- return acc;
23
- }, {})
24
- // "@effect-app/core/Prelude": path.join(__dirname, "packages/core/src/Prelude.code.ts")
25
- }
26
- };
27
- console.log(cfg);
28
- return cfg;
29
- }
30
-
31
- // packages/infra/vitest.config.ts
32
- var __vite_injected_original_dirname2 = "/Users/patrickroza/pj/effect-app/libs/packages/infra";
33
- var vitest_config_default = defineConfig(makeConfig(__vite_injected_original_dirname2));
34
- export {
35
- vitest_config_default as default
36
- };
37
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsicGFja2FnZXMvaW5mcmEvdml0ZXN0LmNvbmZpZy50cyIsICJ2aXRlLmNvbmZpZy5iYXNlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy9wYWNrYWdlcy9pbmZyYVwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy9wYWNrYWdlcy9pbmZyYS92aXRlc3QuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9wYXRyaWNrcm96YS9wai9lZmZlY3QtYXBwL2xpYnMvcGFja2FnZXMvaW5mcmEvdml0ZXN0LmNvbmZpZy50c1wiOy8vLyA8cmVmZXJlbmNlIHR5cGVzPVwidml0ZXN0XCIgLz5cbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gXCJ2aXRlXCJcbmltcG9ydCBtYWtlQ29uZmlnIGZyb20gXCIuLi8uLi92aXRlLmNvbmZpZy5iYXNlXCJcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKG1ha2VDb25maWcoX19kaXJuYW1lKSlcbiIsICJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlic1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy92aXRlLmNvbmZpZy5iYXNlLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9wYXRyaWNrcm96YS9wai9lZmZlY3QtYXBwL2xpYnMvdml0ZS5jb25maWcuYmFzZS50c1wiOy8vLyA8cmVmZXJlbmNlIHR5cGVzPVwidml0ZXN0XCIgLz5cbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCJcbmltcG9ydCBmcyBmcm9tIFwiZnNcIlxuaW1wb3J0IEF1dG9JbXBvcnQgZnJvbSBcInVucGx1Z2luLWF1dG8taW1wb3J0L3ZpdGVcIlxuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSBcInZpdGVzdC9jb25maWdcIlxuXG4vLyBjb25zdCBhdXRvSW1wb3J0ID0gQXV0b0ltcG9ydCh7XG4vLyAgIGR0czogXCIuL3Rlc3QvYXV0by1pbXBvcnRzLmQudHNcIixcbi8vICAgLy8gaW5jbHVkZTogW1xuLy8gICAvLyAgIC9cXC50ZXN0XFwuW3RqXXN4PyQvIC8vIC50cywgLnRzeCwgLmpzLCAuanN4XG4vLyAgIC8vIF0sXG4vLyAgIGltcG9ydHM6IFtcbi8vICAgICBcInZpdGVzdFwiXG4vLyAgIF1cbi8vIH0pXG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIG1ha2VDb25maWcoZGlyTmFtZT86IHN0cmluZykge1xuICBjb25zdCBwcmVmaXggPSBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCBcInBhY2thZ2VzXCIpXG4gIGNvbnN0IHBhY2thZ2VzID0gZnMucmVhZGRpclN5bmMocHJlZml4KS5tYXAoZiA9PiBwcmVmaXggKyBcIi9cIiArIGYpLmZpbHRlcihmID0+IGZzLmxzdGF0U3luYyhmKS5pc0RpcmVjdG9yeSgpIClcbiAgY29uc3QgY2ZnID0ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdmFyLXJlcXVpcmVzXG4gICAgLy9wbHVnaW5zOiBbYXV0b0ltcG9ydF0sXG4gICAgdGVzdDoge1xuICAgICAgaW5jbHVkZTogIFtcIi4vdGVzdC8qKi8qLnRlc3Que2pzLG1qcyxjanMsdHMsbXRzLGN0cyxqc3gsdHN4fVwiXSxcbiAgICAgIHJlcG9ydGVyczogXCJ2ZXJib3NlXCIsXG4gICAgICBnbG9iYWxzOiB0cnVlXG4gICAgfSxcbiAgICByZXNvbHZlOiB7XG4gICAgICBhbGlhczogcGFja2FnZXMucmVkdWNlKChhY2MsIGN1cikgPT4geyAvLyB3b3JrYXJvdW5kIGZvciAvUHJlbHVkZSBpc3N1ZVxuICAgICAgYWNjW0pTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKGN1ciArIFwiL3BhY2thZ2UuanNvblwiLCBcInV0Zi04XCIpKS5uYW1lXSA9IHBhdGgucmVzb2x2ZShjdXIsIGN1ci5lbmRzV2l0aChcImNvcmVcIikgPyBcImRpc3RcIiA6IFwic3JjXCIpXG4gICAgICByZXR1cm4gYWNjXG4gICAgfSwgeyB9KSAvLyBcIkBlZmZlY3QtYXBwL2NvcmUvUHJlbHVkZVwiOiBwYXRoLmpvaW4oX19kaXJuYW1lLCBcInBhY2thZ2VzL2NvcmUvc3JjL1ByZWx1ZGUuY29kZS50c1wiKVxuICB9XG4gIH1cbiAgY29uc29sZS5sb2coY2ZnKVxuICByZXR1cm4gY2ZnXG59XG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQ0EsU0FBUyxvQkFBb0I7OztBQ0E3QixPQUFPLFVBQVU7QUFDakIsT0FBTyxRQUFRO0FBRmYsSUFBTSxtQ0FBbUM7QUFnQjFCLFNBQVIsV0FBNEIsU0FBa0I7QUFDbkQsUUFBTSxTQUFTLEtBQUssUUFBUSxrQ0FBVyxVQUFVO0FBQ2pELFFBQU0sV0FBVyxHQUFHLFlBQVksTUFBTSxFQUFFLElBQUksT0FBSyxTQUFTLE1BQU0sQ0FBQyxFQUFFLE9BQU8sT0FBSyxHQUFHLFVBQVUsQ0FBQyxFQUFFLFlBQVksQ0FBRTtBQUM3RyxRQUFNLE1BQU07QUFBQTtBQUFBO0FBQUEsSUFHVixNQUFNO0FBQUEsTUFDSixTQUFVLENBQUMsa0RBQWtEO0FBQUEsTUFDN0QsV0FBVztBQUFBLE1BQ1gsU0FBUztBQUFBLElBQ1g7QUFBQSxJQUNBLFNBQVM7QUFBQSxNQUNQLE9BQU8sU0FBUyxPQUFPLENBQUMsS0FBSyxRQUFRO0FBQ3JDLFlBQUksS0FBSyxNQUFNLEdBQUcsYUFBYSxNQUFNLGlCQUFpQixPQUFPLENBQUMsRUFBRSxJQUFJLElBQUksS0FBSyxRQUFRLEtBQUssSUFBSSxTQUFTLE1BQU0sSUFBSSxTQUFTLEtBQUs7QUFDL0gsZUFBTztBQUFBLE1BQ1QsR0FBRyxDQUFFLENBQUM7QUFBQTtBQUFBLElBQ1I7QUFBQSxFQUNBO0FBQ0EsVUFBUSxJQUFJLEdBQUc7QUFDZixTQUFPO0FBQ1Q7OztBRHBDQSxJQUFNQSxvQ0FBbUM7QUFJekMsSUFBTyx3QkFBUSxhQUFhLFdBQVdDLGlDQUFTLENBQUM7IiwKICAibmFtZXMiOiBbIl9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lIiwgIl9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lIl0KfQo=