@forge/events 1.0.3 → 2.0.0-next.1
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.
- package/CHANGELOG.md +14 -0
- package/README.md +32 -26
- package/out/__test__/appEvents.test.d.ts +2 -0
- package/out/__test__/appEvents.test.d.ts.map +1 -0
- package/out/__test__/appEvents.test.js +137 -0
- package/out/__test__/jobProgress.test.js +3 -5
- package/out/__test__/queue.test.js +88 -39
- package/out/__test__/utils.js +1 -1
- package/out/appEvents.d.ts +22 -0
- package/out/appEvents.d.ts.map +1 -0
- package/out/appEvents.js +50 -0
- package/out/errors.d.ts +17 -19
- package/out/errors.d.ts.map +1 -1
- package/out/errors.js +21 -34
- package/out/index.d.ts +3 -1
- package/out/index.d.ts.map +1 -1
- package/out/index.js +3 -1
- package/out/jobProgress.d.ts +8 -3
- package/out/jobProgress.d.ts.map +1 -1
- package/out/jobProgress.js +2 -2
- package/out/queries.d.ts +1 -2
- package/out/queries.d.ts.map +1 -1
- package/out/queue.d.ts +2 -2
- package/out/queue.d.ts.map +1 -1
- package/out/queue.js +7 -12
- package/out/text.d.ts +2 -0
- package/out/text.d.ts.map +1 -1
- package/out/text.js +2 -0
- package/out/types.d.ts +24 -9
- package/out/types.d.ts.map +1 -1
- package/out/validators.d.ts +4 -4
- package/out/validators.d.ts.map +1 -1
- package/out/validators.js +22 -11
- package/package.json +1 -1
- package/src/__test__/appEvents.test.ts +201 -0
- package/src/__test__/jobProgress.test.ts +3 -5
- package/src/__test__/queue.test.ts +102 -43
- package/src/__test__/utils.ts +1 -1
- package/src/appEvents.ts +107 -0
- package/src/errors.ts +20 -43
- package/src/index.ts +11 -1
- package/src/jobProgress.ts +11 -5
- package/src/queries.ts +2 -2
- package/src/queue.ts +9 -15
- package/src/text.ts +2 -0
- package/src/types.ts +30 -7
- package/src/validators.ts +27 -10
- package/tsconfig.tsbuildinfo +1 -1
package/out/errors.js
CHANGED
|
@@ -1,51 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InvocationLimitReachedError = exports.JobDoesNotExistError = exports.InternalServerError = exports.PartialSuccessError = exports.RateLimitError = exports.NoEventsToPushError = exports.PayloadTooBigError = exports.TooManyEventsError = exports.InvalidQueueNameError = exports.InvalidPushSettingsError = void 0;
|
|
4
|
-
class
|
|
3
|
+
exports.InvocationLimitReachedError = exports.JobDoesNotExistError = exports.InternalServerError = exports.PartialSuccessError = exports.RateLimitError = exports.NoEventsToPushError = exports.PayloadTooBigError = exports.TooManyEventsError = exports.InvalidPayloadError = exports.InvalidQueueNameError = exports.InvalidPushSettingsError = exports.EventsError = void 0;
|
|
4
|
+
class EventsError extends Error {
|
|
5
5
|
constructor(message) {
|
|
6
6
|
super(message);
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
|
+
exports.EventsError = EventsError;
|
|
10
|
+
class InvalidPushSettingsError extends EventsError {
|
|
11
|
+
}
|
|
9
12
|
exports.InvalidPushSettingsError = InvalidPushSettingsError;
|
|
10
|
-
class InvalidQueueNameError extends
|
|
11
|
-
constructor(message) {
|
|
12
|
-
super(message);
|
|
13
|
-
}
|
|
13
|
+
class InvalidQueueNameError extends EventsError {
|
|
14
14
|
}
|
|
15
15
|
exports.InvalidQueueNameError = InvalidQueueNameError;
|
|
16
|
-
class
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
class InvalidPayloadError extends EventsError {
|
|
17
|
+
}
|
|
18
|
+
exports.InvalidPayloadError = InvalidPayloadError;
|
|
19
|
+
class TooManyEventsError extends EventsError {
|
|
20
20
|
}
|
|
21
21
|
exports.TooManyEventsError = TooManyEventsError;
|
|
22
|
-
class PayloadTooBigError extends
|
|
23
|
-
constructor(message) {
|
|
24
|
-
super(message);
|
|
25
|
-
}
|
|
22
|
+
class PayloadTooBigError extends EventsError {
|
|
26
23
|
}
|
|
27
24
|
exports.PayloadTooBigError = PayloadTooBigError;
|
|
28
|
-
class NoEventsToPushError extends
|
|
29
|
-
constructor(message) {
|
|
30
|
-
super(message);
|
|
31
|
-
}
|
|
25
|
+
class NoEventsToPushError extends EventsError {
|
|
32
26
|
}
|
|
33
27
|
exports.NoEventsToPushError = NoEventsToPushError;
|
|
34
|
-
class RateLimitError extends
|
|
35
|
-
constructor(message) {
|
|
36
|
-
super(message);
|
|
37
|
-
}
|
|
28
|
+
class RateLimitError extends EventsError {
|
|
38
29
|
}
|
|
39
30
|
exports.RateLimitError = RateLimitError;
|
|
40
|
-
class PartialSuccessError extends
|
|
41
|
-
|
|
31
|
+
class PartialSuccessError extends EventsError {
|
|
32
|
+
result;
|
|
33
|
+
failedEvents;
|
|
34
|
+
constructor(message, result, failedEvents) {
|
|
42
35
|
super(message);
|
|
36
|
+
this.result = result;
|
|
43
37
|
this.failedEvents = failedEvents;
|
|
44
38
|
}
|
|
45
|
-
failedEvents;
|
|
46
39
|
}
|
|
47
40
|
exports.PartialSuccessError = PartialSuccessError;
|
|
48
|
-
class InternalServerError extends
|
|
41
|
+
class InternalServerError extends EventsError {
|
|
49
42
|
constructor(message, errorCode, details) {
|
|
50
43
|
super(message);
|
|
51
44
|
this.errorCode = errorCode;
|
|
@@ -55,15 +48,9 @@ class InternalServerError extends Error {
|
|
|
55
48
|
details;
|
|
56
49
|
}
|
|
57
50
|
exports.InternalServerError = InternalServerError;
|
|
58
|
-
class JobDoesNotExistError extends
|
|
59
|
-
constructor(message) {
|
|
60
|
-
super(message);
|
|
61
|
-
}
|
|
51
|
+
class JobDoesNotExistError extends EventsError {
|
|
62
52
|
}
|
|
63
53
|
exports.JobDoesNotExistError = JobDoesNotExistError;
|
|
64
|
-
class InvocationLimitReachedError extends
|
|
65
|
-
constructor(message) {
|
|
66
|
-
super(message);
|
|
67
|
-
}
|
|
54
|
+
class InvocationLimitReachedError extends EventsError {
|
|
68
55
|
}
|
|
69
56
|
exports.InvocationLimitReachedError = InvocationLimitReachedError;
|
package/out/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { Queue } from './queue';
|
|
2
2
|
export { InvalidQueueNameError, TooManyEventsError, PayloadTooBigError, NoEventsToPushError, RateLimitError, PartialSuccessError, InternalServerError, JobDoesNotExistError, InvalidPushSettingsError, InvocationLimitReachedError } from './errors';
|
|
3
|
-
export { JobProgress } from './jobProgress';
|
|
3
|
+
export { JobProgress, JobStats } from './jobProgress';
|
|
4
4
|
export { QueueResponse } from './queueResponse';
|
|
5
5
|
export { InvocationError } from './invocationError';
|
|
6
6
|
export { InvocationErrorCode } from './invocationErrorCode';
|
|
7
7
|
export { RetryOptions } from './retryOptions';
|
|
8
|
+
export { AsyncEvent, PushEvent, PushResult } from './types';
|
|
9
|
+
export { appEvents, AppEvent, AppEventPublishResult, AppEventPublishSuccess, AppEventPublishFailure, AppEventPublishError, AppEventErrorType } from './appEvents';
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
package/out/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC5B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC5B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EACL,SAAS,EACT,QAAQ,EACR,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,aAAa,CAAC"}
|
package/out/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InvocationErrorCode = exports.InvocationError = exports.QueueResponse = exports.JobProgress = exports.InvocationLimitReachedError = exports.InvalidPushSettingsError = exports.JobDoesNotExistError = exports.InternalServerError = exports.PartialSuccessError = exports.RateLimitError = exports.NoEventsToPushError = exports.PayloadTooBigError = exports.TooManyEventsError = exports.InvalidQueueNameError = exports.Queue = void 0;
|
|
3
|
+
exports.appEvents = exports.InvocationErrorCode = exports.InvocationError = exports.QueueResponse = exports.JobProgress = exports.InvocationLimitReachedError = exports.InvalidPushSettingsError = exports.JobDoesNotExistError = exports.InternalServerError = exports.PartialSuccessError = exports.RateLimitError = exports.NoEventsToPushError = exports.PayloadTooBigError = exports.TooManyEventsError = exports.InvalidQueueNameError = exports.Queue = void 0;
|
|
4
4
|
var queue_1 = require("./queue");
|
|
5
5
|
Object.defineProperty(exports, "Queue", { enumerable: true, get: function () { return queue_1.Queue; } });
|
|
6
6
|
var errors_1 = require("./errors");
|
|
@@ -22,3 +22,5 @@ var invocationError_1 = require("./invocationError");
|
|
|
22
22
|
Object.defineProperty(exports, "InvocationError", { enumerable: true, get: function () { return invocationError_1.InvocationError; } });
|
|
23
23
|
var invocationErrorCode_1 = require("./invocationErrorCode");
|
|
24
24
|
Object.defineProperty(exports, "InvocationErrorCode", { enumerable: true, get: function () { return invocationErrorCode_1.InvocationErrorCode; } });
|
|
25
|
+
var appEvents_1 = require("./appEvents");
|
|
26
|
+
Object.defineProperty(exports, "appEvents", { enumerable: true, get: function () { return appEvents_1.appEvents; } });
|
package/out/jobProgress.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { FetchMethod
|
|
1
|
+
import { FetchMethod } from '@forge/api';
|
|
2
|
+
export declare type JobStats = {
|
|
3
|
+
success: number;
|
|
4
|
+
inProgress: number;
|
|
5
|
+
failed: number;
|
|
6
|
+
};
|
|
2
7
|
export declare class JobProgress {
|
|
3
8
|
private readonly id;
|
|
4
9
|
private readonly apiClient;
|
|
5
10
|
constructor(id: string, apiClient?: FetchMethod);
|
|
6
|
-
getStats(): Promise<
|
|
7
|
-
cancel(): Promise<
|
|
11
|
+
getStats(): Promise<JobStats>;
|
|
12
|
+
cancel(): Promise<void>;
|
|
8
13
|
}
|
|
9
14
|
//# sourceMappingURL=jobProgress.d.ts.map
|
package/out/jobProgress.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jobProgress.d.ts","sourceRoot":"","sources":["../src/jobProgress.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"jobProgress.d.ts","sourceRoot":"","sources":["../src/jobProgress.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,WAAW,EAAE,MAAM,YAAY,CAAC;AAUlE,oBAAY,QAAQ,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,EAAE,EAAE,MAAM,EACV,SAAS,GAAE,WAAqC;IAG7D,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IAgB7B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAa9B"}
|
package/out/jobProgress.js
CHANGED
|
@@ -21,7 +21,8 @@ class JobProgress {
|
|
|
21
21
|
(0, validators_1.validateGetStatsPayload)(getStatsRequest);
|
|
22
22
|
const response = await (0, queries_1.post)(queries_1.GET_STATS_PATH, getStatsRequest, this.apiClient);
|
|
23
23
|
await (0, validators_1.validateGetStatsAPIResponse)(response, getStatsRequest);
|
|
24
|
-
|
|
24
|
+
const { success, inProgress, failed } = await response.json();
|
|
25
|
+
return { success, inProgress, failed };
|
|
25
26
|
}
|
|
26
27
|
async cancel() {
|
|
27
28
|
const [queueName, jobId] = this.id.split('#');
|
|
@@ -33,7 +34,6 @@ class JobProgress {
|
|
|
33
34
|
(0, validators_1.validateCancelJobRequest)(cancelJobRequest);
|
|
34
35
|
const response = await (0, queries_1.post)(queries_1.CANCEL_JOB_PATH, cancelJobRequest, this.apiClient);
|
|
35
36
|
await (0, validators_1.validateCancelJobAPIResponse)(response, cancelJobRequest);
|
|
36
|
-
return response;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
exports.JobProgress = JobProgress;
|
package/out/queries.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { APIResponse, FetchMethod } from '@forge/api';
|
|
2
|
-
import { APIRequest } from './types';
|
|
3
2
|
export declare const PUSH_PATH = "/webhook/queue/publish/{contextAri}/{environmentId}/{appId}/{appVersion}";
|
|
4
3
|
export declare const GET_STATS_PATH = "/webhook/queue/stats/{contextAri}/{environmentId}/{appId}/{appVersion}";
|
|
5
4
|
export declare const CANCEL_JOB_PATH = "/webhook/queue/cancel/{contextAri}/{environmentId}/{appId}/{appVersion}";
|
|
6
|
-
export declare const post: (endpoint: string, body:
|
|
5
|
+
export declare const post: (endpoint: string, body: unknown, apiClient: FetchMethod) => Promise<APIResponse>;
|
|
7
6
|
//# sourceMappingURL=queries.d.ts.map
|
package/out/queries.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtD,eAAO,MAAM,SAAS,6EAA6E,CAAC;AACpG,eAAO,MAAM,cAAc,2EAA2E,CAAC;AACvG,eAAO,MAAM,eAAe,4EAA4E,CAAC;AAEzG,eAAO,MAAM,IAAI,aAAoB,MAAM,QAAQ,OAAO,aAAa,WAAW,KAAG,QAAQ,WAAW,CAUvG,CAAC"}
|
package/out/queue.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { FetchMethod } from '@forge/api';
|
|
2
|
-
import {
|
|
2
|
+
import { QueueParams, PushEvent, PushResult } from './types';
|
|
3
3
|
import { JobProgress } from './jobProgress';
|
|
4
4
|
export declare class Queue {
|
|
5
5
|
private readonly queueParams;
|
|
6
6
|
private readonly apiClient;
|
|
7
7
|
constructor(queueParams: QueueParams, apiClient?: FetchMethod);
|
|
8
|
-
push(
|
|
8
|
+
push(events: PushEvent | PushEvent[]): Promise<PushResult>;
|
|
9
9
|
getJob(jobId: string): JobProgress;
|
|
10
10
|
}
|
|
11
11
|
//# sourceMappingURL=queue.d.ts.map
|
package/out/queue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA2B,MAAM,YAAY,CAAC;AAGlE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA2B,MAAM,YAAY,CAAC;AAGlE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAe,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1E,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,qBAAa,KAAK;IAEd,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,WAAW,EAAE,WAAW,EACxB,SAAS,GAAE,WAAqC;IAK7D,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAoBhE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW;CAGnC"}
|
package/out/queue.js
CHANGED
|
@@ -14,27 +14,22 @@ class Queue {
|
|
|
14
14
|
this.apiClient = apiClient;
|
|
15
15
|
(0, validators_1.validateQueueKey)(this.queueParams.key);
|
|
16
16
|
}
|
|
17
|
-
async push(
|
|
18
|
-
(0, validators_1.
|
|
17
|
+
async push(events) {
|
|
18
|
+
const validEvents = (0, validators_1.validatePushEvents)(events);
|
|
19
19
|
const queueName = this.queueParams.key;
|
|
20
20
|
const jobId = (0, uuid_1.v4)();
|
|
21
21
|
const pushRequest = {
|
|
22
22
|
queueName: queueName,
|
|
23
23
|
jobId: jobId,
|
|
24
24
|
type: 'avi:forge:app:event',
|
|
25
|
-
schema: 'ari:cloud:ecosystem::forge/app-event',
|
|
26
|
-
payload:
|
|
25
|
+
schema: 'ari:cloud:ecosystem::forge/app-event-2',
|
|
26
|
+
payload: validEvents,
|
|
27
27
|
time: new Date().toISOString()
|
|
28
28
|
};
|
|
29
|
-
if (pushSettings) {
|
|
30
|
-
(0, validators_1.validatePushSettings)(pushSettings);
|
|
31
|
-
if (pushSettings.delayInSeconds) {
|
|
32
|
-
pushRequest.delayInSeconds = pushSettings.delayInSeconds;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
29
|
const response = await (0, queries_1.post)(queries_1.PUSH_PATH, pushRequest, this.apiClient);
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
const result = { jobId };
|
|
31
|
+
await (0, validators_1.validatePushAPIResponse)(pushRequest, response, result);
|
|
32
|
+
return result;
|
|
38
33
|
}
|
|
39
34
|
getJob(jobId) {
|
|
40
35
|
return new jobProgress_1.JobProgress(jobId, this.apiClient);
|
package/out/text.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export declare const Text: {
|
|
2
2
|
error: {
|
|
3
3
|
invalidQueueName: string;
|
|
4
|
+
invalidEvent: string;
|
|
5
|
+
invalidEventBody: string;
|
|
4
6
|
invalidDelayInSecondsSetting: string;
|
|
5
7
|
maxEventsAllowed: (maxEventsCount: number) => string;
|
|
6
8
|
maxPayloadAllowed: (maxPayloadSize: number) => string;
|
package/out/text.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI;;;;;;2CAMsB,MAAM,KAAG,MAAM;4CAEd,MAAM,KAAG,MAAM;;;;;gCAK3B,MAAM,aAAa,MAAM,KAAG,MAAM;;CAG7D,CAAC"}
|
package/out/text.js
CHANGED
|
@@ -4,6 +4,8 @@ exports.Text = void 0;
|
|
|
4
4
|
exports.Text = {
|
|
5
5
|
error: {
|
|
6
6
|
invalidQueueName: `Queue names can only contain alphanumeric characters, dashes and underscores.`,
|
|
7
|
+
invalidEvent: `Event must be an object.`,
|
|
8
|
+
invalidEventBody: `Event body must be an object.`,
|
|
7
9
|
invalidDelayInSecondsSetting: `The delayInSeconds setting must be between 0 and 900.`,
|
|
8
10
|
maxEventsAllowed: (maxEventsCount) => `This push contains more than the ${maxEventsCount} events allowed.`,
|
|
9
11
|
maxPayloadAllowed: (maxPayloadSize) => `The maximum payload size is ${maxPayloadSize}KB.`,
|
package/out/types.d.ts
CHANGED
|
@@ -1,26 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
};
|
|
4
|
-
export interface PushSettings {
|
|
5
|
-
delayInSeconds: number;
|
|
6
|
-
}
|
|
1
|
+
import { InvocationErrorCode } from './invocationErrorCode';
|
|
2
|
+
export declare type Payload = Record<string, unknown>;
|
|
7
3
|
export interface QueueParams {
|
|
8
4
|
key: string;
|
|
9
5
|
}
|
|
10
6
|
export interface PushRequest extends APIRequest {
|
|
11
|
-
payload:
|
|
7
|
+
payload: PushEvent[];
|
|
12
8
|
schema: string;
|
|
13
9
|
type: string;
|
|
14
|
-
|
|
10
|
+
jobId: string;
|
|
15
11
|
}
|
|
16
12
|
export interface APIRequest {
|
|
17
13
|
queueName: string;
|
|
18
14
|
jobId: string;
|
|
19
15
|
time: string;
|
|
20
16
|
}
|
|
17
|
+
export interface PushEvent {
|
|
18
|
+
body: Body;
|
|
19
|
+
delayInSeconds?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare type Body = Record<string, unknown>;
|
|
22
|
+
export interface PushResult {
|
|
23
|
+
jobId: string;
|
|
24
|
+
}
|
|
21
25
|
export interface FailedEvent {
|
|
22
26
|
errorMessage: string;
|
|
23
|
-
|
|
27
|
+
event: PushEvent;
|
|
28
|
+
}
|
|
29
|
+
export interface AsyncEvent extends PushEvent {
|
|
30
|
+
queueName: string;
|
|
31
|
+
jobId: string;
|
|
32
|
+
eventId: string;
|
|
33
|
+
retryContext?: RetryContext;
|
|
34
|
+
}
|
|
35
|
+
export interface RetryContext {
|
|
36
|
+
retryCount: number;
|
|
37
|
+
retryReason: InvocationErrorCode;
|
|
38
|
+
retryData: any;
|
|
24
39
|
}
|
|
25
40
|
export declare type GetStatsRequest = APIRequest;
|
|
26
41
|
export declare type CancelJobRequest = APIRequest;
|
package/out/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,oBAAY,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,IAAI,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,oBAAY,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,mBAAmB,CAAC;IACjC,SAAS,EAAE,GAAG,CAAC;CAChB;AAED,oBAAY,eAAe,GAAG,UAAU,CAAC;AACzC,oBAAY,gBAAgB,GAAG,UAAU,CAAC"}
|
package/out/validators.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { APIResponse } from '@forge/api';
|
|
2
|
-
import { CancelJobRequest, GetStatsRequest,
|
|
2
|
+
import { CancelJobRequest, GetStatsRequest, PushEvent, PushRequest, PushResult } from './types';
|
|
3
3
|
export declare const validateQueueKey: (queueName: string) => void;
|
|
4
|
-
export declare const validatePushSettings: (
|
|
5
|
-
export declare
|
|
4
|
+
export declare const validatePushSettings: (event: PushEvent) => void;
|
|
5
|
+
export declare function validatePushEvents(arg: PushEvent | PushEvent[]): PushEvent[];
|
|
6
6
|
export declare const validateGetStatsPayload: (getStatsRequest: GetStatsRequest) => void;
|
|
7
7
|
export declare const validateCancelJobRequest: (cancelJobRequest: CancelJobRequest) => void;
|
|
8
8
|
export declare const validateAPIResponse: (response: APIResponse, expectedSuccessStatus: number) => Promise<void>;
|
|
9
|
-
export declare const validatePushAPIResponse: (response: APIResponse,
|
|
9
|
+
export declare const validatePushAPIResponse: (requestBody: PushRequest, response: APIResponse, result: PushResult) => Promise<void>;
|
|
10
10
|
export declare const validateGetStatsAPIResponse: (response: APIResponse, getStatsRequest: GetStatsRequest) => Promise<void>;
|
|
11
11
|
export declare const validateCancelJobAPIResponse: (response: APIResponse, cancelJobRequest: GetStatsRequest) => Promise<void>;
|
|
12
12
|
//# sourceMappingURL=validators.d.ts.map
|
package/out/validators.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAezC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAMhG,eAAO,MAAM,gBAAgB,cAAe,MAAM,SAIjD,CAAC;AAEF,eAAO,MAAM,oBAAoB,UAAW,SAAS,SAIpD,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,SAAS,EAAE,CA6B5E;AAED,eAAO,MAAM,uBAAuB,oBAAqB,eAAe,SAKvE,CAAC;AAEF,eAAO,MAAM,wBAAwB,qBAAsB,gBAAgB,SAK1E,CAAC;AAEF,eAAO,MAAM,mBAAmB,aAAoB,WAAW,yBAAyB,MAAM,kBA6B7F,CAAC;AAEF,eAAO,MAAM,uBAAuB,gBAAuB,WAAW,YAAY,WAAW,UAAU,UAAU,kBAkChH,CAAC;AAEF,eAAO,MAAM,2BAA2B,aAAoB,WAAW,mBAAmB,eAAe,kBAMxG,CAAC;AAEF,eAAO,MAAM,4BAA4B,aAAoB,WAAW,oBAAoB,eAAe,kBAM1G,CAAC"}
|
package/out/validators.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateCancelJobAPIResponse = exports.validateGetStatsAPIResponse = exports.validatePushAPIResponse = exports.validateAPIResponse = exports.validateCancelJobRequest = exports.validateGetStatsPayload = exports.
|
|
3
|
+
exports.validateCancelJobAPIResponse = exports.validateGetStatsAPIResponse = exports.validatePushAPIResponse = exports.validateAPIResponse = exports.validateCancelJobRequest = exports.validateGetStatsPayload = exports.validatePushEvents = exports.validatePushSettings = exports.validateQueueKey = void 0;
|
|
4
4
|
const errors_1 = require("./errors");
|
|
5
5
|
const text_1 = require("./text");
|
|
6
6
|
const VALID_QUEUE_NAME_PATTERN = /^[a-zA-Z0-9-_]+$/;
|
|
@@ -12,25 +12,36 @@ const validateQueueKey = (queueName) => {
|
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
exports.validateQueueKey = validateQueueKey;
|
|
15
|
-
const validatePushSettings = (
|
|
16
|
-
if ((
|
|
15
|
+
const validatePushSettings = (event) => {
|
|
16
|
+
if ((event.delayInSeconds && event.delayInSeconds > 900) || (event.delayInSeconds && event.delayInSeconds < 0)) {
|
|
17
17
|
throw new errors_1.InvalidPushSettingsError(text_1.Text.error.invalidDelayInSecondsSetting);
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
exports.validatePushSettings = validatePushSettings;
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
function validatePushEvents(arg) {
|
|
22
|
+
const events = Array.isArray(arg) ? arg : [arg];
|
|
23
|
+
if (events.length === 0) {
|
|
23
24
|
throw new errors_1.NoEventsToPushError(text_1.Text.error.noEventsPushed);
|
|
24
25
|
}
|
|
25
|
-
if (
|
|
26
|
+
if (events.length > MAXIMUM_EVENTS) {
|
|
26
27
|
throw new errors_1.TooManyEventsError(text_1.Text.error.maxEventsAllowed(MAXIMUM_EVENTS));
|
|
27
28
|
}
|
|
28
|
-
const
|
|
29
|
+
for (const event of events) {
|
|
30
|
+
if (typeof event !== 'object' || Array.isArray(event) || event === null) {
|
|
31
|
+
throw new errors_1.InvalidPayloadError(text_1.Text.error.invalidEvent);
|
|
32
|
+
}
|
|
33
|
+
if (typeof event.body !== 'object' || Array.isArray(event.body) || event.body === null) {
|
|
34
|
+
throw new errors_1.InvalidPayloadError(text_1.Text.error.invalidEventBody);
|
|
35
|
+
}
|
|
36
|
+
(0, exports.validatePushSettings)(event);
|
|
37
|
+
}
|
|
38
|
+
const payloadSizeKB = Buffer.byteLength(JSON.stringify(events)) / 1024;
|
|
29
39
|
if (payloadSizeKB > MAXIMUM_PAYLOAD_SIZE_KB) {
|
|
30
40
|
throw new errors_1.PayloadTooBigError(text_1.Text.error.maxPayloadAllowed(MAXIMUM_PAYLOAD_SIZE_KB));
|
|
31
41
|
}
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
return events;
|
|
43
|
+
}
|
|
44
|
+
exports.validatePushEvents = validatePushEvents;
|
|
34
45
|
const validateGetStatsPayload = (getStatsRequest) => {
|
|
35
46
|
if (!getStatsRequest.jobId) {
|
|
36
47
|
throw new errors_1.JobDoesNotExistError(text_1.Text.error.jobIdEmpty);
|
|
@@ -67,7 +78,7 @@ const validateAPIResponse = async (response, expectedSuccessStatus) => {
|
|
|
67
78
|
}
|
|
68
79
|
};
|
|
69
80
|
exports.validateAPIResponse = validateAPIResponse;
|
|
70
|
-
const validatePushAPIResponse = async (response,
|
|
81
|
+
const validatePushAPIResponse = async (requestBody, response, result) => {
|
|
71
82
|
if (response.status === 413) {
|
|
72
83
|
const responseBody = await response.json();
|
|
73
84
|
throw new errors_1.PayloadTooBigError(responseBody.errorMessage);
|
|
@@ -75,7 +86,7 @@ const validatePushAPIResponse = async (response, requestBody) => {
|
|
|
75
86
|
if (response.status === 202) {
|
|
76
87
|
const responseBody = await response.json();
|
|
77
88
|
const defaultErrorMessage = 'Failed to process some events.';
|
|
78
|
-
const partialSuccessError = new errors_1.PartialSuccessError(defaultErrorMessage, []);
|
|
89
|
+
const partialSuccessError = new errors_1.PartialSuccessError(defaultErrorMessage, result, []);
|
|
79
90
|
if (responseBody.failedEvents && responseBody.failedEvents.length > 0) {
|
|
80
91
|
partialSuccessError.message = `Failed to process ${responseBody.failedEvents.length} event(s).`;
|
|
81
92
|
partialSuccessError.failedEvents = responseBody.failedEvents.map((failedEvent) => {
|
package/package.json
CHANGED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { appEvents, AppEvent } from '../appEvents';
|
|
2
|
+
import { post } from '../queries';
|
|
3
|
+
import { __requestAtlassianAsApp } from '@forge/api';
|
|
4
|
+
|
|
5
|
+
// Mock the dependencies
|
|
6
|
+
jest.mock('../queries', () => ({
|
|
7
|
+
post: jest.fn()
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
jest.mock('@forge/api', () => ({
|
|
11
|
+
__requestAtlassianAsApp: jest.fn()
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
describe('appEvents', () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
// Clear all mocks before each test
|
|
17
|
+
jest.clearAllMocks();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('publishEvent', () => {
|
|
21
|
+
it('should call post with the correct parameters', async () => {
|
|
22
|
+
// Arrange
|
|
23
|
+
const event: AppEvent = { key: 'test-event' };
|
|
24
|
+
const mockResponse = {
|
|
25
|
+
ok: true,
|
|
26
|
+
json: jest.fn().mockResolvedValue({
|
|
27
|
+
failedEvents: []
|
|
28
|
+
})
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Mock the post function to return a successful response
|
|
32
|
+
(post as jest.Mock).mockResolvedValue(mockResponse);
|
|
33
|
+
|
|
34
|
+
// Act
|
|
35
|
+
const result = await appEvents.publish(event);
|
|
36
|
+
|
|
37
|
+
// Assert
|
|
38
|
+
expect(post).toHaveBeenCalledTimes(1);
|
|
39
|
+
expect(post).toHaveBeenCalledWith(
|
|
40
|
+
'/forge/events/v1/app-events',
|
|
41
|
+
{
|
|
42
|
+
events: [
|
|
43
|
+
{
|
|
44
|
+
key: event.key
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
__requestAtlassianAsApp
|
|
49
|
+
);
|
|
50
|
+
expect(result).toEqual({ type: 'success', failedEvents: [] });
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should return a success result for successful requests', async () => {
|
|
54
|
+
// Arrange
|
|
55
|
+
const event: AppEvent = { key: 'test-event' };
|
|
56
|
+
const mockResponse = {
|
|
57
|
+
ok: true,
|
|
58
|
+
json: jest.fn().mockResolvedValue({
|
|
59
|
+
failedEvents: []
|
|
60
|
+
})
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Mock the post function to return a successful response
|
|
64
|
+
(post as jest.Mock).mockResolvedValue(mockResponse);
|
|
65
|
+
|
|
66
|
+
// Act
|
|
67
|
+
const result = await appEvents.publish(event);
|
|
68
|
+
|
|
69
|
+
// Assert
|
|
70
|
+
expect(result).toEqual({ type: 'success', failedEvents: [] });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should return an error result for failed requests', async () => {
|
|
74
|
+
// Arrange
|
|
75
|
+
const event: AppEvent = { key: 'test-event' };
|
|
76
|
+
const mockResponse = {
|
|
77
|
+
ok: false,
|
|
78
|
+
status: 500,
|
|
79
|
+
json: jest.fn().mockResolvedValue({
|
|
80
|
+
errorMessages: ['Internal server error']
|
|
81
|
+
})
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Mock the post function to return a failed response
|
|
85
|
+
(post as jest.Mock).mockResolvedValue(mockResponse);
|
|
86
|
+
|
|
87
|
+
// Act
|
|
88
|
+
const result = await appEvents.publish(event);
|
|
89
|
+
|
|
90
|
+
// Assert
|
|
91
|
+
expect(result).toEqual({
|
|
92
|
+
type: 'error',
|
|
93
|
+
errorType: 'SERVICE_ERROR',
|
|
94
|
+
errorMessage: 'Internal server error'
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should handle validation errors', async () => {
|
|
99
|
+
// Arrange
|
|
100
|
+
const event: AppEvent = { key: 'test-event' };
|
|
101
|
+
const mockResponse = {
|
|
102
|
+
ok: false,
|
|
103
|
+
status: 400,
|
|
104
|
+
json: jest.fn().mockResolvedValue({
|
|
105
|
+
errorMessages: ['Invalid event type']
|
|
106
|
+
})
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Mock the post function to return a validation error response
|
|
110
|
+
(post as jest.Mock).mockResolvedValue(mockResponse);
|
|
111
|
+
|
|
112
|
+
// Act
|
|
113
|
+
const result = await appEvents.publish(event);
|
|
114
|
+
|
|
115
|
+
// Assert
|
|
116
|
+
expect(result).toEqual({
|
|
117
|
+
type: 'error',
|
|
118
|
+
errorType: 'VALIDATION_ERROR',
|
|
119
|
+
errorMessage: 'Invalid event type'
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should handle errors object in the error response', async () => {
|
|
124
|
+
// Arrange
|
|
125
|
+
const event: AppEvent = { key: 'test-event' };
|
|
126
|
+
const errorResponse = {
|
|
127
|
+
errorMessages: [],
|
|
128
|
+
errors: { key: 'Event key is required' }
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const mockResponse = {
|
|
132
|
+
ok: false,
|
|
133
|
+
status: 400,
|
|
134
|
+
json: jest.fn().mockResolvedValue(errorResponse)
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Mock the post function to return an error response with errors object
|
|
138
|
+
(post as jest.Mock).mockResolvedValue(mockResponse);
|
|
139
|
+
|
|
140
|
+
// Act
|
|
141
|
+
const result = await appEvents.publish(event);
|
|
142
|
+
|
|
143
|
+
// Assert
|
|
144
|
+
expect(result).toEqual({
|
|
145
|
+
type: 'error',
|
|
146
|
+
errorType: 'VALIDATION_ERROR',
|
|
147
|
+
errorMessage: 'key: Event key is required'
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should use OTHER as errorType for unknown status codes', async () => {
|
|
152
|
+
// Arrange
|
|
153
|
+
const event: AppEvent = { key: 'test-event' };
|
|
154
|
+
const mockResponse = {
|
|
155
|
+
ok: false,
|
|
156
|
+
status: 418, // I'm a teapot
|
|
157
|
+
json: jest.fn().mockResolvedValue({
|
|
158
|
+
errorMessages: ['I refuse to brew coffee']
|
|
159
|
+
})
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Mock the post function to return a response with unknown status code
|
|
163
|
+
(post as jest.Mock).mockResolvedValue(mockResponse);
|
|
164
|
+
|
|
165
|
+
// Act
|
|
166
|
+
const result = await appEvents.publish(event);
|
|
167
|
+
|
|
168
|
+
// Assert
|
|
169
|
+
expect(result).toEqual({
|
|
170
|
+
type: 'error',
|
|
171
|
+
errorType: 'OTHER',
|
|
172
|
+
errorMessage: 'I refuse to brew coffee'
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should handle empty error messages', async () => {
|
|
177
|
+
// Arrange
|
|
178
|
+
const event: AppEvent = { key: 'test-event' };
|
|
179
|
+
const mockResponse = {
|
|
180
|
+
ok: false,
|
|
181
|
+
status: 500,
|
|
182
|
+
json: jest.fn().mockResolvedValue({
|
|
183
|
+
errorMessages: []
|
|
184
|
+
})
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// Mock the post function to return a response with empty error messages
|
|
188
|
+
(post as jest.Mock).mockResolvedValue(mockResponse);
|
|
189
|
+
|
|
190
|
+
// Act
|
|
191
|
+
const result = await appEvents.publish(event);
|
|
192
|
+
|
|
193
|
+
// Assert
|
|
194
|
+
expect(result).toEqual({
|
|
195
|
+
type: 'error',
|
|
196
|
+
errorType: 'SERVICE_ERROR',
|
|
197
|
+
errorMessage: '{"errorMessages":[]}'
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
});
|