@hotmeshio/hotmesh 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/build/modules/enums.d.ts +110 -0
  2. package/build/modules/enums.js +134 -0
  3. package/build/modules/errors.d.ts +124 -0
  4. package/build/modules/errors.js +191 -0
  5. package/build/modules/key.d.ts +66 -0
  6. package/build/modules/key.js +190 -0
  7. package/build/modules/storage.d.ts +3 -0
  8. package/build/modules/storage.js +5 -0
  9. package/build/modules/utils.d.ts +119 -0
  10. package/build/modules/utils.js +374 -0
  11. package/build/package.json +1 -1
  12. package/build/services/activities/activity.d.ts +104 -0
  13. package/build/services/activities/activity.js +549 -0
  14. package/build/services/activities/await.d.ts +12 -0
  15. package/build/services/activities/await.js +114 -0
  16. package/build/services/activities/cycle.d.ts +19 -0
  17. package/build/services/activities/cycle.js +112 -0
  18. package/build/services/activities/hook.d.ts +27 -0
  19. package/build/services/activities/hook.js +168 -0
  20. package/build/services/activities/index.d.ts +19 -0
  21. package/build/services/activities/index.js +20 -0
  22. package/build/services/activities/interrupt.d.ts +16 -0
  23. package/build/services/activities/interrupt.js +158 -0
  24. package/build/services/activities/signal.d.ts +20 -0
  25. package/build/services/activities/signal.js +134 -0
  26. package/build/services/activities/trigger.d.ts +37 -0
  27. package/build/services/activities/trigger.js +246 -0
  28. package/build/services/activities/worker.d.ts +12 -0
  29. package/build/services/activities/worker.js +106 -0
  30. package/build/services/collator/index.d.ts +111 -0
  31. package/build/services/collator/index.js +293 -0
  32. package/build/services/compiler/deployer.d.ts +40 -0
  33. package/build/services/compiler/deployer.js +488 -0
  34. package/build/services/compiler/index.d.ts +32 -0
  35. package/build/services/compiler/index.js +112 -0
  36. package/build/services/compiler/validator.d.ts +34 -0
  37. package/build/services/compiler/validator.js +147 -0
  38. package/build/services/connector/factory.d.ts +22 -0
  39. package/build/services/connector/factory.js +99 -0
  40. package/build/services/connector/index.d.ts +30 -0
  41. package/build/services/connector/index.js +54 -0
  42. package/build/services/connector/providers/ioredis.d.ts +9 -0
  43. package/build/services/connector/providers/ioredis.js +26 -0
  44. package/build/services/connector/providers/nats.d.ts +9 -0
  45. package/build/services/connector/providers/nats.js +34 -0
  46. package/build/services/connector/providers/postgres.d.ts +20 -0
  47. package/build/services/connector/providers/postgres.js +102 -0
  48. package/build/services/connector/providers/redis.d.ts +9 -0
  49. package/build/services/connector/providers/redis.js +38 -0
  50. package/build/services/engine/index.d.ts +264 -0
  51. package/build/services/engine/index.js +761 -0
  52. package/build/services/exporter/index.d.ts +44 -0
  53. package/build/services/exporter/index.js +126 -0
  54. package/build/services/hotmesh/index.d.ts +483 -0
  55. package/build/services/hotmesh/index.js +622 -0
  56. package/build/services/logger/index.d.ts +16 -0
  57. package/build/services/logger/index.js +54 -0
  58. package/build/services/mapper/index.d.ts +28 -0
  59. package/build/services/mapper/index.js +81 -0
  60. package/build/services/memflow/client.d.ts +108 -0
  61. package/build/services/memflow/client.js +372 -0
  62. package/build/services/memflow/connection.d.ts +23 -0
  63. package/build/services/memflow/connection.js +33 -0
  64. package/build/services/memflow/context.d.ts +143 -0
  65. package/build/services/memflow/context.js +299 -0
  66. package/build/services/memflow/exporter.d.ts +51 -0
  67. package/build/services/memflow/exporter.js +215 -0
  68. package/build/services/memflow/handle.d.ts +90 -0
  69. package/build/services/memflow/handle.js +176 -0
  70. package/build/services/memflow/index.d.ts +116 -0
  71. package/build/services/memflow/index.js +122 -0
  72. package/build/services/memflow/schemas/factory.d.ts +29 -0
  73. package/build/services/memflow/schemas/factory.js +2492 -0
  74. package/build/services/memflow/search.d.ts +142 -0
  75. package/build/services/memflow/search.js +320 -0
  76. package/build/services/memflow/worker.d.ts +124 -0
  77. package/build/services/memflow/worker.js +514 -0
  78. package/build/services/memflow/workflow/all.d.ts +7 -0
  79. package/build/services/memflow/workflow/all.js +15 -0
  80. package/build/services/memflow/workflow/common.d.ts +20 -0
  81. package/build/services/memflow/workflow/common.js +47 -0
  82. package/build/services/memflow/workflow/context.d.ts +6 -0
  83. package/build/services/memflow/workflow/context.js +45 -0
  84. package/build/services/memflow/workflow/contextMethods.d.ts +14 -0
  85. package/build/services/memflow/workflow/contextMethods.js +33 -0
  86. package/build/services/memflow/workflow/didRun.d.ts +7 -0
  87. package/build/services/memflow/workflow/didRun.js +22 -0
  88. package/build/services/memflow/workflow/emit.d.ts +11 -0
  89. package/build/services/memflow/workflow/emit.js +29 -0
  90. package/build/services/memflow/workflow/enrich.d.ts +9 -0
  91. package/build/services/memflow/workflow/enrich.js +17 -0
  92. package/build/services/memflow/workflow/execChild.d.ts +18 -0
  93. package/build/services/memflow/workflow/execChild.js +102 -0
  94. package/build/services/memflow/workflow/execHook.d.ts +65 -0
  95. package/build/services/memflow/workflow/execHook.js +73 -0
  96. package/build/services/memflow/workflow/hook.d.ts +9 -0
  97. package/build/services/memflow/workflow/hook.js +56 -0
  98. package/build/services/memflow/workflow/index.d.ts +74 -0
  99. package/build/services/memflow/workflow/index.js +87 -0
  100. package/build/services/memflow/workflow/interrupt.d.ts +9 -0
  101. package/build/services/memflow/workflow/interrupt.js +24 -0
  102. package/build/services/memflow/workflow/isSideEffectAllowed.d.ts +10 -0
  103. package/build/services/memflow/workflow/isSideEffectAllowed.js +33 -0
  104. package/build/services/memflow/workflow/proxyActivities.d.ts +20 -0
  105. package/build/services/memflow/workflow/proxyActivities.js +97 -0
  106. package/build/services/memflow/workflow/random.d.ts +6 -0
  107. package/build/services/memflow/workflow/random.js +16 -0
  108. package/build/services/memflow/workflow/searchMethods.d.ts +6 -0
  109. package/build/services/memflow/workflow/searchMethods.js +25 -0
  110. package/build/services/memflow/workflow/signal.d.ts +7 -0
  111. package/build/services/memflow/workflow/signal.js +28 -0
  112. package/build/services/memflow/workflow/sleepFor.d.ts +8 -0
  113. package/build/services/memflow/workflow/sleepFor.js +35 -0
  114. package/build/services/memflow/workflow/trace.d.ts +14 -0
  115. package/build/services/memflow/workflow/trace.js +33 -0
  116. package/build/services/memflow/workflow/waitFor.d.ts +8 -0
  117. package/build/services/memflow/workflow/waitFor.js +35 -0
  118. package/build/services/meshcall/index.d.ts +194 -0
  119. package/build/services/meshcall/index.js +452 -0
  120. package/build/services/meshcall/schemas/factory.d.ts +9 -0
  121. package/build/services/meshcall/schemas/factory.js +189 -0
  122. package/build/services/meshdata/index.d.ts +795 -0
  123. package/build/services/meshdata/index.js +1235 -0
  124. package/build/services/meshos/index.d.ts +293 -0
  125. package/build/services/meshos/index.js +547 -0
  126. package/build/services/pipe/functions/array.d.ts +17 -0
  127. package/build/services/pipe/functions/array.js +74 -0
  128. package/build/services/pipe/functions/bitwise.d.ts +9 -0
  129. package/build/services/pipe/functions/bitwise.js +24 -0
  130. package/build/services/pipe/functions/conditional.d.ts +13 -0
  131. package/build/services/pipe/functions/conditional.js +36 -0
  132. package/build/services/pipe/functions/cron.d.ts +12 -0
  133. package/build/services/pipe/functions/cron.js +40 -0
  134. package/build/services/pipe/functions/date.d.ts +58 -0
  135. package/build/services/pipe/functions/date.js +171 -0
  136. package/build/services/pipe/functions/index.d.ts +29 -0
  137. package/build/services/pipe/functions/index.js +30 -0
  138. package/build/services/pipe/functions/json.d.ts +5 -0
  139. package/build/services/pipe/functions/json.js +12 -0
  140. package/build/services/pipe/functions/logical.d.ts +5 -0
  141. package/build/services/pipe/functions/logical.js +12 -0
  142. package/build/services/pipe/functions/math.d.ts +42 -0
  143. package/build/services/pipe/functions/math.js +184 -0
  144. package/build/services/pipe/functions/number.d.ts +21 -0
  145. package/build/services/pipe/functions/number.js +60 -0
  146. package/build/services/pipe/functions/object.d.ts +25 -0
  147. package/build/services/pipe/functions/object.js +81 -0
  148. package/build/services/pipe/functions/string.d.ts +23 -0
  149. package/build/services/pipe/functions/string.js +69 -0
  150. package/build/services/pipe/functions/symbol.d.ts +12 -0
  151. package/build/services/pipe/functions/symbol.js +33 -0
  152. package/build/services/pipe/functions/unary.d.ts +7 -0
  153. package/build/services/pipe/functions/unary.js +18 -0
  154. package/build/services/pipe/index.d.ts +48 -0
  155. package/build/services/pipe/index.js +242 -0
  156. package/build/services/quorum/index.d.ts +90 -0
  157. package/build/services/quorum/index.js +263 -0
  158. package/build/services/reporter/index.d.ts +50 -0
  159. package/build/services/reporter/index.js +348 -0
  160. package/build/services/router/config/index.d.ts +11 -0
  161. package/build/services/router/config/index.js +36 -0
  162. package/build/services/router/consumption/index.d.ts +34 -0
  163. package/build/services/router/consumption/index.js +395 -0
  164. package/build/services/router/error-handling/index.d.ts +8 -0
  165. package/build/services/router/error-handling/index.js +98 -0
  166. package/build/services/router/index.d.ts +57 -0
  167. package/build/services/router/index.js +121 -0
  168. package/build/services/router/lifecycle/index.d.ts +27 -0
  169. package/build/services/router/lifecycle/index.js +80 -0
  170. package/build/services/router/telemetry/index.d.ts +11 -0
  171. package/build/services/router/telemetry/index.js +32 -0
  172. package/build/services/router/throttling/index.d.ts +23 -0
  173. package/build/services/router/throttling/index.js +76 -0
  174. package/build/services/search/factory.d.ts +7 -0
  175. package/build/services/search/factory.js +24 -0
  176. package/build/services/search/index.d.ts +23 -0
  177. package/build/services/search/index.js +10 -0
  178. package/build/services/search/providers/postgres/postgres.d.ts +25 -0
  179. package/build/services/search/providers/postgres/postgres.js +149 -0
  180. package/build/services/search/providers/redis/ioredis.d.ts +19 -0
  181. package/build/services/search/providers/redis/ioredis.js +121 -0
  182. package/build/services/search/providers/redis/redis.d.ts +19 -0
  183. package/build/services/search/providers/redis/redis.js +134 -0
  184. package/build/services/serializer/index.d.ts +42 -0
  185. package/build/services/serializer/index.js +282 -0
  186. package/build/services/store/cache.d.ts +67 -0
  187. package/build/services/store/cache.js +128 -0
  188. package/build/services/store/factory.d.ts +8 -0
  189. package/build/services/store/factory.js +24 -0
  190. package/build/services/store/index.d.ts +89 -0
  191. package/build/services/store/index.js +9 -0
  192. package/build/services/store/providers/postgres/kvsql.d.ts +168 -0
  193. package/build/services/store/providers/postgres/kvsql.js +198 -0
  194. package/build/services/store/providers/postgres/kvtables.d.ts +20 -0
  195. package/build/services/store/providers/postgres/kvtables.js +441 -0
  196. package/build/services/store/providers/postgres/kvtransaction.d.ts +36 -0
  197. package/build/services/store/providers/postgres/kvtransaction.js +248 -0
  198. package/build/services/store/providers/postgres/kvtypes/hash.d.ts +60 -0
  199. package/build/services/store/providers/postgres/kvtypes/hash.js +1287 -0
  200. package/build/services/store/providers/postgres/kvtypes/list.d.ts +33 -0
  201. package/build/services/store/providers/postgres/kvtypes/list.js +194 -0
  202. package/build/services/store/providers/postgres/kvtypes/string.d.ts +20 -0
  203. package/build/services/store/providers/postgres/kvtypes/string.js +115 -0
  204. package/build/services/store/providers/postgres/kvtypes/zset.d.ts +41 -0
  205. package/build/services/store/providers/postgres/kvtypes/zset.js +214 -0
  206. package/build/services/store/providers/postgres/postgres.d.ts +145 -0
  207. package/build/services/store/providers/postgres/postgres.js +1036 -0
  208. package/build/services/store/providers/redis/_base.d.ts +137 -0
  209. package/build/services/store/providers/redis/_base.js +980 -0
  210. package/build/services/store/providers/redis/ioredis.d.ts +20 -0
  211. package/build/services/store/providers/redis/ioredis.js +180 -0
  212. package/build/services/store/providers/redis/redis.d.ts +18 -0
  213. package/build/services/store/providers/redis/redis.js +199 -0
  214. package/build/services/store/providers/store-initializable.d.ts +5 -0
  215. package/build/services/store/providers/store-initializable.js +2 -0
  216. package/build/services/stream/factory.d.ts +8 -0
  217. package/build/services/stream/factory.js +37 -0
  218. package/build/services/stream/index.d.ts +69 -0
  219. package/build/services/stream/index.js +11 -0
  220. package/build/services/stream/providers/nats/nats.d.ts +60 -0
  221. package/build/services/stream/providers/nats/nats.js +225 -0
  222. package/build/services/stream/providers/postgres/kvtables.d.ts +3 -0
  223. package/build/services/stream/providers/postgres/kvtables.js +146 -0
  224. package/build/services/stream/providers/postgres/postgres.d.ts +107 -0
  225. package/build/services/stream/providers/postgres/postgres.js +519 -0
  226. package/build/services/stream/providers/redis/ioredis.d.ts +61 -0
  227. package/build/services/stream/providers/redis/ioredis.js +272 -0
  228. package/build/services/stream/providers/redis/redis.d.ts +61 -0
  229. package/build/services/stream/providers/redis/redis.js +305 -0
  230. package/build/services/stream/providers/stream-initializable.d.ts +4 -0
  231. package/build/services/stream/providers/stream-initializable.js +2 -0
  232. package/build/services/sub/factory.d.ts +7 -0
  233. package/build/services/sub/factory.js +29 -0
  234. package/build/services/sub/index.d.ts +22 -0
  235. package/build/services/sub/index.js +10 -0
  236. package/build/services/sub/providers/nats/nats.d.ts +19 -0
  237. package/build/services/sub/providers/nats/nats.js +105 -0
  238. package/build/services/sub/providers/postgres/postgres.d.ts +19 -0
  239. package/build/services/sub/providers/postgres/postgres.js +92 -0
  240. package/build/services/sub/providers/redis/ioredis.d.ts +17 -0
  241. package/build/services/sub/providers/redis/ioredis.js +81 -0
  242. package/build/services/sub/providers/redis/redis.d.ts +17 -0
  243. package/build/services/sub/providers/redis/redis.js +72 -0
  244. package/build/services/task/index.d.ts +36 -0
  245. package/build/services/task/index.js +206 -0
  246. package/build/services/telemetry/index.d.ts +52 -0
  247. package/build/services/telemetry/index.js +306 -0
  248. package/build/services/worker/index.d.ts +77 -0
  249. package/build/services/worker/index.js +197 -0
  250. package/package.json +1 -1
  251. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  252. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  253. package/typedoc.json +0 -47
  254. package/types/activity.ts +0 -268
  255. package/types/app.ts +0 -20
  256. package/types/async.ts +0 -6
  257. package/types/cache.ts +0 -1
  258. package/types/collator.ts +0 -9
  259. package/types/error.ts +0 -56
  260. package/types/exporter.ts +0 -102
  261. package/types/hook.ts +0 -44
  262. package/types/hotmesh.ts +0 -314
  263. package/types/index.ts +0 -306
  264. package/types/job.ts +0 -233
  265. package/types/logger.ts +0 -8
  266. package/types/manifest.ts +0 -70
  267. package/types/map.ts +0 -5
  268. package/types/memflow.ts +0 -645
  269. package/types/meshcall.ts +0 -235
  270. package/types/meshdata.ts +0 -278
  271. package/types/ms.d.ts +0 -7
  272. package/types/nats.ts +0 -270
  273. package/types/pipe.ts +0 -90
  274. package/types/postgres.ts +0 -114
  275. package/types/provider.ts +0 -161
  276. package/types/quorum.ts +0 -167
  277. package/types/redis.ts +0 -404
  278. package/types/serializer.ts +0 -40
  279. package/types/stats.ts +0 -117
  280. package/types/stream.ts +0 -231
  281. package/types/task.ts +0 -7
  282. package/types/telemetry.ts +0 -16
  283. package/types/transition.ts +0 -20
