@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.
Files changed (48) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +32 -26
  3. package/out/__test__/appEvents.test.d.ts +2 -0
  4. package/out/__test__/appEvents.test.d.ts.map +1 -0
  5. package/out/__test__/appEvents.test.js +137 -0
  6. package/out/__test__/jobProgress.test.js +3 -5
  7. package/out/__test__/queue.test.js +88 -39
  8. package/out/__test__/utils.js +1 -1
  9. package/out/appEvents.d.ts +22 -0
  10. package/out/appEvents.d.ts.map +1 -0
  11. package/out/appEvents.js +50 -0
  12. package/out/errors.d.ts +17 -19
  13. package/out/errors.d.ts.map +1 -1
  14. package/out/errors.js +21 -34
  15. package/out/index.d.ts +3 -1
  16. package/out/index.d.ts.map +1 -1
  17. package/out/index.js +3 -1
  18. package/out/jobProgress.d.ts +8 -3
  19. package/out/jobProgress.d.ts.map +1 -1
  20. package/out/jobProgress.js +2 -2
  21. package/out/queries.d.ts +1 -2
  22. package/out/queries.d.ts.map +1 -1
  23. package/out/queue.d.ts +2 -2
  24. package/out/queue.d.ts.map +1 -1
  25. package/out/queue.js +7 -12
  26. package/out/text.d.ts +2 -0
  27. package/out/text.d.ts.map +1 -1
  28. package/out/text.js +2 -0
  29. package/out/types.d.ts +24 -9
  30. package/out/types.d.ts.map +1 -1
  31. package/out/validators.d.ts +4 -4
  32. package/out/validators.d.ts.map +1 -1
  33. package/out/validators.js +22 -11
  34. package/package.json +1 -1
  35. package/src/__test__/appEvents.test.ts +201 -0
  36. package/src/__test__/jobProgress.test.ts +3 -5
  37. package/src/__test__/queue.test.ts +102 -43
  38. package/src/__test__/utils.ts +1 -1
  39. package/src/appEvents.ts +107 -0
  40. package/src/errors.ts +20 -43
  41. package/src/index.ts +11 -1
  42. package/src/jobProgress.ts +11 -5
  43. package/src/queries.ts +2 -2
  44. package/src/queue.ts +9 -15
  45. package/src/text.ts +2 -0
  46. package/src/types.ts +30 -7
  47. package/src/validators.ts +27 -10
  48. 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 InvalidPushSettingsError extends Error {
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 Error {
11
- constructor(message) {
12
- super(message);
13
- }
13
+ class InvalidQueueNameError extends EventsError {
14
14
  }
15
15
  exports.InvalidQueueNameError = InvalidQueueNameError;
16
- class TooManyEventsError extends Error {
17
- constructor(message) {
18
- super(message);
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 Error {
23
- constructor(message) {
24
- super(message);
25
- }
22
+ class PayloadTooBigError extends EventsError {
26
23
  }
27
24
  exports.PayloadTooBigError = PayloadTooBigError;
28
- class NoEventsToPushError extends Error {
29
- constructor(message) {
30
- super(message);
31
- }
25
+ class NoEventsToPushError extends EventsError {
32
26
  }
33
27
  exports.NoEventsToPushError = NoEventsToPushError;
34
- class RateLimitError extends Error {
35
- constructor(message) {
36
- super(message);
37
- }
28
+ class RateLimitError extends EventsError {
38
29
  }
39
30
  exports.RateLimitError = RateLimitError;
40
- class PartialSuccessError extends Error {
41
- constructor(message, failedEvents) {
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 Error {
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 Error {
59
- constructor(message) {
60
- super(message);
61
- }
51
+ class JobDoesNotExistError extends EventsError {
62
52
  }
63
53
  exports.JobDoesNotExistError = JobDoesNotExistError;
64
- class InvocationLimitReachedError extends Error {
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
@@ -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;AAC5C,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"}
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; } });
@@ -1,9 +1,14 @@
1
- import { FetchMethod, APIResponse } from '@forge/api';
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<APIResponse>;
7
- cancel(): Promise<APIResponse>;
11
+ getStats(): Promise<JobStats>;
12
+ cancel(): Promise<void>;
8
13
  }
9
14
  //# sourceMappingURL=jobProgress.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jobProgress.d.ts","sourceRoot":"","sources":["../src/jobProgress.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAU/E,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,WAAW,CAAC;IAehC,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC;CAcrC"}
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"}
@@ -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
- return response;
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: APIRequest, apiClient: FetchMethod) => Promise<APIResponse>;
5
+ export declare const post: (endpoint: string, body: unknown, apiClient: FetchMethod) => Promise<APIResponse>;
7
6
  //# sourceMappingURL=queries.d.ts.map
@@ -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;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,eAAO,MAAM,SAAS,6EAA6E,CAAC;AACpG,eAAO,MAAM,cAAc,2EAA2E,CAAC;AACvG,eAAO,MAAM,eAAe,4EAA4E,CAAC;AAEzG,eAAO,MAAM,IAAI,aAAoB,MAAM,QAAQ,UAAU,aAAa,WAAW,KAAG,QAAQ,WAAW,CAU1G,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 { Payload, QueueParams, PushSettings } from './types';
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(payloads: Payload | Payload[], pushSettings?: PushSettings): Promise<string>;
8
+ push(events: PushEvent | PushEvent[]): Promise<PushResult>;
9
9
  getJob(jobId: string): JobProgress;
10
10
  }
11
11
  //# sourceMappingURL=queue.d.ts.map
@@ -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,OAAO,EAAE,WAAW,EAAE,YAAY,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,QAAQ,EAAE,OAAO,GAAG,OAAO,EAAE,EAAE,YAAY,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA0BvF,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW;CAGnC"}
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(payloads, pushSettings) {
18
- (0, validators_1.validatePushPayloads)(payloads);
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: Array.isArray(payloads) ? payloads : [payloads],
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
- await (0, validators_1.validatePushAPIResponse)(response, pushRequest);
37
- return `${queueName}#${jobId}`;
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;;;;2CAIsB,MAAM,KAAG,MAAM;4CAEd,MAAM,KAAG,MAAM;;;;;gCAK3B,MAAM,aAAa,MAAM,KAAG,MAAM;;CAG7D,CAAC"}
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
- export declare type Payload = string | number | boolean | {
2
- [key: string]: Payload;
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: Payload[];
7
+ payload: PushEvent[];
12
8
  schema: string;
13
9
  type: string;
14
- delayInSeconds?: number;
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
- payload: Payload;
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;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oBAAY,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAC;CACxB;AACD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,oBAAY,eAAe,GAAG,UAAU,CAAC;AACzC,oBAAY,gBAAgB,GAAG,UAAU,CAAC"}
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"}
@@ -1,12 +1,12 @@
1
1
  import { APIResponse } from '@forge/api';
2
- import { CancelJobRequest, GetStatsRequest, Payload, PushRequest, PushSettings } from './types';
2
+ import { CancelJobRequest, GetStatsRequest, PushEvent, PushRequest, PushResult } from './types';
3
3
  export declare const validateQueueKey: (queueName: string) => void;
4
- export declare const validatePushSettings: (settings: PushSettings) => void;
5
- export declare const validatePushPayloads: (payloads: Payload | Payload[]) => void;
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, requestBody: PushRequest) => Promise<void>;
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
@@ -1 +1 @@
1
- {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAczC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMhG,eAAO,MAAM,gBAAgB,cAAe,MAAM,SAIjD,CAAC;AAEF,eAAO,MAAM,oBAAoB,aAAc,YAAY,SAI1D,CAAC;AAEF,eAAO,MAAM,oBAAoB,aAAc,OAAO,GAAG,OAAO,EAAE,SAajE,CAAC;AAEF,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,aAAoB,WAAW,eAAe,WAAW,kBAkC5F,CAAC;AAEF,eAAO,MAAM,2BAA2B,aAAoB,WAAW,mBAAmB,eAAe,kBAMxG,CAAC;AAEF,eAAO,MAAM,4BAA4B,aAAoB,WAAW,oBAAoB,eAAe,kBAM1G,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.validatePushPayloads = exports.validatePushSettings = exports.validateQueueKey = void 0;
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 = (settings) => {
16
- if ((settings.delayInSeconds && settings.delayInSeconds > 900) || settings.delayInSeconds < 0) {
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
- const validatePushPayloads = (payloads) => {
22
- if (!payloads || (Array.isArray(payloads) && payloads.length === 0)) {
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 (Array.isArray(payloads) && payloads.length > MAXIMUM_EVENTS) {
26
+ if (events.length > MAXIMUM_EVENTS) {
26
27
  throw new errors_1.TooManyEventsError(text_1.Text.error.maxEventsAllowed(MAXIMUM_EVENTS));
27
28
  }
28
- const payloadSizeKB = Buffer.byteLength(JSON.stringify(payloads)) / 1024;
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
- exports.validatePushPayloads = validatePushPayloads;
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, requestBody) => {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/events",
3
- "version": "1.0.3",
3
+ "version": "2.0.0-next.1",
4
4
  "description": "Forge Async Event methods",
5
5
  "author": "Atlassian",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -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
+ });