nesoi 3.1.6 → 3.1.8

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 (55) hide show
  1. package/lib/compiler/apps/monolyth/stages/4_dump_modules_stage.js +8 -0
  2. package/lib/compiler/elements/element.d.ts +2 -1
  3. package/lib/compiler/elements/element.js +1 -0
  4. package/lib/compiler/elements/topic.element.d.ts +6 -0
  5. package/lib/compiler/elements/topic.element.js +24 -0
  6. package/lib/compiler/helpers/name_helpers.js +2 -1
  7. package/lib/compiler/module.d.ts +2 -1
  8. package/lib/compiler/module.js +7 -0
  9. package/lib/compiler/stages/7_dump_stage.js +3 -2
  10. package/lib/compiler/treeshake.d.ts +3 -0
  11. package/lib/compiler/treeshake.js +21 -0
  12. package/lib/compiler/typescript/typescript_compiler.js +1 -0
  13. package/lib/elements/blocks/block.schema.d.ts +1 -1
  14. package/lib/elements/blocks/topic/topic.builder.d.ts +36 -0
  15. package/lib/elements/blocks/topic/topic.builder.js +37 -0
  16. package/lib/elements/blocks/topic/topic.d.ts +20 -0
  17. package/lib/elements/blocks/topic/topic.js +44 -0
  18. package/lib/elements/blocks/topic/topic.schema.d.ts +17 -0
  19. package/lib/elements/blocks/topic/topic.schema.js +22 -0
  20. package/lib/elements/edge/controller/adapters/cli.controller_adapter.d.ts +4 -2
  21. package/lib/elements/edge/controller/adapters/cli.controller_adapter.js +5 -0
  22. package/lib/elements/edge/controller/adapters/controller_adapter.d.ts +2 -1
  23. package/lib/elements/edge/controller/adapters/controller_adapter.js +4 -0
  24. package/lib/elements/edge/controller/controller.builder.d.ts +23 -1
  25. package/lib/elements/edge/controller/controller.builder.js +51 -2
  26. package/lib/elements/edge/controller/controller.d.ts +14 -1
  27. package/lib/elements/edge/controller/controller.js +34 -1
  28. package/lib/elements/edge/controller/controller.schema.d.ts +16 -1
  29. package/lib/elements/edge/controller/controller.schema.js +19 -2
  30. package/lib/elements/entities/bucket/bucket.d.ts +2 -2
  31. package/lib/elements/entities/bucket/bucket.js +23 -15
  32. package/lib/elements/entities/bucket/model/bucket_model_field.builder.d.ts +1 -1
  33. package/lib/elements/entities/bucket/model/bucket_model_field.builder.js +1 -0
  34. package/lib/elements/index.d.ts +1 -0
  35. package/lib/elements/index.js +3 -1
  36. package/lib/engine/apps/inline.app.d.ts +5 -0
  37. package/lib/engine/apps/inline.app.js +16 -0
  38. package/lib/engine/daemon.js +1 -1
  39. package/lib/engine/data/error.d.ts +7 -2
  40. package/lib/engine/data/error.js +11 -3
  41. package/lib/engine/module.d.ts +7 -2
  42. package/lib/engine/module.js +20 -0
  43. package/lib/engine/space.d.ts +12 -0
  44. package/lib/engine/space.js +13 -0
  45. package/lib/engine/transaction/nodes/topic.trx_node.d.ts +17 -0
  46. package/lib/engine/transaction/nodes/topic.trx_node.js +50 -0
  47. package/lib/engine/transaction/trx_node.d.ts +3 -1
  48. package/lib/engine/transaction/trx_node.js +8 -0
  49. package/lib/engine/util/crypto.d.ts +4 -13
  50. package/lib/engine/util/crypto.js +26 -37
  51. package/lib/engine/util/log.d.ts +1 -1
  52. package/lib/engine/util/log.js +1 -0
  53. package/lib/schema.d.ts +5 -1
  54. package/package.json +1 -1
  55. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Controller = exports.ControllerEndpoint = void 0;
3
+ exports.Controller = exports.ControllerTopic = exports.ControllerEndpoint = void 0;
4
4
  const cli_controller_adapter_1 = require("./adapters/cli.controller_adapter");
5
5
  const trx_node_1 = require("../../../engine/transaction/trx_node");
