@effect-app/infra 1.23.4 → 1.23.5
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 +6 -0
- package/_cjs/services/QueueMaker/SQLQueue.cjs +38 -38
- package/_cjs/services/QueueMaker/SQLQueue.cjs.map +1 -1
- package/dist/services/QueueMaker/SQLQueue.d.ts +0 -3
- package/dist/services/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/services/QueueMaker/SQLQueue.js +22 -22
- package/package.json +3 -3
- package/src/services/QueueMaker/SQLQueue.ts +22 -22
- package/tsconfig.src.json +0 -1
- package/tsconfig.test.json +0 -1
- package/vitest.config.ts.timestamp-1711656440838-19c636fe320df.mjs +0 -0
- package/vitest.config.ts.timestamp-1711724061890-6ecedb0a07fdd.mjs +0 -0
- package/vitest.config.ts.timestamp-1711743489537-da8d9e5f66c9f.mjs +0 -0
- package/vitest.config.ts.timestamp-1711744615239-dcf257a844e01.mjs +37 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,12 +5,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.QueueId = void 0;
|
|
7
7
|
exports.makeSQLQueue = makeSQLQueue;
|
|
8
|
+
var _SQL = require("@effect-app/infra-adapters/SQL");
|
|
8
9
|
var _setupRequest = require("@effect-app/infra/api/setupRequest");
|
|
9
10
|
var _RequestContext = require("@effect-app/infra/RequestContext");
|
|
10
11
|
var _errors = require("@effect-app/infra/services/QueueMaker/errors");
|
|
11
12
|
var _service = require("@effect-app/infra/services/QueueMaker/service");
|
|
12
13
|
var _RequestContextContainer = require("@effect-app/infra/services/RequestContextContainer");
|
|
13
14
|
var _sql = require("@effect/sql");
|
|
15
|
+
var _crypto = require("crypto");
|
|
14
16
|
var _dateFns = require("date-fns");
|
|
15
17
|
var _effectApp = require("effect-app");
|
|
16
18
|
var _ids = require("effect-app/ids");
|
|
@@ -18,41 +20,42 @@ var _schema = require("effect-app/schema");
|
|
|
18
20
|
var _utils = require("effect-app/utils");
|
|
19
21
|
var _logger = require("../../logger.cjs");
|
|
20
22
|
const QueueId = exports.QueueId = _effectApp.S.Number.pipe(_effectApp.S.brand("QueueId"));
|
|
21
|
-
|
|
22
|
-
* Currently limited to one process draining at a time, due to in-process Semaphore instead of row-level locking.
|
|
23
|
-
*/
|
|
23
|
+
// TODO: let the model track and Auto Generate versionColumn on every update instead
|
|
24
24
|
function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
25
25
|
return _effectApp.Effect.gen(function* () {
|
|
26
26
|
const base = {
|
|
27
|
-
id:
|
|
28
|
-
meta:
|
|
27
|
+
id: _SQL.Model.Generated(QueueId),
|
|
28
|
+
meta: _SQL.Model.JsonFromString(_service.QueueMeta),
|
|
29
29
|
name: _effectApp.S.NonEmptyString255,
|
|
30
|
-
createdAt:
|
|
31
|
-
updatedAt:
|
|
30
|
+
createdAt: _SQL.Model.DateTimeInsert,
|
|
31
|
+
updatedAt: _SQL.Model.DateTimeUpdate,
|
|
32
32
|
// TODO: at+owner
|
|
33
|
-
processingAt:
|
|
34
|
-
finishedAt:
|
|
33
|
+
processingAt: _SQL.Model.FieldOption(_effectApp.S.Date),
|
|
34
|
+
finishedAt: _SQL.Model.FieldOption(_effectApp.S.Date),
|
|
35
|
+
etag: _effectApp.S.String // TODO: use a Model thing that auto updates it?
|
|
35
36
|
// TODO: record locking.. / optimistic locking
|
|
36
37
|
// rowVersion: Model.DateTimeFromNumberWithNow
|
|
37
38
|
};
|
|
38
|
-
class Queue extends
|
|
39
|
-
body:
|
|
39
|
+
class Queue extends _SQL.Model.Class("Queue")({
|
|
40
|
+
body: _SQL.Model.JsonFromString(schema),
|
|
40
41
|
...base
|
|
41
42
|
}) {}
|
|
42
|
-
class Drain extends
|
|
43
|
-
body:
|
|
43
|
+
class Drain extends _SQL.Model.Class("Drain")({
|
|
44
|
+
body: _SQL.Model.JsonFromString(drainSchema),
|
|
44
45
|
...base
|
|
45
46
|
}) {}
|
|
46
47
|
const sql = yield* _sql.SqlClient.SqlClient;
|
|
47
|
-
const queueRepo = yield*
|
|
48
|
+
const queueRepo = yield* _SQL.Model.makeRepository(Queue, {
|
|
48
49
|
tableName: "queue",
|
|
49
50
|
spanPrefix: "QueueRepo",
|
|
50
|
-
idColumn: "id"
|
|
51
|
+
idColumn: "id",
|
|
52
|
+
versionColumn: "etag"
|
|
51
53
|
});
|
|
52
|
-
const drainRepo = yield*
|
|
54
|
+
const drainRepo = yield* _SQL.Model.makeRepository(Drain, {
|
|
53
55
|
tableName: "queue",
|
|
54
56
|
spanPrefix: "DrainRepo",
|
|
55
|
-
idColumn: "id"
|
|
57
|
+
idColumn: "id",
|
|
58
|
+
versionColumn: "etag"
|
|
56
59
|
});
|
|
57
60
|
const decodeDrain = _effectApp.S.decode(Drain);
|
|
58
61
|
const drain = () => {
|
|
@@ -62,8 +65,6 @@ function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
|
62
65
|
WHERE name = ${queueDrainName} AND finishedAt IS NULL AND (processingAt IS NULL OR processingAt < ${limit.getTime()})
|
|
63
66
|
LIMIT 1`;
|
|
64
67
|
};
|
|
65
|
-
// temporary workaround until we have a SQLite rowversion..
|
|
66
|
-
const lock = yield* _effectApp.Effect.makeSemaphore(1);
|
|
67
68
|
const q = {
|
|
68
69
|
offer: (body, meta) => _effectApp.Effect.gen(function* () {
|
|
69
70
|
yield* queueRepo.insert(Queue.insert.make({
|
|
@@ -71,28 +72,27 @@ function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
|
71
72
|
meta,
|
|
72
73
|
name: queueName,
|
|
73
74
|
processingAt: _effectApp.Option.none(),
|
|
74
|
-
finishedAt: _effectApp.Option.none()
|
|
75
|
+
finishedAt: _effectApp.Option.none(),
|
|
76
|
+
etag: (0, _crypto.randomUUID)()
|
|
75
77
|
}));
|
|
76
78
|
}),
|
|
77
79
|
take: _effectApp.Effect.gen(function* () {
|
|
78
80
|
while (true) {
|
|
79
|
-
const first = yield*
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return null;
|
|
95
|
-
}));
|
|
81
|
+
const [first] = yield* drain();
|
|
82
|
+
if (first) {
|
|
83
|
+
const dec = yield* decodeDrain(first);
|
|
84
|
+
const {
|
|
85
|
+
createdAt,
|
|
86
|
+
updatedAt,
|
|
87
|
+
...rest
|
|
88
|
+
} = dec;
|
|
89
|
+
yield* drainRepo.update(Drain.update.make({
|
|
90
|
+
...rest,
|
|
91
|
+
processingAt: _effectApp.Option.some(new Date())
|
|
92
|
+
}) // auto in lib , etag: randomUUID()
|
|
93
|
+
);
|
|
94
|
+
return dec;
|
|
95
|
+
}
|
|
96
96
|
if (first) return first;
|
|
97
97
|
yield* _effectApp.Effect.sleep(250);
|
|
98
98
|
}
|
|
@@ -104,7 +104,7 @@ function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
|
104
104
|
}) => drainRepo.update(Drain.update.make({
|
|
105
105
|
...q,
|
|
106
106
|
finishedAt: _effectApp.Option.some(new Date())
|
|
107
|
-
}))
|
|
107
|
+
})) // auto in lib , etag: randomUUID()
|
|
108
108
|
};
|
|
109
109
|
const rcc = yield* _RequestContextContainer.RequestContextContainer;
|
|
110
110
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SQLQueue.cjs","names":["
|
|
1
|
+
{"version":3,"file":"SQLQueue.cjs","names":["_SQL","require","_setupRequest","_RequestContext","_errors","_service","_RequestContextContainer","_sql","_crypto","_dateFns","_effectApp","_ids","_schema","_utils","_logger","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","etag","String","Queue","Class","body","Drain","sql","SqlClient","queueRepo","makeRepository","tableName","spanPrefix","idColumn","versionColumn","drainRepo","decodeDrain","decode","drain","limit","subMinutes","getTime","q","offer","insert","make","Option","none","randomUUID","take","first","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","InfraLogger","logInfo","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":";;;;;;;AAAA,IAAAA,IAAA,GAAAC,OAAA;AACA,IAAAC,aAAA,GAAAD,OAAA;AACA,IAAAE,eAAA,GAAAF,OAAA;AACA,IAAAG,OAAA,GAAAH,OAAA;AAEA,IAAAI,QAAA,GAAAJ,OAAA;AACA,IAAAK,wBAAA,GAAAL,OAAA;AACA,IAAAM,IAAA,GAAAN,OAAA;AACA,IAAAO,OAAA,GAAAP,OAAA;AACA,IAAAQ,QAAA,GAAAR,OAAA;AACA,IAAAS,UAAA,GAAAT,OAAA;AACA,IAAAU,IAAA,GAAAV,OAAA;AACA,IAAAW,OAAA,GAAAX,OAAA;AACA,IAAAY,MAAA,GAAAZ,OAAA;AACA,IAAAa,OAAA,GAAAb,OAAA;AAEO,MAAMc,OAAO,GAAAC,OAAA,CAAAD,OAAA,GAAGE,YAAC,CAACC,MAAM,CAACC,IAAI,CAACF,YAAC,CAACG,KAAK,CAAC,SAAS,CAAC,CAAC;AAGxD;AACM,SAAUC,YAAYA,CAM1BC,SAA4B,EAC5BC,cAAiC,EACjCC,MAA2B,EAC3BC,WAA0C;EAE1C,OAAOC,iBAAM,CAACC,GAAG,CAAC,aAAS;IACzB,MAAMC,IAAI,GAAG;MACXC,EAAE,EAAEC,UAAK,CAACC,SAAS,CAAChB,OAAO,CAAC;MAC5BiB,IAAI,EAAEF,UAAK,CAACG,cAAc,CAACC,kBAAS,CAAC;MACrCC,IAAI,EAAElB,YAAC,CAACmB,iBAAiB;MACzBC,SAAS,EAAEP,UAAK,CAACQ,cAAc;MAC/BC,SAAS,EAAET,UAAK,CAACU,cAAc;MAC/B;MACAC,YAAY,EAAEX,UAAK,CAACY,WAAW,CAACzB,YAAC,CAAC0B,IAAI,CAAC;MACvCC,UAAU,EAAEd,UAAK,CAACY,WAAW,CAACzB,YAAC,CAAC0B,IAAI,CAAC;MACrCE,IAAI,EAAE5B,YAAC,CAAC6B,MAAM,CAAC;MACf;MACA;KACD;IACD,MAAMC,KAAM,SAAQjB,UAAK,CAACkB,KAAK,CAAQ,OAAO,CAAC,CAAC;MAC9CC,IAAI,EAAEnB,UAAK,CAACG,cAAc,CAACT,MAAM,CAAC;MAClC,GAAGI;KACJ,CAAC;IACF,MAAMsB,KAAM,SAAQpB,UAAK,CAACkB,KAAK,CAAQ,OAAO,CAAC,CAAC;MAC9CC,IAAI,EAAEnB,UAAK,CAACG,cAAc,CAACR,WAAW,CAAC;MACvC,GAAGG;KACJ,CAAC;IACF,MAAMuB,GAAG,GAAG,OAAOC,cAAS,CAACA,SAAS;IAEtC,MAAMC,SAAS,GAAG,OAAOvB,UAAK,CAACwB,cAAc,CAACP,KAAK,EAAE;MACnDQ,SAAS,EAAE,OAAO;MAClBC,UAAU,EAAE,WAAW;MACvBC,QAAQ,EAAE,IAAI;MACdC,aAAa,EAAE;KAChB,CAAC;IAEF,MAAMC,SAAS,GAAG,OAAO7B,UAAK,CAACwB,cAAc,CAACJ,KAAK,EAAE;MACnDK,SAAS,EAAE,OAAO;MAClBC,UAAU,EAAE,WAAW;MACvBC,QAAQ,EAAE,IAAI;MACdC,aAAa,EAAE;KAChB,CAAC;IAEF,MAAME,WAAW,GAAG3C,YAAC,CAAC4C,MAAM,CAACX,KAAK,CAAC;IAEnC,MAAMY,KAAK,GAAGA,CAAA,KAAK;MACjB,MAAMC,KAAK,GAAG,IAAAC,mBAAU,EAAC,IAAIrB,IAAI,EAAE,EAAE,EAAE,CAAC;MACxC,OAAOQ,GAAyB;;mBAEnB5B,cAAc,uEAAuEwC,KAAK,CAACE,OAAO,EAAE;YAC3G;IACR,CAAC;IAED,MAAMC,CAAC,GAAG;MACRC,KAAK,EAAEA,CAAClB,IAAS,EAAEjB,IAA2B,KAC5CN,iBAAM,CAACC,GAAG,CAAC,aAAS;QAClB,OAAO0B,SAAS,CAACe,MAAM,CACrBrB,KAAK,CAACqB,MAAM,CAACC,IAAI,CAAC;UAChBpB,IAAI;UACJjB,IAAI;UACJG,IAAI,EAAEb,SAAS;UACfmB,YAAY,EAAE6B,iBAAM,CAACC,IAAI,EAAE;UAC3B3B,UAAU,EAAE0B,iBAAM,CAACC,IAAI,EAAE;UACzB1B,IAAI,EAAE,IAAA2B,kBAAU;SACjB,CAAC,CACH;MACH,CAAC,CAAC;MACJC,IAAI,EAAE/C,iBAAM,CAACC,GAAG,CAAC,aAAS;QACxB,OAAO,IAAI,EAAE;UACX,MAAM,CAAC+C,KAAK,CAAC,GAAG,OAAOZ,KAAK,EAAE;UAC9B,IAAIY,KAAK,EAAE;YACT,MAAMC,GAAG,GAAG,OAAOf,WAAW,CAACc,KAAK,CAAC;YACrC,MAAM;cAAErC,SAAS;cAAEE,SAAS;cAAE,GAAGqC;YAAI,CAAE,GAAGD,GAAG;YAC7C,OAAOhB,SAAS,CAACkB,MAAM,CACrB3B,KAAK,CAAC2B,MAAM,CAACR,IAAI,CAAC;cAAE,GAAGO,IAAI;cAAEnC,YAAY,EAAE6B,iBAAM,CAACQ,IAAI,CAAC,IAAInC,IAAI,EAAE;YAAC,CAAE,CAAC,CAAC;aACvE;YACD,OAAOgC,GAAG;UACZ;UACA,IAAID,KAAK,EAAE,OAAOA,KAAK;UACvB,OAAOhD,iBAAM,CAACqD,KAAK,CAAC,GAAG,CAAC;QAC1B;MACF,CAAC,CAAC;MACFC,MAAM,EAAEA,CAAC;QAAE3C,SAAS;QAAEE,SAAS;QAAE,GAAG2B;MAAC,CAAS,KAC5CP,SAAS,CAACkB,MAAM,CAAC3B,KAAK,CAAC2B,MAAM,CAACR,IAAI,CAAC;QAAE,GAAGH,CAAC;QAAEtB,UAAU,EAAE0B,iBAAM,CAACQ,IAAI,CAAC,IAAInC,IAAI,EAAE;MAAC,CAAE,CAAC,CAAC,CAAC;KACtF;IACD,MAAMsC,GAAG,GAAG,OAAOC,gDAAuB;IAE1C,OAAO;MACLC,OAAO,EAAEA,CAAC,GAAGC,QAAQ,KACnB1D,iBAAM,CACHC,GAAG,CAAC,aAAS;QACZ,MAAM0D,cAAc,GAAG,OAAOJ,GAAG,CAACI,cAAc;QAChD,MAAMC,IAAI,GAAG,OAAO5D,iBAAM,CAAC6D,aAAa,CAACC,iBAAM,CAACC,UAAU,CAAC;QAC3D,OAAO,OAAO/D,iBAAM,CACjBgE,OAAO,CACNN,QAAQ,EACPO,CAAC,IACAzB,CAAC,CAACC,KAAK,CAACwB,CAAC,EAAE;UACTN,cAAc,EAAE,IAAIO,8BAAc,CAACP,cAAc,CAAC;UAAE;UACpDC,IAAI,EAAEhB,iBAAM,CAACuB,cAAc,CAACP,IAAI;SACjC,CAAC,EACJ;UACEQ,OAAO,EAAE;SACV,CACF;MACL,CAAC,CAAC,CACD3E,IAAI,CACHO,iBAAM,CAACqE,QAAQ,CAAC,iBAAiB,GAAGzE,SAAS,EAAE;QAC7C0E,iBAAiB,EAAE,KAAK;QACxBC,IAAI,EAAE,UAAU;QAChBC,UAAU,EAAE;UAAE,cAAc,EAAEd,QAAQ,CAACe,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACC,IAAI;QAAC;OAC1D,CAAC,CACH;MACLvC,KAAK,EAAEA,CACLwC,WAA2D,EAC3DC,SAAkB,KAElB7E,iBAAM,CAACC,GAAG,CAAC,aAAS;QAClB,MAAM6E,qBAAqB,GAAG,IAAAC,mCAA2B,EAAC;UAAEtE,IAAI,EAAE,iBAAiB,GAAGZ;QAAc,CAAE,CAAC;QACvG,MAAMmF,cAAc,GAAIC,GAAU,IAChCjF,iBAAM,CACHkF,OAAO,CAACD,GAAG,CAAC,CACZxF,IAAI,CAACO,iBAAM,CACTmF,OAAO,CAAC,CAAC;UAAE5D,IAAI;UAAEjB;QAAI,CAAE,KAAI;UAC1B,IAAI8E,MAAM,GAAGC,mBAAW,CACrBC,OAAO,CAAC,IAAIzF,cAAc,+BAA+B,CAAC,CAC1DJ,IAAI,CACHO,iBAAM,CAACuF,YAAY,CAAC;YAAEhE,IAAI,EAAE,IAAAiE,aAAM,EAACjE,IAAI,CAAC;YAAEjB,IAAI,EAAE,IAAAkF,aAAM,EAAClF,IAAI;UAAC,CAAE,CAAC,EAC/DN,iBAAM,CAACyF,QAAQ,CAACb,WAAW,CAACrD,IAAI,CAAC,CAAC,EAClCuD,qBAAqB,EACpBJ,CAAC,IACA,IAAAgB,iCAAmB,EACjBhB,CAAC,EACDR,8BAAc,CAACyB,OAAO,CAACrF,IAAI,CAACqD,cAAc,EAAE;YAC1CxD,EAAE,EAAE,IAAAyF,cAAS,EAACrE,IAAI,CAACpB,EAAE,CAAC;YACtB0F,MAAM,EAAE,IAAa;YACrBpF,IAAI,EAAE,IAAAC,yBAAiB,EAAC,GAAGb,cAAc,IAAI0B,IAAI,CAACoD,IAAI,EAAE;WACzD,CAAC,CACH,EACH3E,iBAAM,CACHqE,QAAQ,CAAC,gBAAgBxE,cAAc,IAAI0B,IAAI,CAACoD,IAAI,EAAE,EAAE;YACvDL,iBAAiB,EAAE,KAAK;YACxBC,IAAI,EAAE,UAAU;YAChBC,UAAU,EAAE;cACV,YAAY,EAAE3E,cAAc;cAC5B,iBAAiB,EAAEgF,SAAS;cAC5B,aAAa,EAAEtD;;WAElB,CAAC,CACL;UACH,IAAIjB,IAAI,CAACsD,IAAI,EAAE;YACbwB,MAAM,GAAGpF,iBAAM,CAAC8F,cAAc,CAACV,MAAM,EAAEtB,iBAAM,CAACiC,YAAY,CAACzF,IAAI,CAACsD,IAAI,CAAC,CAAC;UACxE;UACA,OAAOwB,MAAM;QACf,CAAC,CAAC,CAAC;QAET,OAAO,OAAO5C,CAAC,CACZO,IAAI,CACJtD,IAAI,CACHO,iBAAM,CAACmF,OAAO,CAAEa,CAAC,IACfhB,cAAc,CAACgB,CAAC,CAAC,CAACvG,IAAI,CACpBO,iBAAM,CAACiG,eAAe,EACtBjG,iBAAM,CAACkG,IAAI,EACXlG,iBAAM,CAACmF,OAAO,CAACgB,gBAAK,CAACC,IAAI,CAAC,EAC1BpG,iBAAM,CAACqG,GAAG,CAAC7D,CAAC,CAACc,MAAM,CAAC0C,CAAC,CAAC,CAAC,CACxB,CACF,EACDlB,qBAAqB,EACrB9E,iBAAM,CAACsG,OAAO,CACf;MACL,CAAC;KAC+B;EACtC,CAAC,CAAC;AACJ","ignoreList":[]}
|
|
@@ -6,9 +6,6 @@ export declare const QueueId: S.brand<typeof import("@effect/schema/Schema").Num
|
|
|
6
6
|
withDefault: S.PropertySignature<":", number, never, ":", number, true, never>;
|
|
7
7
|
}, "QueueId">;
|
|
8
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
9
|
export declare function makeSQLQueue<Evt extends {
|
|
13
10
|
id: S.StringId;
|
|
14
11
|
_tag: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SQLQueue.d.ts","sourceRoot":"","sources":["../../../src/services/QueueMaker/SQLQueue.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SQLQueue.d.ts","sourceRoot":"","sources":["../../../src/services/QueueMaker/SQLQueue.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oDAAoD,CAAA;AAC5F,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAGvC,OAAO,EAAE,MAAM,EAAiB,CAAC,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAE7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAIrD,eAAO,MAAM,OAAO;;aAAoC,CAAA;AACxD,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAGzC,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;;YA8G9B,MAAM,EAAE,MAAM,eACP,CAAC,EAAE,EAAE,QAAQ,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,cAC/C,MAAM;yDA0DzB"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { Model } from "@effect-app/infra-adapters/SQL";
|
|
1
2
|
import { setupRequestContext } from "@effect-app/infra/api/setupRequest";
|
|
2
3
|
import { RequestContext } from "@effect-app/infra/RequestContext";
|
|
3
4
|
import { reportNonInterruptedFailure } from "@effect-app/infra/services/QueueMaker/errors";
|
|
4
5
|
import { QueueMeta } from "@effect-app/infra/services/QueueMaker/service";
|
|
5
6
|
import { RequestContextContainer } from "@effect-app/infra/services/RequestContextContainer";
|
|
6
|
-
import {
|
|
7
|
+
import { SqlClient } from "@effect/sql";
|
|
8
|
+
import { randomUUID } from "crypto";
|
|
7
9
|
import { subMinutes } from "date-fns";
|
|
8
10
|
import { Effect, Fiber, Option, S, Tracer } from "effect-app";
|
|
9
11
|
import { RequestId } from "effect-app/ids";
|
|
@@ -11,9 +13,7 @@ import { NonEmptyString255 } from "effect-app/schema";
|
|
|
11
13
|
import { pretty } from "effect-app/utils";
|
|
12
14
|
import { InfraLogger } from "../../logger.js";
|
|
13
15
|
export const QueueId = S.Number.pipe(S.brand("QueueId"));
|
|
14
|
-
|
|
15
|
-
* Currently limited to one process draining at a time, due to in-process Semaphore instead of row-level locking.
|
|
16
|
-
*/
|
|
16
|
+
// TODO: let the model track and Auto Generate versionColumn on every update instead
|
|
17
17
|
export function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
18
18
|
return Effect.gen(function* () {
|
|
19
19
|
const base = {
|
|
@@ -24,7 +24,8 @@ export function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
|
24
24
|
updatedAt: Model.DateTimeUpdate,
|
|
25
25
|
// TODO: at+owner
|
|
26
26
|
processingAt: Model.FieldOption(S.Date),
|
|
27
|
-
finishedAt: Model.FieldOption(S.Date)
|
|
27
|
+
finishedAt: Model.FieldOption(S.Date),
|
|
28
|
+
etag: S.String // TODO: use a Model thing that auto updates it?
|
|
28
29
|
// TODO: record locking.. / optimistic locking
|
|
29
30
|
// rowVersion: Model.DateTimeFromNumberWithNow
|
|
30
31
|
};
|
|
@@ -42,12 +43,14 @@ export function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
|
42
43
|
const queueRepo = yield* Model.makeRepository(Queue, {
|
|
43
44
|
tableName: "queue",
|
|
44
45
|
spanPrefix: "QueueRepo",
|
|
45
|
-
idColumn: "id"
|
|
46
|
+
idColumn: "id",
|
|
47
|
+
versionColumn: "etag"
|
|
46
48
|
});
|
|
47
49
|
const drainRepo = yield* Model.makeRepository(Drain, {
|
|
48
50
|
tableName: "queue",
|
|
49
51
|
spanPrefix: "DrainRepo",
|
|
50
|
-
idColumn: "id"
|
|
52
|
+
idColumn: "id",
|
|
53
|
+
versionColumn: "etag"
|
|
51
54
|
});
|
|
52
55
|
const decodeDrain = S.decode(Drain);
|
|
53
56
|
const drain = () => {
|
|
@@ -57,8 +60,6 @@ export function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
|
57
60
|
WHERE name = ${queueDrainName} AND finishedAt IS NULL AND (processingAt IS NULL OR processingAt < ${limit.getTime()})
|
|
58
61
|
LIMIT 1`;
|
|
59
62
|
};
|
|
60
|
-
// temporary workaround until we have a SQLite rowversion..
|
|
61
|
-
const lock = yield* Effect.makeSemaphore(1);
|
|
62
63
|
const q = {
|
|
63
64
|
offer: (body, meta) => Effect.gen(function* () {
|
|
64
65
|
yield* queueRepo.insert(Queue.insert.make({
|
|
@@ -66,27 +67,26 @@ export function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
|
66
67
|
meta,
|
|
67
68
|
name: queueName,
|
|
68
69
|
processingAt: Option.none(),
|
|
69
|
-
finishedAt: Option.none()
|
|
70
|
+
finishedAt: Option.none(),
|
|
71
|
+
etag: randomUUID()
|
|
70
72
|
}));
|
|
71
73
|
}),
|
|
72
74
|
take: Effect.gen(function* () {
|
|
73
75
|
while (true) {
|
|
74
|
-
const first = yield*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return null;
|
|
83
|
-
}));
|
|
76
|
+
const [first] = yield* drain();
|
|
77
|
+
if (first) {
|
|
78
|
+
const dec = yield* decodeDrain(first);
|
|
79
|
+
const { createdAt, updatedAt, ...rest } = dec;
|
|
80
|
+
yield* drainRepo.update(Drain.update.make({ ...rest, processingAt: Option.some(new Date()) }) // auto in lib , etag: randomUUID()
|
|
81
|
+
);
|
|
82
|
+
return dec;
|
|
83
|
+
}
|
|
84
84
|
if (first)
|
|
85
85
|
return first;
|
|
86
86
|
yield* Effect.sleep(250);
|
|
87
87
|
}
|
|
88
88
|
}),
|
|
89
|
-
finish: ({ createdAt, updatedAt, ...q }) => drainRepo.update(Drain.update.make({ ...q, finishedAt: Option.some(new Date()) }))
|
|
89
|
+
finish: ({ createdAt, updatedAt, ...q }) => drainRepo.update(Drain.update.make({ ...q, finishedAt: Option.some(new Date()) })) // auto in lib , etag: randomUUID()
|
|
90
90
|
};
|
|
91
91
|
const rcc = yield* RequestContextContainer;
|
|
92
92
|
return {
|
|
@@ -141,4 +141,4 @@ export function makeSQLQueue(queueName, queueDrainName, schema, drainSchema) {
|
|
|
141
141
|
};
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
144
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU1FMUXVldWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvUXVldWVNYWtlci9TUUxRdWV1ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sZ0NBQWdDLENBQUE7QUFDdEQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sb0NBQW9DLENBQUE7QUFDeEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtDQUFrQyxDQUFBO0FBQ2pFLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDhDQUE4QyxDQUFBO0FBRTFGLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQTtBQUN6RSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxvREFBb0QsQ0FBQTtBQUM1RixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3ZDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxRQUFRLENBQUE7QUFDbkMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUNyQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUM3RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFDMUMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDckQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBQ3pDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUU3QyxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFBO0FBR3hELG9GQUFvRjtBQUNwRixNQUFNLFVB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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "1.23.
|
|
3
|
+
"version": "1.23.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"pure-rand": "6.1.0",
|
|
20
20
|
"redlock": "^4.2.0",
|
|
21
21
|
"@effect-app/core": "1.10.2",
|
|
22
|
-
"effect-app": "1.
|
|
22
|
+
"@effect-app/schema": "1.12.2",
|
|
23
23
|
"@effect-app/infra-adapters": "1.11.7",
|
|
24
|
-
"
|
|
24
|
+
"effect-app": "1.17.5"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@babel/cli": "^7.25.6",
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { Model } from "@effect-app/infra-adapters/SQL"
|
|
1
2
|
import { setupRequestContext } from "@effect-app/infra/api/setupRequest"
|
|
2
3
|
import { RequestContext } from "@effect-app/infra/RequestContext"
|
|
3
4
|
import { reportNonInterruptedFailure } from "@effect-app/infra/services/QueueMaker/errors"
|
|
4
5
|
import type { QueueBase } from "@effect-app/infra/services/QueueMaker/service"
|
|
5
6
|
import { QueueMeta } from "@effect-app/infra/services/QueueMaker/service"
|
|
6
7
|
import { RequestContextContainer } from "@effect-app/infra/services/RequestContextContainer"
|
|
7
|
-
import {
|
|
8
|
+
import { SqlClient } from "@effect/sql"
|
|
9
|
+
import { randomUUID } from "crypto"
|
|
8
10
|
import { subMinutes } from "date-fns"
|
|
9
11
|
import { Effect, Fiber, Option, S, Tracer } from "effect-app"
|
|
10
12
|
import { RequestId } from "effect-app/ids"
|
|
@@ -15,9 +17,7 @@ import { InfraLogger } from "../../logger.js"
|
|
|
15
17
|
export const QueueId = S.Number.pipe(S.brand("QueueId"))
|
|
16
18
|
export type QueueId = typeof QueueId.Type
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
* Currently limited to one process draining at a time, due to in-process Semaphore instead of row-level locking.
|
|
20
|
-
*/
|
|
20
|
+
// TODO: let the model track and Auto Generate versionColumn on every update instead
|
|
21
21
|
export function makeSQLQueue<
|
|
22
22
|
Evt extends { id: S.StringId; _tag: string },
|
|
23
23
|
DrainEvt extends { id: S.StringId; _tag: string },
|
|
@@ -38,7 +38,8 @@ export function makeSQLQueue<
|
|
|
38
38
|
updatedAt: Model.DateTimeUpdate,
|
|
39
39
|
// TODO: at+owner
|
|
40
40
|
processingAt: Model.FieldOption(S.Date),
|
|
41
|
-
finishedAt: Model.FieldOption(S.Date)
|
|
41
|
+
finishedAt: Model.FieldOption(S.Date),
|
|
42
|
+
etag: S.String // TODO: use a Model thing that auto updates it?
|
|
42
43
|
// TODO: record locking.. / optimistic locking
|
|
43
44
|
// rowVersion: Model.DateTimeFromNumberWithNow
|
|
44
45
|
}
|
|
@@ -55,13 +56,15 @@ export function makeSQLQueue<
|
|
|
55
56
|
const queueRepo = yield* Model.makeRepository(Queue, {
|
|
56
57
|
tableName: "queue",
|
|
57
58
|
spanPrefix: "QueueRepo",
|
|
58
|
-
idColumn: "id"
|
|
59
|
+
idColumn: "id",
|
|
60
|
+
versionColumn: "etag"
|
|
59
61
|
})
|
|
60
62
|
|
|
61
63
|
const drainRepo = yield* Model.makeRepository(Drain, {
|
|
62
64
|
tableName: "queue",
|
|
63
65
|
spanPrefix: "DrainRepo",
|
|
64
|
-
idColumn: "id"
|
|
66
|
+
idColumn: "id",
|
|
67
|
+
versionColumn: "etag"
|
|
65
68
|
})
|
|
66
69
|
|
|
67
70
|
const decodeDrain = S.decode(Drain)
|
|
@@ -74,9 +77,6 @@ export function makeSQLQueue<
|
|
|
74
77
|
LIMIT 1`
|
|
75
78
|
}
|
|
76
79
|
|
|
77
|
-
// temporary workaround until we have a SQLite rowversion..
|
|
78
|
-
const lock = yield* Effect.makeSemaphore(1)
|
|
79
|
-
|
|
80
80
|
const q = {
|
|
81
81
|
offer: (body: Evt, meta: typeof QueueMeta.Type) =>
|
|
82
82
|
Effect.gen(function*() {
|
|
@@ -86,28 +86,28 @@ export function makeSQLQueue<
|
|
|
86
86
|
meta,
|
|
87
87
|
name: queueName,
|
|
88
88
|
processingAt: Option.none(),
|
|
89
|
-
finishedAt: Option.none()
|
|
89
|
+
finishedAt: Option.none(),
|
|
90
|
+
etag: randomUUID()
|
|
90
91
|
})
|
|
91
92
|
)
|
|
92
93
|
}),
|
|
93
94
|
take: Effect.gen(function*() {
|
|
94
95
|
while (true) {
|
|
95
|
-
const first = yield*
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}))
|
|
96
|
+
const [first] = yield* drain()
|
|
97
|
+
if (first) {
|
|
98
|
+
const dec = yield* decodeDrain(first)
|
|
99
|
+
const { createdAt, updatedAt, ...rest } = dec
|
|
100
|
+
yield* drainRepo.update(
|
|
101
|
+
Drain.update.make({ ...rest, processingAt: Option.some(new Date()) }) // auto in lib , etag: randomUUID()
|
|
102
|
+
)
|
|
103
|
+
return dec
|
|
104
|
+
}
|
|
105
105
|
if (first) return first
|
|
106
106
|
yield* Effect.sleep(250)
|
|
107
107
|
}
|
|
108
108
|
}),
|
|
109
109
|
finish: ({ createdAt, updatedAt, ...q }: Drain) =>
|
|
110
|
-
drainRepo.update(Drain.update.make({ ...q, finishedAt: Option.some(new Date()) }))
|
|
110
|
+
drainRepo.update(Drain.update.make({ ...q, finishedAt: Option.some(new Date()) })) // auto in lib , etag: randomUUID()
|
|
111
111
|
}
|
|
112
112
|
const rcc = yield* RequestContextContainer
|
|
113
113
|
|
package/tsconfig.src.json
CHANGED
package/tsconfig.test.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
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=
|