@webda/async 4.0.0-beta.2 → 4.0.0-beta.3

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 (62) hide show
  1. package/README.md +89 -4
  2. package/lib/{models.d.ts → asyncaction.model.d.ts} +75 -37
  3. package/lib/asyncaction.model.d.ts.map +1 -0
  4. package/lib/asyncaction.model.js +269 -0
  5. package/lib/asyncaction.model.js.map +1 -0
  6. package/lib/index.d.ts +6 -4
  7. package/lib/index.d.ts.map +1 -1
  8. package/lib/index.js +6 -4
  9. package/lib/index.js.map +1 -1
  10. package/lib/services/asyncevents.service.d.ts +154 -0
  11. package/lib/services/asyncevents.service.d.ts.map +1 -0
  12. package/lib/services/asyncevents.service.js +219 -0
  13. package/lib/services/asyncevents.service.js.map +1 -0
  14. package/lib/services/{asyncjobservice.d.ts → asyncjobservice.service.d.ts} +78 -61
  15. package/lib/services/asyncjobservice.service.d.ts.map +1 -0
  16. package/lib/services/asyncjobservice.service.js +584 -0
  17. package/lib/services/asyncjobservice.service.js.map +1 -0
  18. package/lib/services/{localrunner.d.ts → localrunner.service.d.ts} +24 -10
  19. package/lib/services/localrunner.service.d.ts.map +1 -0
  20. package/lib/services/localrunner.service.js +87 -0
  21. package/lib/services/localrunner.service.js.map +1 -0
  22. package/lib/services/{runner.d.ts → runner.service.d.ts} +17 -12
  23. package/lib/services/runner.service.d.ts.map +1 -0
  24. package/lib/services/{runner.js → runner.service.js} +16 -13
  25. package/lib/services/runner.service.js.map +1 -0
  26. package/lib/services/servicerunner.service.d.ts +105 -0
  27. package/lib/services/servicerunner.service.d.ts.map +1 -0
  28. package/lib/services/servicerunner.service.js +131 -0
  29. package/lib/services/servicerunner.service.js.map +1 -0
  30. package/package.json +32 -42
  31. package/webda.module.json +1925 -890
  32. package/lib/models.d.ts.map +0 -1
  33. package/lib/models.js +0 -179
  34. package/lib/models.js.map +0 -1
  35. package/lib/models.spec.d.ts +0 -7
  36. package/lib/models.spec.d.ts.map +0 -1
  37. package/lib/models.spec.js +0 -64
  38. package/lib/models.spec.js.map +0 -1
  39. package/lib/services/asyncjobservice.d.ts.map +0 -1
  40. package/lib/services/asyncjobservice.js +0 -469
  41. package/lib/services/asyncjobservice.js.map +0 -1
  42. package/lib/services/asyncjobservice.spec.d.ts +0 -2
  43. package/lib/services/asyncjobservice.spec.d.ts.map +0 -1
  44. package/lib/services/asyncjobservice.spec.js +0 -561
  45. package/lib/services/asyncjobservice.spec.js.map +0 -1
  46. package/lib/services/localrunner.d.ts.map +0 -1
  47. package/lib/services/localrunner.js +0 -70
  48. package/lib/services/localrunner.js.map +0 -1
  49. package/lib/services/localrunner.spec.d.ts +0 -2
  50. package/lib/services/localrunner.spec.d.ts.map +0 -1
  51. package/lib/services/localrunner.spec.js +0 -113
  52. package/lib/services/localrunner.spec.js.map +0 -1
  53. package/lib/services/runner.d.ts.map +0 -1
  54. package/lib/services/runner.js.map +0 -1
  55. package/lib/services/servicerunner.d.ts +0 -68
  56. package/lib/services/servicerunner.d.ts.map +0 -1
  57. package/lib/services/servicerunner.js +0 -97
  58. package/lib/services/servicerunner.js.map +0 -1
  59. package/lib/services/servicerunner.spec.d.ts +0 -2
  60. package/lib/services/servicerunner.spec.d.ts.map +0 -1
  61. package/lib/services/servicerunner.spec.js +0 -111
  62. package/lib/services/servicerunner.spec.js.map +0 -1
package/README.md CHANGED
@@ -13,10 +13,95 @@ This module is part of Webda Application Framework that allows you to quickly de
13
13
 
14
14
  <!-- README_HEADER -->
15
15
 
16
- This package is exposing a logic of asynchronous tasks management.
17
- You have different types of runner available.
18
- It allows you to launch other language/binary from within your application
19
- and capure the output.
16
+ # @webda/async
17
+
18
+ > Durable asynchronous job orchestration for Webda — queue a service method call, track its status, and optionally schedule it for later execution.
19
+
20
+ ## When to use it
21
+
22
+ - You need to offload long-running work (report generation, data imports) to a background worker without blocking the HTTP response.
23
+ - You want to schedule a recurring or time-delayed operation (cron-based or timestamp-based).
24
+ - You need a persistent audit trail of job executions with status, logs, and results stored in a Webda Store.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pnpm add @webda/async
30
+ ```
31
+
32
+ ## Configuration
33
+
34
+ ```json
35
+ {
36
+ "services": {
37
+ "AsyncActionsQueue": {
38
+ "type": "MemoryQueue"
39
+ },
40
+ "asyncJobService": {
41
+ "type": "AsyncJobService",
42
+ "queue": "AsyncActionsQueue",
43
+ "url": "/async",
44
+ "runners": ["serviceRunner"],
45
+ "includeCron": true,
46
+ "logsLimit": 500
47
+ },
48
+ "serviceRunner": {
49
+ "type": "ServiceRunner"
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ | Parameter | Type | Default | Required | Description |
56
+ |---|---|---|---|---|
57
+ | `queue` | string | `"AsyncActionsQueue"` | Yes | Name of the Queue service to dispatch jobs through |
58
+ | `url` | string | `"/async"` | No | URL prefix for the status hook endpoint |
59
+ | `runners` | string[] | `[]` | Yes | List of Runner service names to execute jobs |
60
+ | `localLaunch` | boolean | `false` | No | Execute jobs inline (no queue) — useful for development |
61
+ | `fallbackOnFirst` | boolean | `false` | No | Use first runner if no runner matches the job type |
62
+ | `concurrencyLimit` | number | — | No | Maximum number of jobs running concurrently |
63
+ | `includeCron` | boolean | `true` | No | Auto-schedule `@Cron`-annotated methods as async actions |
64
+ | `logsLimit` | number | `500` | No | Max log lines retained per job in the store |
65
+ | `asyncOperationDefinition` | string | — | No | Path to a JSON file of operation definitions generated by `webda operations` |
66
+ | `schedulerResolution` | number | `60000` | No | Scheduler tick interval in milliseconds |
67
+
68
+ ## Usage
69
+
70
+ ```typescript
71
+ import { Service } from "@webda/core";
72
+ import { Bean, Inject } from "@webda/core";
73
+ import AsyncJobService from "@webda/async/services/asyncjobservice";
74
+
75
+ @Bean
76
+ export class ReportService extends Service {
77
+ @Inject("asyncJobService")
78
+ asyncJobService: AsyncJobService;
79
+
80
+ // Expose an HTTP endpoint that queues a job and returns immediately
81
+ async generateReport(ctx: any): Promise<void> {
82
+ const action = await this.asyncJobService.launchAsAsyncAction(
83
+ "ReportService", // service name
84
+ "runReport", // method name
85
+ ctx.getParameters().reportId
86
+ );
87
+ ctx.write({ jobId: action.getUuid(), status: action.status });
88
+ }
89
+
90
+ // This method runs inside the worker process
91
+ async runReport(reportId: string): Promise<void> {
92
+ // ... long-running work here
93
+ }
94
+ }
95
+
96
+ // Start the worker (typically in a separate process)
97
+ // asyncJobService.worker().then(() => console.log("worker stopped"));
98
+ ```
99
+
100
+ ## Reference
101
+
102
+ - API reference: see the auto-generated typedoc at `docs/pages/Modules/async/`.
103
+ - Source: [`packages/async`](https://github.com/loopingz/webda.io/tree/main/packages/async)
104
+ - Related: [`@webda/amqp`](../amqp) for a RabbitMQ-backed queue, [`@webda/aws`](../aws) for SQS, [`@webda/core`](../core) for the base `Queue` and `Store` abstractions.
20
105
 
21
106
  <!-- README_FOOTER -->
22
107
  ## Sponsors
@@ -1,4 +1,4 @@
1
- import { CoreModel, OperationContext, WebContext } from "@webda/core";
1
+ import { CoreModel, IOperationContext, OperationContext, WebContext } from "@webda/core";
2
2
  import { WorkerLogLevel } from "@webda/workout";
3
3
  /**
4
4
  * Represent an item for processing queue
@@ -20,23 +20,21 @@ export interface AsyncActionQueueItem {
20
20
  /**
21
21
  * Define here a model that can be used along with Store service
22
22
  * @WebdaModel
23
+ * @WebdaPlural AsyncActions
23
24
  */
24
25
  export default class AsyncAction extends CoreModel {
25
26
  /**
26
- * Set type
27
+ * Create a new action
28
+ * @param data - initial data
27
29
  */
28
- constructor();
30
+ constructor(data?: Partial<AsyncAction>);
29
31
  /**
30
32
  * By default AsyncAction are not considered internal
31
33
  *
32
34
  * Internal: That execute a method or operation of Webda application framework
33
- * @returns
35
+ * @returns false
34
36
  */
35
37
  isInternal(): boolean;
36
- /**
37
- * Action uuid
38
- */
39
- uuid: string;
40
38
  /**
41
39
  * Current status
42
40
  */
@@ -70,11 +68,11 @@ export default class AsyncAction extends CoreModel {
70
68
  */
71
69
  statusDetails: any;
72
70
  /**
73
- *
71
+ * Type of action
74
72
  */
75
73
  type: string;
76
74
  /**
77
- *
75
+ * Arguments of the action
78
76
  */
79
77
  arguments?: any[];
80
78
  /**
@@ -91,61 +89,86 @@ export default class AsyncAction extends CoreModel {
91
89
  * It should be a verb
92
90
  */
93
91
  action?: "STOP" | string;
92
+ /**
93
+ * Maximum number of log lines kept
94
+ * @returns the limit
95
+ */
94
96
  getLogsLimit(): number;
95
97
  /**
96
98
  * Allow to report status for a job
97
- * @param context
99
+ *
100
+ * Only a job runner with a valid HMAC can call it
101
+ * @param context - the web context of the job runner
98
102
  */
99
- statusAction(context: OperationContext): Promise<void>;
103
+ statusAction(context?: OperationContext): Promise<void>;
100
104
  /**
101
- * Return the hook url if empty fallback to the service url
102
- * @returns
105
+ * Return the absolute url of this action status route ({uuid}/status)
106
+ *
107
+ * Remote runners report to AsyncJobService.getHookUrl() instead, as this route
108
+ * still has to be authorized by the application request filters
109
+ * @returns the absolute url of the status action
103
110
  */
104
111
  getHookUrl(): string;
105
112
  /**
106
- *
107
- * @param body
113
+ * Update the action with a status report
114
+ * @param body - the status report
115
+ * @param time - the job time header
116
+ * @returns this
108
117
  */
109
118
  update(body: any, time?: string): Promise<this>;
110
119
  /**
111
- *
112
- * @param context
113
- * @param action
120
+ * Verify the job HMAC headers
121
+ * @param context - the web context
114
122
  */
115
- protected verifyJobRequest<K extends AsyncAction = AsyncAction>(context: WebContext): Promise<void>;
123
+ protected verifyJobRequest(context: WebContext): Promise<void>;
116
124
  /**
117
125
  * Get the hmac for the job
118
- * @param jobTime
119
- * @returns
126
+ * @param jobTime - the job time header
127
+ * @returns the hex hmac
120
128
  */
121
129
  getHmac(jobTime: string): string;
122
130
  /**
123
- * Ensure action hook is ok
124
- * @param context
125
- * @param _action
126
- * @returns
131
+ * Only job runners with a valid HMAC can report status or use binaries
132
+ * @param context - the operation context
133
+ * @param action - the action
134
+ * @returns true or the reason of refusal
127
135
  */
128
- checkAct(context: OperationContext<any, any>, action: string): Promise<void>;
136
+ canAct(context: IOperationContext, action: string): Promise<string | boolean>;
137
+ /**
138
+ * Throw a Forbidden error if the action is not allowed
139
+ * @param context - the operation context
140
+ * @param action - the action
141
+ */
142
+ checkAct(context: IOperationContext, action: string): Promise<void>;
129
143
  }
130
144
  /**
131
145
  * Define a Webda Async Action
132
146
  *
133
147
  * @WebdaModel
148
+ * @WebdaPlural AsyncWebdaActions
134
149
  */
135
150
  export declare class AsyncWebdaAction extends AsyncAction {
151
+ /**
152
+ * Log level to capture
153
+ */
154
+ logLevel: WorkerLogLevel;
155
+ /**
156
+ * Service to call
157
+ */
136
158
  serviceName?: string;
159
+ /**
160
+ * Method to call
161
+ */
137
162
  method?: string;
138
- logLevel: WorkerLogLevel;
139
163
  /**
140
- *
141
- * @param serviceName service to call
164
+ * @param serviceName service to call or initial data
142
165
  * @param method method to call
143
- * @param arguments to call with the method
166
+ * @param args to call with the method
144
167
  */
145
- constructor(serviceName?: string, method?: string, ...args: any[]);
168
+ constructor(serviceName?: string | Partial<AsyncWebdaAction>, method?: string, ...args: any[]);
146
169
  /**
147
170
  * Execute a serviceName.method(...args) so this is internal
148
- * @returns
171
+ * @returns true
149
172
  */
150
173
  isInternal(): boolean;
151
174
  }
@@ -153,17 +176,32 @@ export declare class AsyncWebdaAction extends AsyncAction {
153
176
  * Operation called asynchronously
154
177
  *
155
178
  * @WebdaModel
179
+ * @WebdaPlural AsyncOperationActions
156
180
  */
157
181
  export declare class AsyncOperationAction extends AsyncAction {
182
+ /**
183
+ * Operation to call
184
+ */
158
185
  operationId: string;
159
- context: OperationContext;
186
+ /**
187
+ * Context to call the operation with
188
+ */
189
+ context: any;
190
+ /**
191
+ * Log level to capture
192
+ */
160
193
  logLevel: WorkerLogLevel;
161
- constructor(operationId: string, context: OperationContext, logLevel?: WorkerLogLevel);
194
+ /**
195
+ * @param operationId operation to call or initial data
196
+ * @param context context to use
197
+ * @param logLevel log level to capture
198
+ */
199
+ constructor(operationId?: string | Partial<AsyncOperationAction>, context?: OperationContext, logLevel?: WorkerLogLevel);
162
200
  /**
163
201
  * Execute a webda.callOperation(context ,id) so this is internal
164
- * @returns
202
+ * @returns true
165
203
  */
166
204
  isInternal(): boolean;
167
205
  }
168
206
  export { AsyncAction };
169
- //# sourceMappingURL=models.d.ts.map
207
+ //# sourceMappingURL=asyncaction.model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncaction.model.d.ts","sourceRoot":"","sources":["../src/asyncaction.model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,269 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { Action, CoreModel, WebContext, WebdaError, useContext, useLog, useParameters, useRouter } from "@webda/core";
36
+ import * as crypto from "node:crypto";
37
+ /**
38
+ * Headers sent by a job runner to authenticate against the status hook
39
+ */
40
+ const JOB_HEADERS = ["X-Job-Hash", "X-Job-Time"];
41
+ /**
42
+ * Check if the context carries the job runner headers
43
+ * @param context - the context to check
44
+ * @returns true if both job headers are present
45
+ */
46
+ function hasJobHeaders(context) {
47
+ return (context instanceof WebContext &&
48
+ JOB_HEADERS.every(h => context.getHttpContext()?.getUniqueHeader(h) !== undefined));
49
+ }
50
+ let AsyncAction = (() => {
51
+ var _a;
52
+ let _classSuper = CoreModel;
53
+ let _instanceExtraInitializers = [];
54
+ let _statusAction_decorators;
55
+ return _a = class AsyncAction extends _classSuper {
56
+ /**
57
+ * Create a new action
58
+ * @param data - initial data
59
+ */
60
+ constructor(data) {
61
+ super(data);
62
+ /**
63
+ * Current status
64
+ */
65
+ this.status = __runInitializers(this, _instanceExtraInitializers);
66
+ if (data) {
67
+ Object.assign(this, data);
68
+ }
69
+ this.type ?? (this.type = this.constructor.name);
70
+ }
71
+ /**
72
+ * By default AsyncAction are not considered internal
73
+ *
74
+ * Internal: That execute a method or operation of Webda application framework
75
+ * @returns false
76
+ */
77
+ isInternal() {
78
+ return false;
79
+ }
80
+ /**
81
+ * Maximum number of log lines kept
82
+ * @returns the limit
83
+ */
84
+ getLogsLimit() {
85
+ return 1000;
86
+ }
87
+ /**
88
+ * Allow to report status for a job
89
+ *
90
+ * Only a job runner with a valid HMAC can call it
91
+ * @param context - the web context of the job runner
92
+ */
93
+ async statusAction(context = useContext()) {
94
+ if (!(context instanceof WebContext)) {
95
+ throw new Error("Only WebContext can call this action");
96
+ }
97
+ await this.checkAct(context, "status");
98
+ await this.update(await context.getRequestBody(), context.getHttpContext().getUniqueHeader("X-Job-Time"));
99
+ context.write({ ...this, logs: undefined, statusDetails: undefined });
100
+ }
101
+ /**
102
+ * Return the absolute url of this action status route ({uuid}/status)
103
+ *
104
+ * Remote runners report to AsyncJobService.getHookUrl() instead, as this route
105
+ * still has to be authorized by the application request filters
106
+ * @returns the absolute url of the status action
107
+ */
108
+ getHookUrl() {
109
+ return `${useParameters().apiUrl ?? ""}${useRouter().getModelUrl(this)}/${this.uuid}/status`;
110
+ }
111
+ /**
112
+ * Update the action with a status report
113
+ * @param body - the status report
114
+ * @param time - the job time header
115
+ * @returns this
116
+ */
117
+ async update(body, time = undefined) {
118
+ if (body.logs && Array.isArray(body.logs)) {
119
+ this.logs ?? (this.logs = []);
120
+ this.logs.push(...body.logs);
121
+ // Prevent having too much logs
122
+ if (this.logs.length > this.getLogsLimit()) {
123
+ this.logs = this.logs.slice(-1 * this.getLogsLimit());
124
+ }
125
+ }
126
+ this._lastJobUpdate = Number.parseInt(time || "0") || 0;
127
+ if (Date.now() - this._lastJobUpdate > 60) {
128
+ this._lastJobUpdate = Date.now();
129
+ }
130
+ await this.patch({
131
+ _lastJobUpdate: this._lastJobUpdate,
132
+ logs: this.logs,
133
+ status: body.status || this.status,
134
+ errorMessage: body.errorMessage || this.errorMessage,
135
+ statusDetails: body.statusDetails || this.statusDetails,
136
+ results: body.results || this.results
137
+ });
138
+ return this;
139
+ }
140
+ /**
141
+ * Verify the job HMAC headers
142
+ * @param context - the web context
143
+ */
144
+ async verifyJobRequest(context) {
145
+ const jobTime = context.getHttpContext().getUniqueHeader("X-Job-Time");
146
+ const jobHash = context.getHttpContext().getUniqueHeader("X-Job-Hash");
147
+ // Ensure hash mac is correct
148
+ if (jobHash !== this.getHmac(jobTime)) {
149
+ useLog("TRACE", "Invalid Job HMAC");
150
+ throw new WebdaError.Forbidden("Invalid Job HMAC");
151
+ }
152
+ // Set the context extension
153
+ context.setExtension("asyncJob", this);
154
+ }
155
+ /**
156
+ * Get the hmac for the job
157
+ * @param jobTime - the job time header
158
+ * @returns the hex hmac
159
+ */
160
+ getHmac(jobTime) {
161
+ return crypto.createHmac("sha256", this.__secretKey).update(jobTime).digest("hex");
162
+ }
163
+ /**
164
+ * Only job runners with a valid HMAC can report status or use binaries
165
+ * @param context - the operation context
166
+ * @param action - the action
167
+ * @returns true or the reason of refusal
168
+ */
169
+ async canAct(context, action) {
170
+ if ("status" === action || ["get_binary", "attach_binary", "update_binary_metadata"].includes(action)) {
171
+ if (!hasJobHeaders(context)) {
172
+ return "Only Job runner can call this action";
173
+ }
174
+ try {
175
+ await this.verifyJobRequest(context);
176
+ return true;
177
+ }
178
+ catch (err) {
179
+ return err.message;
180
+ }
181
+ }
182
+ return "This model does not support any action: override canAct";
183
+ }
184
+ /**
185
+ * Throw a Forbidden error if the action is not allowed
186
+ * @param context - the operation context
187
+ * @param action - the action
188
+ */
189
+ async checkAct(context, action) {
190
+ const result = await this.canAct(context, action);
191
+ if (result !== true) {
192
+ throw new WebdaError.Forbidden(typeof result === "string" ? result : "Forbidden");
193
+ }
194
+ }
195
+ },
196
+ (() => {
197
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
198
+ _statusAction_decorators = [Action({ name: "status", openapi: { hidden: true } })];
199
+ __esDecorate(_a, null, _statusAction_decorators, { kind: "method", name: "statusAction", static: false, private: false, access: { has: obj => "statusAction" in obj, get: obj => obj.statusAction }, metadata: _metadata }, null, _instanceExtraInitializers);
200
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
201
+ })(),
202
+ _a;
203
+ })();
204
+ /**
205
+ * Define here a model that can be used along with Store service
206
+ * @WebdaModel
207
+ * @WebdaPlural AsyncActions
208
+ */
209
+ export default AsyncAction;
210
+ /**
211
+ * Define a Webda Async Action
212
+ *
213
+ * @WebdaModel
214
+ * @WebdaPlural AsyncWebdaActions
215
+ */
216
+ export class AsyncWebdaAction extends AsyncAction {
217
+ /**
218
+ * @param serviceName service to call or initial data
219
+ * @param method method to call
220
+ * @param args to call with the method
221
+ */
222
+ constructor(serviceName, method, ...args) {
223
+ super(typeof serviceName === "object" ? serviceName : undefined);
224
+ if (typeof serviceName !== "object") {
225
+ this.serviceName = serviceName;
226
+ this.method = method;
227
+ this.arguments = args;
228
+ }
229
+ this.logLevel ?? (this.logLevel = "INFO");
230
+ }
231
+ /**
232
+ * Execute a serviceName.method(...args) so this is internal
233
+ * @returns true
234
+ */
235
+ isInternal() {
236
+ return true;
237
+ }
238
+ }
239
+ /**
240
+ * Operation called asynchronously
241
+ *
242
+ * @WebdaModel
243
+ * @WebdaPlural AsyncOperationActions
244
+ */
245
+ export class AsyncOperationAction extends AsyncAction {
246
+ /**
247
+ * @param operationId operation to call or initial data
248
+ * @param context context to use
249
+ * @param logLevel log level to capture
250
+ */
251
+ constructor(operationId, context, logLevel = "INFO") {
252
+ super(typeof operationId === "object" ? operationId : undefined);
253
+ if (typeof operationId !== "object") {
254
+ this.operationId = operationId;
255
+ this.context = context;
256
+ this.logLevel = logLevel;
257
+ }
258
+ this.logLevel ?? (this.logLevel = "INFO");
259
+ }
260
+ /**
261
+ * Execute a webda.callOperation(context ,id) so this is internal
262
+ * @returns true
263
+ */
264
+ isInternal() {
265
+ return true;
266
+ }
267
+ }
268
+ export { AsyncAction };
269
+ //# sourceMappingURL=asyncaction.model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncaction.model.js","sourceRoot":"","sources":["../src/asyncaction.model.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- export * from "./models.js";
2
- export * from "./services/asyncjobservice.js";
3
- export * from "./services/runner.js";
4
- export * from "./services/localrunner.js";
1
+ export * from "./asyncaction.model.js";
2
+ export * from "./services/asyncjobservice.service.js";
3
+ export * from "./services/runner.service.js";
4
+ export * from "./services/localrunner.service.js";
5
+ export * from "./services/servicerunner.service.js";
6
+ export * from "./services/asyncevents.service.js";
5
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC"}
package/lib/index.js CHANGED
@@ -1,5 +1,7 @@
1
- export * from "./models.js";
2
- export * from "./services/asyncjobservice.js";
3
- export * from "./services/runner.js";
4
- export * from "./services/localrunner.js";
1
+ export * from "./asyncaction.model.js";
2
+ export * from "./services/asyncjobservice.service.js";
3
+ export * from "./services/runner.service.js";
4
+ export * from "./services/localrunner.service.js";
5
+ export * from "./services/servicerunner.service.js";
6
+ export * from "./services/asyncevents.service.js";
5
7
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC"}