UNPKG

@unchainedshop/plugins

Version:

Official plugin collection for the Unchained Engine with payment, delivery, and pricing adapters

170 lines (169 loc) 7.38 kB
import { WorkerAdapter, WorkerDirector } from '@unchainedshop/core'; const { BUDGETSMS_USERNAME, BUDGETSMS_USERID, BUDGETSMS_HANDLE } = process.env; const BudgetSMSWorker = { ...WorkerAdapter, key: 'shop.unchained.worker-plugin.budgetsms', label: 'Send Messages through BudgetSMS', version: '1.0.0', type: 'BUDGETSMS', doWork: async ({ from, to, text, test = false, customid, price = false, mccmnc = false, credit = false, ...params }) => { try { if (!BUDGETSMS_USERNAME || !BUDGETSMS_USERID || !BUDGETSMS_HANDLE) { throw new Error('Missing BudgetSMS credentials. Please set BUDGETSMS_USERNAME, BUDGETSMS_USERID, and BUDGETSMS_HANDLE'); } const username = BUDGETSMS_USERNAME.trim(); const userid = BUDGETSMS_USERID.trim(); const handle = BUDGETSMS_HANDLE.trim(); if (!/^\d+$/.test(userid)) { throw new Error('BUDGETSMS_USERID must be numeric only. Found: ' + userid); } const url = test ? 'https://api.budgetsms.net/testsms/' : 'https://api.budgetsms.net/sendsms/'; const formattedTo = to.replace(/^\+|^00/, '').replace(/[\s-]/g, ''); const queryParams = new URLSearchParams({ username: username, userid: userid, handle: handle, msg: text || '', from: from || '', to: formattedTo, ...(customid && { customid }), ...(!test && price && { price: '1' }), ...(!test && mccmnc && { mccmnc: '1' }), ...(!test && credit && { credit: '1' }), ...params, }); const fullUrl = `${url}?${queryParams.toString()}`; const response = await fetch(fullUrl, { method: 'GET', headers: { Accept: 'text/plain', 'User-Agent': 'Unchained/BudgetSMS-Plugin', }, }); const responseText = await response.text().then((text) => text.trim()); if (responseText.startsWith('OK')) { const parts = responseText.split(' '); const result = { sms_id: parts[1] || null, status: test ? 'test_successful' : 'sent', test_mode: test, }; if (test) { result.message = 'Test SMS validated successfully (no credit deducted)'; } else { let index = 2; if (price && parts[index] && parts[index + 1]) { result.price = parseFloat(parts[index]); result.parts = parseInt(parts[index + 1]); index += 2; } if (mccmnc && parts[index]) { result.mccmnc = parts[index]; index += 1; } if (credit && parts[index]) { result.remaining_credit = parseFloat(parts[index]); } } return { success: true, result, error: null, }; } if (responseText.startsWith('ERR')) { const parts = responseText.split(' '); const errorCode = parts[1] || 'UNKNOWN'; const errorMessages = { '1001': 'Authentication failed OR insufficient credit (BudgetSMS returns 1001 for both)', '1002': 'Account not active', '1003': 'Insufficient credit', '1004': 'No access to this API', '1005': 'No handle provided', '1006': 'No UserID provided', '1007': 'No Username provided', '2001': 'SMS message text is empty', '2002': 'SMS numeric senderid can be max. 16 numbers', '2003': 'SMS alphanumeric sender can be max. 11 characters', '2004': 'SMS senderid is empty or invalid', '2005': 'Destination number is too short', '2006': 'Destination is not numeric', '2007': 'Destination is empty', '2008': 'SMS text is not OK (check encoding?)', '2009': 'Parameter issue', '2010': 'Destination number is invalidly formatted', '2011': 'Destination is invalid', '2012': 'SMS message text is too long', '2013': 'SMS message is invalid', '2014': 'SMS CustomID is used before', '2015': 'Charset problem', '2016': 'Invalid UTF-8 encoding', '3001': 'No route to destination', '3002': 'No routes are setup', '3003': 'Invalid destination', '4001': 'System error, related to customid', '4002': 'System error, temporary issue', }; let message = errorMessages[errorCode] || `Unknown error code: ${errorCode}`; if (errorCode === '1001') { message += '. Note: Check your account balance - BudgetSMS may return 1001 when credit is 0.'; } return { success: false, error: { name: 'BUDGETSMS_ERROR', code: errorCode, message, }, }; } return { success: false, error: { name: 'BUDGETSMS_ERROR', message: 'Unexpected response format from BudgetSMS API', response: responseText, }, }; } catch (err) { return { success: false, error: { name: err.name, message: err.message, stack: err.stack, }, }; } }, }; WorkerDirector.registerAdapter(BudgetSMSWorker); export async function checkBudgetSmsCredentials() { const url = 'https://api.budgetsms.net/checkcredit/'; const username = process.env.BUDGETSMS_USERNAME?.trim(); const userid = process.env.BUDGETSMS_USERID?.trim(); const handle = process.env.BUDGETSMS_HANDLE?.trim(); if (!username || !userid || !handle) { return { error: 'Missing credentials' }; } if (!/^\d+$/.test(userid)) { return { error: 'UserID must be numeric only' }; } const queryParams = new URLSearchParams({ username, userid, handle }); try { const response = await fetch(`${url}?${queryParams.toString()}`, { method: 'GET' }); const text = await response.text(); if (text.startsWith('OK')) { const credit = parseFloat(text.split(' ')[1]) || 0; return { success: true, credit }; } else { return { error: text }; } } catch (err) { return { error: err.message }; } }