@hotmeshio/hotmesh 0.1.15 → 0.1.17

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 (134) hide show
  1. package/README.md +623 -209
  2. package/build/index.d.ts +14 -3
  3. package/build/index.js +17 -4
  4. package/build/modules/enums.d.ts +12 -12
  5. package/build/modules/enums.js +15 -25
  6. package/build/modules/errors.d.ts +16 -16
  7. package/build/modules/errors.js +28 -28
  8. package/build/modules/key.d.ts +0 -37
  9. package/build/modules/key.js +4 -45
  10. package/build/modules/utils.d.ts +7 -15
  11. package/build/modules/utils.js +21 -44
  12. package/build/package.json +18 -15
  13. package/build/services/activities/activity.d.ts +0 -31
  14. package/build/services/activities/activity.js +1 -50
  15. package/build/services/activities/await.js +0 -4
  16. package/build/services/activities/cycle.d.ts +0 -7
  17. package/build/services/activities/cycle.js +1 -16
  18. package/build/services/activities/hook.d.ts +0 -6
  19. package/build/services/activities/hook.js +2 -12
  20. package/build/services/activities/interrupt.js +0 -8
  21. package/build/services/activities/signal.d.ts +0 -6
  22. package/build/services/activities/signal.js +0 -15
  23. package/build/services/activities/trigger.d.ts +4 -5
  24. package/build/services/activities/trigger.js +22 -16
  25. package/build/services/activities/worker.js +0 -4
  26. package/build/services/collator/index.d.ts +0 -70
  27. package/build/services/collator/index.js +1 -91
  28. package/build/services/compiler/deployer.js +6 -38
  29. package/build/services/compiler/index.d.ts +0 -15
  30. package/build/services/compiler/index.js +0 -20
  31. package/build/services/compiler/validator.d.ts +0 -3
  32. package/build/services/compiler/validator.js +0 -25
  33. package/build/services/connector/clients/ioredis.js +0 -2
  34. package/build/services/connector/clients/redis.js +0 -2
  35. package/build/services/connector/index.js +0 -2
  36. package/build/services/engine/index.d.ts +1 -10
  37. package/build/services/engine/index.js +1 -48
  38. package/build/services/exporter/index.d.ts +0 -27
  39. package/build/services/exporter/index.js +0 -33
  40. package/build/services/hotmesh/index.d.ts +8 -4
  41. package/build/services/hotmesh/index.js +20 -19
  42. package/build/services/logger/index.js +0 -2
  43. package/build/services/mapper/index.d.ts +0 -14
  44. package/build/services/mapper/index.js +0 -14
  45. package/build/services/meshcall/index.d.ts +21 -0
  46. package/build/services/meshcall/index.js +202 -0
  47. package/build/services/meshcall/schemas/factory.d.ts +2 -0
  48. package/build/services/meshcall/schemas/factory.js +179 -0
  49. package/build/services/meshdata/index.d.ts +75 -0
  50. package/build/services/meshdata/index.js +541 -0
  51. package/build/services/meshflow/client.d.ts +18 -0
  52. package/build/services/{durable → meshflow}/client.js +9 -40
  53. package/build/services/{durable → meshflow}/connection.d.ts +2 -1
  54. package/build/services/{durable → meshflow}/connection.js +1 -0
  55. package/build/services/meshflow/exporter.d.ts +29 -0
  56. package/build/services/{durable → meshflow}/exporter.js +0 -29
  57. package/build/services/meshflow/handle.d.ts +22 -0
  58. package/build/services/{durable → meshflow}/handle.js +0 -46
  59. package/build/services/meshflow/index.d.ts +17 -0
  60. package/build/services/meshflow/index.js +23 -0
  61. package/build/services/meshflow/schemas/factory.d.ts +4 -0
  62. package/build/services/{durable → meshflow}/schemas/factory.js +2 -30
  63. package/build/services/meshflow/search.d.ts +23 -0
  64. package/build/services/{durable → meshflow}/search.js +0 -99
  65. package/build/services/{durable → meshflow}/worker.d.ts +3 -2
  66. package/build/services/{durable → meshflow}/worker.js +23 -39
  67. package/build/services/meshflow/workflow.d.ts +27 -0
  68. package/build/services/{durable → meshflow}/workflow.js +27 -169
  69. package/build/services/pipe/functions/date.d.ts +0 -7
  70. package/build/services/pipe/functions/date.js +0 -7
  71. package/build/services/pipe/functions/math.js +0 -2
  72. package/build/services/pipe/index.d.ts +0 -15
  73. package/build/services/pipe/index.js +2 -23
  74. package/build/services/quorum/index.d.ts +1 -7
  75. package/build/services/quorum/index.js +0 -21
  76. package/build/services/reporter/index.d.ts +0 -5
  77. package/build/services/reporter/index.js +0 -9
  78. package/build/services/router/index.d.ts +0 -9
  79. package/build/services/router/index.js +2 -30
  80. package/build/services/serializer/index.js +6 -23
  81. package/build/services/store/cache.d.ts +0 -19
  82. package/build/services/store/cache.js +0 -19
  83. package/build/services/store/clients/ioredis.d.ts +0 -6
  84. package/build/services/store/clients/ioredis.js +0 -7
  85. package/build/services/store/clients/redis.d.ts +0 -6
  86. package/build/services/store/clients/redis.js +0 -6
  87. package/build/services/store/index.d.ts +0 -55
  88. package/build/services/store/index.js +14 -87
  89. package/build/services/stream/clients/ioredis.js +1 -4
  90. package/build/services/task/index.d.ts +0 -9
  91. package/build/services/task/index.js +0 -31
  92. package/build/services/telemetry/index.d.ts +0 -7
  93. package/build/services/telemetry/index.js +1 -13
  94. package/build/services/worker/index.d.ts +1 -4
  95. package/build/services/worker/index.js +0 -6
  96. package/build/types/activity.d.ts +0 -81
  97. package/build/types/error.d.ts +5 -5
  98. package/build/types/exporter.d.ts +1 -14
  99. package/build/types/hotmesh.d.ts +4 -12
  100. package/build/types/hotmesh.js +0 -3
  101. package/build/types/index.d.ts +5 -3
  102. package/build/types/index.js +1 -1
  103. package/build/types/job.d.ts +1 -95
  104. package/build/types/meshcall.d.ts +54 -0
  105. package/build/types/meshdata.d.ts +59 -0
  106. package/build/types/meshdata.js +2 -0
  107. package/build/types/meshflow.d.ts +202 -0
  108. package/build/types/meshflow.js +2 -0
  109. package/build/types/pipe.d.ts +0 -65
  110. package/build/types/quorum.d.ts +0 -12
  111. package/build/types/redis.d.ts +0 -6
  112. package/build/types/stream.d.ts +0 -59
  113. package/build/types/stream.js +0 -4
  114. package/index.ts +12 -3
  115. package/package.json +18 -15
  116. package/typedoc.json +38 -0
  117. package/types/error.ts +5 -5
  118. package/types/exporter.ts +1 -1
  119. package/types/hotmesh.ts +3 -2
  120. package/types/index.ts +25 -7
  121. package/types/job.ts +19 -1
  122. package/types/meshcall.ts +192 -0
  123. package/types/meshdata.ts +273 -0
  124. package/types/{durable.ts → meshflow.ts} +33 -9
  125. package/build/services/durable/client.d.ts +0 -49
  126. package/build/services/durable/exporter.d.ts +0 -51
  127. package/build/services/durable/handle.d.ts +0 -58
  128. package/build/services/durable/index.d.ts +0 -19
  129. package/build/services/durable/index.js +0 -25
  130. package/build/services/durable/schemas/factory.d.ts +0 -33
  131. package/build/services/durable/search.d.ts +0 -120
  132. package/build/services/durable/workflow.d.ts +0 -143
  133. package/build/types/durable.d.ts +0 -467
  134. /package/build/types/{durable.js → meshcall.js} +0 -0
@@ -7,8 +7,8 @@ const collator_1 = require("../collator");
7
7
  const serializer_1 = require("../serializer");
8
8
  const pipe_1 = require("../pipe");
9
9
  const validator_1 = require("./validator");
10
- const DEFAULT_METADATA_RANGE_SIZE = 26; //metadata is 26 slots ([a-z] * 1)
11
- const DEFAULT_DATA_RANGE_SIZE = 260; //data is 260 slots ([a-zA-Z] * 5)
10
+ const DEFAULT_METADATA_RANGE_SIZE = 26;
11
+ const DEFAULT_DATA_RANGE_SIZE = 260;
12
12
  const DEFAULT_RANGE_SIZE = DEFAULT_METADATA_RANGE_SIZE + DEFAULT_DATA_RANGE_SIZE;
13
13
  class Deployer {
14
14
  constructor(manifest) {
@@ -41,21 +41,18 @@ class Deployer {
41
41
  };
42
42
  }
43
43
  async generateSymKeys() {
44
- //note: symbol ranges are additive (per version); path assignments are immutable
45
44
  for (const graph of this.manifest.app.graphs) {
46
- //generate JOB symbols
47
45
  const [, trigger] = this.findTrigger(graph);
48
46
  const topic = trigger.subscribes;
49
47
  const [lower, upper, symbols] = await this.store.reserveSymbolRange(`$${topic}`, DEFAULT_RANGE_SIZE, 'JOB');
50
- const prefix = ''; //job meta/data is NOT namespaced
48
+ const prefix = '';
51
49
  const newSymbols = this.bindSymbols(lower, upper, symbols, prefix, trigger.PRODUCES);
52
50
  if (Object.keys(newSymbols).length) {
53
51
  await this.store.addSymbols(`$${topic}`, newSymbols);
54
52
  }
55
- //generate ACTIVITY symbols
56
53
  for (const [activityId, activity] of Object.entries(graph.activities)) {
57
54
  const [lower, upper, symbols] = await this.store.reserveSymbolRange(activityId, DEFAULT_RANGE_SIZE, 'ACTIVITY');
58
- const prefix = `${activityId}/`; //activity meta/data is namespaced
55
+ const prefix = `${activityId}/`;
59
56
  this.bindSelf(activity.consumes, activity.produces, activityId);
60
57
  const newSymbols = this.bindSymbols(lower, upper, symbols, prefix, activity.produces);
61
58
  if (Object.keys(newSymbols).length) {
@@ -65,7 +62,6 @@ class Deployer {
65
62
  }
66
63
  }
67
64
  bindSelf(consumes, produces, activityId) {
68
- //bind self-referential mappings
69
65
  for (const selfId of [activityId, '$self']) {
70
66
  const selfConsumes = consumes[selfId];
71
67
  if (selfConsumes) {
@@ -89,7 +85,7 @@ class Deployer {
89
85
  const symbol = (0, utils_1.getSymKey)(startIndex);
90
86
  startIndex++;
91
87
  newSymbols[fullPath] = symbol;
92
- currentSymbols[fullPath] = symbol; // update the currentSymbols to include this new symbol
88
+ currentSymbols[fullPath] = symbol;
93
89
  }
94
90
  }
95
91
  return newSymbols;
@@ -102,20 +98,16 @@ class Deployer {
102
98
  if (!jobSchema && !outputSchema)
103
99
  continue;
104
100
  const activities = graph.activities;
105
- // Find the trigger activity and bind the job schema to it
106
- // at execution time, the trigger is a standin for the job
107
101
  for (const activityKey in activities) {
108
102
  if (activities[activityKey].type === 'trigger') {
109
103
  const trigger = activities[activityKey];
110
104
  if (jobSchema) {
111
- //possible for trigger to have job mappings
112
105
  if (!trigger.job) {
113
106
  trigger.job = {};
114
107
  }
115
108
  trigger.job.schema = jobSchema;
116
109
  }
117
110
  if (outputSchema) {
118
- //impossible for trigger to have output mappings.
119
111
  trigger.output = { schema: outputSchema };
120
112
  }
121
113
  }
@@ -136,8 +128,6 @@ class Deployer {
136
128
  }
137
129
  }
138
130
  }
139
- //the cycle/goto activity includes and ancestor target;
140
- //update with the cycle flag, so it can be rerun
141
131
  bindCycleTarget() {
142
132
  for (const graph of this.manifest.app.graphs) {
143
133
  const activities = graph.activities;
@@ -149,8 +139,6 @@ class Deployer {
149
139
  }
150
140
  }
151
141
  }
152
- //it's more intuitive for SDK users to use 'topic',
153
- //but the compiler is desiged to be generic and uses the attribute, 'subtypes'
154
142
  convertTopicsToTypes() {
155
143
  for (const graph of this.manifest.app.graphs) {
156
144
  const activities = graph.activities;
@@ -164,7 +152,6 @@ class Deployer {
164
152
  }
165
153
  }
166
154
  }
167
- //legacy; remove at beta (assume no legacy refs to 'activity' at that point)
168
155
  convertActivitiesToHooks() {
169
156
  for (const graph of this.manifest.app.graphs) {
170
157
  const activities = graph.activities;
@@ -184,11 +171,8 @@ class Deployer {
184
171
  const toTransitions = graph.transitions[fromActivity];
185
172
  for (const transition of toTransitions) {
186
173
  const to = transition.to;
187
- //DAGs have one parent; easy to optimize for
188
174
  graph.activities[to].parent = fromActivity;
189
175
  }
190
- //temporarily bind the transitions to the parent activity,
191
- // so the consumer/producer registrar picks up the bindings
192
176
  graph.activities[fromActivity].transitions = toTransitions;
193
177
  }
194
178
  }
@@ -248,10 +232,6 @@ class Deployer {
248
232
  traverse(obj[key], newPath);
249
233
  }
250
234
  else {
251
- //wildcard mapping (e.g., 'friends[25]')
252
- //when this is resolved, it will be expanded to
253
- //`'friends/0', ..., 'friends/24'`, providing 25 dynamic
254
- //slots in the flow's output data
255
235
  const pathName = [...path, key].join('/');
256
236
  if (!pathName.includes('[')) {
257
237
  const finalPath = `data/${pathName}`;
@@ -261,17 +241,15 @@ class Deployer {
261
241
  }
262
242
  else {
263
243
  const [left, right] = pathName.split('[');
264
- //check if this variable isLiteralKeyType (#, -, or _)
265
244
  const [amount, _] = right.split(']');
266
245
  if (!isNaN(parseInt(amount))) {
267
- //loop to create all possible paths (0 to amount)
268
246
  for (let i = 0; i < parseInt(amount); i++) {
269
247
  const finalPath = `data/${left}/${i}`;
270
248
  if (!result.includes(finalPath)) {
271
249
  result.push(finalPath);
272
250
  }
273
251
  }
274
- } //else ignore (amount might be '-' or '_') `-` is marker data; `_` is job data;
252
+ }
275
253
  }
276
254
  }
277
255
  }
@@ -293,7 +271,6 @@ class Deployer {
293
271
  }
294
272
  resolveMappingDependencies() {
295
273
  const dynamicMappingRules = [];
296
- //recursive function to descend into the object and find all dynamic mapping rules
297
274
  function traverse(obj, consumes) {
298
275
  for (const key in obj) {
299
276
  if (typeof obj[key] === 'string') {
@@ -323,7 +300,6 @@ class Deployer {
323
300
  }
324
301
  }
325
302
  const groupedRules = this.groupMappingRules(dynamicMappingRules);
326
- // Iterate through the graph and add 'produces' field to each activity
327
303
  for (const graph of graphs) {
328
304
  const activities = graph.activities;
329
305
  for (const activityId in activities) {
@@ -334,7 +310,6 @@ class Deployer {
334
310
  }
335
311
  groupMappingRules(rules) {
336
312
  rules = Array.from(new Set(rules)).sort();
337
- // Group by the first symbol before the period (this is the activity name)
338
313
  const groupedRules = {};
339
314
  for (const rule of rules) {
340
315
  const [group, resolved] = this.resolveMappableValue(rule);
@@ -353,7 +328,6 @@ class Deployer {
353
328
  return [group, path.join('/')];
354
329
  }
355
330
  else {
356
- //normalize paths to be relative to the activity
357
331
  const [group, type, subtype, ...path] = parts;
358
332
  const prefix = {
359
333
  hook: 'hook/data',
@@ -370,7 +344,6 @@ class Deployer {
370
344
  const activities = graph.activities;
371
345
  for (const activityKey in activities) {
372
346
  const target = activities[activityKey];
373
- //remove transitions; no longer necessary for runtime
374
347
  delete target.transitions;
375
348
  activitySchemas[activityKey] = target;
376
349
  }
@@ -383,7 +356,6 @@ class Deployer {
383
356
  for (const graph of graphs) {
384
357
  const activities = graph.activities;
385
358
  const subscribesTopic = graph.subscribes;
386
- // Find the activity ID associated with the subscribes topic
387
359
  for (const activityKey in activities) {
388
360
  if (activities[activityKey].type === 'trigger') {
389
361
  publicSubscriptions[subscribesTopic] = activityKey;
@@ -446,7 +418,6 @@ class Deployer {
446
418
  if (!targetActivity.hook) {
447
419
  targetActivity.hook = {};
448
420
  }
449
- //create back-reference to the hook topic
450
421
  targetActivity.hook.topic = topic;
451
422
  }
452
423
  }
@@ -455,7 +426,6 @@ class Deployer {
455
426
  await this.store.setHookRules(hookRules);
456
427
  }
457
428
  async deployConsumerGroups() {
458
- //create one engine group
459
429
  const params = { appId: this.manifest.app.id };
460
430
  const key = this.store.mintKey(key_1.KeyType.STREAMS, params);
461
431
  await this.deployConsumerGroup(key, 'ENGINE');
@@ -463,12 +433,10 @@ class Deployer {
463
433
  const activities = graph.activities;
464
434
  for (const activityKey in activities) {
465
435
  const activity = activities[activityKey];
466
- //only precreate if the topic is concrete and not `mappable`
467
436
  if (activity.type === 'worker' &&
468
437
  pipe_1.Pipe.resolve(activity.subtype, {}) === activity.subtype) {
469
438
  params.topic = activity.subtype;
470
439
  const key = this.store.mintKey(key_1.KeyType.STREAMS, params);
471
- //create one worker group per unique activity subtype (the topic)
472
440
  await this.deployConsumerGroup(key, 'WORKER');
473
441
  }
474
442
  }
@@ -2,28 +2,13 @@ import { ILogger } from '../logger';
2
2
  import { StoreService } from '../store';
3
3
  import { HotMeshManifest } from '../../types/hotmesh';
4
4
  import { RedisClient, RedisMulti } from '../../types/redis';
5
- /**
6
- * The compiler service converts a graph into a executable program.
7
- */
8
5
  declare class CompilerService {
9
6
  store: StoreService<RedisClient, RedisMulti> | null;
10
7
  logger: ILogger;
11
8
  constructor(store: StoreService<RedisClient, RedisMulti>, logger: ILogger);
12
- /**
13
- * verifies and plans the deployment of an app to Redis; the app is not deployed yet
14
- * @param path
15
- */
16
9
  plan(mySchemaOrPath: string): Promise<HotMeshManifest>;
17
10
  isPath(input: string): boolean;
18
- /**
19
- * deploys an app to Redis but does NOT activate it.
20
- */
21
11
  deploy(mySchemaOrPath: string): Promise<HotMeshManifest>;
22
- /**
23
- * activates a deployed version of an app;
24
- * @param appId
25
- * @param appVersion
26
- */
27
12
  activate(appId: string, appVersion: string): Promise<boolean>;
28
13
  saveAsJSON(originalPath: string, schema: HotMeshManifest): Promise<void>;
29
14
  }
@@ -33,18 +33,11 @@ const json_schema_ref_parser_1 = __importDefault(require("@apidevtools/json-sche
33
33
  const js_yaml_1 = __importDefault(require("js-yaml"));
34
34
  const deployer_1 = require("./deployer");
35
35
  const validator_1 = require("./validator");
36
- /**
37
- * The compiler service converts a graph into a executable program.
38
- */
39
36
  class CompilerService {
40
37
  constructor(store, logger) {
41
38
  this.store = store;
42
39
  this.logger = logger;
43
40
  }
44
- /**
45
- * verifies and plans the deployment of an app to Redis; the app is not deployed yet
46
- * @param path
47
- */
48
41
  async plan(mySchemaOrPath) {
49
42
  try {
50
43
  let schema;
@@ -54,10 +47,8 @@ class CompilerService {
54
47
  else {
55
48
  schema = js_yaml_1.default.load(mySchemaOrPath);
56
49
  }
57
- // 1) validate the manifest file
58
50
  const validator = new validator_1.Validator(schema);
59
51
  validator.validate(this.store);
60
- // 2) todo: add a PlannerService module that will plan the deployment (what might break, drift, etc)
61
52
  return schema;
62
53
  }
63
54
  catch (err) {
@@ -67,9 +58,6 @@ class CompilerService {
67
58
  isPath(input) {
68
59
  return !input.trim().startsWith('app:');
69
60
  }
70
- /**
71
- * deploys an app to Redis but does NOT activate it.
72
- */
73
61
  async deploy(mySchemaOrPath) {
74
62
  try {
75
63
  let schema;
@@ -80,13 +68,10 @@ class CompilerService {
80
68
  else {
81
69
  schema = js_yaml_1.default.load(mySchemaOrPath);
82
70
  }
83
- // 2) validate the manifest file (synchronous operation...no callbacks)
84
71
  const validator = new validator_1.Validator(schema);
85
72
  validator.validate(this.store);
86
- // 3) deploy the schema (segment, optimize, etc; save to Redis)
87
73
  const deployer = new deployer_1.Deployer(schema);
88
74
  await deployer.deploy(this.store);
89
- // 4) save the app version to Redis (so it can be activated later)
90
75
  await this.store.setApp(schema.app.id, schema.app.version);
91
76
  return schema;
92
77
  }
@@ -94,11 +79,6 @@ class CompilerService {
94
79
  this.logger.error('compiler-deploy-error', err);
95
80
  }
96
81
  }
97
- /**
98
- * activates a deployed version of an app;
99
- * @param appId
100
- * @param appVersion
101
- */
102
82
  async activate(appId, appVersion) {
103
83
  return await this.store.activateAppVersion(appId, appVersion);
104
84
  }
@@ -10,9 +10,6 @@ declare class Validator {
10
10
  static SYS_VARS: string[];
11
11
  static CONTEXT_VARS: string[];
12
12
  constructor(manifest: HotMeshManifest);
13
- /**
14
- * validate the manifest file
15
- */
16
13
  validate(store: StoreService<RedisClient, RedisMulti>): Promise<void>;
17
14
  validateActivityIds(): void;
18
15
  isMappingStatement(value: string): boolean;
@@ -10,9 +10,6 @@ class Validator {
10
10
  this.store = null;
11
11
  this.manifest = manifest;
12
12
  }
13
- /**
14
- * validate the manifest file
15
- */
16
13
  async validate(store) {
17
14
  this.store = store;
18
15
  this.getMappingStatements();
@@ -28,12 +25,10 @@ class Validator {
28
25
  this.validateHooks();
29
26
  this.validateConditionalStatements();
30
27
  }
31
- // 1.1) Validate the manifest file activity ids are unique (no duplicates)
32
28
  validateActivityIds() {
33
29
  const activityIdsSet = new Set();
34
30
  this.manifest.app.graphs.forEach((graph) => {
35
31
  const ids = Object.keys(graph.activities);
36
- // Check for duplicates and add ids to the set
37
32
  ids.forEach((id) => {
38
33
  if (activityIdsSet.has(id)) {
39
34
  throw new Error(`Duplicate activity id found: ${id}`);
@@ -72,9 +67,7 @@ class Validator {
72
67
  });
73
68
  this.mappingStatements = mappingStatements;
74
69
  }
75
- // 1.2) Validate no activity ids are referenced that don't exist
76
70
  validateReferencedActivityIds() {
77
- // get list of all mapping statements and validate
78
71
  const mappingStatements = this.mappingStatements;
79
72
  const activityIds = this.activityIds;
80
73
  for (const activity in mappingStatements) {
@@ -99,41 +92,23 @@ class Validator {
99
92
  isContextVariable(value) {
100
93
  return ['{$input}', '{$output}', '{$item}', '{$key}', '{$index}'].includes(value);
101
94
  }
102
- // 1.3) Validate the mapping/@pipe statements are valid
103
95
  validateMappingStatements() {
104
- // Implement the method content
105
96
  }
106
- // 1.4) Validate the transitions are valid
107
97
  validateTransitions() {
108
- // Implement the method content
109
98
  }
110
- // 1.5) Validate the transition conditions are valid
111
99
  validateTransitionConditions() {
112
- // Implement the method content
113
100
  }
114
- // 1.6) Validate the stats
115
101
  validateStats() {
116
- // Implement the method content
117
102
  }
118
- // 1.7) Validate the schemas
119
103
  validateSchemas() {
120
- // Implement the method content
121
104
  }
122
- // 1.8) Validate the topics are unique and handled
123
105
  validateUniqueHandledTopics() {
124
- // Implement the method content
125
106
  }
126
- // 1.9) Validate that every graph has publishes and subscribes
127
107
  validateGraphPublishSubscribe() {
128
- // Implement the method content
129
108
  }
130
- // 1.10) Validate hooks, including mapping statements
131
109
  validateHooks() {
132
- // Implement the method content
133
110
  }
134
- // 1.11) Validate conditional statements
135
111
  validateConditionalStatements() {
136
- // Implement the method content
137
112
  }
138
113
  }
139
114
  exports.Validator = Validator;
@@ -45,6 +45,4 @@ RedisConnection.instances = new Map();
45
45
  RedisConnection.clientOptions = {
46
46
  host: 'localhost',
47
47
  port: 6379,
48
- //password: config.REDIS_PASSWORD,
49
- //db: config.REDIS_DATABASE,
50
48
  };
@@ -57,6 +57,4 @@ RedisConnection.clientOptions = {
57
57
  port: 6379,
58
58
  tls: false,
59
59
  },
60
- //password: config.REDIS_PASSWORD,
61
- //database: config.REDIS_DATABASE,
62
60
  };
@@ -5,8 +5,6 @@ const utils_1 = require("../../modules/utils");
5
5
  const ioredis_1 = require("../connector/clients/ioredis");
6
6
  const redis_1 = require("../connector/clients/redis");
7
7
  class ConnectorService {
8
- //1) Initialize `store`, `stream`, and `subscription` Redis clients.
9
- //2) Bind to the target if not already present
10
8
  static async initRedisClients(Redis, options, target) {
11
9
  if (!target.store || !target.stream || !target.sub) {
12
10
  const instances = [];
@@ -42,17 +42,13 @@ declare class EngineService {
42
42
  reporting: boolean;
43
43
  jobId: number;
44
44
  inited: string;
45
+ constructor();
45
46
  static init(namespace: string, appId: string, guid: string, config: HotMeshConfig, logger: ILogger): Promise<EngineService>;
46
47
  verifyEngineFields(config: HotMeshConfig): void;
47
48
  initStoreChannel(store: RedisClient): Promise<void>;
48
49
  initSubChannel(sub: RedisClient): Promise<void>;
49
50
  initStreamChannel(stream: RedisClient): Promise<void>;
50
51
  initRouter(config: HotMeshConfig): Promise<Router>;
51
- /**
52
- * resolves the distributed executable version using a delay
53
- * to allow deployment race conditions to resolve
54
- * @private
55
- */
56
52
  fetchAndVerifyVID(vid: AppVID, count?: number): Promise<AppVID>;
57
53
  getVID(vid?: AppVID): Promise<AppVID>;
58
54
  setCacheMode(cacheMode: CacheMode, untilVersion: string): void;
@@ -92,11 +88,6 @@ declare class EngineService {
92
88
  delistJobCallback(jobId: string): void;
93
89
  hasOneTimeSubscription(context: JobState): boolean;
94
90
  runJobCompletionTasks(context: JobState, options?: JobCompletionOptions): Promise<string | void>;
95
- /**
96
- * Job hash expiration is typically reliant on the metadata field
97
- * if the activity concludes normally. However, if the job is `interrupted`,
98
- * it will be expired immediately.
99
- */
100
91
  resolveExpires(context: JobState, options: JobCompletionOptions): number;
101
92
  export(jobId: string): Promise<JobExport>;
102
93
  getRaw(jobId: string): Promise<StringStringType>;
@@ -94,11 +94,6 @@ class EngineService {
94
94
  throttle,
95
95
  }, this.stream, this.store, this.logger);
96
96
  }
97
- /**
98
- * resolves the distributed executable version using a delay
99
- * to allow deployment race conditions to resolve
100
- * @private
101
- */
102
97
  async fetchAndVerifyVID(vid, count = 0) {
103
98
  if (isNaN(Number(vid.version))) {
104
99
  const app = await this.store.getApp(vid.id, true);
@@ -122,7 +117,6 @@ class EngineService {
122
117
  if (this.cacheMode === 'nocache') {
123
118
  const app = await this.store.getApp(this.appId, true);
124
119
  if (app.version.toString() === this.untilVersion.toString()) {
125
- //new version is deployed; OK to cache again
126
120
  if (!this.apps)
127
121
  this.apps = {};
128
122
  this.apps[this.appId] = app;
@@ -171,7 +165,6 @@ class EngineService {
171
165
  this.logger.error('engine-throttle-error', { error: e });
172
166
  }
173
167
  }
174
- // ************* METADATA/MODEL METHODS *************
175
168
  async initActivity(topic, data = {}, context) {
176
169
  const [activityId, schema] = await this.getSchema(topic);
177
170
  const ActivityHandler = activities_1.default[utils_1.polyfill.resolveActivityType(schema.type)];
@@ -197,13 +190,11 @@ class EngineService {
197
190
  throw new Error(`no app found for id ${this.appId}`);
198
191
  }
199
192
  if (this.isPrivate(topic)) {
200
- //private subscriptions use the schema id (.activityId)
201
193
  const activityId = topic.substring(1);
202
194
  const schema = await this.store.getSchema(activityId, await this.getVID(app));
203
195
  return [activityId, schema];
204
196
  }
205
197
  else {
206
- //public subscriptions use a topic (a.b.c) that is associated with a schema id
207
198
  const activityId = await this.store.getSubscription(topic, await this.getVID(app));
208
199
  if (activityId) {
209
200
  const schema = await this.store.getSchema(activityId, await this.getVID(app));
@@ -218,7 +209,6 @@ class EngineService {
218
209
  isPrivate(topic) {
219
210
  return topic.startsWith('.');
220
211
  }
221
- // ************* COMPILER METHODS *************
222
212
  async plan(pathOrYAML) {
223
213
  const compiler = new compiler_1.CompilerService(this.store, this.logger);
224
214
  return await compiler.plan(pathOrYAML);
@@ -227,7 +217,6 @@ class EngineService {
227
217
  const compiler = new compiler_1.CompilerService(this.store, this.logger);
228
218
  return await compiler.deploy(pathOrYAML);
229
219
  }
230
- // ************* REPORTER METHODS *************
231
220
  async getStats(topic, query) {
232
221
  const { id, version } = await this.getVID();
233
222
  const reporter = new reporter_1.ReporterService({ id, version }, this.store, this.logger);
@@ -252,7 +241,6 @@ class EngineService {
252
241
  sparse: query.sparse,
253
242
  };
254
243
  }
255
- // ****************** STREAM RE-ENTRY POINT *****************
256
244
  async processStreamMessage(streamData) {
257
245
  this.logger.debug('engine-process', {
258
246
  jid: streamData.metadata.jid,
@@ -274,22 +262,18 @@ class EngineService {
274
262
  data: streamData.data,
275
263
  };
276
264
  if (streamData.type === stream_1.StreamDataType.TIMEHOOK) {
277
- //TIMEHOOK AWAKEN
278
265
  const activityHandler = (await this.initActivity(`.${streamData.metadata.aid}`, context.data, context));
279
266
  await activityHandler.processTimeHookEvent(streamData.metadata.jid);
280
267
  }
281
268
  else if (streamData.type === stream_1.StreamDataType.WEBHOOK) {
282
- //WEBHOOK AWAKEN (SIGNAL IN)
283
269
  const activityHandler = (await this.initActivity(`.${streamData.metadata.aid}`, context.data, context));
284
270
  await activityHandler.processWebHookEvent(streamData.status, streamData.code);
285
271
  }
286
272
  else if (streamData.type === stream_1.StreamDataType.TRANSITION) {
287
- //TRANSITION (ADJACENT ACTIVITY)
288
- const activityHandler = (await this.initActivity(`.${streamData.metadata.aid}`, context.data, context)); //todo: `as Activity` (type is more generic)
273
+ const activityHandler = (await this.initActivity(`.${streamData.metadata.aid}`, context.data, context));
289
274
  await activityHandler.process();
290
275
  }
291
276
  else if (streamData.type === stream_1.StreamDataType.AWAIT) {
292
- //TRIGGER JOB
293
277
  context.metadata = {
294
278
  ...context.metadata,
295
279
  pj: streamData.metadata.jid,
@@ -304,12 +288,10 @@ class EngineService {
304
288
  await activityHandler.process();
305
289
  }
306
290
  else if (streamData.type === stream_1.StreamDataType.RESULT) {
307
- //AWAIT RESULT
308
291
  const activityHandler = (await this.initActivity(`.${context.metadata.aid}`, streamData.data, context));
309
292
  await activityHandler.processEvent(streamData.status, streamData.code);
310
293
  }
311
294
  else {
312
- //WORKER RESULT
313
295
  const activityHandler = (await this.initActivity(`.${streamData.metadata.aid}`, streamData.data, context));
314
296
  await activityHandler.processEvent(streamData.status, streamData.code, 'output');
315
297
  }
@@ -319,10 +301,8 @@ class EngineService {
319
301
  aid: streamData.metadata.aid,
320
302
  });
321
303
  }
322
- // ***************** `AWAIT` ACTIVITY RETURN RESPONSE ****************
323
304
  async execAdjacentParent(context, jobOutput, emit = false) {
324
305
  if (this.hasParentJob(context)) {
325
- //errors are stringified `StreamError` objects
326
306
  const error = this.resolveError(jobOutput.metadata);
327
307
  const spn = context['$self']?.output?.metadata?.l2s ||
328
308
  context['$self']?.output?.metadata?.l1s;
@@ -367,11 +347,8 @@ class EngineService {
367
347
  return JSON.parse(metadata.err);
368
348
  }
369
349
  }
370
- // ****************** `INTERRUPT` ACTIVE JOBS *****************
371
350
  async interrupt(topic, jobId, options = {}) {
372
- //immediately interrupt the job, going directly to the data source
373
351
  await this.store.interrupt(topic, jobId, options);
374
- //now that the job is interrupted, we can clean up
375
352
  const context = (await this.getState(topic, jobId));
376
353
  const completionOpts = {
377
354
  interrupt: options.descend,
@@ -379,12 +356,9 @@ class EngineService {
379
356
  };
380
357
  return (await this.runJobCompletionTasks(context, completionOpts));
381
358
  }
382
- // ****************** `SCRUB` CLEAN COMPLETED JOBS *****************
383
359
  async scrub(jobId) {
384
- //todo: do not allow scrubbing of non-existent or actively running job
385
360
  await this.store.scrub(jobId);
386
361
  }
387
- // ****************** `HOOK` ACTIVITY RE-ENTRY POINT *****************
388
362
  async hook(topic, data, status = stream_1.StreamStatus.SUCCESS, code = 200) {
389
363
  const hookRule = await this.taskService.getHookRule(topic);
390
364
  const [aid] = await this.getSchema(`.${hookRule.to}`);
@@ -447,8 +421,6 @@ class EngineService {
447
421
  throw new Error(`unable to find hook rule for topic ${hookTopic}`);
448
422
  }
449
423
  }
450
- // ********************** PUB/SUB ENTRY POINT **********************
451
- //publish (returns just the job id)
452
424
  async pub(topic, data, context, extended) {
453
425
  const activityHandler = await this.initActivity(topic, data, context);
454
426
  if (activityHandler) {
@@ -458,29 +430,24 @@ class EngineService {
458
430
  throw new Error(`unable to process activity for topic ${topic}`);
459
431
  }
460
432
  }
461
- //subscribe to all jobs for a topic
462
433
  async sub(topic, callback) {
463
434
  const subscriptionCallback = async (topic, message) => {
464
435
  callback(message.topic, message.job);
465
436
  };
466
437
  return await this.subscribe.subscribe(key_1.KeyType.QUORUM, subscriptionCallback, this.appId, topic);
467
438
  }
468
- //unsubscribe to all jobs for a topic
469
439
  async unsub(topic) {
470
440
  return await this.subscribe.unsubscribe(key_1.KeyType.QUORUM, this.appId, topic);
471
441
  }
472
- //subscribe to all jobs for a wildcard topic
473
442
  async psub(wild, callback) {
474
443
  const subscriptionCallback = async (topic, message) => {
475
444
  callback(message.topic, message.job);
476
445
  };
477
446
  return await this.subscribe.psubscribe(key_1.KeyType.QUORUM, subscriptionCallback, this.appId, wild);
478
447
  }
479
- //unsubscribe to all jobs for a wildcard topic
480
448
  async punsub(wild) {
481
449
  return await this.subscribe.punsubscribe(key_1.KeyType.QUORUM, this.appId, wild);
482
450
  }
483
- //publish and await (returns the job and data (if ready)); throws error with jobid if not
484
451
  async pubsub(topic, data, context, timeout = enums_1.HMSH_OTT_WAIT_TIME) {
485
452
  context = {
486
453
  metadata: {
@@ -504,7 +471,6 @@ class EngineService {
504
471
  }
505
472
  });
506
473
  setTimeout(() => {
507
- //note: job is still active (the subscriber timed out)
508
474
  this.delistJobCallback(jobId);
509
475
  reject({
510
476
  code: enums_1.HMSH_CODE_TIMEOUT,
@@ -515,7 +481,6 @@ class EngineService {
515
481
  });
516
482
  }
517
483
  async pubOneTimeSubs(context, jobOutput, emit = false) {
518
- //todo: subscriber should query for the job...only publish minimum context needed
519
484
  if (this.hasOneTimeSubscription(context)) {
520
485
  const message = {
521
486
  type: 'job',
@@ -554,9 +519,7 @@ class EngineService {
554
519
  hasOneTimeSubscription(context) {
555
520
  return Boolean(context.metadata.ngn);
556
521
  }
557
- // ********** JOB COMPLETION/CLEANUP (AND JOB EMIT) ***********
558
522
  async runJobCompletionTasks(context, options = {}) {
559
- //'emit' indicates the job is still active
560
523
  const isAwait = this.hasParentJob(context, true);
561
524
  const isOneTimeSub = this.hasOneTimeSubscription(context);
562
525
  const topic = await this.getPublishesTopic(context);
@@ -572,15 +535,9 @@ class EngineService {
572
535
  }
573
536
  return msgId;
574
537
  }
575
- /**
576
- * Job hash expiration is typically reliant on the metadata field
577
- * if the activity concludes normally. However, if the job is `interrupted`,
578
- * it will be expired immediately.
579
- */
580
538
  resolveExpires(context, options) {
581
539
  return options.expire ?? context.metadata.expire ?? enums_1.HMSH_EXPIRE_JOB_SECONDS;
582
540
  }
583
- // ****** GET JOB STATE/COLLATION STATUS BY ID *********
584
541
  async export(jobId) {
585
542
  return await this.exporter.export(jobId);
586
543
  }
@@ -591,15 +548,11 @@ class EngineService {
591
548
  const { id: appId } = await this.getVID();
592
549
  return await this.store.getStatus(jobId, appId);
593
550
  }
594
- //todo: add 'options' parameter;
595
- // (e.g, if {dimensions:true}, use hscan to deliver
596
- // the full set of dimensional job data)
597
551
  async getState(topic, jobId) {
598
552
  const jobSymbols = await this.store.getSymbols(`$${topic}`);
599
553
  const consumes = {
600
554
  [`$${topic}`]: Object.keys(jobSymbols),
601
555
  };
602
- //job data exists at the 'zero' dimension; pass an empty object
603
556
  const dIds = {};
604
557
  const output = await this.store.getState(jobId, consumes, dIds);
605
558
  if (!output) {