Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@forge/events

Package Overview
Dependencies
Maintainers
8
Versions
289
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@forge/events - npm Package Compare versions

Comparing version 0.2.0-next.0 to 0.2.0-next.1

out/__test__/jobProgress.test.d.ts

6

CHANGELOG.md
# @forge/events
## 0.2.0-next.1
### Minor Changes
- a056b40: Add Queue.getStats()
## 0.2.0-next.0

@@ -4,0 +10,0 @@

3

out/errors.d.ts

@@ -29,2 +29,5 @@ import { FailedEvent } from './types';

}
export declare class JobDoesNotExistError extends Error {
constructor(message: string);
}
//# sourceMappingURL=errors.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InternalServerError = exports.PartialSuccessError = exports.RateLimitError = exports.NoEventsToPushError = exports.PayloadTooBigError = exports.TooManyEventsError = exports.InvalidQueueNameError = exports.InvalidPushSettingsError = void 0;
exports.JobDoesNotExistError = exports.InternalServerError = exports.PartialSuccessError = exports.RateLimitError = exports.NoEventsToPushError = exports.PayloadTooBigError = exports.TooManyEventsError = exports.InvalidQueueNameError = exports.InvalidPushSettingsError = void 0;
class InvalidPushSettingsError extends Error {

@@ -55,1 +55,7 @@ constructor(message) {

exports.InternalServerError = InternalServerError;
class JobDoesNotExistError extends Error {
constructor(message) {
super(message);
}
}
exports.JobDoesNotExistError = JobDoesNotExistError;

3

out/index.d.ts
export { Queue } from './queue';
export { InvalidQueueNameError, TooManyEventsError, PayloadTooBigError, NoEventsToPushError, RateLimitError, PartialSuccessError, InternalServerError } from './errors';
export { InvalidQueueNameError, TooManyEventsError, PayloadTooBigError, NoEventsToPushError, RateLimitError, PartialSuccessError, InternalServerError, JobDoesNotExistError } from './errors';
export { JobProgress } from './jobProgress';
//# sourceMappingURL=index.d.ts.map

@@ -13,1 +13,4 @@ "use strict";

Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return errors_1.InternalServerError; } });
Object.defineProperty(exports, "JobDoesNotExistError", { enumerable: true, get: function () { return errors_1.JobDoesNotExistError; } });
var jobProgress_1 = require("./jobProgress");
Object.defineProperty(exports, "JobProgress", { enumerable: true, get: function () { return jobProgress_1.JobProgress; } });

@@ -1,4 +0,5 @@

import { PushBodyParams, APIRequest } from './types';
export declare const getPushBody: (params: PushBodyParams) => APIRequest;
import { APIRequest, APIResponse, FetchMethod } from './types';
export declare const PUSH_PATH = "/webhook/queue/publish/{cloudId}/{environmentId}/{appId}/{appVersion}";
export declare const GET_STATS_PATH = "/webhook/queue/stats/{cloudId}/{environmentId}/{appId}/{appVersion}";
export declare const post: (endpoint: string, body: APIRequest, apiClient: FetchMethod) => Promise<APIResponse>;
//# sourceMappingURL=queries.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PUSH_PATH = exports.getPushBody = void 0;
exports.getPushBody = (params) => ({
queueName: params.queueName,
type: params.type,
schema: params.schema,
payload: params.payload,
time: new Date().toISOString()
});
exports.post = exports.GET_STATS_PATH = exports.PUSH_PATH = void 0;
exports.PUSH_PATH = '/webhook/queue/publish/{cloudId}/{environmentId}/{appId}/{appVersion}';
exports.GET_STATS_PATH = '/webhook/queue/stats/{cloudId}/{environmentId}/{appId}/{appVersion}';
exports.post = async (endpoint, body, apiClient) => {
const request = {
method: 'POST',
body: JSON.stringify(body),
headers: {
'content-type': 'application/json'
}
};
return await apiClient(endpoint, request);
};

@@ -1,2 +0,3 @@