@@ -0,0 +1,1036 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.PostgresStoreService = void 0;
27
+ const errors_1 = require("../../../../modules/errors");
28
+ const key_1 = require("../../../../modules/key");
29
+ const serializer_1 = require("../../../serializer");
30
+ const utils_1 = require("../../../../modules/utils");
31
+ const enums_1 = require("../../../../modules/enums");
32
+ const cache_1 = require("../../cache");
33
+ const __1 = require("../..");
34
+ const kvsql_1 = require("./kvsql");
35
+ const kvtables_1 = require("./kvtables");
36
+ class PostgresStoreService extends __1.StoreService {
37
+ transact() {
38
+ return this.storeClient.transact();
39
+ }
40
+ constructor(storeClient) {
41
+ super(storeClient);
42
+ //Instead of directly referencing the 'pg' package and methods like 'query',
43
+ // the PostgresStore wraps the 'pg' client in a class that implements
44
+ // the Redis client interface. This allows the same methods to be called
45
+ // that were used when authoring the Redis client store provider.
46
+ //In general, this.storeClient will behave like Redis, but will
47
+ // use the 'pg' package and will read/write to a Postgres database.
48
+ this.pgClient = storeClient;
49
+ this.storeClient = new kvsql_1.KVSQL(storeClient, this.namespace, this.appId);
50
+ //kvTables will provision tables and indexes in the Postgres db as necessary
51
+ this.kvTables = (0, kvtables_1.KVTables)(this);
52
+ }
53
+ async init(namespace = key_1.HMNS, appId, logger) {
54
+ //bind appId and namespace to storeClient once initialized
55
+ // (it uses these values to construct keys for the store)
56
+ this.storeClient.namespace = this.namespace = namespace;
57
+ this.storeClient.appId = this.appId = appId;
58
+ this.logger = logger;
59
+ //confirm db tables exist
60
+ await this.kvTables.deploy(appId);
61
+ //note: getSettings will contact db to confirm r/w access
62
+ const settings = await this.getSettings(true);
63
+ this.cache = new cache_1.Cache(appId, settings);
64
+ this.serializer = new serializer_1.SerializerService();
65
+ await this.getApp(appId);
66
+ return this.cache.getApps();
67
+ }
68
+ isSuccessful(result) {
69
+ return result > 0 || result === 'OK' || result === true;
70
+ }
71
+ async delistSignalKey(key, target) {
72
+ await this.kvsql().del(`${key}:${target}`);
73
+ }
74
+ async zAdd(key, score, value, transaction) {
75
+ //default call signature uses 'ioredis' NPM Package format
76
+ return await this.kvsql(transaction).zadd(key, Number(score), value.toString());
77
+ }
78
+ async zRangeByScore(key, score, value) {
79
+ const result = await this.kvsql().zrangebyscore(key, Number(score), Number(value));
80
+ if (result?.length > 0) {
81
+ return result[0];
82
+ }
83
+ return null;
84
+ }
85
+ mintKey(type, params) {
86
+ if (!this.namespace)
87
+ throw new Error('namespace not set');
88
+ return key_1.KeyService.mintKey(this.namespace, type, params);
89
+ }
90
+ /**
91
+ * strongly types the transaction or storeClient as KVSQL,
92
+ * so methods are visible to the compiler/code editor
93
+ */
94
+ kvsql(transaction) {
95
+ return (transaction || this.storeClient);
96
+ }
97
+ invalidateCache() {
98
+ this.cache.invalidate();
99
+ }
100
+ /**
101
+ * At any given time only a single engine will
102
+ * check for and process work items in the
103
+ * time and signal task queues.
104
+ */
105
+ async reserveScoutRole(scoutType, delay = enums_1.HMSH_SCOUT_INTERVAL_SECONDS) {
106
+ const key = this.mintKey(key_1.KeyType.WORK_ITEMS, {
107
+ appId: this.appId,
108
+ scoutType,
109
+ });
110
+ const success = await this.kvsql().set(key, `${scoutType}:${(0, utils_1.formatISODate)(new Date())}`, { nx: true, ex: delay - 1 });
111
+ return this.isSuccessful(success);
112
+ }
113
+ async releaseScoutRole(scoutType) {
114
+ const key = this.mintKey(key_1.KeyType.WORK_ITEMS, {
115
+ appId: this.appId,
116
+ scoutType,
117
+ });
118
+ const success = await this.kvsql().del(key);
119
+ return this.isSuccessful(success);
120
+ }
121
+ async getSettings(bCreate = false) {
122
+ let settings = this.cache?.getSettings();
123
+ if (settings) {
124
+ return settings;
125
+ }
126
+ else {
127
+ if (bCreate) {
128
+ const packageJson = await Promise.resolve().then(() => __importStar(require('../../../../package.json')));
129
+ const version = packageJson['version'] || '0.0.0';
130
+ settings = { namespace: key_1.HMNS, version };
131
+ await this.setSettings(settings);
132
+ return settings;
133
+ }
134
+ }
135
+ throw new Error('settings not found');
136
+ }
137
+ async setSettings(manifest) {
138
+ //HotMesh heartbeat. If a connection is made, the version will be set
139
+ const params = {};
140
+ const key = this.mintKey(key_1.KeyType.HOTMESH, params);
141
+ return await this.kvsql().hset(key, manifest);
142
+ }
143
+ async reserveSymbolRange(target, size, type, tryCount = 1) {
144
+ const rangeKey = this.mintKey(key_1.KeyType.SYMKEYS, { appId: this.appId });
145
+ const symbolKey = this.mintKey(key_1.KeyType.SYMKEYS, {
146
+ activityId: target,
147
+ appId: this.appId,
148
+ });
149
+ //reserve the slot in a `pending` state (range will be established in the next step)
150
+ const response = await this.kvsql().hsetnx(rangeKey, target, '?:?');
151
+ if (response) {
152
+ //if the key didn't exist, set the inclusive range and seed metadata fields
153
+ const upperLimit = await this.kvsql().hincrbyfloat(rangeKey, ':cursor', size);
154
+ const lowerLimit = upperLimit - size;
155
+ const inclusiveRange = `${lowerLimit}:${upperLimit - 1}`;
156
+ await this.kvsql().hset(rangeKey, { [target]: inclusiveRange });
157
+ const metadataSeeds = this.seedSymbols(target, type, lowerLimit);
158
+ await this.kvsql().hset(symbolKey, metadataSeeds);
159
+ return [lowerLimit + serializer_1.MDATA_SYMBOLS.SLOTS, upperLimit - 1, {}];
160
+ }
161
+ else {
162
+ //if the key already existed, get the lower limit and add the number of symbols
163
+ const range = await this.kvsql().hget(rangeKey, target);
164
+ const [lowerLimitString] = range.split(':');
165
+ if (lowerLimitString === '?') {
166
+ await (0, utils_1.sleepFor)(tryCount * 1000);
167
+ if (tryCount < 5) {
168
+ return this.reserveSymbolRange(target, size, type, tryCount + 1);
169
+ }
170
+ else {
171
+ throw new Error('Symbol range reservation failed due to deployment contention');
172
+ }
173
+ }
174
+ else {
175
+ const lowerLimit = parseInt(lowerLimitString, 10);
176
+ const symbols = await this.kvsql().hgetall(symbolKey);
177
+ const symbolCount = Object.keys(symbols).length;
178
+ const actualLowerLimit = lowerLimit + serializer_1.MDATA_SYMBOLS.SLOTS + symbolCount;
179
+ const upperLimit = Number(lowerLimit + size - 1);
180
+ return [actualLowerLimit, upperLimit, symbols];
181
+ }
182
+ }
183
+ }
184
+ async getAllSymbols() {
185
+ //get hash with all reserved symbol ranges
186
+ const rangeKey = this.mintKey(key_1.KeyType.SYMKEYS, { appId: this.appId });
187
+ const ranges = await this.kvsql().hgetall(rangeKey);
188
+ const rangeKeys = Object.keys(ranges).sort();
189
+ delete rangeKeys[':cursor'];
190
+ //wrap the transact call in kvsql so datatypes are consistent
191
+ const transaction = this.kvsql(this.transact());
192
+ for (const rangeKey of rangeKeys) {
193
+ const symbolKey = this.mintKey(key_1.KeyType.SYMKEYS, {
194
+ activityId: rangeKey,
195
+ appId: this.appId,
196
+ });
197
+ transaction.hgetall(symbolKey);
198
+ }
199
+ const results = (await transaction.exec());
200
+ const symbolSets = {};
201
+ results.forEach((result, index) => {
202
+ if (result) {
203
+ let vals;
204
+ if (Array.isArray(result) && result.length === 2) {
205
+ vals = result[1];
206
+ }
207
+ else {
208
+ vals = result;
209
+ }
210
+ for (const [key, value] of Object.entries(vals)) {
211
+ symbolSets[value] = key.startsWith(rangeKeys[index])
212
+ ? key
213
+ : `${rangeKeys[index]}/${key}`;
214
+ }
215
+ }
216
+ });
217
+ return symbolSets;
218
+ }
219
+ async getSymbols(activityId) {
220
+ let symbols = this.cache.getSymbols(this.appId, activityId);
221
+ if (symbols) {
222
+ return symbols;
223
+ }
224
+ else {
225
+ const params = { activityId, appId: this.appId };
226
+ const key = this.mintKey(key_1.KeyType.SYMKEYS, params);
227
+ symbols = (await this.kvsql().hgetall(key));
228
+ this.cache.setSymbols(this.appId, activityId, symbols);
229
+ return symbols;
230
+ }
231
+ }
232
+ async addSymbols(activityId, symbols) {
233
+ if (!symbols || !Object.keys(symbols).length)
234
+ return false;
235
+ const params = { activityId, appId: this.appId };
236
+ const key = this.mintKey(key_1.KeyType.SYMKEYS, params);
237
+ const success = await this.kvsql().hset(key, symbols);
238
+ this.cache.deleteSymbols(this.appId, activityId);
239
+ return success > 0;
240
+ }
241
+ seedSymbols(target, type, startIndex) {
242
+ if (type === 'JOB') {
243
+ return this.seedJobSymbols(startIndex);
244
+ }
245
+ return this.seedActivitySymbols(startIndex, target);
246
+ }
247
+ seedJobSymbols(startIndex) {
248
+ const hash = {};
249
+ serializer_1.MDATA_SYMBOLS.JOB.KEYS.forEach((key) => {
250
+ hash[`metadata/${key}`] = (0, utils_1.getSymKey)(startIndex);
251
+ startIndex++;
252
+ });
253
+ return hash;
254
+ }
255
+ seedActivitySymbols(startIndex, activityId) {
256
+ const hash = {};
257
+ serializer_1.MDATA_SYMBOLS.ACTIVITY.KEYS.forEach((key) => {
258
+ hash[`${activityId}/output/metadata/${key}`] = (0, utils_1.getSymKey)(startIndex);
259
+ startIndex++;
260
+ });
261
+ return hash;
262
+ }
263
+ async getSymbolValues() {
264
+ let symvals = this.cache.getSymbolValues(this.appId);
265
+ if (symvals) {
266
+ return symvals;
267
+ }
268
+ else {
269
+ const key = this.mintKey(key_1.KeyType.SYMVALS, { appId: this.appId });
270
+ symvals = await this.kvsql().hgetall(key);
271
+ this.cache.setSymbolValues(this.appId, symvals);
272
+ return symvals;
273
+ }
274
+ }
275
+ async addSymbolValues(symvals) {
276
+ if (!symvals || !Object.keys(symvals).length)
277
+ return false;
278
+ const key = this.mintKey(key_1.KeyType.SYMVALS, { appId: this.appId });
279
+ const success = await this.kvsql().hset(key, symvals);
280
+ this.cache.deleteSymbolValues(this.appId);
281
+ return this.isSuccessful(success);
282
+ }
283
+ async getSymbolKeys(symbolNames) {
284
+ const symbolLookups = [];
285
+ for (const symbolName of symbolNames) {
286
+ symbolLookups.push(this.getSymbols(symbolName));
287
+ }
288
+ const symbolSets = await Promise.all(symbolLookups);
289
+ const symKeys = {};
290
+ for (const symbolName of symbolNames) {
291
+ symKeys[symbolName] = symbolSets.shift();
292
+ }
293
+ return symKeys;
294
+ }
295
+ async getApp(id, refresh = false) {
296
+ let app = this.cache.getApp(id);
297
+ if (refresh || !(app && Object.keys(app).length > 0)) {
298
+ const params = { appId: id };
299
+ const key = this.mintKey(key_1.KeyType.APP, params);
300
+ const sApp = await this.kvsql().hgetall(key);
301
+ if (!sApp)
302
+ return null;
303
+ app = {};
304
+ for (const field in sApp) {
305
+ try {
306
+ if (field === 'active') {
307
+ app[field] = sApp[field] === 'true';
308
+ }
309
+ else {
310
+ app[field] = sApp[field];
311
+ }
312
+ }
313
+ catch (e) {
314
+ app[field] = sApp[field];
315
+ }
316
+ }
317
+ this.cache.setApp(id, app);
318
+ }
319
+ return app;
320
+ }
321
+ async setApp(id, version) {
322
+ const params = { appId: id };
323
+ const key = this.mintKey(key_1.KeyType.APP, params);
324
+ const versionId = `versions/${version}`;
325
+ const payload = {
326
+ id,
327
+ version,
328
+ [versionId]: `deployed:${(0, utils_1.formatISODate)(new Date())}`,
329
+ };
330
+ await this.kvsql().hset(key, payload);
331
+ this.cache.setApp(id, payload);
332
+ return payload;
333
+ }
334
+ async activateAppVersion(id, version) {
335
+ const params = { appId: id };
336
+ const key = this.mintKey(key_1.KeyType.APP, params);
337
+ const versionId = `versions/${version}`;
338
+ const app = await this.getApp(id, true);
339
+ if (app && app[versionId]) {
340
+ const payload = {
341
+ id,
342
+ version: version.toString(),
343
+ [versionId]: `activated:${(0, utils_1.formatISODate)(new Date())}`,
344
+ active: true,
345
+ };
346
+ Object.entries(payload).forEach(([key, value]) => {
347
+ payload[key] = value.toString();
348
+ });
349
+ await this.kvsql().hset(key, payload);
350
+ return true;
351
+ }
352
+ throw new Error(`Version ${version} does not exist for app ${id}`);
353
+ }
354
+ async registerAppVersion(appId, version) {
355
+ const params = { appId };
356
+ const key = this.mintKey(key_1.KeyType.APP, params);
357
+ const payload = {
358
+ id: appId,
359
+ version: version.toString(),
360
+ [`versions/${version}`]: (0, utils_1.formatISODate)(new Date()),
361
+ };
362
+ return await this.kvsql().hset(key, payload);
363
+ }
364
+ async setStats(jobKey, jobId, dateTime, stats, appVersion, transaction) {
365
+ const params = {
366
+ appId: appVersion.id,
367
+ jobId,
368
+ jobKey,
369
+ dateTime,
370
+ };
371
+ const localTransaction = transaction || this.transact();
372
+ if (stats.general.length) {
373
+ const generalStatsKey = this.mintKey(key_1.KeyType.JOB_STATS_GENERAL, params);
374
+ for (const { target, value } of stats.general) {
375
+ this.kvsql(localTransaction).hincrbyfloat(generalStatsKey, target, value);
376
+ }
377
+ }
378
+ for (const { target, value } of stats.index) {
379
+ const indexParams = { ...params, facet: target };
380
+ const indexStatsKey = this.mintKey(key_1.KeyType.JOB_STATS_INDEX, indexParams);
381
+ this.kvsql(localTransaction).rpush(indexStatsKey, value.toString());
382
+ }
383
+ for (const { target, value } of stats.median) {
384
+ const medianParams = { ...params, facet: target };
385
+ const medianStatsKey = this.mintKey(key_1.KeyType.JOB_STATS_MEDIAN, medianParams);
386
+ await this.kvsql(localTransaction).zadd(medianStatsKey, Number(value), target);
387
+ }
388
+ if (!transaction) {
389
+ return await localTransaction.exec();
390
+ }
391
+ }
392
+ hGetAllResult(result) {
393
+ //default response signature uses 'redis' NPM Package format
394
+ return result;
395
+ }
396
+ async getJobStats(jobKeys) {
397
+ const transaction = this.kvsql(this.transact());
398
+ for (const jobKey of jobKeys) {
399
+ transaction.hgetall(jobKey);
400
+ }
401
+ const results = await transaction.exec();
402
+ const output = {};
403
+ for (const [index, result] of results.entries()) {
404
+ const key = jobKeys[index];
405
+ const statsHash = result;
406
+ if (statsHash && Object.keys(statsHash).length > 0) {
407
+ const resolvedStatsHash = { ...statsHash };
408
+ for (const [key, val] of Object.entries(resolvedStatsHash)) {
409
+ resolvedStatsHash[key] = Number(val);
410
+ }
411
+ output[key] = resolvedStatsHash;
412
+ }
413
+ else {
414
+ output[key] = {};
415
+ }
416
+ }
417
+ return output;
418
+ }
419
+ async getJobIds(indexKeys, idRange) {
420
+ const transaction = this.kvsql(this.transact());
421
+ for (const idsKey of indexKeys) {
422
+ transaction.lrange(idsKey, idRange[0], idRange[1]); //0,-1 returns all ids
423
+ }
424
+ const results = await transaction.exec();
425
+ const output = {};
426
+ for (const [index, result] of results.entries()) {
427
+ const key = indexKeys[index];
428
+ const idsList = result[1] || result;
429
+ if (idsList && idsList.length > 0) {
430
+ output[key] = idsList;
431
+ }
432
+ else {
433
+ output[key] = [];
434
+ }
435
+ }
436
+ return output;
437
+ }
438
+ async setStatus(collationKeyStatus, jobId, appId, transaction) {
439
+ const jobKey = this.mintKey(key_1.KeyType.JOB_STATE, { appId, jobId });
440
+ return await this.kvsql(transaction).hincrbyfloat(jobKey, ':', collationKeyStatus);
441
+ }
442
+ async getStatus(jobId, appId) {
443
+ const jobKey = this.mintKey(key_1.KeyType.JOB_STATE, { appId, jobId });
444
+ const status = await this.kvsql().hget(jobKey, ':');
445
+ if (status === null) {
446
+ throw new Error(`Job ${jobId} not found`);
447
+ }
448
+ return Number(status);
449
+ }
450
+ async setState({ ...state }, status, jobId, symbolNames, dIds, transaction) {
451
+ delete state['metadata/js'];
452
+ const hashKey = this.mintKey(key_1.KeyType.JOB_STATE, {
453
+ appId: this.appId,
454
+ jobId,
455
+ });
456
+ const symKeys = await this.getSymbolKeys(symbolNames);
457
+ const symVals = await this.getSymbolValues();
458
+ this.serializer.resetSymbols(symKeys, symVals, dIds);
459
+ const hashData = this.serializer.package(state, symbolNames);
460
+ if (status !== null) {
461
+ hashData[':'] = status.toString();
462
+ }
463
+ else {
464
+ delete hashData[':'];
465
+ }
466
+ await this.kvsql(transaction).hset(hashKey, hashData);
467
+ return jobId;
468
+ }
469
+ /**
470
+ * Returns custom search fields and values.
471
+ * NOTE: The `fields` param should NOT prefix items with an underscore.
472
+ * NOTE: Literals are allowed if quoted.
473
+ */
474
+ async getQueryState(jobId, fields) {
475
+ const key = this.mintKey(key_1.KeyType.JOB_STATE, { appId: this.appId, jobId });
476
+ const _fields = fields.map((field) => {
477
+ if (field.startsWith('"')) {
478
+ return field.slice(1, -1);
479
+ }
480
+ return `_${field}`;
481
+ });
482
+ const jobDataArray = await this.kvsql().hmget(key, _fields);
483
+ const jobData = {};
484
+ fields.forEach((field, index) => {
485
+ if (field.startsWith('"')) {
486
+ field = field.slice(1, -1);
487
+ }
488
+ jobData[field] = jobDataArray[index];
489
+ });
490
+ return jobData;
491
+ }
492
+ async getState(jobId, consumes, dIds) {
493
+ //get abbreviated field list (the symbols for the paths)
494
+ const key = this.mintKey(key_1.KeyType.JOB_STATE, { appId: this.appId, jobId });
495
+ const symbolNames = Object.keys(consumes);
496
+ const symKeys = await this.getSymbolKeys(symbolNames);
497
+ this.serializer.resetSymbols(symKeys, {}, dIds);
498
+ const fields = this.serializer.abbreviate(consumes, symbolNames, [':']);
499
+ const jobDataArray = await this.kvsql().hmget(key, fields);
500
+ const jobData = {};
501
+ let atLeast1 = false; //if status field (':') isn't present assume 404
502
+ fields.forEach((field, index) => {
503
+ if (jobDataArray[index]) {
504
+ atLeast1 = true;
505
+ }
506
+ jobData[field] = jobDataArray[index];
507
+ });
508
+ if (atLeast1) {
509
+ const symVals = await this.getSymbolValues();
510
+ this.serializer.resetSymbols(symKeys, symVals, dIds);
511
+ const state = this.serializer.unpackage(jobData, symbolNames);
512
+ let status = 0;
513
+ if (state[':']) {
514
+ status = Number(state[':']);
515
+ state[`metadata/js`] = status;
516
+ delete state[':'];
517
+ }
518
+ return [state, status];
519
+ }
520
+ else {
521
+ throw new errors_1.GetStateError(jobId);
522
+ }
523
+ }
524
+ async getRaw(jobId) {
525
+ const jobKey = this.mintKey(key_1.KeyType.JOB_STATE, {
526
+ appId: this.appId,
527
+ jobId,
528
+ });
529
+ const job = await this.kvsql().hgetall(jobKey);
530
+ if (!job) {
531
+ throw new errors_1.GetStateError(jobId);
532
+ }
533
+ return job;
534
+ }
535
+ /**
536
+ * collate is a generic method for incrementing a value in a hash
537
+ * in order to track their progress during processing.
538
+ */
539
+ async collate(jobId, activityId, amount, dIds, transaction) {
540
+ const jobKey = this.mintKey(key_1.KeyType.JOB_STATE, {
541
+ appId: this.appId,
542
+ jobId,
543
+ });
544
+ const collationKey = `${activityId}/output/metadata/as`; //activity state
545
+ const symbolNames = [activityId];
546
+ const symKeys = await this.getSymbolKeys(symbolNames);
547
+ const symVals = await this.getSymbolValues();
548
+ this.serializer.resetSymbols(symKeys, symVals, dIds);
549
+ const payload = { [collationKey]: amount.toString() };
550
+ const hashData = this.serializer.package(payload, symbolNames);
551
+ const targetId = Object.keys(hashData)[0];
552
+ return await this.kvsql(transaction).hincrbyfloat(jobKey, targetId, amount);
553
+ }
554
+ /**
555
+ * Synthentic collation affects those activities in the graph
556
+ * that represent the synthetic DAG that was materialized during compilation;
557
+ * Synthetic collation distinguishes `re-entry due to failure` from
558
+ * `purposeful re-entry`.
559
+ */
560
+ async collateSynthetic(jobId, guid, amount, transaction) {
561
+ const jobKey = this.mintKey(key_1.KeyType.JOB_STATE, {
562
+ appId: this.appId,
563
+ jobId,
564
+ });
565
+ return await this.kvsql(transaction).hincrbyfloat(jobKey, guid, amount);
566
+ }
567
+ async setStateNX(jobId, appId, status) {
568
+ const hashKey = this.mintKey(key_1.KeyType.JOB_STATE, { appId, jobId });
569
+ const result = await this.kvsql().hsetnx(hashKey, ':', status?.toString() ?? '1');
570
+ return this.isSuccessful(result);
571
+ }
572
+ async getSchema(activityId, appVersion) {
573
+ const schema = this.cache.getSchema(appVersion.id, appVersion.version, activityId);
574
+ if (schema) {
575
+ return schema;
576
+ }
577
+ else {
578
+ const schemas = await this.getSchemas(appVersion);
579
+ return schemas[activityId];
580
+ }
581
+ }
582
+ async getSchemas(appVersion) {
583
+ let schemas = this.cache.getSchemas(appVersion.id, appVersion.version);
584
+ if (schemas && Object.keys(schemas).length > 0) {
585
+ return schemas;
586
+ }
587
+ else {
588
+ const params = {
589
+ appId: appVersion.id,
590
+ appVersion: appVersion.version,
591
+ };
592
+ const key = this.mintKey(key_1.KeyType.SCHEMAS, params);
593
+ schemas = {};
594
+ const hash = await this.kvsql().hgetall(key);
595
+ Object.entries(hash).forEach(([key, value]) => {
596
+ schemas[key] = JSON.parse(value);
597
+ });
598
+ this.cache.setSchemas(appVersion.id, appVersion.version, schemas);
599
+ return schemas;
600
+ }
601
+ }
602
+ async setSchemas(schemas, appVersion) {
603
+ const params = {
604
+ appId: appVersion.id,
605
+ appVersion: appVersion.version,
606
+ };
607
+ const key = this.mintKey(key_1.KeyType.SCHEMAS, params);
608
+ const _schemas = { ...schemas };
609
+ Object.entries(_schemas).forEach(([key, value]) => {
610
+ _schemas[key] = JSON.stringify(value);
611
+ });
612
+ const response = await this.kvsql().hset(key, _schemas);
613
+ this.cache.setSchemas(appVersion.id, appVersion.version, schemas);
614
+ return response;
615
+ }
616
+ async setSubscriptions(subscriptions, appVersion) {
617
+ const params = {
618
+ appId: appVersion.id,
619
+ appVersion: appVersion.version,
620
+ };
621
+ const key = this.mintKey(key_1.KeyType.SUBSCRIPTIONS, params);
622
+ const _subscriptions = { ...subscriptions };
623
+ Object.entries(_subscriptions).forEach(([key, value]) => {
624
+ _subscriptions[key] = JSON.stringify(value);
625
+ });
626
+ const status = await this.kvsql().hset(key, _subscriptions);
627
+ this.cache.setSubscriptions(appVersion.id, appVersion.version, subscriptions);
628
+ return this.isSuccessful(status);
629
+ }
630
+ async getSubscriptions(appVersion) {
631
+ let subscriptions = this.cache.getSubscriptions(appVersion.id, appVersion.version);
632
+ if (subscriptions && Object.keys(subscriptions).length > 0) {
633
+ return subscriptions;
634
+ }
635
+ else {
636
+ const params = {
637
+ appId: appVersion.id,
638
+ appVersion: appVersion.version,
639
+ };
640
+ const key = this.mintKey(key_1.KeyType.SUBSCRIPTIONS, params);
641
+ subscriptions = await this.kvsql().hgetall(key) || {};
642
+ Object.entries(subscriptions).forEach(([key, value]) => {
643
+ subscriptions[key] = JSON.parse(value);
644
+ });
645
+ this.cache.setSubscriptions(appVersion.id, appVersion.version, subscriptions);
646
+ return subscriptions;
647
+ }
648
+ }
649
+ async getSubscription(topic, appVersion) {
650
+ const subscriptions = await this.getSubscriptions(appVersion);
651
+ return subscriptions[topic];
652
+ }
653
+ async setTransitions(transitions, appVersion) {
654
+ const params = {
655
+ appId: appVersion.id,
656
+ appVersion: appVersion.version,
657
+ };
658
+ const key = this.mintKey(key_1.KeyType.SUBSCRIPTION_PATTERNS, params);
659
+ const _subscriptions = { ...transitions };
660
+ Object.entries(_subscriptions).forEach(([key, value]) => {
661
+ _subscriptions[key] = JSON.stringify(value);
662
+ });
663
+ if (Object.keys(_subscriptions).length !== 0) {
664
+ const response = await this.kvsql().hset(key, _subscriptions);
665
+ this.cache.setTransitions(appVersion.id, appVersion.version, transitions);
666
+ return response;
667
+ }
668
+ }
669
+ async getTransitions(appVersion) {
670
+ let transitions = this.cache.getTransitions(appVersion.id, appVersion.version);
671
+ if (transitions && Object.keys(transitions).length > 0) {
672
+ return transitions;
673
+ }
674
+ else {
675
+ const params = {
676
+ appId: appVersion.id,
677
+ appVersion: appVersion.version,
678
+ };
679
+ const key = this.mintKey(key_1.KeyType.SUBSCRIPTION_PATTERNS, params);
680
+ transitions = {};
681
+ const hash = await this.kvsql().hgetall(key);
682
+ Object.entries(hash).forEach(([key, value]) => {
683
+ transitions[key] = JSON.parse(value);
684
+ });
685
+ this.cache.setTransitions(appVersion.id, appVersion.version, transitions);
686
+ return transitions;
687
+ }
688
+ }
689
+ async setHookRules(hookRules) {
690
+ const key = this.mintKey(key_1.KeyType.HOOKS, { appId: this.appId });
691
+ const _hooks = {};
692
+ Object.entries(hookRules).forEach(([key, value]) => {
693
+ _hooks[key.toString()] = JSON.stringify(value);
694
+ });
695
+ if (Object.keys(_hooks).length !== 0) {
696
+ const response = await this.kvsql().hset(key, _hooks);
697
+ this.cache.setHookRules(this.appId, hookRules);
698
+ return response;
699
+ }
700
+ }
701
+ async getHookRules() {
702
+ let patterns = this.cache.getHookRules(this.appId);
703
+ if (patterns && Object.keys(patterns).length > 0) {
704
+ return patterns;
705
+ }
706
+ else {
707
+ const key = this.mintKey(key_1.KeyType.HOOKS, { appId: this.appId });
708
+ const _hooks = await this.kvsql().hgetall(key);
709
+ patterns = {};
710
+ Object.entries(_hooks).forEach(([key, value]) => {
711
+ patterns[key] = JSON.parse(value);
712
+ });
713
+ this.cache.setHookRules(this.appId, patterns);
714
+ return patterns;
715
+ }
716
+ }
717
+ async setHookSignal(hook, transaction) {
718
+ const key = this.mintKey(key_1.KeyType.SIGNALS, { appId: this.appId });
719
+ const { topic, resolved, jobId } = hook;
720
+ const signalKey = `${topic}:${resolved}`;
721
+ await this.kvsql(transaction).setnxex(`${key}:${signalKey}`, jobId, Math.max(hook.expire, enums_1.HMSH_SIGNAL_EXPIRE));
722
+ }
723
+ async getHookSignal(topic, resolved) {
724
+ const key = this.mintKey(key_1.KeyType.SIGNALS, { appId: this.appId });
725
+ const response = await this.kvsql().get(`${key}:${topic}:${resolved}`);
726
+ return response ? response.toString() : undefined;
727
+ }
728
+ async deleteHookSignal(topic, resolved) {
729
+ const key = this.mintKey(key_1.KeyType.SIGNALS, { appId: this.appId });
730
+ const response = await this.kvsql().del(`${key}:${topic}:${resolved}`);
731
+ return response ? Number(response) : undefined;
732
+ }
733
+ async addTaskQueues(keys) {
734
+ const transaction = this.kvsql(this.transact());
735
+ const zsetKey = this.mintKey(key_1.KeyType.WORK_ITEMS, { appId: this.appId });
736
+ for (const key of keys) {
737
+ transaction.zadd(zsetKey, Date.now(), key, { nx: true });
738
+ }
739
+ await transaction.exec();
740
+ }
741
+ async getActiveTaskQueue() {
742
+ let workItemKey = this.cache.getActiveTaskQueue(this.appId) || null;
743
+ if (!workItemKey) {
744
+ const zsetKey = this.mintKey(key_1.KeyType.WORK_ITEMS, { appId: this.appId });
745
+ const result = await this.kvsql().zrange(zsetKey, 0, 0);
746
+ workItemKey = result.length > 0 ? result[0] : null;
747
+ if (workItemKey) {
748
+ this.cache.setWorkItem(this.appId, workItemKey);
749
+ }
750
+ }
751
+ return workItemKey;
752
+ }
753
+ async deleteProcessedTaskQueue(workItemKey, key, processedKey, scrub = false) {
754
+ const zsetKey = this.mintKey(key_1.KeyType.WORK_ITEMS, { appId: this.appId });
755
+ const didRemove = await this.kvsql().zrem(zsetKey, workItemKey);
756
+ if (didRemove) {
757
+ if (scrub) {
758
+ //indexes can be designed to be self-cleaning; `engine.hookAll` exposes this option
759
+ this.kvsql().del(processedKey);
760
+ this.kvsql().del(key.split(':').slice(0, 5).join(':'));
761
+ }
762
+ else {
763
+ await this.kvsql().rename(processedKey, key);
764
+ }
765
+ }
766
+ this.cache.removeWorkItem(this.appId);
767
+ }
768
+ async processTaskQueue(sourceKey, destinationKey) {
769
+ return await this.kvsql().lmove(sourceKey, destinationKey, 'LEFT', 'RIGHT');
770
+ }
771
+ async expireJob(jobId, inSeconds, transaction) {
772
+ if (!isNaN(inSeconds) && inSeconds > 0) {
773
+ const jobKey = this.mintKey(key_1.KeyType.JOB_STATE, {
774
+ appId: this.appId,
775
+ jobId,
776
+ });
777
+ await this.kvsql(transaction).expire(jobKey, inSeconds);
778
+ }
779
+ }
780
+ async getDependencies(jobId) {
781
+ const depParams = { appId: this.appId, jobId };
782
+ const depKey = this.mintKey(key_1.KeyType.JOB_DEPENDENTS, depParams);
783
+ return this.kvsql().lrange(depKey, 0, -1);
784
+ }
785
+ /**
786
+ * registers a hook activity to be awakened (uses ZSET to
787
+ * store the 'sleep group' and LIST to store the events
788
+ * for the given sleep group. Sleep groups are
789
+ * organized into 'n'-second blocks (LISTS))
790
+ */
791
+ async registerTimeHook(jobId, gId, activityId, type, deletionTime, dad, transaction) {
792
+ const listKey = this.mintKey(key_1.KeyType.TIME_RANGE, {
793
+ appId: this.appId,
794
+ timeValue: deletionTime,
795
+ });
796
+ //register the task in the LIST
797
+ const timeEvent = [type, activityId, gId, dad, jobId].join(key_1.VALSEP);
798
+ const len = await this.kvsql(transaction).rpush(listKey, timeEvent);
799
+ //register the LIST in the ZSET
800
+ if (transaction || len === 1) {
801
+ const zsetKey = this.mintKey(key_1.KeyType.TIME_RANGE, { appId: this.appId });
802
+ await this.zAdd(zsetKey, deletionTime.toString(), listKey, transaction);
803
+ }
804
+ }
805
+ async getNextTask(listKey) {
806
+ const zsetKey = this.mintKey(key_1.KeyType.TIME_RANGE, { appId: this.appId });
807
+ listKey = listKey || await this.zRangeByScore(zsetKey, 0, Date.now());
808
+ if (listKey) {
809
+ let [pType, pKey] = this.resolveTaskKeyContext(listKey);
810
+ const timeEvent = await this.kvsql().lpop(pKey);
811
+ if (timeEvent) {
812
+ //deconstruct composite key
813
+ let [type, activityId, gId, _pd, ...jobId] = timeEvent.split(key_1.VALSEP);
814
+ const jid = jobId.join(key_1.VALSEP);
815
+ if (type === 'delist') {
816
+ pType = 'delist';
817
+ }
818
+ else if (type === 'child') {
819
+ pType = 'child';
820
+ }
821
+ else if (type === 'expire-child') {
822
+ type = 'expire';
823
+ }
824
+ return [listKey, jid, gId, activityId, pType];
825
+ }
826
+ await this.kvsql().zrem(zsetKey, listKey);
827
+ return true;
828
+ }
829
+ return false;
830
+ }
831
+ /**
832
+ * when processing time jobs, the target LIST ID returned
833
+ * from the ZSET query can be prefixed to denote what to
834
+ * do with the work list. (not everything is known in advance,
835
+ * so the ZSET key defines HOW to approach the work in the
836
+ * generic LIST (lists typically contain target job ids)
837
+ * @param {string} listKey - composite key
838
+ */
839
+ resolveTaskKeyContext(listKey) {
840
+ if (listKey.startsWith(`${key_1.TYPSEP}INTERRUPT`)) {
841
+ return ['interrupt', listKey.split(key_1.TYPSEP)[2]];
842
+ }
843
+ else if (listKey.startsWith(`${key_1.TYPSEP}EXPIRE`)) {
844
+ return ['expire', listKey.split(key_1.TYPSEP)[2]];
845
+ }
846
+ else {
847
+ return ['sleep', listKey];
848
+ }
849
+ }
850
+ /**
851
+ * Interrupts a job and sets sets a job error (410), if 'throw'!=false.
852
+ * This method is called by the engine and not by an activity and is
853
+ * followed by a call to execute job completion/cleanup tasks
854
+ * associated with a job completion event.
855
+ *
856
+ * Todo: move most of this logic to the engine (too much logic for the store)
857
+ */
858
+ async interrupt(topic, jobId, options = {}) {
859
+ try {
860
+ //verify job exists
861
+ const status = await this.getStatus(jobId, this.appId);
862
+ if (status <= 0) {
863
+ //verify still active; job already completed
864
+ throw new Error(`Job ${jobId} already completed`);
865
+ }
866
+ //decrement job status (:) by 1bil
867
+ const amount = -1000000000;
868
+ const jobKey = this.mintKey(key_1.KeyType.JOB_STATE, {
869
+ appId: this.appId,
870
+ jobId,
871
+ });
872
+ const result = await this.kvsql().hincrbyfloat(jobKey, ':', amount);
873
+ if (result <= amount) {
874
+ //verify active state; job already interrupted
875
+ throw new Error(`Job ${jobId} already completed`);
876
+ }
877
+ //persist the error unless specifically told not to
878
+ if (options.throw !== false) {
879
+ const errKey = `metadata/err`; //job errors are stored at the path `metadata/err`
880
+ const symbolNames = [`$${topic}`]; //the symbol for `metadata/err` is in the backend
881
+ const symKeys = await this.getSymbolKeys(symbolNames);
882
+ const symVals = await this.getSymbolValues();
883
+ this.serializer.resetSymbols(symKeys, symVals, {});
884
+ //persists the standard 410 error (job is `gone`)
885
+ const err = JSON.stringify({
886
+ code: options.code ?? enums_1.HMSH_CODE_INTERRUPT,
887
+ message: options.reason ?? `job [${jobId}] interrupted`,
888
+ stack: options.stack ?? '',
889
+ job_id: jobId,
890
+ });
891
+ const payload = { [errKey]: amount.toString() };
892
+ const hashData = this.serializer.package(payload, symbolNames);
893
+ const errSymbol = Object.keys(hashData)[0];
894
+ await this.kvsql().hset(jobKey, { [errSymbol]: err });
895
+ }
896
+ }
897
+ catch (e) {
898
+ if (!options.suppress) {
899
+ throw e;
900
+ }
901
+ else {
902
+ this.logger.debug('suppressed-interrupt', { message: e.message });
903
+ }
904
+ }
905
+ }
906
+ async scrub(jobId) {
907
+ const jobKey = this.mintKey(key_1.KeyType.JOB_STATE, {
908
+ appId: this.appId,
909
+ jobId,
910
+ });
911
+ await this.kvsql().del(jobKey);
912
+ }
913
+ async findJobs(queryString = '*', limit = 1000,
914
+ //NOTE: unused in SQL provider; leave to keep signature consistent
915
+ batchSize = 1000, cursor = '0') {
916
+ const matchKey = this.mintKey(key_1.KeyType.JOB_STATE, {
917
+ appId: this.appId,
918
+ jobId: queryString,
919
+ });
920
+ const { cursor: _cursor, keys } = await this.kvsql().scan(Number(cursor), limit, matchKey);
921
+ return [_cursor.toPrecision(), keys];
922
+ }
923
+ async findJobFields(jobId, fieldMatchPattern = '*', limit = 1000, batchSize = 1000, // Unused in SQL provider
924
+ cursor = '0') {
925
+ const matchingFields = {};
926
+ const jobKey = this.mintKey(key_1.KeyType.JOB_STATE, {
927
+ appId: this.appId,
928
+ jobId,
929
+ });
930
+ let enumType;
931
+ let dimension = null;
932
+ if (fieldMatchPattern.includes(',')) {
933
+ const dimReg = /\d[^-]+-/gi;
934
+ const dimensions = fieldMatchPattern.match(dimReg);
935
+ dimension = ',' + (dimensions?.[0] ?? '');
936
+ enumType = 'hmark';
937
+ }
938
+ else {
939
+ enumType = 'jmark';
940
+ }
941
+ const offset = parseInt(cursor, 10) || 0; // Convert cursor to numeric offset
942
+ const tableName = this.kvsql().tableForKey(jobKey, 'hash');
943
+ // Initialize parameters array and parameter index
944
+ const params = [jobKey];
945
+ let paramIndex = params.length + 1; // Starts from 2 since $1 is jobKey
946
+ // Build the valid_job CTE to get the job's UUID id
947
+ const validJobSql = `
948
+ SELECT id
949
+ FROM ${tableName}
950
+ WHERE key = $1
951
+ AND (expired_at IS NULL OR expired_at > NOW())
952
+ LIMIT 1
953
+ `;
954
+ // Build conditions for the WHERE clause
955
+ const conditions = [];
956
+ // Add enumType condition
957
+ conditions.push(`a.type = $${paramIndex}`);
958
+ params.push(enumType);
959
+ paramIndex++;
960
+ // Add dimension condition if applicable
961
+ if (dimension) {
962
+ conditions.push(`a.field LIKE $${paramIndex}`);
963
+ params.push(`%${dimension}%`);
964
+ paramIndex++;
965
+ }
966
+ // Add limit and offset parameters
967
+ const limitParamIndex = paramIndex;
968
+ const offsetParamIndex = paramIndex + 1;
969
+ params.push(limit, offset);
970
+ paramIndex += 2;
971
+ // Construct the final SQL query
972
+ const sql = `
973
+ WITH valid_job AS (
974
+ ${validJobSql}
975
+ )
976
+ SELECT a.field, a.value
977
+ FROM ${tableName}_attributes a
978
+ JOIN valid_job j ON a.job_id = j.id
979
+ WHERE ${conditions.join(' AND ')}
980
+ LIMIT $${limitParamIndex} OFFSET $${offsetParamIndex}
981
+ `;
982
+ // Execute the query and map the results
983
+ const res = await this.pgClient.query(sql, params);
984
+ for (const row of res.rows) {
985
+ matchingFields[row.field] = row.value;
986
+ }
987
+ // Determine the next cursor
988
+ const nextCursor = res.rows.length < limit ? '0' : String(offset + res.rows.length);
989
+ return [nextCursor, matchingFields];
990
+ }
991
+ async setThrottleRate(options) {
992
+ const key = this.mintKey(key_1.KeyType.THROTTLE_RATE, { appId: this.appId });
993
+ //engine guids are session specific. no need to persist
994
+ if (options.guid) {
995
+ return;
996
+ }
997
+ //if a topic, update one
998
+ const rate = options.throttle.toString();
999
+ if (options.topic) {
1000
+ await this.kvsql().hset(key, {
1001
+ [options.topic]: rate,
1002
+ });
1003
+ }
1004
+ else {
1005
+ //if no topic, update all
1006
+ const transaction = this.transact();
1007
+ transaction.del(key);
1008
+ transaction.hset(key, { ':': rate });
1009
+ await transaction.exec();
1010
+ }
1011
+ }
1012
+ async getThrottleRates() {
1013
+ const key = this.mintKey(key_1.KeyType.THROTTLE_RATE, { appId: this.appId });
1014
+ const response = await this.kvsql().hgetall(key);
1015
+ return response ?? {};
1016
+ }
1017
+ async getThrottleRate(topic) {
1018
+ //always return a valid number range
1019
+ const resolveRate = (response, topic) => {
1020
+ const rate = topic in response ? Number(response[topic]) : 0;
1021
+ if (isNaN(rate))
1022
+ return 0;
1023
+ if (rate == -1)
1024
+ return enums_1.MAX_DELAY;
1025
+ return Math.max(Math.min(rate, enums_1.MAX_DELAY), 0);
1026
+ };
1027
+ const response = await this.getThrottleRates();
1028
+ const globalRate = resolveRate(response, ':');
1029
+ if (topic === ':' || !(topic in response)) {
1030
+ //use global rate unless worker specifies rate
1031
+ return globalRate;
1032
+ }
1033
+ return resolveRate(response, topic);
1034
+ }
1035
+ }
1036
+ exports.PostgresStoreService = PostgresStoreService;