nesoi 3.3.20 → 3.3.21

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 (44) hide show
  1. package/lib/elements/edge/controller/adapters/controller_adapter.d.ts +4 -1
  2. package/lib/elements/edge/controller/adapters/controller_adapter.js +8 -4
  3. package/lib/elements/edge/controller/controller.js +3 -3
  4. package/lib/elements/edge/controller/controller.schema.d.ts +2 -1
  5. package/lib/elements/edge/controller/controller.schema.js +3 -1
  6. package/lib/elements/entities/bucket/adapters/bucket_adapter.d.ts +25 -3
  7. package/lib/elements/entities/bucket/adapters/bucket_adapter.js +21 -2
  8. package/lib/elements/entities/bucket/adapters/memory.nql.js +80 -44
  9. package/lib/elements/entities/bucket/adapters/test.bucket_adapter.d.ts +22 -0
  10. package/lib/elements/entities/bucket/adapters/test.bucket_adapter.js +23 -0
  11. package/lib/elements/entities/bucket/bucket.js +2 -2
  12. package/lib/elements/entities/bucket/cache/bucket_cache.d.ts +16 -1
  13. package/lib/elements/entities/bucket/cache/bucket_cache.js +36 -15
  14. package/lib/elements/entities/bucket/graph/bucket_graph.js +28 -18
  15. package/lib/elements/entities/bucket/query/nql.schema.d.ts +3 -0
  16. package/lib/elements/entities/bucket/query/nql_compiler.d.ts +10 -4
  17. package/lib/elements/entities/bucket/query/nql_compiler.js +42 -35
  18. package/lib/elements/entities/bucket/query/nql_engine.d.ts +4 -1
  19. package/lib/elements/entities/bucket/query/nql_engine.js +3 -5
  20. package/lib/elements/entities/message/template/message_template_field.builder.d.ts +2 -0
  21. package/lib/elements/entities/message/template/message_template_field.builder.js +5 -0
  22. package/lib/engine/daemon.d.ts +19 -0
  23. package/lib/engine/daemon.js +40 -2
  24. package/lib/engine/data/tree.d.ts +1 -2
  25. package/lib/engine/data/tree.js +6 -94
  26. package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +1 -1
  27. package/lib/engine/transaction/nodes/bucket.trx_node.js +15 -15
  28. package/lib/engine/transaction/nodes/bucket_query.trx_node.js +2 -2
  29. package/lib/engine/transaction/nodes/external.trx_node.d.ts +3 -1
  30. package/lib/engine/transaction/nodes/external.trx_node.js +54 -4
  31. package/lib/engine/transaction/nodes/job.trx_node.js +3 -2
  32. package/lib/engine/transaction/nodes/machine.trx_node.js +1 -1
  33. package/lib/engine/transaction/nodes/queue.trx_node.js +1 -1
  34. package/lib/engine/transaction/nodes/resource.trx_node.js +1 -1
  35. package/lib/engine/transaction/nodes/topic.trx_node.js +1 -1
  36. package/lib/engine/transaction/trx.d.ts +7 -1
  37. package/lib/engine/transaction/trx.js +15 -1
  38. package/lib/engine/transaction/trx_engine.config.d.ts +6 -1
  39. package/lib/engine/transaction/trx_engine.d.ts +5 -5
  40. package/lib/engine/transaction/trx_engine.js +59 -36
  41. package/lib/engine/transaction/trx_node.d.ts +1 -1
  42. package/lib/engine/transaction/trx_node.js +1 -1
  43. package/package.json +1 -1
  44. package/tsconfig.build.tsbuildinfo +1 -1
