@node-idempotency/fastify
Version:
fastify plugin that provides Race-Condition free idempotency for HTTP requests, preventing unintended duplicate operations.
88 lines • 3.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.idempotencyAsPlugin = void 0;
const shared_1 = require("@node-idempotency/shared");
const core_1 = require("@node-idempotency/core");
const setHeaders = (response, headers) => {
Object.keys(headers).forEach((key) => {
if (headers[key]) {
void response.header(key, headers[key]);
}
});
};
const onResponse = async (request, reply, payload, nodeIdempotency) => {
const idempotencyReq = {
headers: request.headers,
body: request.body,
path: request.url,
method: request.method,
};
const { statusCode } = reply;
const additional = { statusCode };
Object.values(shared_1.headers2Cache).forEach((header) => {
const head = reply.getHeader(header);
if (head) {
additional[header] = head;
}
});
const res = {
additional,
...(statusCode < 400 ? { body: payload } : { error: payload }),
};
await nodeIdempotency.onResponse(idempotencyReq, res);
};
const onRequest = async (request, reply, nodeIdempotency) => {
const idempotencyReq = {
headers: request.headers,
body: request.body,
path: request.url,
method: request.method,
};
try {
const idempotencyResponse = await nodeIdempotency.onRequest(idempotencyReq);
if (!idempotencyResponse) {
return;
}
if (idempotencyResponse.additional?.statusCode) {
const { statusCode } = idempotencyResponse.additional;
void reply.status(statusCode);
}
const headers = Object.values(shared_1.headers2Cache).reduce((res, cur) => {
if (idempotencyResponse?.additional?.[cur]) {
res[cur] = idempotencyResponse.additional[cur];
}
return res;
}, {});
setHeaders(reply, {
...headers,
[shared_1.HTTPHeaderEnum.idempotentReplayed]: "true",
});
return await reply.send(idempotencyResponse.body || idempotencyResponse.error);
}
catch (err) {
if (err instanceof core_1.IdempotencyError) {
const status = shared_1.idempotency2HttpCodeMap[err.code] || 500;
if (err.code === core_1.IdempotencyErrorCodes.REQUEST_IN_PROGRESS) {
setHeaders(reply, { [shared_1.HTTPHeaderEnum.retryAfter]: "1" });
}
return await reply.status(status).send(err);
}
}
};
const idempotencyAsPlugin = async (fastify, options) => {
const storageAdapter = await (0, shared_1.buildStorageAdapter)(options.storage);
const idempotency = new core_1.Idempotency(storageAdapter, options);
fastify.addHook("preHandler", async (request, reply) => {
await onRequest(request, reply, idempotency);
});
fastify.addHook("onSend", async (request, reply, payload) => {
await onResponse(request, reply, payload, idempotency);
});
fastify.addHook("onClose", async () => {
if (typeof storageAdapter.disconnect === "function") {
await storageAdapter.disconnect();
}
});
};
exports.idempotencyAsPlugin = idempotencyAsPlugin;
//# sourceMappingURL=idempotent-fastify.js.map