6
+ const error_1 = require("../../../engine/data/error");
6
7
  /**
7
8
  * @category Elements
8
9
  * @subcategory Edge
@@ -33,6 +34,38 @@ class ControllerEndpoint {
33
34
  }
34
35
  }
35
36
  exports.ControllerEndpoint = ControllerEndpoint;
37
+ /**
38
+ * @category Elements
39
+ * @subcategory Edge
40
+ */
41
+ class ControllerTopic {
42
+ constructor(schema, adapter, path) {
43
+ this.schema = schema;
44
+ this.adapter = adapter;
45
+ this.path = path;
46
+ }
47
+ async subscribe(fn, authn) {
48
+ const response = await this.adapter.trx(trx => {
49
+ trx_node_1.TrxNode.checkAuthn(trx, this.schema.authn);
50
+ return trx.topic(this.schema.name).subscribe(fn);
51
+ }, authn);
52
+ if (response.state === 'error') {
53
+ throw error_1.NesoiError.Controller.SubscribeFailed({ topic: this.schema.alias });
54
+ }
55
+ return response.output;
56
+ }
57
+ async unsubscribe(id) {
58
+ const response = await this.adapter.trx(trx => {
59
+ trx_node_1.TrxNode.checkAuthn(trx, this.schema.authn);
60
+ return trx.topic(this.schema.name).unsubscribe(id);
61
+ });
62
+ if (response.state === 'error') {
63
+ throw error_1.NesoiError.Controller.UnsubscribeFailed({ topic: this.schema.alias });
64
+ }
65
+ return response.output;
66
+ }
67
+ }
68
+ exports.ControllerTopic = ControllerTopic;
36
69
  class Controller {
37
70
  constructor(module, schema, config, services = {}) {
38
71
  this.schema = schema;
@@ -15,6 +15,20 @@ export declare class $ControllerEndpoint {
15
15
  $t: string;
16
16
  constructor(name: string, alias: string, authn: string[], tags: string[], msg: $Dependency, target: $Dependency);
17
17
  }
18
+ /**
19
+ * @category Schemas
20
+ * @subcategory Edge
21
+ */
22
+ export declare class $ControllerTopic {
23
+ name: string;
24
+ alias: string;
25
+ authn: string[];
26
+ tags: string[];
27
+ msgs: $Dependency[];
28
+ topic: $Dependency;
29
+ $t: string;
30
+ constructor(name: string, alias: string, authn: string[], tags: string[], msgs: $Dependency[], topic: $Dependency);
31
+ }
18
32
  /**
19
33
  * @category Schemas
20
34
  * @subcategory Edge
@@ -53,8 +67,9 @@ export declare class $Controller {
53
67
  authn: string[];
54
68
  input: $Dependency[];
55
69
  domains: Record<string, $ControllerDomain>;
70
+ topics: Record<string, $ControllerTopic>;
56
71
  $t: "controller";
57
72
  '#authn': AnyUsers;
58
73
  '#input': $Message;
59
- constructor(module: string, name: string, alias: string, authn: string[], input: $Dependency[], domains?: Record<string, $ControllerDomain>);
74
+ constructor(module: string, name: string, alias: string, authn: string[], input: $Dependency[], domains?: Record<string, $ControllerDomain>, topics?: Record<string, $ControllerTopic>);
60
75
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.$Controller = exports.$ControllerDomain = exports.$ControllerGroup = exports.$ControllerEndpoint = void 0;
3
+ exports.$Controller = exports.$ControllerDomain = exports.$ControllerGroup = exports.$ControllerTopic = exports.$ControllerEndpoint = void 0;
4
4
  /**
5
5
  * @category Schemas
6
6
  * @subcategory Edge
@@ -17,6 +17,22 @@ class $ControllerEndpoint {
17
17
  }
18
18
  }
19
19
  exports.$ControllerEndpoint = $ControllerEndpoint;
20
+ /**
21
+ * @category Schemas
22
+ * @subcategory Edge
23
+ */
24
+ class $ControllerTopic {
25
+ constructor(name, alias, authn, tags, msgs, topic) {
26
+ this.name = name;
27
+ this.alias = alias;
28
+ this.authn = authn;
29
+ this.tags = tags;
30
+ this.msgs = msgs;
31
+ this.topic = topic;
32
+ this.$t = 'controller.topic';
33
+ }
34
+ }
35
+ exports.$ControllerTopic = $ControllerTopic;
20
36
  /**
21
37
  * @category Schemas
22
38
  * @subcategory Edge
@@ -54,13 +70,14 @@ exports.$ControllerDomain = $ControllerDomain;
54
70
  * @subcategory Edge
55
71
  */
56
72
  class $Controller {
57
- constructor(module, name, alias, authn, input, domains = {}) {
73
+ constructor(module, name, alias, authn, input, domains = {}, topics = {}) {
58
74
  this.module = module;
59
75
  this.name = name;
60
76
  this.alias = alias;
61
77
  this.authn = authn;
62
78
  this.input = input;
63
79
  this.domains = domains;
80
+ this.topics = topics;
64
81
  this.$t = 'controller';
65
82
  }
66
83
  }
@@ -197,8 +197,8 @@ export declare class Bucket<M extends $Module, $ extends $Bucket> {
197
197
  */
198
198
  protected addMeta(trx: AnyTrxNode, obj: Record<string, any>, operation: 'create' | 'update'): void;
199
199
  getTenancyQuery(trx: AnyTrxNode): import("./query/nql.schema").NQL_Query<any, any> | undefined;
200
- protected encrypt(trx: AnyTrxNode, obj: Record<string, any>, fields?: $BucketModelFields): void;
201
- protected decrypt(trx: AnyTrxNode, obj: Record<string, any>, fields?: $BucketModelFields): void;
200
+ protected encrypt(trx: AnyTrxNode, obj: Record<string, any>, fields?: $BucketModelFields): Promise<void>;
201
+ protected decrypt(trx: AnyTrxNode, obj: Record<string, any>, fields?: $BucketModelFields): Promise<void>;
202
202
  /**
203
203
  * Copy all files from the object to the bucket's Drive
204
204
  * - Call `drive.upload` to send the files to the drive preserving the local copy
@@ -101,7 +101,7 @@ class Bucket {
101
101
  }
102
102
  // Encryption
103
103
  if (this.schema.model.hasEncryptedField) {
104
- this.decrypt(trx, raw);
104
+ await this.decrypt(trx, raw);
105
105
  }
106
106
  return raw;
107
107
  }
@@ -132,7 +132,7 @@ class Bucket {
132
132
  // Encryption
133
133
  if (this.schema.model.hasEncryptedField) {
134
134
  for (const raw of raws) {
135
- this.decrypt(trx, raw);
135
+ await this.decrypt(trx, raw);
136
136
  }
137
137
  }
138
138
  return raws;
@@ -196,7 +196,7 @@ class Bucket {
196
196
  // Encryption
197
197
  if (linkObj) {
198
198
  if (this.schema.model.hasEncryptedField) {
199
- this.decrypt(trx, linkObj);
199
+ await this.decrypt(trx, linkObj);
200
200
  }
201
201
  }
202
202
  return linkObj;
@@ -230,10 +230,10 @@ class Bucket {
230
230
  if (linkObj && this.schema.model.hasEncryptedField) {
231
231
  if (Array.isArray(linkObj)) {
232
232
  for (const obj of linkObj)
233
- this.decrypt(trx, obj);
233
+ await this.decrypt(trx, obj);
234
234
  }
235
235
  else {
236
- this.decrypt(trx, linkObj);
236
+ await this.decrypt(trx, linkObj);
237
237
  }
238
238
  }
239
239
  return linkObj;
@@ -287,7 +287,7 @@ class Bucket {
287
287
  this.addMeta(trx, obj, 'create');
288
288
  // Encryption
289
289
  if (this.schema.model.hasEncryptedField) {
290
- this.encrypt(trx, obj);
290
+ await this.encrypt(trx, obj);
291
291
  }
292
292
  // Drive
293
293
  if (this.schema.model.hasFileField) {
@@ -413,7 +413,7 @@ class Bucket {
413
413
  this.addMeta(trx, obj, 'update');
414
414
  // Encryption
415
415
  if (this.schema.model.hasEncryptedField) {
416
- this.encrypt(trx, obj);
416
+ await this.encrypt(trx, obj);
417
417
  }
418
418
  // Drive
419
419
  if (this.schema.model.hasFileField) {
@@ -461,7 +461,7 @@ class Bucket {
461
461
  this.addMeta(trx, obj, 'create');
462
462
  // Encryption
463
463
  if (this.schema.model.hasEncryptedField) {
464
- this.encrypt(trx, obj);
464
+ await this.encrypt(trx, obj);
465
465
  }
466
466
  // Drive
467
467
  if (this.schema.model.hasFileField) {
@@ -678,7 +678,7 @@ class Bucket {
678
678
  // Encryption
679
679
  if (this.schema.model.hasEncryptedField) {
680
680
  for (const obj of result.data) {
681
- this.decrypt(trx, obj);
681
+ await this.decrypt(trx, obj);
682
682
  }
683
683
  }
684
684
  // Build
@@ -712,27 +712,35 @@ class Bucket {
712
712
  return this.schema.tenancy[match.provider]?.(match.user);
713
713
  }
714
714
  // Encryption
715
- encrypt(trx, obj, fields = this.schema.model.fields) {
715
+ async encrypt(trx, obj, fields = this.schema.model.fields) {
716
716
  for (const key in fields) {
717
717
  const field = fields[key];
718
718
  if (field.crypto) {
719
719
  const key = trx.value(field.crypto.key);
720
- tree_1.Tree.set(obj, field.path, val => crypto_1.Crypto.encrypt(val, key));
720
+ const val = tree_1.Tree.get(obj, field.path);
721
+ if (val !== undefined) {
722
+ const encrypted = await crypto_1.NesoiCrypto.encrypt(val, key);
723
+ tree_1.Tree.set(obj, field.path, () => encrypted);
724
+ }
721
725
  }
722
726
  if (field.children) {
723
- this.encrypt(trx, obj, field.children);
727
+ await this.encrypt(trx, obj, field.children);
724
728
  }
725
729
  }
726
730
  }
727
- decrypt(trx, obj, fields = this.schema.model.fields) {
731
+ async decrypt(trx, obj, fields = this.schema.model.fields) {
728
732
  for (const key in fields) {
729
733
  const field = fields[key];
730
734
  if (field.crypto) {
731
735
  const key = trx.value(field.crypto.key);
732
- tree_1.Tree.set(obj, field.path, val => crypto_1.Crypto.decrypt(val, key));
736
+ const val = tree_1.Tree.get(obj, field.path);
737
+ if (val !== undefined) {
738
+ const encrypted = await crypto_1.NesoiCrypto.decrypt(val, key);
739
+ tree_1.Tree.set(obj, field.path, () => encrypted);
740
+ }
733
741
  }
734
742
  if (field.children) {
735
- this.decrypt(trx, obj, field.children);
743
+ await this.decrypt(trx, obj, field.children);
736
744
  }
737
745
  }
738
746
  }
@@ -164,7 +164,7 @@ export declare class BucketModelFieldBuilder<Module extends $Module, Input, Outp
164
164
  * > If you want unconstrained enum you must specify `null` here.
165
165
  */
166
166
  maxLength(val: number | null): void;
167
- encrypt(key: keyof Module['constants']['values'], algorithm?: string): void;
167
+ encrypt(key: keyof Module['constants']['values'], algorithm?: string): this;
168
168
  static build(builder: AnyBucketModelFieldBuilder, name: string, basePath?: string): {
169
169
  schema: $BucketModelField;
170
170
  hasFile: boolean;
@@ -152,6 +152,7 @@ class BucketModelFieldBuilder {
152
152
  algorithm,
153
153
  key: key
154
154
  };
155
+ return this;
155
156
  }
156
157
  // Build
157
158
  static build(builder, name, basePath = '') {
@@ -7,5 +7,6 @@ export { $Bucket } from './entities/bucket/bucket.schema';
7
7
  export { $Job } from './blocks/job/job.schema';
8
8
  export { $Resource } from './blocks/resource/resource.schema';
9
9
  export { $Queue } from './blocks/queue/queue.schema';
10
+ export { $Topic } from './blocks/topic/topic.schema';
10
11
  export { $Externals } from './edge/externals/externals.schema';
11
12
  export { $Space, $Module } from '../schema';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.$Externals = exports.$Queue = exports.$Resource = exports.$Job = exports.$Bucket = exports.$Message = exports.$Constants = exports.$Machine = exports.$Controller = exports.MemoryBucketAdapter = void 0;
3
+ exports.$Externals = exports.$Topic = exports.$Queue = exports.$Resource = exports.$Job = exports.$Bucket = exports.$Message = exports.$Constants = exports.$Machine = exports.$Controller = exports.MemoryBucketAdapter = void 0;
4
4
  var memory_bucket_adapter_1 = require("./entities/bucket/adapters/memory.bucket_adapter");
5
5
  Object.defineProperty(exports, "MemoryBucketAdapter", { enumerable: true, get: function () { return memory_bucket_adapter_1.MemoryBucketAdapter; } });
6
6
  var controller_schema_1 = require("./edge/controller/controller.schema");
@@ -19,5 +19,7 @@ var resource_schema_1 = require("./blocks/resource/resource.schema");
19
19
  Object.defineProperty(exports, "$Resource", { enumerable: true, get: function () { return resource_schema_1.$Resource; } });
20
20
  var queue_schema_1 = require("./blocks/queue/queue.schema");
21
21
  Object.defineProperty(exports, "$Queue", { enumerable: true, get: function () { return queue_schema_1.$Queue; } });
22
+ var topic_schema_1 = require("./blocks/topic/topic.schema");
23
+ Object.defineProperty(exports, "$Topic", { enumerable: true, get: function () { return topic_schema_1.$Topic; } });
22
24
  var externals_schema_1 = require("./edge/externals/externals.schema");
23
25
  Object.defineProperty(exports, "$Externals", { enumerable: true, get: function () { return externals_schema_1.$Externals; } });
@@ -38,6 +38,11 @@ export declare class InlineApp<S extends $Space, ModuleNames extends string = Mo
38
38
  * TODO: allow overriding this behavior with adapters
39
39
  */
40
40
  protected linkExternals(modules: Record<string, Module<S, $Module>>): void;
41
+ /**
42
+ * This method injects values from environment variables into each module's
43
+ * app constants.
44
+ */
45
+ protected linkAppValues(modules: Record<string, Module<S, $Module>>): void;
41
46
  modules<M extends ModuleName<S>>(modules: M[]): InlineApp<S, M & ModuleNames>;
42
47
  service<T extends IService>($: T): InlineApp<S, ModuleNames, Services & { [K in T["name"]]: T; }>;
43
48
  get config(): AppConfigFactory<S, ModuleNames, Services, typeof this>;
@@ -85,6 +85,8 @@ class InlineApp extends app_1.App {
85
85
  }
86
86
  log_1.Log.debug('app', this.name, 'Linking externals');
87
87
  this.linkExternals(modules);
88
+ log_1.Log.debug('app', this.name, 'Linking app values');
89
+ this.linkAppValues(modules);
88
90
  return {
89
91
  modules,
90
92
  services,
@@ -132,6 +134,20 @@ class InlineApp extends app_1.App {
132
134
  });
133
135
  });
134
136
  }
137
+ /**
138
+ * This method injects values from environment variables into each module's
139
+ * app constants.
140
+ */
141
+ linkAppValues(modules) {
142
+ Object.values(modules).forEach(module => {
143
+ const values = module.schema.constants.values;
144
+ Object.values(values).forEach(value => {
145
+ if (value.scope !== 'app')
146
+ return;
147
+ value.value = process.env[value.key];
148
+ });
149
+ });
150
+ }
135
151
  // Type Builder Overrides
136
152
  modules(modules) {
137
153
  super.modules(modules);
@@ -154,7 +154,7 @@ class DaemonTrx {
154
154
  * @param fn A function to execute inside the transaction
155
155
  * @returns A `TrxStatus` containing metadata about the transaction and the function response
156
156
  */
157
- async run(fn) {
157
+ run(fn) {
158
158
  return this.trxEngine.trx(fn, this.authnRequest);
159
159
  }
160
160
  }
@@ -1,7 +1,6 @@
1
1
  import { AnyModule } from "../module";
2
2
  import { $MessageTemplateRule } from "../../elements/entities/message/template/message_template.schema";
3
3
  import { $Resource } from "../../elements/blocks/resource/resource.schema";
4
- import { $Controller } from "../../elements/edge/controller/controller.schema";
5
4
  import { AnyQuery } from "../../elements/entities/bucket/query/nql.schema";
6
5
  export declare namespace NesoiError {
7
6
  class BaseError extends Error {
@@ -46,6 +45,7 @@ export declare namespace NesoiError {
46
45
  function ResourceNotIncluded(module: AnyModule, resource: string): BaseError;
47
46
  function MachineNotIncluded(module: AnyModule, machine: string): BaseError;
48
47
  function QueueNotIncluded(module: AnyModule, queue: string): BaseError;
48
+ function TopicNotIncluded(module: AnyModule, topic: string): BaseError;
49
49
  function ControllerNotIncluded(module: AnyModule, controller: string): BaseError;
50
50
  function InlineMessageNotFoundOnMerge(msg: string): BaseError;
51
51
  function InlineJobNotFoundOnMerge(job: string): BaseError;
@@ -251,6 +251,11 @@ export declare namespace NesoiError {
251
251
  function UnmetCondition(alias: string, msg: string): BaseError;
252
252
  }
253
253
  namespace Controller {
254
- function PortNotFound(controller: $Controller, port: string): BaseError;
254
+ function SubscribeFailed($: {
255
+ topic: string;
256
+ }): BaseError;
257
+ function UnsubscribeFailed($: {
258
+ topic: string;
259
+ }): BaseError;
255
260
  }
256
261
  }
@@ -111,6 +111,10 @@ var NesoiError;
111
111
  return new BaseError('Module.QueueNotIncluded', `Queue ${queue} not included on module ${module.name}`, Status.NOT_FOUND);
112
112
  }
113
113
  Module.QueueNotIncluded = QueueNotIncluded;
114
+ function TopicNotIncluded(module, topic) {
115
+ return new BaseError('Module.TopicNotIncluded', `Topic ${topic} not included on module ${module.name}`, Status.NOT_FOUND);
116
+ }
117
+ Module.TopicNotIncluded = TopicNotIncluded;
114
118
  function ControllerNotIncluded(module, controller) {
115
119
  return new BaseError('Module.ControllerNotIncluded', `Controller ${controller} not included on module ${module.name}`, Status.NOT_FOUND);
116
120
  }
@@ -406,9 +410,13 @@ var NesoiError;
406
410
  */
407
411
  let Controller;
408
412
  (function (Controller) {
409
- function PortNotFound(controller, port) {
410
- return new BaseError('Controller.PortNotFound', `Port ${port} not found on controller ${controller.name}`, Status.NOT_FOUND);
413
+ function SubscribeFailed($) {
414
+ return new BaseError('Controller.SubscribeFailed', `Failed to subscribe to topic '${$.topic}'`, Status.BAD_REQUEST, $);
415
+ }
416
+ Controller.SubscribeFailed = SubscribeFailed;
417
+ function UnsubscribeFailed($) {
418
+ return new BaseError('Controller.UnsubscribeFailed', `Failed to unsubscribe to topic '${$.topic}'`, Status.BAD_REQUEST, $);
411
419
  }
412
- Controller.PortNotFound = PortNotFound;
420
+ Controller.UnsubscribeFailed = UnsubscribeFailed;
413
421
  })(Controller = NesoiError.Controller || (NesoiError.Controller = {}));
414
422
  })(NesoiError || (exports.NesoiError = NesoiError = {}));
@@ -32,8 +32,11 @@ import { AnyQueueBuilder } from "../elements/blocks/queue/queue.builder";
32
32
  import { $Queue } from "../elements/blocks/queue/queue.schema";
33
33
  import { NQL_Engine } from "../elements/entities/bucket/query/nql_engine";
34
34
  import { AnyDaemon } from './daemon';
35
- export type AnyBuilder = AnyExternalsBuilder | ConstantsBuilder | AnyMessageBuilder | AnyBucketBuilder | AnyJobBuilder | AnyResourceJobBuilder | AnyMachineJobBuilder | AnyResourceBuilder | AnyMachineBuilder | AnyControllerBuilder | AnyQueueBuilder;
36
- export type AnyElementSchema = $Externals | $Constants | $Message | $Bucket | $Job | $Resource | $Machine | $Controller | $Queue;
35
+ import { AnyTopicBuilder } from "../elements/blocks/topic/topic.builder";
36
+ import { $Topic } from "../elements/blocks/topic/topic.schema";
37
+ import { Topic } from "../elements/blocks/topic/topic";
38
+ export type AnyBuilder = AnyExternalsBuilder | ConstantsBuilder | AnyMessageBuilder | AnyBucketBuilder | AnyJobBuilder | AnyResourceJobBuilder | AnyMachineJobBuilder | AnyResourceBuilder | AnyMachineBuilder | AnyControllerBuilder | AnyQueueBuilder | AnyTopicBuilder;
39
+ export type AnyElementSchema = $Externals | $Constants | $Message | $Bucket | $Job | $Resource | $Machine | $Controller | $Queue | $Topic;
37
40
  export type AnyInlineElementSchema = $Message | $Job;
38
41
  export type VirtualModuleDef = {
39
42
  name: string;
@@ -71,6 +74,7 @@ export declare class Module<S extends $Space, $ extends $Module> {
71
74
  resources: { [B in keyof $["resources"]]: Resource<S, $, $["resources"][B]>; };
72
75
  machines: { [B in keyof $["machines"]]: Machine<S, $, $["machines"][B]>; };
73
76
  queues: { [B in keyof $["queues"]]: Queue<$, $["queues"][B]>; };
77
+ topics: { [B in keyof $["topics"]]: Topic<S, $, $["topics"][B]>; };
74
78
  controllers: { [B in keyof $["controllers"]]: Controller<S, $, $["controllers"][B]>; };
75
79
  trash?: AnyBucket;
76
80
  /**
@@ -124,6 +128,7 @@ export declare class Module<S extends $Space, $ extends $Module> {
124
128
  resources?: $Resource[];
125
129
  machines?: $Machine[];
126
130
  queues?: $Queue[];
131
+ topics?: $Topic[];
127
132
  controllers?: $Controller[];
128
133
  }): this;
129
134
  /**
@@ -60,6 +60,8 @@ const queue_builder_1 = require("../elements/blocks/queue/queue.builder");
60
60
  const nql_engine_1 = require("../elements/entities/bucket/query/nql_engine");
61
61
  const daemon_1 = require("./daemon");
62
62
  const trash_1 = require("./data/trash");
63
+ const topic_builder_1 = require("../elements/blocks/topic/topic.builder");
64
+ const topic_1 = require("../elements/blocks/topic/topic");
63
65
  /**
64
66
  * A `Module` is an isolated named collection of _Elements_.
65
67
  *
@@ -92,6 +94,7 @@ class Module {
92
94
  machines: {},
93
95
  controllers: {},
94
96
  queues: {},
97
+ topics: {},
95
98
  };
96
99
  /* Entities */
97
100
  this.buckets = {};
@@ -101,6 +104,7 @@ class Module {
101
104
  this.resources = {};
102
105
  this.machines = {};
103
106
  this.queues = {};
107
+ this.topics = {};
104
108
  /* Edge */
105
109
  this.controllers = {};
106
110
  this.schema.name = name;
@@ -120,6 +124,7 @@ class Module {
120
124
  machines: Object.keys(this.machines),
121
125
  controllers: Object.keys(this.controllers),
122
126
  queues: Object.keys(this.queues),
127
+ topics: Object.keys(this.topics),
123
128
  });
124
129
  }
125
130
  // Manual injection
@@ -156,6 +161,9 @@ class Module {
156
161
  schemas.queues?.forEach(schema => {
157
162
  this.schema.queues[schema.name] = schema;
158
163
  });
164
+ schemas.topics?.forEach(schema => {
165
+ this.schema.topics[schema.name] = schema;
166
+ });
159
167
  schemas.controllers?.forEach(schema => {
160
168
  this.schema.controllers[schema.name] = schema;
161
169
  });
@@ -296,6 +304,11 @@ class Module {
296
304
  this.schema.queues[node.name] = schema;
297
305
  this.mergeInlineMessages(inlineMessages);
298
306
  }
307
+ else if (node.builder.$b === 'topic') {
308
+ const { schema, inlineMessages } = topic_builder_1.TopicBuilder.build(node, tree, this.schema);
309
+ this.schema.topics[node.name] = schema;
310
+ this.mergeInlineMessages(inlineMessages);
311
+ }
299
312
  else {
300
313
  throw error_1.NesoiError.Module.UnknownBuilderType(this, node.filepath.toString(), node.name, node.builder.$b);
301
314
  }
@@ -357,6 +370,9 @@ class Module {
357
370
  Object.entries(this.schema.queues).forEach(([name, schema]) => {
358
371
  this.queues[name] = new queue_1.Queue(this, schema);
359
372
  });
373
+ Object.entries(this.schema.topics).forEach(([name, schema]) => {
374
+ this.topics[name] = new topic_1.Topic(this, schema);
375
+ });
360
376
  this.nql = new nql_engine_1.NQL_Engine(this);
361
377
  if (config.trash?.[this.name]) {
362
378
  this.trash = new bucket_1.Bucket(this, trash_1.$TrashBucket, config.trash[this.name], services);
@@ -391,6 +407,10 @@ class Module {
391
407
  for (const name in this.queues || []) {
392
408
  this.destroyElement('queue', name);
393
409
  }
410
+ // Destroy topics
411
+ for (const name in this.topics || []) {
412
+ this.destroyElement('topic', name);
413
+ }
394
414
  // Destroy controllers
395
415
  for (const name in this.controllers || []) {
396
416
  this.destroyElement('controller', name);
@@ -11,6 +11,7 @@ import { $Message } from "../elements/entities/message/message.schema";
11
11
  import { BucketModelDef } from "../elements/entities/bucket/model/bucket_model.builder";
12
12
  import { QueueBuilder } from "../elements/blocks/queue/queue.builder";
13
13
  import { $Bucket, $Job, $Resource } from "../elements";
14
+ import { TopicBuilder } from "../elements/blocks/topic/topic.builder";
14
15
  /**
15
16
  * When using Nesoi as a framework (not a library), the `Space`
16
17
  * is a collection of all modules.
@@ -155,6 +156,17 @@ export declare class Space<$ extends $Space> {
155
156
  queue<M extends keyof $['modules'], K extends string, Module extends $Module = $['modules'][M]>(globalName: `${M & string}::${K}`): QueueBuilder<$, Module, Module["queues"][K] & {
156
157
  name: K;
157
158
  }>;
159
+ /**
160
+ * > Elements / Blocks / Topic
161
+ *
162
+ * A `Topic` is used to broadcast messages to different listeners.
163
+ *
164
+ * @param globalName A _Topic_ name in the format `module::name`
165
+ * @returns A `Topic` builder
166
+ */
167
+ topic<M extends keyof $['modules'], K extends string, Module extends $Module = $['modules'][M]>(globalName: `${M & string}::${K}`): TopicBuilder<$, Module, Module["topics"][K] & {
168
+ name: K;
169
+ }>;
158
170
  /**
159
171
  * > Elements / Edge / Externals
160
172
  *
@@ -49,6 +49,7 @@ const bucket_model_builder_1 = require("../elements/entities/bucket/model/bucket
49
49
  const bucket_model_field_builder_1 = require("../elements/entities/bucket/model/bucket_model_field.builder");
50
50
  const error_1 = require("../compiler/error");
51
51
  const queue_builder_1 = require("../elements/blocks/queue/queue.builder");
52
+ const topic_builder_1 = require("../elements/blocks/topic/topic.builder");
52
53
  /**
53
54
  * When using Nesoi as a framework (not a library), the `Space`
54
55
  * is a collection of all modules.
@@ -221,6 +222,18 @@ class Space {
221
222
  const [module, name] = globalName.split('::');
222
223
  return new queue_builder_1.QueueBuilder(module, name);
223
224
  }
225
+ /**
226
+ * > Elements / Blocks / Topic
227
+ *
228
+ * A `Topic` is used to broadcast messages to different listeners.
229
+ *
230
+ * @param globalName A _Topic_ name in the format `module::name`
231
+ * @returns A `Topic` builder
232
+ */
233
+ topic(globalName) {
234
+ const [module, name] = globalName.split('::');
235
+ return new topic_builder_1.TopicBuilder(module, name);
236
+ }
224
237
  // Edge
225
238
  /**
226
239
  * > Elements / Edge / Externals
@@ -0,0 +1,17 @@
1
+ import { $Module } from "../../../schema";
2
+ import { TrxNode } from '../trx_node';
3
+ import { $Topic } from "../../../elements/blocks/topic/topic.schema";
4
+ import { Topic } from "../../../elements/blocks/topic/topic";
5
+ import { AnyMessage } from "../../../elements/entities/message/message";
6
+ /**
7
+ * @category Engine
8
+ * @subcategory Transaction
9
+ */
10
+ export declare class TopicTrxNode<M extends $Module, $ extends $Topic> {
11
+ private trx;
12
+ private topic;
13
+ constructor(trx: TrxNode<any, M, any>, topic: Topic<any, M, $>);
14
+ subscribe(fn: (msg: AnyMessage) => void): Promise<string>;
15
+ unsubscribe(id: string): Promise<void>;
16
+ publish(raw: $['#input']['#raw']): Promise<void>;
17
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TopicTrxNode = void 0;
4
+ const trx_node_1 = require("../trx_node");
5
+ /**
6
+ * @category Engine
7
+ * @subcategory Transaction
8
+ */
9
+ class TopicTrxNode {
10
+ constructor(trx, topic) {
11
+ this.trx = trx;
12
+ this.topic = topic;
13
+ }
14
+ async subscribe(fn) {
15
+ const trx = trx_node_1.TrxNode.makeChildNode(this.trx, this.topic.schema.module, 'topic', this.topic.schema.name);
16
+ await trx_node_1.TrxNode.open(trx, 'subscribe', {});
17
+ let id;
18
+ try {
19
+ id = await this.topic.subscribe(this.trx, fn);
20
+ }
21
+ catch (e) {
22
+ throw await trx_node_1.TrxNode.error(trx, e);
23
+ }
24
+ await trx_node_1.TrxNode.ok(trx, { id });
25
+ return id;
26
+ }
27
+ async unsubscribe(id) {
28
+ const trx = trx_node_1.TrxNode.makeChildNode(this.trx, this.topic.schema.module, 'topic', this.topic.schema.name);
29
+ await trx_node_1.TrxNode.open(trx, 'unsubscribe', {});
30
+ try {
31
+ await this.topic.unsubscribe(this.trx, id);
32
+ }
33
+ catch (e) {
34
+ throw await trx_node_1.TrxNode.error(trx, e);
35
+ }
36
+ await trx_node_1.TrxNode.ok(trx, undefined);
37
+ }
38
+ async publish(raw) {
39
+ const trx = trx_node_1.TrxNode.makeChildNode(this.trx, this.topic.schema.module, 'topic', this.topic.schema.name);
40
+ await trx_node_1.TrxNode.open(trx, 'publish', { raw });
41
+ try {
42
+ await this.topic.consumeRaw(trx, raw);
43
+ }
44
+ catch (e) {
45
+ throw await trx_node_1.TrxNode.error(trx, e);
46
+ }
47
+ await trx_node_1.TrxNode.ok(trx, undefined);
48
+ }
49
+ }
50
+ exports.TopicTrxNode = TopicTrxNode;