@@ -39,7 +39,7 @@ class BucketTrxNode {
39
39
  /*
40
40
  Wrap
41
41
  */
42
- async wrap(action, input, fn, fmtTrxOut) {
42
+ async wrap(action, input, fn, fmtTrxOut, idempotent = false) {
43
43
  const wrapped = async (parentTrx, bucket) => {
44
44
  const trx = trx_node_1.TrxNode.makeChildNode(parentTrx, bucket.schema.module, 'bucket', bucket.schema.name);
45
45
  trx_node_1.TrxNode.open(trx, action, input);
@@ -54,8 +54,8 @@ class BucketTrxNode {
54
54
  return out;
55
55
  };
56
56
  if (this.external) {
57
- const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag);
58
- return ext.run(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
57
+ const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag, idempotent);
58
+ return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
59
59
  }
60
60
  else {
61
61
  return wrapped(this.trx, this.bucket);
@@ -72,7 +72,7 @@ class BucketTrxNode {
72
72
  return this.wrap('readOne', { id }, (trx, bucket) => bucket.readOne(trx, id, {
73
73
  silent: true,
74
74
  no_tenancy: !this.enableTenancy
75
- }));
75
+ }), undefined, true);
76
76
  }
77
77
  /**
78
78
  * Returns one object by `id` formated with the specified view,
@@ -84,7 +84,7 @@ class BucketTrxNode {
84
84
  return this.wrap('viewOne', { id }, (trx, bucket) => bucket.viewOne(trx, id, view, {
85
85
  silent: true,
86
86
  no_tenancy: !this.enableTenancy
87
- }));
87
+ }), undefined, true);
88
88
  }
89
89
  /**
90
90
  * Returns one object by `id`, without pre-formatting,
@@ -93,7 +93,7 @@ class BucketTrxNode {
93
93
  async readOneOrFail(id) {
94
94
  return this.wrap('readOneOrFail', { id }, (trx, bucket) => bucket.readOne(trx, id, {
95
95
  no_tenancy: !this.enableTenancy
96
- }));
96
+ }), undefined, true);
97
97
  }
98
98
  /**
99
99
  * Returns one object by `id`, without pre-formatting,
@@ -104,7 +104,7 @@ class BucketTrxNode {
104
104
  async viewOneOrFail(id, view = 'default') {
105
105
  return this.wrap('viewOneOrFail', { id }, (trx, bucket) => bucket.viewOne(trx, id, view, {
106
106
  no_tenancy: !this.enableTenancy
107
- }));
107
+ }), undefined, true);
108
108
  }
109
109
  /*
110
110
  Read/View All
@@ -115,7 +115,7 @@ class BucketTrxNode {
115
115
  async readAll() {
116
116
  return this.wrap('readAll', {}, (trx, bucket) => bucket.readAll(trx, {
117
117
  no_tenancy: !this.enableTenancy
118
- }), objs => ({ length: objs.length }));
118
+ }), objs => ({ length: objs.length }), true);
119
119
  }
120
120
  /**
121
121
  * Returns a list of all objects formated with the specified view.
@@ -125,7 +125,7 @@ class BucketTrxNode {
125
125
  async viewAll(view = 'default') {
126
126
  return this.wrap('viewAll', {}, (trx, bucket) => bucket.viewAll(trx, view, {
127
127
  no_tenancy: !this.enableTenancy
128
- }), objs => ({ length: objs.length }));
128
+ }), objs => ({ length: objs.length }), true);
129
129
  }
130
130
  /*
131
131
  Query
@@ -154,7 +154,7 @@ class BucketTrxNode {
154
154
  silent: true,
155
155
  no_tenancy: !this.enableTenancy,
156
156
  index
157
- }));
157
+ }), undefined, true);
158
158
  }
159
159
  /**
160
160
  * Returns one or more objects referenced by the graph link,
@@ -165,7 +165,7 @@ class BucketTrxNode {
165
165
  silent: true,
166
166
  no_tenancy: !this.enableTenancy,
167
167
  indexes
168
- }));
168
+ }), undefined, true);
169
169
  }
170
170
  /**
171
171
  * Returns one or more objects referenced by the graph link built with a view,
@@ -175,7 +175,7 @@ class BucketTrxNode {
175
175
  return this.wrap('viewLink', { id, link, view }, (trx, bucket) => bucket.viewLink(trx, id, link, view, {
176
176
  silent: true,
177
177
  no_tenancy: !this.enableTenancy
178
- }));
178
+ }), undefined, true);
179
179
  }
180
180
  /**
181
181
  * Returns one or more objects referenced by the graph link,
@@ -184,7 +184,7 @@ class BucketTrxNode {
184
184
  async readLinkOrFail(id, link) {
185
185
  return this.wrap('readLinkOrFail', { id, link }, (trx, bucket) => bucket.readLink(trx, id, link, {
186
186
  no_tenancy: !this.enableTenancy
187
- }));
187
+ }), undefined, true);
188
188
  }
189
189
  /**
190
190
  * Returns one or more objects referenced by the graph link built with a view,
@@ -193,7 +193,7 @@ class BucketTrxNode {
193
193
  async viewLinkOrFail(id, link, view = 'default') {
194
194
  return this.wrap('viewLinkOrFail', { id, link, view }, (trx, bucket) => bucket.viewLink(trx, id, link, view, {
195
195
  no_tenancy: !this.enableTenancy
196
- }));
196
+ }), undefined, true);
197
197
  }
198
198
  /**
199
199
  * Returns `true` if the graph link resolves to at least 1 object.
@@ -201,7 +201,7 @@ class BucketTrxNode {
201
201
  async hasLink(id, link) {
202
202
  return this.wrap('hasLink', { id, link }, (trx, bucket) => bucket.hasLink(trx, id, link, {
203
203
  no_tenancy: !this.enableTenancy
204
- }));
204
+ }), undefined, true);
205
205
  }
206
206
  /*
207
207
  Create
@@ -70,8 +70,8 @@ class BucketQueryTrxNode {
70
70
  return out;
71
71
  };
72
72
  if (this.external) {
73
- const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag);
74
- return ext.run(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
73
+ const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag, true);
74
+ return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
75
75
  }
76
76
  else {
77
77
  return wrapped(this.trx, this.bucket);
@@ -9,7 +9,9 @@ import { Tag } from "../../dependency";
9
9
  export declare class ExternalTrxNode<M extends $Module, $ extends $Topic> {
10
10
  private trx;
11
11
  private tag;
12
+ private idempotent;
12
13
  private daemon;
13
- constructor(trx: TrxNode<any, M, any>, tag: Tag);
14
+ constructor(trx: TrxNode<any, M, any>, tag: Tag, idempotent?: boolean);
15
+ run_and_hold(element: (trx: AnyTrxNode) => any, fn: (trx: AnyTrxNode, element: any) => Promise<any>): Promise<any>;
14
16
  run(element: (trx: AnyTrxNode) => any, fn: (trx: AnyTrxNode, element: any) => Promise<any>): Promise<any>;
15
17
  }
@@ -10,17 +10,19 @@ const error_1 = require("../../data/error");
10
10
  class ExternalTrxNode {
11
11
  trx;
12
12
  tag;
13
+ idempotent;
13
14
  daemon;
14
- constructor(trx, tag) {
15
+ constructor(trx, tag, idempotent = false) {
15
16
  this.trx = trx;
16
17
  this.tag = tag;
18
+ this.idempotent = idempotent;
17
19
  const _module = trx_node_1.TrxNode.getModule(trx);
18
20
  if (!_module.daemon) {
19
21
  throw error_1.NesoiError.Trx.DaemonNotFound(_module.name);
20
22
  }
21
23
  this.daemon = _module.daemon;
22
24
  }
23
- async run(element, fn) {
25
+ async run_and_hold(element, fn) {
24
26
  const root = this.trx.trx;
25
27
  const module = trx_node_1.TrxNode.getModule(this.trx);
26
28
  const trx = trx_node_1.TrxNode.makeChildNode(this.trx, module.name, 'externals', this.tag.full);
@@ -29,7 +31,14 @@ class ExternalTrxNode {
29
31
  });
30
32
  let out;
31
33
  try {
32
- const res = await this.daemon.trx(this.tag.module)
34
+ const dtrx = await this.daemon.trx(this.tag.module)
35
+ .origin('ext:' + root.id);
36
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
37
+ if (this.idempotent)
38
+ dtrx.idempotent;
39
+ else
40
+ dtrx.idempotent_inherit(trx);
41
+ const res = await dtrx
33
42
  .auth_inherit(trx)
34
43
  .run_and_hold(async (extTrx) => {
35
44
  try {
@@ -46,7 +55,48 @@ class ExternalTrxNode {
46
55
  throw res.status.error;
47
56
  }
48
57
  out = res.status.output;
49
- root.holdNode(res);
58
+ if (!trx.trx.idempotent) {
59
+ root.holdNode(res);
60
+ }
61
+ }
62
+ catch (e) {
63
+ throw trx_node_1.TrxNode.error(trx, e);
64
+ }
65
+ trx_node_1.TrxNode.ok(trx, out);
66
+ return out;
67
+ }
68
+ async run(element, fn) {
69
+ const root = this.trx.trx;
70
+ const module = trx_node_1.TrxNode.getModule(this.trx);
71
+ const trx = trx_node_1.TrxNode.makeChildNode(this.trx, module.name, 'externals', this.tag.full);
72
+ trx_node_1.TrxNode.open(trx, '~', {
73
+ tag: this.tag
74
+ });
75
+ let out;
76
+ try {
77
+ const dtrx = await this.daemon.trx(this.tag.module);
78
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
79
+ if (this.idempotent)
80
+ dtrx.idempotent;
81
+ else
82
+ dtrx.idempotent_inherit(trx);
83
+ const res = await dtrx
84
+ .auth_inherit(trx)
85
+ .run(async (extTrx) => {
86
+ try {
87
+ return await fn(extTrx, element(extTrx));
88
+ }
89
+ catch (e) {
90
+ throw trx_node_1.TrxNode.error(extTrx, e);
91
+ }
92
+ finally {
93
+ trx_node_1.TrxNode.merge(trx, extTrx);
94
+ }
95
+ }, root.id);
96
+ if (res.state === 'error') {
97
+ throw res.error;
98
+ }
99
+ out = res.output;
50
100
  }
51
101
  catch (e) {
52
102
  throw trx_node_1.TrxNode.error(trx, e);
@@ -46,8 +46,9 @@ class JobTrxNode {
46
46
  return out;
47
47
  };
48
48
  if (this.external) {
49
- const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag);
50
- return ext.run(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
49
+ const root = this.trx.trx;
50
+ const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag, root.idempotent);
51
+ return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
51
52
  }
52
53
  else {
53
54
  return wrapped(this.trx, this.job);
@@ -45,7 +45,7 @@ class MachineTrxNode {
45
45
  };
46
46
  if (this.external) {
47
47
  const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag);
48
- return ext.run(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
48
+ return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
49
49
  }
50
50
  else {
51
51
  return wrapped(this.trx, this.machine);
@@ -45,7 +45,7 @@ class QueueTrxNode {
45
45
  };
46
46
  if (this.external) {
47
47
  const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag);
48
- return ext.run(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
48
+ return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
49
49
  }
50
50
  else {
51
51
  return wrapped(this.trx, this.queue);
@@ -45,7 +45,7 @@ class ResourceTrxNode {
45
45
  };
46
46
  if (this.external) {
47
47
  const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag);
48
- return ext.run(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
48
+ return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
49
49
  }
50
50
  else {
51
51
  return wrapped(this.trx, this.resource);
@@ -45,7 +45,7 @@ class TopicTrxNode {
45
45
  };
46
46
  if (this.external) {
47
47
  const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag);
48
- return ext.run(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
48
+ return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
49
49
  }
50
50
  else {
51
51
  return wrapped(this.trx, this.resource);
@@ -7,6 +7,7 @@ import { NesoiDatetime } from '../data/datetime';
7
7
  import { NesoiError } from '../data/error';
8
8
  import { AnyBucketCache } from "../../elements/entities/bucket/cache/bucket_cache";
9
9
  import { AnyBucket } from "../../elements/entities/bucket/bucket";
10
+ import { NQLRunner } from "../../elements/entities/bucket/query/nql_engine";
10
11
  type TrxOrigin = TrxEngineOrigin | `trx:${string}`;
11
12
  type TrxState = 'open' | 'hold' | 'ok' | 'error';
12
13
  /**
@@ -34,6 +35,7 @@ export declare class Trx<S extends $Space, M extends $Module, AuthUsers extends
34
35
  private module;
35
36
  id: string;
36
37
  private origin;
38
+ idempotent: boolean;
37
39
  root: TrxNode<S, M, AuthUsers>;
38
40
  nodes: Record<string, TrxNode<S, M, AuthUsers>>;
39
41
  holds: Record<string, TrxNodeHold<any>>;
@@ -42,7 +44,7 @@ export declare class Trx<S extends $Space, M extends $Module, AuthUsers extends
42
44
  ctx: Record<string, any>;
43
45
  cache_config: Record<string, 'eager'>;
44
46
  cache: Record<string, AnyBucketCache>;
45
- constructor(engine: AnyTrxEngine, module: Module<S, M>, origin: TrxOrigin, auth?: {
47
+ constructor(engine: AnyTrxEngine, module: Module<S, M>, origin: TrxOrigin, idempotent?: boolean, auth?: {
46
48
  tokens: AuthRequest<any>;
47
49
  users: AuthUsers;
48
50
  }, id?: string, root?: TrxNode<S, M, AuthUsers>, nodes?: Record<string, TrxNode<S, M, AuthUsers>>);
@@ -56,6 +58,10 @@ export declare class Trx<S extends $Space, M extends $Module, AuthUsers extends
56
58
  * These are configured through the TrxNode.cache method.
57
59
  */
58
60
  static getCache(node: AnyTrxNode, bucket: AnyBucket): Promise<AnyBucketCache | undefined>;
61
+ static getCacheCustomBuckets(node: AnyTrxNode): Record<string, {
62
+ scope: string;
63
+ nql: NQLRunner;
64
+ }>;
59
65
  /**
60
66
  * Context Manipulation
61
67
  *
@@ -70,6 +70,7 @@ class Trx {
70
70
  module;
71
71
  id;
72
72
  origin;
73
+ idempotent;
73
74
  root;
74
75
  nodes;
75
76
  holds = {};
@@ -78,11 +79,12 @@ class Trx {
78
79
  ctx = {};
79
80
  cache_config = {};
80
81
  cache = {};
81
- constructor(engine, module, origin, auth, id, root, nodes) {
82
+ constructor(engine, module, origin, idempotent, auth, id, root, nodes) {
82
83
  this.engine = engine;
83
84
  this.module = module;
84
85
  this.id = id || (Math.random() + 1).toString(36).substring(7);
85
86
  this.origin = origin;
87
+ this.idempotent = idempotent ?? false;
86
88
  this.root = root || new trx_node_1.TrxNode('root', this, undefined, module, auth, false, id);
87
89
  this.nodes = nodes || {};
88
90
  }
@@ -129,6 +131,18 @@ class Trx {
129
131
  }
130
132
  return cache;
131
133
  }
134
+ static getCacheCustomBuckets(node) {
135
+ const trx = node.trx;
136
+ const buckets = {};
137
+ for (const tag in trx.cache) {
138
+ const adapter = trx.cache[tag].innerAdapter;
139
+ buckets[tag] = {
140
+ scope: `__cache_${tag}`,
141
+ nql: adapter.nql
142
+ };
143
+ }
144
+ return buckets;
145
+ }
132
146
  /**
133
147
  * Context Manipulation
134
148
  *
@@ -10,5 +10,10 @@ export type TrxEngineConfig<S extends $Space, M extends $Module, AuthUsers exten
10
10
  * Adapter used to store transactions of this module.
11
11
  */
12
12
  adapter?: (schema: M) => BucketAdapter<TrxData>;
13
- wrap?: <T extends Trx<S, M, AuthUsers>>(trx: T, fn: TrxEngineWrapFn<S, M>, services: Services) => Promise<any>;
13
+ wrap?: {
14
+ begin: <T extends Trx<S, M, AuthUsers>>(trx: T, services: Services) => Promise<void>;
15
+ continue: <T extends Trx<S, M, AuthUsers>>(trx: T, services: Services) => Promise<void>;
16
+ commit: <T extends Trx<S, M, AuthUsers>>(trx: T, services: Services) => Promise<void>;
17
+ rollback: <T extends Trx<S, M, AuthUsers>>(trx: T, services: Services) => Promise<void>;
18
+ }[];
14
19
  };
