@azure/functions-extensions-servicebus
Version:
Node.js Azure ServiceBus extension implementations for Azure Functions
889 lines (826 loc) • 39 kB
JavaScript
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/grpcClientFactory.ts":
/*!**********************************!*\
!*** ./src/grpcClientFactory.ts ***!
\**********************************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.createGrpcClient = void 0;
const grpc = __importStar(__webpack_require__(/*! @grpc/grpc-js */ "@grpc/grpc-js"));
const protoLoader = __importStar(__webpack_require__(/*! @grpc/proto-loader */ "@grpc/proto-loader"));
const path_1 = __importDefault(__webpack_require__(/*! path */ "path"));
/**
* Creates and returns a gRPC client for the specified service.
*
* @template T - The type of gRPC client to create, extends grpc.Client
*
* @param options - The configuration options for creating the gRPC client
* @param options.protoPath - Path to the .proto file that defines the service
* @param options.serviceName - Name of the service in the proto file
* @param options.address - The server address to connect to (e.g., "localhost:50051")
* @param options.credentials - gRPC channel credentials to use for secure communication (defaults to insecure)
* @param options.grpcMaxMessageLength - Maximum message length in bytes for both sending and receiving gRPC messages
* @param options.includeDirs - Additional directories to search for imported .proto files
*
* @returns A new instance of the specified gRPC client
*
* @throws {Error} When the specified service name is not found in the proto file
*
* @example
* const client = createGrpcClient<MyServiceClient>({
* protoPath: './protos/my_service.proto',
* serviceName: 'MyService',
* address: 'localhost:50051',
* grpcMaxMessageLength: 4 * 1024 * 1024, // 4MB
* });
*/
function createGrpcClient({ protoPath, serviceName, address, credentials = grpc.credentials.createInsecure(), grpcMaxMessageLength, includeDirs = [], }) {
// Load the .proto file and generate the package definition
const packageDefinition = protoLoader.loadSync(protoPath, {
keepCase: false,
longs: String,
enums: String,
defaults: true,
oneofs: true,
includeDirs: [path_1.default.dirname(protoPath), ...includeDirs],
});
// Load the gRPC object from the package definition
const grpcObject = grpc.loadPackageDefinition(packageDefinition);
// Retrieve the service client constructor from the loaded gRPC object
const ServiceClientConstructor = grpcObject[serviceName];
// Throw an error if the service is not found in the proto file
if (!ServiceClientConstructor) {
throw new Error(`Service "${serviceName}" not found in proto file: ${protoPath}`);
}
const clientOptions = {
'grpc.max_send_message_length': grpcMaxMessageLength,
'grpc.max_receive_message_length': grpcMaxMessageLength,
};
// Create and return a new instance of the service client
return new ServiceClientConstructor(address, credentials, clientOptions);
}
exports.createGrpcClient = createGrpcClient;
/***/ }),
/***/ "./src/servicebus/ServiceBusMessageActions.ts":
/*!****************************************************!*\
!*** ./src/servicebus/ServiceBusMessageActions.ts ***!
\****************************************************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ServiceBusMessageActions = void 0;
const grpc = __importStar(__webpack_require__(/*! @grpc/grpc-js */ "@grpc/grpc-js"));
const path_1 = __importDefault(__webpack_require__(/*! path */ "path"));
const grpcClientFactory_1 = __webpack_require__(/*! ../grpcClientFactory */ "./src/grpcClientFactory.ts");
const grpcUriBuilder_1 = __webpack_require__(/*! ../util/grpcUriBuilder */ "./src/util/grpcUriBuilder.ts");
const PROTO_PATH = path_1.default.join(__dirname, '/proto/settlement.proto');
// Client implementation with Promise-based methods
class ServiceBusMessageActions {
constructor() {
const { uri, grpcMaxMessageLength } = grpcUriBuilder_1.GrpcUriBuilder.build();
this.client = (0, grpcClientFactory_1.createGrpcClient)({
protoPath: PROTO_PATH,
serviceName: 'Settlement',
address: uri,
credentials: grpc.credentials.createInsecure(),
grpcMaxMessageLength,
});
}
static getInstance() {
if (!ServiceBusMessageActions.instance) {
ServiceBusMessageActions.instance = new ServiceBusMessageActions();
}
return ServiceBusMessageActions.instance;
}
// Add this private helper method to the ServiceBusMessageActions class
validateLockToken(message) {
const locktoken = message.lockToken;
if (!locktoken) {
throw new Error('ArgumentException: lockToken is required in ServiceBusReceivedMessage.');
}
return locktoken;
}
/**
* Completes (settles) the specified message, removing it from the queue or subscription.
*
* @param message - The received Service Bus message to complete.
* @returns A promise that resolves when the operation is successful.
* @throws Error if the lockToken is missing or the gRPC call fails.
*/
complete(message) {
return __awaiter(this, void 0, void 0, function* () {
const locktoken = this.validateLockToken(message);
return new Promise((resolve, reject) => {
const request = { locktoken };
this.client.complete(request, (error) => {
if (error) {
console.error('Complete request failed:', {
code: error.code,
message: error.message,
details: error.details,
});
reject(error);
}
else {
resolve();
}
});
});
});
}
/**
* Abandons the specified message, making it available again for processing.
*
* @param message - The received Service Bus message to abandon.
* @param propertiesToModify - Optional properties to modify on the message.
* @returns A promise that resolves when the operation is successful.
* @throws Error if the lockToken is missing or the gRPC call fails.
*/
abandon(message, propertiesToModify) {
return __awaiter(this, void 0, void 0, function* () {
const locktoken = this.validateLockToken(message);
return new Promise((resolve, reject) => {
const request = {
locktoken,
propertiesToModify: propertiesToModify || new Uint8Array(),
};
this.client.abandon(request, (error) => {
if (error) {
console.error('Abandon request failed:', {
code: error.code,
message: error.message,
details: error.details,
});
reject(error);
}
else {
resolve();
}
});
});
});
}
/**
* Deadletters the specified message, moving it to the dead-letter queue.
*
* @param message - The received Service Bus message to deadletter.
* @param propertiesToModify - Optional properties to modify on the message.
* @param deadletterReason - Optional reason for deadlettering the message.
* @param deadletterErrorDescription - Optional error description for deadlettering.
* @returns A promise that resolves when the operation is successful.
* @throws Error if the lockToken is missing or the gRPC call fails.
*/
deadletter(message, propertiesToModify, deadletterReason, deadletterErrorDescription) {
return __awaiter(this, void 0, void 0, function* () {
const locktoken = this.validateLockToken(message);
return new Promise((resolve, reject) => {
const request = {
locktoken,
propertiesToModify: propertiesToModify || new Uint8Array(),
deadletterReason,
deadletterErrorDescription,
};
this.client.deadletter(request, (error) => {
if (error) {
console.error('Deadletter request failed:', {
code: error.code,
message: error.message,
details: error.details,
});
reject(error);
}
else {
resolve();
}
});
});
});
}
/**
* Defers the specified message, making it invisible until retrieved by sequence number.
*
* @param message - The received Service Bus message to defer.
* @param propertiesToModify - Optional properties to modify on the message.
* @returns A promise that resolves when the operation is successful.
* @throws Error if the lockToken is missing or the gRPC call fails.
*/
defer(message, propertiesToModify) {
return __awaiter(this, void 0, void 0, function* () {
const locktoken = this.validateLockToken(message);
return new Promise((resolve, reject) => {
const request = {
locktoken,
propertiesToModify: propertiesToModify || new Uint8Array(),
};
this.client.defer(request, (error) => {
if (error) {
console.error('Defer request failed:', {
code: error.code,
message: error.message,
details: error.details,
});
reject(error);
}
else {
resolve();
}
});
});
});
}
/**
* Renews the lock on the specified message, extending its lock duration.
*
* @param message - The received Service Bus message whose lock should be renewed.
* @returns A promise that resolves when the operation is successful.
* @throws Error if the lockToken is missing or the gRPC call fails.
*/
renewMessageLock(message) {
return __awaiter(this, void 0, void 0, function* () {
const locktoken = this.validateLockToken(message);
return new Promise((resolve, reject) => {
const request = { locktoken };
this.client.renewMessageLock(request, (error) => {
if (error) {
console.error('RenewMessageLock request failed:', {
code: error.code,
message: error.message,
details: error.details,
});
reject(error);
}
else {
resolve();
}
});
});
});
}
/**
* Sets the state for the specified session.
*
* @param sessionId - The session ID for which to set the state.
* @param sessionState - The state to set for the session.
* @returns A promise that resolves when the operation is successful.
* @throws Error if the gRPC call fails.
*/
setSessionState(sessionId, sessionState) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
const request = { sessionId, sessionState };
this.client.setSessionState(request, (error) => {
if (error) {
console.error('SetSessionState request failed:', {
code: error.code,
message: error.message,
details: error.details,
});
reject(error);
}
else {
resolve();
}
});
});
});
}
/**
* Releases the specified session, making it available for other receivers.
*
* @param sessionId - The session ID to release.
* @returns A promise that resolves when the operation is successful.
* @throws Error if the gRPC call fails.
*/
releaseSession(sessionId) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
const request = { sessionId };
this.client.releaseSession(request, (error) => {
if (error) {
console.error('ReleaseSession request failed:', {
code: error.code,
message: error.message,
details: error.details,
});
reject(error);
}
else {
resolve();
}
});
});
});
}
/**
* Renews the lock on the specified session, extending its lock duration.
*
* @param sessionId - The session ID whose lock should be renewed.
* @returns A promise that resolves to the new locked-until date.
* @throws Error if the gRPC call fails or if no response is returned.
*/
renewSessionLock(sessionId) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
const request = { sessionId };
this.client.renewSessionLock(request, (error, response) => {
if (error) {
console.error('RenewSessionLock request failed:', {
code: error.code,
message: error.message,
details: error.details,
});
reject(error);
}
else if (response && response.lockedUntil) {
resolve(response.lockedUntil);
}
else {
const err = new Error('No response or lockedUntil returned from renewSessionLock');
console.error(err);
reject(err);
}
});
});
});
}
/**
* Resets the singleton instance (for testing purposes).
*/
static resetInstance() {
ServiceBusMessageActions.instance = null;
}
}
exports.ServiceBusMessageActions = ServiceBusMessageActions;
ServiceBusMessageActions.instance = null;
/***/ }),
/***/ "./src/servicebus/azureServiceBusMessageFactory.ts":
/*!*********************************************************!*\
!*** ./src/servicebus/azureServiceBusMessageFactory.ts ***!
\*********************************************************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.AzureServiceBusMessageFactory = void 0;
const core_amqp_1 = __webpack_require__(/*! @azure/core-amqp */ "@azure/core-amqp");
const long_1 = __importDefault(__webpack_require__(/*! long */ "long"));
const serviceBusMessageDecoder_1 = __webpack_require__(/*! ../util/serviceBusMessageDecoder */ "./src/util/serviceBusMessageDecoder.ts");
const ServiceBusMessageActions_1 = __webpack_require__(/*! ./ServiceBusMessageActions */ "./src/servicebus/ServiceBusMessageActions.ts");
const ENQUEUED_TIME_ANNOTATION = 'x-opt-enqueued-time';
const SEQUENCE_NUMBER_ANNOTATION = 'x-opt-sequence-number';
const DEAD_LETTER_REASON_ANNOTATION = 'DeadLetterReason';
const DEAD_LETTER_ERROR_DESCRIPTION_ANNOTATION = 'DeadLetterErrorDescription';
/**
* Factory class for creating and processing Azure Service Bus messages Manager.
*
* This factory class provides methods to:
* - Build ServiceBusMessage instances from model binding data in Azure Functions
* - Convert between different message formats (AMQP, Rhea)
* - Extract and decode message body content with proper type handling
*
* The factory handles all necessary transformations of message properties,
* annotations, and content to ensure proper integration with the Azure
* Service Bus messaging system.
*/
class AzureServiceBusMessageFactory {
/**
* Builds a ServiceBusMessageContext instance from model binding data.
* This method extracts the Service Bus message content from the provided model binding data,
* @param modelBindingData - The model binding data containing the Service Bus message content.
* This can be a single ModelBindingData object or an array of ModelBindingData objects.
* @returns A ServiceBusMessageContext instance.
*/
static buildServiceBusMessageFromModelBindingData(modelBindingData) {
const client = ServiceBusMessageActions_1.ServiceBusMessageActions.getInstance();
const toMessage = (data) => {
if (!data.content) {
throw new Error('ModelBindingData.content is null or undefined.');
}
const { decodedMessage, lockToken } = serviceBusMessageDecoder_1.ServiceBusMessageDecoder.decode(data.content);
return this.createServiceBusReceivedMessageFromRhea(decodedMessage, lockToken);
};
const messages = Array.isArray(modelBindingData)
? modelBindingData.map(toMessage)
: toMessage(modelBindingData);
return {
messages,
actions: client,
};
}
/**
* Creates a ServiceBusReceivedMessage from an AMQP annotated message.
* This method extracts relevant properties and formats them into the ServiceBusReceivedMessage structure.
*
* @param amqpMessage - The AMQP annotated message to convert.
* @param lockToken - lock token for the message.
* @returns A ServiceBusReceivedMessage object.
*/
static createServiceBusReceivedMessageFromAmqp(amqpMessage, lockToken) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
// Extract common properties from the AMQP message
const receivedMessage = {
// Message body
body: AzureServiceBusMessageFactory.decodeAmqpBody(amqpMessage.body, (_a = amqpMessage.properties) === null || _a === void 0 ? void 0 : _a.contentType),
// Message properties
messageId: (_c = (_b = amqpMessage.properties) === null || _b === void 0 ? void 0 : _b.messageId) === null || _c === void 0 ? void 0 : _c.toString(),
correlationId: (_e = (_d = amqpMessage.properties) === null || _d === void 0 ? void 0 : _d.correlationId) === null || _e === void 0 ? void 0 : _e.toString(),
contentType: (_f = amqpMessage.properties) === null || _f === void 0 ? void 0 : _f.contentType,
subject: (_g = amqpMessage.properties) === null || _g === void 0 ? void 0 : _g.subject,
to: (_h = amqpMessage.properties) === null || _h === void 0 ? void 0 : _h.to,
replyTo: (_j = amqpMessage.properties) === null || _j === void 0 ? void 0 : _j.replyTo,
replyToSessionId: (_k = amqpMessage.properties) === null || _k === void 0 ? void 0 : _k.replyToGroupId,
sessionId: (_l = amqpMessage.properties) === null || _l === void 0 ? void 0 : _l.groupId,
timeToLive: (_m = amqpMessage.header) === null || _m === void 0 ? void 0 : _m.timeToLive,
// Application properties
applicationProperties: amqpMessage.applicationProperties || {},
// Message annotations and delivery annotations
deliveryCount: ((_o = amqpMessage.header) === null || _o === void 0 ? void 0 : _o.deliveryCount) || 0,
// Lock token (if provided)
lockToken: lockToken,
// AMQP annotated message for full access
_rawAmqpMessage: amqpMessage,
// Timestamps (convert from AMQP format if available)
enqueuedTimeUtc: ((_p = amqpMessage.messageAnnotations) === null || _p === void 0 ? void 0 : _p[ENQUEUED_TIME_ANNOTATION]) !== undefined &&
(typeof amqpMessage.messageAnnotations[ENQUEUED_TIME_ANNOTATION] === 'string' ||
typeof amqpMessage.messageAnnotations[ENQUEUED_TIME_ANNOTATION] === 'number')
? new Date(amqpMessage.messageAnnotations[ENQUEUED_TIME_ANNOTATION])
: undefined,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
sequenceNumber: ((_q = amqpMessage.messageAnnotations) === null || _q === void 0 ? void 0 : _q[SEQUENCE_NUMBER_ANNOTATION]) !== undefined
? // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
long_1.default.fromNumber(Number(amqpMessage.messageAnnotations[SEQUENCE_NUMBER_ANNOTATION]))
: undefined,
// Dead letter properties
deadLetterReason: (_r = amqpMessage.applicationProperties) === null || _r === void 0 ? void 0 : _r[DEAD_LETTER_REASON_ANNOTATION],
deadLetterErrorDescription: (_s = amqpMessage.applicationProperties) === null || _s === void 0 ? void 0 : _s[DEAD_LETTER_ERROR_DESCRIPTION_ANNOTATION],
// State
state: 'active',
};
return receivedMessage;
}
/**
* Creates a ServiceBusReceivedMessage from a Rhea message.
* This method extracts relevant properties and formats them into the ServiceBusReceivedMessage structure.
*
* @param rheaMessage - The Rhea message to convert.
* @param lockToken - Optional lock token for the message.
* @returns A ServiceBusReceivedMessage object.
*/
static createServiceBusReceivedMessageFromRhea(rheaMessage, lockToken) {
const amqpMessage = core_amqp_1.AmqpAnnotatedMessage.fromRheaMessage(rheaMessage);
return AzureServiceBusMessageFactory.createServiceBusReceivedMessageFromAmqp(amqpMessage, lockToken);
}
/**
* Decodes the body of an AMQP message section based on its typecode and content type.
* Supports decoding binary data, plain text, and JSON content.
*
* @param section - The AMQP message section containing a typecode and content buffer.
* @returns The decoded message body or undefined if decoding fails.
*/
static decodeAmqpBody(section, contentType) {
if (typeof section === 'object' &&
section !== null &&
'typecode' in section &&
'content' in section &&
typeof section.typecode === 'number' &&
Buffer.isBuffer(section.content)) {
const { typecode, content } = section;
//typecode = 117 is Binary content
if (typecode === 117) {
const text = content.toString('utf8');
switch (contentType) {
case 'text/plain':
case 'application/xml':
return text;
case 'application/json':
try {
return JSON.parse(text);
}
catch (_a) {
return text; // fallback if not valid JSON
}
default:
return text; // unknown content type convert binary to string and return
}
}
return content;
}
// Not a valid AMQP body section
return section;
}
}
exports.AzureServiceBusMessageFactory = AzureServiceBusMessageFactory;
/***/ }),
/***/ "./src/servicebus/registerServiceBusMessageFactory.ts":
/*!************************************************************!*\
!*** ./src/servicebus/registerServiceBusMessageFactory.ts ***!
\************************************************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.registerServiceBusMessageFactory = void 0;
const functions_extensions_base_1 = __webpack_require__(/*! @azure/functions-extensions-base */ "@azure/functions-extensions-base");
const azureServiceBusMessageFactory_1 = __webpack_require__(/*! ./azureServiceBusMessageFactory */ "./src/servicebus/azureServiceBusMessageFactory.ts");
const AZURE_SERVICE_BUS = 'AzureServiceBusReceivedMessage';
function registerServiceBusMessageFactory() {
try {
const resourceFactoryResolver = functions_extensions_base_1.ResourceFactoryResolver.getInstance();
// Check if a factory is already registered to avoid conflicts
if (!resourceFactoryResolver.hasResourceFactory(AZURE_SERVICE_BUS)) {
resourceFactoryResolver.registerResourceFactory(AZURE_SERVICE_BUS, (modelBindingData) => {
return azureServiceBusMessageFactory_1.AzureServiceBusMessageFactory.buildServiceBusMessageFromModelBindingData(modelBindingData);
});
}
}
catch (error) {
throw new Error(`Service Bus Message Factory initialization failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
exports.registerServiceBusMessageFactory = registerServiceBusMessageFactory;
/***/ }),
/***/ "./src/util/grpcUriBuilder.ts":
/*!************************************!*\
!*** ./src/util/grpcUriBuilder.ts ***!
\************************************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.GrpcUriBuilder = void 0;
const minimist_1 = __importDefault(__webpack_require__(/*! minimist */ "minimist"));
/**
* GrpcUriBuilder is a utility class to build a gRPC URI from command line arguments.
* It expects two arguments: 'host' and 'port'.
*/
class GrpcUriBuilder {
/**
* Builds a gRPC URI from command line arguments.
* The expected arguments are 'host' and 'port'.
* @returns A string representing the gRPC URI in the format "host:port".
* @throws Error if 'host' or 'port' arguments are missing.
*/
static build() {
const parsedArgs = (0, minimist_1.default)(process.argv.slice(2));
const { host, port, 'functions-grpc-max-message-length': grpcMaxMessageLength } = parsedArgs;
const missing = [];
if (!host)
missing.push("'host'");
if (!port)
missing.push("'port'");
if (!grpcMaxMessageLength)
missing.push("'functions-grpc-max-message-length'");
if (missing.length) {
throw new Error(`Missing required arguments: ${missing.join(', ')}`);
}
return { uri: `${String(host)}:${String(port)}`, grpcMaxMessageLength: Number(grpcMaxMessageLength) };
}
}
exports.GrpcUriBuilder = GrpcUriBuilder;
/***/ }),
/***/ "./src/util/lockTokenUtil.ts":
/*!***********************************!*\
!*** ./src/util/lockTokenUtil.ts ***!
\***********************************/
/***/ ((__unused_webpack_module, exports) => {
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.LockTokenUtil = void 0;
/**
* Utility class for handling lock tokens in Azure Service Bus messages.
* Provides methods to convert lock tokens to string format and extract them from messages.
*/
class LockTokenUtil {
/**
* Converts a lock token from a Buffer to a string format.
* The lock token is expected to be in a specific byte order.
* @param lockToken - The lock token as a Buffer.
* @returns The lock token as a formatted string.
*/
static convertToString(lockToken) {
return [
lockToken.subarray(0, 4).reverse().toString('hex'),
lockToken.subarray(4, 6).reverse().toString('hex'),
lockToken.subarray(6, 8).reverse().toString('hex'),
lockToken.subarray(8, 10).toString('hex'),
lockToken.subarray(10).toString('hex'),
].join('-');
}
/**
* Extracts the lock token from a Service Bus message.
* @param message - The Service Bus message as a Buffer.
* @param index - The index at which the lock token is located.
* @returns The extracted lock token as a string.
*/
static extractFromMessage(message, index) {
const raw = Buffer.isBuffer(message) ? message.subarray(0, index) : new Uint8Array(message.slice(0, index));
return this.convertToString(Buffer.from(raw.subarray(0, 16)));
}
}
exports.LockTokenUtil = LockTokenUtil;
LockTokenUtil.X_OPT_LOCK_TOKEN = Buffer.from('x-opt-lock-token');
/***/ }),
/***/ "./src/util/serviceBusMessageDecoder.ts":
/*!**********************************************!*\
!*** ./src/util/serviceBusMessageDecoder.ts ***!
\**********************************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ServiceBusMessageDecoder = void 0;
const rhea = __webpack_require__(/*! rhea */ "rhea");
const lockTokenUtil_1 = __webpack_require__(/*! ./lockTokenUtil */ "./src/util/lockTokenUtil.ts");
class ServiceBusMessageDecoder {
/**
* Decodes a Service Bus message from a buffer.
* @param content Buffer that contains the Service Bus message with lock token
* @returns An object containing the decoded message and the lock token
*/
static decode(content) {
if (!content || content.length === 0)
throw new Error('Content buffer is empty');
const index = content.indexOf(lockTokenUtil_1.LockTokenUtil.X_OPT_LOCK_TOKEN);
if (index === -1)
throw new Error('Lock token not found in content');
const lockToken = lockTokenUtil_1.LockTokenUtil.extractFromMessage(content, index);
const amqpSlice = content.subarray(index + lockTokenUtil_1.LockTokenUtil.X_OPT_LOCK_TOKEN.length);
const decodedMessage = rhea.message.decode(Buffer.from(amqpSlice));
return { decodedMessage: decodedMessage, lockToken };
}
}
exports.ServiceBusMessageDecoder = ServiceBusMessageDecoder;
/***/ }),
/***/ "@azure/core-amqp":
/*!***********************************!*\
!*** external "@azure/core-amqp" ***!
\***********************************/
/***/ ((module) => {
module.exports = require("@azure/core-amqp");
/***/ }),
/***/ "@azure/functions-extensions-base":
/*!***************************************************!*\
!*** external "@azure/functions-extensions-base" ***!
\***************************************************/
/***/ ((module) => {
module.exports = require("@azure/functions-extensions-base");
/***/ }),
/***/ "@grpc/grpc-js":
/*!********************************!*\
!*** external "@grpc/grpc-js" ***!
\********************************/
/***/ ((module) => {
module.exports = require("@grpc/grpc-js");
/***/ }),
/***/ "@grpc/proto-loader":
/*!*************************************!*\
!*** external "@grpc/proto-loader" ***!
\*************************************/
/***/ ((module) => {
module.exports = require("@grpc/proto-loader");
/***/ }),
/***/ "long":
/*!***********************!*\
!*** external "long" ***!
\***********************/
/***/ ((module) => {
module.exports = require("long");
/***/ }),
/***/ "minimist":
/*!***************************!*\
!*** external "minimist" ***!
\***************************/
/***/ ((module) => {
module.exports = require("minimist");
/***/ }),
/***/ "path":
/*!***********************!*\
!*** external "path" ***!
\***********************/
/***/ ((module) => {
module.exports = require("path");
/***/ }),
/***/ "rhea":
/*!***********************!*\
!*** external "rhea" ***!
\***********************/
/***/ ((module) => {
module.exports = require("rhea");
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it uses a non-standard name for the exports (exports).
(() => {
var exports = __webpack_exports__;
/*!**********************!*\
!*** ./src/index.ts ***!
\**********************/
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", ({ value: true }));
const registerServiceBusMessageFactory_1 = __webpack_require__(/*! ./servicebus/registerServiceBusMessageFactory */ "./src/servicebus/registerServiceBusMessageFactory.ts");
(0, registerServiceBusMessageFactory_1.registerServiceBusMessageFactory)();
})();
module.exports = __webpack_exports__;
/******/ })()
;
//# sourceMappingURL=azure-functions-extensions-servicebus.js.map