UNPKG

nats

Version:

Node.js client for NATS, a lightweight, high-performance cloud native messaging system

200 lines 7.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkJsErrorCode = exports.isTerminal409 = exports.setMaxWaitingToFail = exports.Js409Errors = exports.checkJsError = exports.newJsErrorMsg = exports.isHeartbeatMsg = exports.isFlowControlMsg = exports.validName = exports.validateName = exports.minValidation = exports.validateStreamName = exports.validateDurableName = void 0; /* * Copyright 2021-2024 The NATS Authors * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const encoders_1 = require("../nats-base-client/encoders"); const headers_1 = require("../nats-base-client/headers"); const msg_1 = require("../nats-base-client/msg"); const core_1 = require("../nats-base-client/core"); function validateDurableName(name) { return minValidation("durable", name); } exports.validateDurableName = validateDurableName; function validateStreamName(name) { return minValidation("stream", name); } exports.validateStreamName = validateStreamName; function minValidation(context, name = "") { // minimum validation on streams/consumers matches nats cli if (name === "") { throw Error(`${context} name required`); } const bad = [".", "*", ">", "/", "\\", " ", "\t", "\n", "\r"]; bad.forEach((v) => { if (name.indexOf(v) !== -1) { // make the error have a meaningful character switch (v) { case "\n": v = "\\n"; break; case "\r": v = "\\r"; break; case "\t": v = "\\t"; break; default: // nothing } throw Error(`invalid ${context} name - ${context} name cannot contain '${v}'`); } }); return ""; } exports.minValidation = minValidation; function validateName(context, name = "") { if (name === "") { throw Error(`${context} name required`); } const m = validName(name); if (m.length) { throw new Error(`invalid ${context} name - ${context} name ${m}`); } } exports.validateName = validateName; function validName(name = "") { if (name === "") { throw Error(`name required`); } const RE = /^[-\w]+$/g; const m = name.match(RE); if (m === null) { for (const c of name.split("")) { const mm = c.match(RE); if (mm === null) { return `cannot contain '${c}'`; } } } return ""; } exports.validName = validName; /** * Returns true if the message is a flow control message * @param msg */ function isFlowControlMsg(msg) { if (msg.data.length > 0) { return false; } const h = msg.headers; if (!h) { return false; } return h.code >= 100 && h.code < 200; } exports.isFlowControlMsg = isFlowControlMsg; /** * Returns true if the message is a heart beat message * @param msg */ function isHeartbeatMsg(msg) { var _a; return isFlowControlMsg(msg) && ((_a = msg.headers) === null || _a === void 0 ? void 0 : _a.description) === "Idle Heartbeat"; } exports.isHeartbeatMsg = isHeartbeatMsg; function newJsErrorMsg(code, description, subject) { const h = (0, headers_1.headers)(code, description); const arg = { hdr: 1, sid: 0, size: 0 }; const msg = new msg_1.MsgImpl(arg, encoders_1.Empty, {}); msg._headers = h; msg._subject = subject; return msg; } exports.newJsErrorMsg = newJsErrorMsg; function checkJsError(msg) { // JS error only if no payload - otherwise assume it is application data if (msg.data.length !== 0) { return null; } const h = msg.headers; if (!h) { return null; } return checkJsErrorCode(h.code, h.description); } exports.checkJsError = checkJsError; var Js409Errors; (function (Js409Errors) { Js409Errors["MaxBatchExceeded"] = "exceeded maxrequestbatch of"; Js409Errors["MaxExpiresExceeded"] = "exceeded maxrequestexpires of"; Js409Errors["MaxBytesExceeded"] = "exceeded maxrequestmaxbytes of"; Js409Errors["MaxMessageSizeExceeded"] = "message size exceeds maxbytes"; Js409Errors["PushConsumer"] = "consumer is push based"; Js409Errors["MaxWaitingExceeded"] = "exceeded maxwaiting"; Js409Errors["IdleHeartbeatMissed"] = "idle heartbeats missed"; Js409Errors["ConsumerDeleted"] = "consumer deleted"; // FIXME: consumer deleted - instead of no responder (terminal error) // leadership changed - })(Js409Errors || (exports.Js409Errors = Js409Errors = {})); let MAX_WAITING_FAIL = false; function setMaxWaitingToFail(tf) { MAX_WAITING_FAIL = tf; } exports.setMaxWaitingToFail = setMaxWaitingToFail; function isTerminal409(err) { if (err.code !== core_1.ErrorCode.JetStream409) { return false; } const fatal = [ Js409Errors.MaxBatchExceeded, Js409Errors.MaxExpiresExceeded, Js409Errors.MaxBytesExceeded, Js409Errors.MaxMessageSizeExceeded, Js409Errors.PushConsumer, Js409Errors.IdleHeartbeatMissed, Js409Errors.ConsumerDeleted, ]; if (MAX_WAITING_FAIL) { fatal.push(Js409Errors.MaxWaitingExceeded); } return fatal.find((s) => { return err.message.indexOf(s) !== -1; }) !== undefined; } exports.isTerminal409 = isTerminal409; function checkJsErrorCode(code, description = "") { if (code < 300) { return null; } description = description.toLowerCase(); switch (code) { case 404: // 404 for jetstream will provide different messages ensure we // keep whatever the server returned return new core_1.NatsError(description, core_1.ErrorCode.JetStream404NoMessages); case 408: return new core_1.NatsError(description, core_1.ErrorCode.JetStream408RequestTimeout); case 409: { // the description can be exceeded max waiting or max ack pending, which are // recoverable, but can also be terminal errors where the request exceeds // some value in the consumer configuration const ec = description.startsWith(Js409Errors.IdleHeartbeatMissed) ? core_1.ErrorCode.JetStreamIdleHeartBeat : core_1.ErrorCode.JetStream409; return new core_1.NatsError(description, ec); } case 503: return core_1.NatsError.errorForCode(core_1.ErrorCode.JetStreamNotEnabled, new Error(description)); default: if (description === "") { description = core_1.ErrorCode.Unknown; } return new core_1.NatsError(description, `${code}`); } } exports.checkJsErrorCode = checkJsErrorCode; //# sourceMappingURL=jsutil.js.map