@@ -20,8 +20,8 @@ export type TrxData = {
20
20
  export type HeldTrxNode<Output> = {
21
21
  id: string;
22
22
  status: TrxStatus<Output>;
23
- commit: () => Promise<AnyTrx>;
24
- rollback: (error: string) => Promise<AnyTrx>;
23
+ commit: () => Promise<any>;
24
+ rollback: (error: string) => Promise<any>;
25
25
  };
26
26
  export type BucketMetadata = ReturnType<AnyBucket['getQueryMeta']> & {
27
27
  tag: Tag;
@@ -45,9 +45,9 @@ export declare class TrxEngine<S extends $Space, M extends $Module, AuthUsers ex
45
45
  private adapter;
46
46
  constructor(origin: TrxEngineOrigin, module: Module<S, M>, authnProviders?: AuthUsers | undefined, config?: TrxEngineConfig<S, M, any, any> | undefined, services?: Record<string, IService>);
47
47
  getModule(): Module<S, M>;
48
- get(id?: string): Promise<Trx<S, M, any>>;
49
- trx(fn: (trx: TrxNode<S, M, any>) => Promise<TrxNodeStatus>, id?: string, tokens?: AuthRequest<keyof AuthUsers>, users?: Partial<AuthUsers>): Promise<TrxStatus<any>>;
50
- trx_hold(fn: (trx: TrxNode<S, M, any>) => Promise<any>, id?: string, authn?: AuthRequest<keyof AuthUsers>, users?: Partial<AuthUsers>): Promise<HeldTrxNode<any>>;
48
+ get(id?: string, origin?: string, idempotent?: boolean): Promise<Trx<S, M, any>>;
49
+ trx(fn: (trx: TrxNode<S, M, any>) => Promise<TrxNodeStatus>, id?: string, tokens?: AuthRequest<keyof AuthUsers>, users?: Partial<AuthUsers>, origin?: string, idempotent?: boolean): Promise<TrxStatus<any>>;
50
+ trx_hold(fn: (trx: TrxNode<S, M, any>) => Promise<any>, id?: string, authn?: AuthRequest<keyof AuthUsers>, users?: Partial<AuthUsers>, origin?: string, idempotent?: boolean): Promise<HeldTrxNode<any>>;
51
51
  getBucketMetadata(tag: Tag): BucketMetadata;
52
52
  getBucketDrive(tag: Tag): DriveAdapter | undefined;
53
53
  authenticate(node: TrxNode<S, M, any>, tokens?: AuthRequest<keyof AuthUsers>, users?: AnyUsers, force?: boolean): Promise<void>;
@@ -32,7 +32,7 @@ class TrxEngine {
32
32
  this.authnProviders = authnProviders;
33
33
  this.config = config;
34
34
  this.services = services;
35
- this.innerTrx = new trx_1.Trx(this, this.module, `trx:${origin}`);
35
+ this.innerTrx = new trx_1.Trx(this, this.module, `trx:${origin}`, true);
36
36
  this.$TrxBucket = new elements_1.$Bucket(this.module.name, '__trx__', `Transaction of Module '${this.module.name}'`, new bucket_model_schema_1.$BucketModel({
37
37
  id: new bucket_model_schema_1.$BucketModelField('id', 'id', 'string', 'ID', true),
38
38
  origin: new bucket_model_schema_1.$BucketModelField('origin', 'origin', 'string', 'Origin', true),
@@ -45,39 +45,59 @@ class TrxEngine {
45
45
  getModule() {
46
46
  return this.module;
47
47
  }
48
- async get(id) {
48
+ async get(id, origin, idempotent = false) {
49
+ const _origin = origin ?? this.origin;
49
50
  let trx;
50
51
  if (!id) {
51
- trx = new trx_1.Trx(this, this.module, this.origin);
52
- log_1.Log.info('module', this.module.name, `Begin ${(0, log_1.scopeTag)('trx', trx.id)} @ ${(0, log_1.anyScopeTag)(this.origin)}`);
53
- await this.adapter.create(this.innerTrx.root, {
54
- id: trx.id,
55
- origin: trx.origin,
56
- start: trx.start,
57
- end: trx.end,
58
- module: this.module.name
59
- });
52
+ trx = new trx_1.Trx(this, this.module, _origin, idempotent);
53
+ log_1.Log.info('module', this.module.name, `Begin ${(0, log_1.scopeTag)('trx', trx.id)}${idempotent ? '*' : ''} @ ${(0, log_1.anyScopeTag)(_origin)}`);
54
+ for (const wrap of this.config?.wrap || []) {
55
+ await wrap.begin(trx, this.services);
56
+ }
57
+ if (!idempotent) {
58
+ await this.adapter.create(this.innerTrx.root, {
59
+ id: trx.id,
60
+ origin: trx.origin,
61
+ start: trx.start,
62
+ end: trx.end,
63
+ module: this.module.name
64
+ });
65
+ }
60
66
  return trx;
61
67
  }
62
68
  else {
69
+ if (idempotent) {
70
+ log_1.Log.debug('module', this.module.name, `Continue Idempotent ${(0, log_1.scopeTag)('trx', id)}* @ ${(0, log_1.anyScopeTag)(_origin)}`);
71
+ const trx = new trx_1.Trx(this, this.module, _origin, idempotent, undefined, id);
72
+ for (const wrap of this.config?.wrap || []) {
73
+ await wrap.continue(trx, this.services);
74
+ }
75
+ return trx;
76
+ }
63
77
  const trxData = await this.adapter.get(this.innerTrx.root, id);
64
78
  if (trxData) {
65
- log_1.Log.info('module', this.module.name, `Continue ${(0, log_1.scopeTag)('trx', trxData.id)} @ ${(0, log_1.anyScopeTag)(this.origin)}`);
79
+ log_1.Log.debug('module', this.module.name, `Continue ${(0, log_1.scopeTag)('trx', trxData.id)} @ ${(0, log_1.anyScopeTag)(_origin)}`);
66
80
  // Objects read from adapters are not the proper JS class, so they don't
67
81
  // carry methods. This must be used to recover the methods.
68
- trx = Object.assign(new trx_1.Trx(this, this.module, this.origin), {
82
+ trx = Object.assign(new trx_1.Trx(this, this.module, _origin, idempotent), {
69
83
  id: trxData.id,
70
84
  origin: trxData.origin,
71
85
  start: trxData.start,
72
86
  end: trxData.end
73
87
  });
88
+ for (const wrap of this.config?.wrap || []) {
89
+ await wrap.continue(trx, this.services);
90
+ }
74
91
  }
75
92
  else {
76
- log_1.Log.info('module', this.module.name, `Chain ${(0, log_1.scopeTag)('trx', id)} @ ${(0, log_1.anyScopeTag)(this.origin)}`);
77
- trx = new trx_1.Trx(this, this.module, this.origin, undefined, id);
93
+ log_1.Log.info('module', this.module.name, `Chain ${(0, log_1.scopeTag)('trx', id)} @ ${(0, log_1.anyScopeTag)(_origin)}`);
94
+ trx = new trx_1.Trx(this, this.module, _origin, idempotent, undefined, id);
95
+ for (const wrap of this.config?.wrap || []) {
96
+ await wrap.begin(trx, this.services);
97
+ }
78
98
  await this.adapter.create(this.innerTrx.root, {
79
99
  id: trx.id,
80
- origin: this.origin,
100
+ origin: _origin,
81
101
  start: trx.start,
82
102
  end: trx.end,
83
103
  module: this.module.name
@@ -86,17 +106,11 @@ class TrxEngine {
86
106
  }
87
107
  return trx;
88
108
  }
89
- async trx(fn, id, tokens, users) {
90
- const trx = await this.get(id);
109
+ async trx(fn, id, tokens, users, origin, idempotent = false) {
110
+ const trx = await this.get(id, origin, idempotent);
91
111
  try {
92
112
  await this.authenticate(trx.root, tokens, users);
93
- let output;
94
- if (this.config?.wrap) {
95
- output = await this.config?.wrap(trx, fn, this.services);
96
- }
97
- else {
98
- output = await fn(trx.root);
99
- }
113
+ const output = await fn(trx.root);
100
114
  await this.commit(trx, output);
101
115
  }
102
116
  catch (e) {
@@ -104,17 +118,12 @@ class TrxEngine {
104
118
  }
105
119
  return trx.status();
106
120
  }
107
- async trx_hold(fn, id, authn, users) {
108
- const trx = await this.get(id);
121
+ async trx_hold(fn, id, authn, users, origin, idempotent = false) {
122
+ const trx = await this.get(id, origin, idempotent);
109
123
  let output = {};
110
124
  try {
111
125
  await this.authenticate(trx.root, authn, users);
112
- if (this.config?.wrap) {
113
- output = await this.config?.wrap(trx, fn, this.services);
114
- }
115
- else {
116
- output = await fn(trx.root);
117
- }
126
+ output = await fn(trx.root);
118
127
  await this.hold(trx, output);
119
128
  }
120
129
  catch (e) {
@@ -146,6 +155,8 @@ class TrxEngine {
146
155
  const _users = { ...users };
147
156
  const _tokens = {};
148
157
  for (const providerName in this.authnProviders) {
158
+ if (providerName in _users)
159
+ continue;
149
160
  const provider = this.authnProviders[providerName];
150
161
  if (!provider) {
151
162
  throw error_1.NesoiError.Auth.NoProviderRegisteredForModule(this.module.name, providerName);
@@ -163,8 +174,10 @@ class TrxEngine {
163
174
  }
164
175
  //
165
176
  async hold(trx, output) {
166
- log_1.Log.info('module', this.module.name, `Hold ${(0, log_1.scopeTag)('trx', trx.id)} @ ${(0, log_1.anyScopeTag)(this.origin)}`);
177
+ log_1.Log.debug('module', this.module.name, `Hold ${(0, log_1.scopeTag)('trx', trx.id)} @ ${(0, log_1.anyScopeTag)(this.origin)}`);
167
178
  trx_node_1.TrxNode.hold(trx.root, output);
179
+ if (trx.idempotent)
180
+ return trx;
168
181
  await this.adapter.put(this.innerTrx.root, {
169
182
  id: trx.id,
170
183
  origin: this.origin,
@@ -175,9 +188,11 @@ class TrxEngine {
175
188
  return trx;
176
189
  }
177
190
  async commit(trx, output) {
178
- log_1.Log.info('module', this.module.name, `Commit ${(0, log_1.scopeTag)('trx', trx.id)} @ ${(0, log_1.anyScopeTag)(this.origin)}`);
179
191
  trx_node_1.TrxNode.ok(trx.root, output);
180
192
  trx.end = datetime_1.NesoiDatetime.now();
193
+ if (trx.idempotent)
194
+ return trx;
195
+ log_1.Log.info('module', this.module.name, `Commit ${(0, log_1.scopeTag)('trx', trx.id)} @ ${(0, log_1.anyScopeTag)(this.origin)}`);
181
196
  await this.adapter.put(this.innerTrx.root, {
182
197
  id: trx.id,
183
198
  origin: this.origin,
@@ -186,13 +201,18 @@ class TrxEngine {
186
201
  module: this.module.name
187
202
  });
188
203
  await trx_1.Trx.onCommit(trx);
204
+ for (const wrap of this.config?.wrap || []) {
205
+ await wrap.commit(trx, this.services);
206
+ }
189
207
  return trx;
190
208
  }
191
209
  async rollback(trx, error) {
192
210
  log_1.Log.error('module', this.module.name, `[${error.status}] ${error.toString()}`, error.stack);
193
- log_1.Log.warn('module', this.module.name, `Rollback ${(0, log_1.scopeTag)('trx', trx.id)} @ ${(0, log_1.anyScopeTag)(this.origin)}`);
194
211
  trx_node_1.TrxNode.error(trx.root, error);
195
212
  trx.end = datetime_1.NesoiDatetime.now();
213
+ if (trx.idempotent)
214
+ return trx;
215
+ log_1.Log.warn('module', this.module.name, `Rollback ${(0, log_1.scopeTag)('trx', trx.id)} @ ${(0, log_1.anyScopeTag)(this.origin)}`);
196
216
  await this.adapter.put(this.innerTrx.root, {
197
217
  id: trx.id,
198
218
  origin: this.origin,
@@ -201,6 +221,9 @@ class TrxEngine {
201
221
  module: this.module.name
202
222
  });
203
223
  await trx_1.Trx.onRollback(trx);
224
+ for (const wrap of this.config?.wrap || []) {
225
+ await wrap.rollback(trx, this.services);
226
+ }
204
227
  return trx;
205
228
  }
206
229
  }
@@ -56,7 +56,7 @@ export declare class TrxNode<Space extends $Space, M extends $Module, AuthUsers
56
56
  message<Raw extends M['#input']['#raw'], Msg extends $Message = M['messages'][Raw['$'] & keyof M['messages']]>(raw: Raw): Promise<M['#input']['#parsed']>;
57
57
  value<K extends keyof M['constants']['values']>(name: K): M['constants']['values'][K]['value'];
58
58
  enum<EnumName extends keyof M['constants']['enums']>(name: EnumName): Enum<M['constants']['enums'][EnumName]>;
59
- cache(config: Record<keyof M['buckets'], 'eager'>): this;
59
+ cache(config: Partial<Record<keyof M['buckets'], 'eager'>>): this;
60
60
  bucket<Name extends keyof M['buckets'], Bucket extends M['buckets'][Name]>(name: Name): BucketTrxNode<M, Bucket>;
61
61
  job<Name extends keyof M['jobs'], Job extends M['jobs'][Name]>(name: Name): JobTrxNode<M, Job>;
62
62
  static jobWithCustomCtx<M extends $Module, JobName extends keyof M['jobs'], Job extends M['jobs'][JobName]>(node: AnyTrxNode, name: string, ctx?: Record<string, any>): JobTrxNode<M, Job>;
@@ -120,7 +120,6 @@ class TrxNode {
120
120
  }
121
121
  return new constants_1.Enum(this.module.schema.constants.enums[key]);
122
122
  }
123
- // Blocks
124
123
  /*
125
124
  Cache
126
125
  */
@@ -132,6 +131,7 @@ class TrxNode {
132
131
  }
133
132
  return this;
134
133
  }
134
+ // Blocks
135
135
  bucket(name) {
136
136
  const tag = dependency_1.Tag.fromNameOrShort(this.module.name, 'bucket', name);
137
137
  return new bucket_trx_node_1.BucketTrxNode(this, tag);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nesoi",
3
- "version": "3.3.20",
3
+ "version": "3.3.21",
4
4
  "description": "Declarative framework for data-driven applications",
5
5
  "repository": {
6
6
  "type": "git",