@webda/async 4.0.0-beta.1 → 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 (41) hide show
  1. package/README.md +89 -4
  2. package/lib/{models.d.ts → asyncaction.model.d.ts} +76 -42
  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 +7 -4
  7. package/lib/index.d.ts.map +1 -0
  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} +79 -74
  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 -9
  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 -11
  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 +33 -37
  31. package/webda.module.json +1895 -857
  32. package/lib/models.js +0 -177
  33. package/lib/models.js.map +0 -1
  34. package/lib/services/asyncjobservice.js +0 -505
  35. package/lib/services/asyncjobservice.js.map +0 -1
  36. package/lib/services/localrunner.js +0 -70
  37. package/lib/services/localrunner.js.map +0 -1
  38. package/lib/services/runner.js.map +0 -1
  39. package/lib/services/servicerunner.d.ts +0 -67
  40. package/lib/services/servicerunner.js +0 -97
  41. package/lib/services/servicerunner.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
@@ -17,31 +17,24 @@ export interface AsyncActionQueueItem {
17
17
  */
18
18
  type: string;
19
19
  }
20
- /**
21
- * Job information
22
- */
23
- export interface Job {
24
- }
25
20
  /**
26
21
  * Define here a model that can be used along with Store service
27
22
  * @WebdaModel
23
+ * @WebdaPlural AsyncActions
28
24
  */
29
25
  export default class AsyncAction extends CoreModel {
30
26
  /**
31
- * Set type
27
+ * Create a new action
28
+ * @param data - initial data
32
29
  */
33
- constructor();
30
+ constructor(data?: Partial<AsyncAction>);
34
31
  /**
35
32
  * By default AsyncAction are not considered internal
36
33
  *
37
34
  * Internal: That execute a method or operation of Webda application framework
38
- * @returns
35
+ * @returns false
39
36
  */
40
37
  isInternal(): boolean;
41
- /**
42
- * Action uuid
43
- */
44
- uuid: string;
45
38
  /**
46
39
  * Current status
47
40
  */
@@ -61,7 +54,7 @@ export default class AsyncAction extends CoreModel {
61
54
  /**
62
55
  * Job information
63
56
  */
64
- job: Job;
57
+ job: any;
65
58
  /**
66
59
  * Last time the job was updated
67
60
  */
@@ -75,11 +68,11 @@ export default class AsyncAction extends CoreModel {
75
68
  */
76
69
  statusDetails: any;
77
70
  /**
78
- *
71
+ * Type of action
79
72
  */
80
73
  type: string;
81
74
  /**
82
- *
75
+ * Arguments of the action
83
76
  */
84
77
  arguments?: any[];
85
78
  /**
@@ -96,61 +89,86 @@ export default class AsyncAction extends CoreModel {
96
89
  * It should be a verb
97
90
  */
98
91
  action?: "STOP" | string;
92
+ /**
93
+ * Maximum number of log lines kept
94
+ * @returns the limit
95
+ */
99
96
  getLogsLimit(): number;
100
97
  /**
101
98
  * Allow to report status for a job
102
- * @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
103
102
  */
104
- statusAction(context: WebContext): Promise<void>;
103
+ statusAction(context?: OperationContext): Promise<void>;
105
104
  /**
106
- * Return the hook url if empty fallback to the service url
107
- * @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
108
110
  */
109
111
  getHookUrl(): string;
110
112
  /**
111
- *
112
- * @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
113
117
  */
114
118
  update(body: any, time?: string): Promise<this>;
115
119
  /**
116
- *
117
- * @param context
118
- * @param action
120
+ * Verify the job HMAC headers
121
+ * @param context - the web context
119
122
  */
120
- protected verifyJobRequest<K extends AsyncAction = AsyncAction>(context: WebContext): Promise<void>;
123
+ protected verifyJobRequest(context: WebContext): Promise<void>;
121
124
  /**
122
125
  * Get the hmac for the job
123
- * @param jobTime
124
- * @returns
126
+ * @param jobTime - the job time header
127
+ * @returns the hex hmac
125
128
  */
126
129
  getHmac(jobTime: string): string;
127
130
  /**
128
- * Ensure action hook is ok
129
- * @param context
130
- * @param _action
131
- * @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
135
+ */
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
132
141
  */
133
- checkAct(context: OperationContext<any, any>, action: string): Promise<void>;
142
+ checkAct(context: IOperationContext, action: string): Promise<void>;
134
143
  }
135
144
  /**
136
145
  * Define a Webda Async Action
137
146
  *
138
147
  * @WebdaModel
148
+ * @WebdaPlural AsyncWebdaActions
139
149
  */
140
150
  export declare class AsyncWebdaAction extends AsyncAction {
151
+ /**
152
+ * Log level to capture
153
+ */
154
+ logLevel: WorkerLogLevel;
155
+ /**
156
+ * Service to call
157
+ */
141
158
  serviceName?: string;
159
+ /**
160
+ * Method to call
161
+ */
142
162
  method?: string;
143
- logLevel: WorkerLogLevel;
144
163
  /**
145
- *
146
- * @param serviceName service to call
164
+ * @param serviceName service to call or initial data
147
165
  * @param method method to call
148
- * @param arguments to call with the method
166
+ * @param args to call with the method
149
167
  */
150
- constructor(serviceName?: string, method?: string, ...args: any[]);
168
+ constructor(serviceName?: string | Partial<AsyncWebdaAction>, method?: string, ...args: any[]);
151
169
  /**
152
170
  * Execute a serviceName.method(...args) so this is internal
153
- * @returns
171
+ * @returns true
154
172
  */
155
173
  isInternal(): boolean;
156
174
  }
@@ -158,16 +176,32 @@ export declare class AsyncWebdaAction extends AsyncAction {
158
176
  * Operation called asynchronously
159
177
  *
160
178
  * @WebdaModel
179
+ * @WebdaPlural AsyncOperationActions
161
180
  */
162
181
  export declare class AsyncOperationAction extends AsyncAction {
182
+ /**
183
+ * Operation to call
184
+ */
163
185
  operationId: string;
164
- context: OperationContext;
186
+ /**
187
+ * Context to call the operation with
188
+ */
189
+ context: any;
190
+ /**
191
+ * Log level to capture
192
+ */
165
193
  logLevel: WorkerLogLevel;
166
- 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);
167
200
  /**
168
201
  * Execute a webda.callOperation(context ,id) so this is internal
169
- * @returns
202
+ * @returns true
170
203
  */
171
204
  isInternal(): boolean;
172
205
  }
173
206
  export { AsyncAction };
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,4 +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";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
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"}