import { APIResponse, FetchMethod, Payload, QueueParams, PushSettings } from './types';
import { FetchMethod, Payload, QueueParams, PushSettings } from './types';
import { JobProgress } from './jobProgress';
export declare class Queue {

@@ -6,6 +7,5 @@ private readonly apiClient;

constructor(queueParams: QueueParams, apiClient?: FetchMethod);
push(payloads: Payload | Payload[], pushSettings?: PushSettings): Promise<APIResponse>;
private query;
private buildRequest;
push(payloads: Payload | Payload[], pushSettings?: PushSettings): Promise<string>;
getJob(jobId: string): JobProgress;
}
//# sourceMappingURL=queue.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Queue = void 0;
const tslib_1 = require("tslib");
const queries_1 = require("./queries");
const validators_1 = require("./validators");
async function getResponseBody(response, body) {
await validators_1.validateAPIResponse(response, body);
return response;
}
const v4_1 = tslib_1.__importDefault(require("uuid/v4"));
const jobProgress_1 = require("./jobProgress");
class Queue {
constructor(queueParams, apiClient) {
validators_1.validateQueueName(queueParams.key);
validators_1.validateQueueKey(queueParams.key);
this.queueParams = queueParams;

@@ -18,7 +17,11 @@ this.apiClient = apiClient || global.api.asApp().__requestAtlassian;

validators_1.validatePayloads(payloads);
const queryParams = {
const queueName = this.queueParams.key;
const jobId = v4_1.default();
const pushRequest = {
queueName: queueName,
jobId: jobId,
type: 'avi:forge:app:event',
schema: 'ari:cloud:ecosystem::forge/app-event',
payload: Array.isArray(payloads) ? payloads : [payloads],
queueName: this.queueParams.key,
schema: 'ari:cloud:ecosystem::forge/app-event',
type: 'avi:forge:app:event'
time: new Date().toISOString()
};

@@ -28,22 +31,13 @@ if (pushSettings) {

if (pushSettings.delayInSeconds) {
queryParams.delayInSeconds = pushSettings.delayInSeconds;
pushRequest.delayInSeconds = pushSettings.delayInSeconds;
}
}
const requestBody = queries_1.getPushBody(queryParams);
return this.query(queries_1.PUSH_PATH, requestBody);
const response = await queries_1.post(queries_1.PUSH_PATH, pushRequest, this.apiClient);
await validators_1.validatePushAPIResponse(response, pushRequest);
return `${queueName}#${jobId}`;
}
async query(endpoint, body) {
const response = await this.apiClient(endpoint, this.buildRequest(body));
return await getResponseBody(response, body);
getJob(jobId) {
return new jobProgress_1.JobProgress(jobId, this.apiClient);
}
buildRequest(requestBody) {
return {
method: 'POST',
body: JSON.stringify(requestBody),
headers: {
'content-type': 'application/json'
}
};
}
}
exports.Queue = Queue;

@@ -13,5 +13,4 @@ import { RequestInit, Response } from 'node-fetch';

}
export interface PushBodyParams {
export interface PushRequest extends APIRequest {
payload: Payload[];
queueName: string;
schema: string;

@@ -21,3 +20,5 @@ type: string;

}
export interface APIRequest extends PushBodyParams {
export interface APIRequest {
queueName: string;
jobId: string;
time: string;

@@ -29,2 +30,3 @@ }

}
export declare type GetStatsRequest = APIRequest;
//# sourceMappingURL=types.d.ts.map

@@ -1,6 +0,8 @@

import { APIResponse, Payload, APIRequest, PushSettings } from './types';
export declare const validateQueueName: (queueName: string) => void;
import { APIResponse, GetStatsRequest, Payload, PushRequest, PushSettings } from './types';
export declare const validateQueueKey: (queueName: string) => void;
export declare const validatePushSettings: (settings: PushSettings) => void;
export declare const validatePayloads: (payloads: Payload | Payload[]) => void;
export declare const validateAPIResponse: (response: APIResponse, requestBody: APIRequest) => Promise<void>;
export declare const validateAPIResponse: (response: APIResponse, expectedSuccessStatus: number) => Promise<void>;
export declare const validatePushAPIResponse: (response: APIResponse, requestBody: PushRequest) => Promise<void>;
export declare const validateGetStatsAPIResponse: (response: APIResponse, getStatsRequest: GetStatsRequest) => Promise<void>;
//# sourceMappingURL=validators.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateAPIResponse = exports.validatePayloads = exports.validatePushSettings = exports.validateQueueName = void 0;
exports.validateGetStatsAPIResponse = exports.validatePushAPIResponse = exports.validateAPIResponse = exports.validatePayloads = exports.validatePushSettings = exports.validateQueueKey = void 0;
const errors_1 = require("./errors");

@@ -8,5 +8,5 @@ const VALID_QUEUE_NAME_PATTERN = /^[a-zA-Z0-9-_]+$/;

const MAXIMUM_PAYLOAD_SIZE_KB = 200;
exports.validateQueueName = (queueName) => {
exports.validateQueueKey = (queueName) => {
if (!queueName || !VALID_QUEUE_NAME_PATTERN.test(queueName)) {
throw new errors_1.InvalidQueueNameError('Queue name can only contain alphanumeric, dash and underscore characters');
throw new errors_1.InvalidQueueNameError('Queue names can only contain alphanumeric characters and the dash and underscore characters.');
}

@@ -31,6 +31,13 @@ };

};
exports.validateAPIResponse = async (response, requestBody) => {
exports.validateAPIResponse = async (response, expectedSuccessStatus) => {
if (response.status === 429) {
throw new errors_1.RateLimitError(`Too many requests`);
}
if (response.status != expectedSuccessStatus && response.status) {
const responseBody = await response.json();
const errorMessage = responseBody.message ? `: ${responseBody.message}` : '';
throw new errors_1.InternalServerError(`${response.status} ${response.statusText}${errorMessage}`, responseBody.code, responseBody.details);
}
};
exports.validatePushAPIResponse = async (response, requestBody) => {
if (response.status === 413) {

@@ -42,4 +49,7 @@ const responseBody = await response.json();

const responseBody = await response.json();
const defaultErrorMessage = 'Failed to process some events.';
const partialSuccessError = new errors_1.PartialSuccessError(defaultErrorMessage, []);
if (responseBody.failedEvents && responseBody.failedEvents.length > 0) {
throw new errors_1.PartialSuccessError(`Failed to process ${responseBody.failedEvents.length} events`, responseBody.failedEvents.map((failedEvent) => {
partialSuccessError.message = `Failed to process ${responseBody.failedEvents.length} event(s).`;
partialSuccessError.failedEvents = responseBody.failedEvents.map((failedEvent) => {
return {

@@ -49,13 +59,19 @@ errorMessage: failedEvent.errorMessage,

};
}));
});
}
else {
throw new errors_1.PartialSuccessError(`Failed to process events`, []);
if (responseBody.errorMessage) {
partialSuccessError.message =
partialSuccessError.message !== defaultErrorMessage
? `${partialSuccessError.message} ${responseBody.errorMessage}`
: responseBody.errorMessage;
}
throw partialSuccessError;
}
if (response.status != 201 && response.status) {
const responseBody = await response.json();
const errorMessage = responseBody.message ? `: ${responseBody.message}` : '';
throw new errors_1.InternalServerError(`${response.status} ${response.statusText}${errorMessage}`, responseBody.code, responseBody.details);
await exports.validateAPIResponse(response, 201);
};
exports.validateGetStatsAPIResponse = async (response, getStatsRequest) => {
if (response.status === 404) {
throw new errors_1.JobDoesNotExistError(`The job ${getStatsRequest.jobId} doesn't exist for the queue ${getStatsRequest.queueName}`);
}
await exports.validateAPIResponse(response, 200);
};
{
"name": "@forge/events",
"version": "0.2.0-next.0",
"version": "0.2.0-next.1",
"description": "Forge Async Event methods",

@@ -5,0 +5,0 @@ "author": "Atlassian",

@@ -31,3 +31,3 @@ Library for asynchronous data processing.

async function demo() {
const queue = new Queue({queueName: "queue-name"}, apiClient);
const queue = new Queue({key: "queue-name"}, apiClient);
const payloads = {

@@ -34,0 +34,0 @@ page: 1

@@ -58,1 +58,7 @@ import { FailedEvent } from './types';

}
export class JobDoesNotExistError extends Error {
constructor(message: string) {
super(message);
}
}

@@ -9,3 +9,5 @@ export { Queue } from './queue';

PartialSuccessError,
InternalServerError
InternalServerError,
JobDoesNotExistError
} from './errors';
export { JobProgress } from './jobProgress';

@@ -1,11 +0,16 @@

import { PushBodyParams, APIRequest } from './types';
import { APIRequest, APIResponse, FetchMethod } from './types';
export const getPushBody = (params: PushBodyParams): APIRequest => ({
queueName: params.queueName,
type: params.type,
schema: params.schema,
payload: params.payload,
time: new Date().toISOString()
});
export const PUSH_PATH = '/webhook/queue/publish/{cloudId}/{environmentId}/{appId}/{appVersion}';
export const GET_STATS_PATH = '/webhook/queue/stats/{cloudId}/{environmentId}/{appId}/{appVersion}';
export const PUSH_PATH = '/webhook/queue/publish/{cloudId}/{environmentId}/{appId}/{appVersion}';
export const post = async (endpoint: string, body: APIRequest, apiClient: FetchMethod): Promise<APIResponse> => {
const request = {
method: 'POST',
body: JSON.stringify(body),
headers: {
'content-type': 'application/json'
}
};
return await apiClient(endpoint, request);
};

@@ -1,10 +0,7 @@

import { getPushBody, PUSH_PATH } from './queries';
import { validateAPIResponse, validatePayloads, validateQueueName, validatePushSettings } from './validators';
import { APIResponse, FetchMethod, Payload, PushBodyParams, QueueParams, APIRequest, PushSettings } from './types';
import { PUSH_PATH, post } from './queries';
import { validatePushAPIResponse, validatePayloads, validateQueueKey, validatePushSettings } from './validators';
import { FetchMethod, Payload, QueueParams, PushSettings, PushRequest } from './types';
import uuid from 'uuid/v4';
import { JobProgress } from './jobProgress';
async function getResponseBody(response: APIResponse, body: any): Promise<APIResponse> {
await validateAPIResponse(response, body);
return response;
}
export class Queue {

@@ -15,3 +12,3 @@ private readonly apiClient: FetchMethod;

constructor(queueParams: QueueParams, apiClient?: FetchMethod) {
validateQueueName(queueParams.key);
validateQueueKey(queueParams.key);
this.queueParams = queueParams;

@@ -21,10 +18,14 @@ this.apiClient = apiClient || (global as any).api.asApp().__requestAtlassian;

async push(payloads: Payload | Payload[], pushSettings?: PushSettings): Promise<APIResponse> {
async push(payloads: Payload | Payload[], pushSettings?: PushSettings): Promise<string> {
validatePayloads(payloads);
const queueName = this.queueParams.key;
const jobId = uuid();
const queryParams: PushBodyParams = {
const pushRequest: PushRequest = {
queueName: queueName,
jobId: jobId,
type: 'avi:forge:app:event',
schema: 'ari:cloud:ecosystem::forge/app-event',
payload: Array.isArray(payloads) ? payloads : [payloads],
queueName: this.queueParams.key,
schema: 'ari:cloud:ecosystem::forge/app-event',
type: 'avi:forge:app:event'
time: new Date().toISOString()
};

@@ -35,24 +36,14 @@

if (pushSettings.delayInSeconds) {
queryParams.delayInSeconds = pushSettings.delayInSeconds;
pushRequest.delayInSeconds = pushSettings.delayInSeconds;
}
}
const requestBody = getPushBody(queryParams);
return this.query(PUSH_PATH, requestBody);
const response = await post(PUSH_PATH, pushRequest, this.apiClient);
await validatePushAPIResponse(response, pushRequest);
return `${queueName}#${jobId}`;
}
private async query(endpoint: string, body: APIRequest): Promise<APIResponse> {
const response = await this.apiClient(endpoint, this.buildRequest(body));
return await getResponseBody(response, body);
getJob(jobId: string): JobProgress {
return new JobProgress(jobId, this.apiClient);
}
private buildRequest(requestBody: APIRequest) {
return {
method: 'POST',
body: JSON.stringify(requestBody),
headers: {
'content-type': 'application/json'
}
};
}
}

@@ -14,5 +14,4 @@ import { RequestInit, Response } from 'node-fetch';

export interface PushBodyParams {
export interface PushRequest extends APIRequest {
payload: Payload[];
queueName: string;
schema: string;

@@ -23,3 +22,5 @@ type: string;

export interface APIRequest extends PushBodyParams {
export interface APIRequest {
queueName: string;
jobId: string;
time: string;

@@ -32,1 +33,3 @@ }

}
export type GetStatsRequest = APIRequest;
import {
InternalServerError,
InvalidQueueNameError,
JobDoesNotExistError,
NoEventsToPushError,

@@ -11,3 +12,3 @@ PartialSuccessError,

} from './errors';
import { APIResponse, Payload, APIRequest, PushSettings } from './types';
import { APIResponse, GetStatsRequest, Payload, PushRequest, PushSettings } from './types';

@@ -18,5 +19,7 @@ const VALID_QUEUE_NAME_PATTERN = /^[a-zA-Z0-9-_]+$/;

export const validateQueueName = (queueName: string) => {
export const validateQueueKey = (queueName: string) => {
if (!queueName || !VALID_QUEUE_NAME_PATTERN.test(queueName)) {
throw new InvalidQueueNameError('Queue name can only contain alphanumeric, dash and underscore characters');
throw new InvalidQueueNameError(
'Queue names can only contain alphanumeric characters and the dash and underscore characters.'
);
}

@@ -46,3 +49,3 @@ };

export const validateAPIResponse = async (response: APIResponse, requestBody: APIRequest) => {
export const validateAPIResponse = async (response: APIResponse, expectedSuccessStatus: number) => {
if (response.status === 429) {

@@ -52,2 +55,15 @@ throw new RateLimitError(`Too many requests`);

if (response.status != expectedSuccessStatus && response.status) {
//Catch all errors from server that we have not handled
const responseBody = await response.json();
const errorMessage = responseBody.message ? `: ${responseBody.message}` : '';
throw new InternalServerError(
`${response.status} ${response.statusText}${errorMessage}`,
responseBody.code,
responseBody.details
);
}
};
export const validatePushAPIResponse = async (response: APIResponse, requestBody: PushRequest) => {
if (response.status === 413) {

@@ -61,27 +77,37 @@ //Server can return this error response if it has a different max payload size and max number of events limits

const responseBody = await response.json();
const defaultErrorMessage = 'Failed to process some events.';
const partialSuccessError = new PartialSuccessError(defaultErrorMessage, []);
if (responseBody.failedEvents && responseBody.failedEvents.length > 0) {
throw new PartialSuccessError(
`Failed to process ${responseBody.failedEvents.length} events`,
responseBody.failedEvents.map((failedEvent: any) => {
return {
errorMessage: failedEvent.errorMessage,
payload: requestBody.payload[+failedEvent.index]
};
})
);
} else {
throw new PartialSuccessError(`Failed to process events`, []);
partialSuccessError.message = `Failed to process ${responseBody.failedEvents.length} event(s).`;
partialSuccessError.failedEvents = responseBody.failedEvents.map((failedEvent: any) => {
return {
errorMessage: failedEvent.errorMessage,
payload: requestBody.payload[+failedEvent.index]
};
});
}
if (responseBody.errorMessage) {
//Append any extra error message from backend
partialSuccessError.message =
partialSuccessError.message !== defaultErrorMessage
? `${partialSuccessError.message} ${responseBody.errorMessage}`
: responseBody.errorMessage;
}
throw partialSuccessError;
}
if (response.status != 201 && response.status) {
//Catch all errors from server that we have not handled
const responseBody = await response.json();
const errorMessage = responseBody.message ? `: ${responseBody.message}` : '';
throw new InternalServerError(
`${response.status} ${response.statusText}${errorMessage}`,
responseBody.code,
responseBody.details
await validateAPIResponse(response, 201);
};
export const validateGetStatsAPIResponse = async (response: APIResponse, getStatsRequest: GetStatsRequest) => {
if (response.status === 404) {
throw new JobDoesNotExistError(
`The job ${getStatsRequest.jobId} doesn't exist for the queue ${getStatsRequest.queueName}`
);
}
await validateAPIResponse(response, 200);
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc