piper-utils 1.1.66 → 1.1.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/main.js +262 -1
- package/bin/main.js.map +1 -1
- package/package.json +1 -1
- package/src/audit/audit.js +436 -0
- package/src/audit/audit.test.js +342 -0
- package/src/index.js +16 -0
package/bin/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","mappings":"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","sources":["webpack://piper-utils/external commonjs \"sequelize\"","webpack://piper-utils/external commonjs \"@aws-sdk/client-s3\"","webpack://piper-utils/external commonjs \"dayjs/plugin/customParseFormat\"","webpack://piper-utils/./src/database/dbUtils/partnerAccess/accessContext.js","webpack://piper-utils/./src/dynamo/dynamoUtils.js","webpack://piper-utils/./src/eventManager/handleEvents.js","webpack://piper-utils/external commonjs \"dayjs/plugin/utc.js\"","webpack://piper-utils/./src/database/dbUtils/partnerAccess/accessWrites.js","webpack://piper-utils/./src/eventManager/watchBucket.js","webpack://piper-utils/./src/database/dbUtils/partnerAccess/accessGates.js","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/defaultFilters.js","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/createFilters.js","webpack://piper-utils/external commonjs \"dayjs\"","webpack://piper-utils/./src/sns/SNSUtils.js","webpack://piper-utils/external commonjs \"dayjs/plugin/isSameOrBefore\"","webpack://piper-utils/./src/database/dbUtils/partnerAccess/accessScope.js","webpack://piper-utils/external commonjs \"@aws-sdk/lib-dynamodb\"","webpack://piper-utils/./src/database/dbUtils/partnerAccess/createAccessHelpers.js","webpack://piper-utils/external commonjs \"bluebird\"","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/accessRightsUtils.js","webpack://piper-utils/external commonjs \"@aws-sdk/client-sns\"","webpack://piper-utils/external commonjs \"lodash\"","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/createSort.js","webpack://piper-utils/./src/requestResponse/requestResponse.js","webpack://piper-utils/./src/eventManager/publishEvents.js","webpack://piper-utils/./src/database/dbSetup/migrations.js","webpack://piper-utils/./src/eventManager/handleFile.js","webpack://piper-utils/./src/s3/S3Utils/S3Utils.js","webpack://piper-utils/external commonjs \"umzug\"","webpack://piper-utils/external commonjs \"@aws-sdk/client-dynamodb\"","webpack://piper-utils/./src/requestResponse/errorCodes.js","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/findAll.js","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/createIncludes.js","webpack://piper-utils/webpack/bootstrap","webpack://piper-utils/./src/index.js"],"sourcesContent":["module.exports = require(\"sequelize\");","module.exports = require(\"@aws-sdk/client-s3\");","module.exports = require(\"dayjs/plugin/customParseFormat\");","import { isSuperUser, isPartnerUser, getAccessRightsInfo } from '../queryStringUtils/accessRightsUtils.js';\nimport { errorList } from '../../../requestResponse/errorCodes.js';\n\n/**\n * Resolve the caller's access level from the Lambda event.\n * Synchronous — reads JWT claims only, no Dynamo lookups.\n *\n * Returns an access object:\n * { level: 'global' } — super user or local/test env\n * { level: 'partner', partnerId, partnerBusinessId: null, businessIds: null }\n * { level: 'standard', businessIds: string[] }\n *\n * Partner fields (partnerBusinessId, businessIds) start null and are\n * lazy-loaded by ensurePartnerScope on first use.\n *\n * @param {object} event - Lambda event with Cognito authorizer claims.\n * @returns {object} Access object.\n */\nexport function resolveAccess(event) {\n if (isSuperUser(event)) {\n return { level: 'global' };\n }\n\n const env = process.env.BUILD_ENV;\n if (env === 'local' || env === 'test') {\n return { level: 'global' };\n }\n\n const partnerId = isPartnerUser(event);\n if (partnerId) {\n return { level: 'partner', partnerId, partnerBusinessId: null, businessIds: null };\n }\n\n const arBusinessIds = getAccessRightsInfo(event);\n const businessIds = Object.keys(arBusinessIds);\n if (businessIds.length > 0) {\n return { level: 'standard', businessIds };\n }\n\n throw errorList.unauthorized;\n}\n\n/**\n * Lazy-load partner scope from Dynamo. Populates partnerBusinessId and\n * businessIds on the access object, then caches for the request lifetime.\n *\n * No-op for non-partner access objects or if already loaded.\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {{ getPartnerById: Function }} deps - Injected so piper-utils stays DB-agnostic.\n * @returns {object} The same access object, now populated.\n */\nexport async function ensurePartnerScope(access, { getPartnerById }) {\n if (!access || access.level !== 'partner') {\n return access;\n }\n if (access.businessIds !== null && access.businessIds !== undefined) {\n return access;\n }\n try {\n const partner = await getPartnerById(access.partnerId);\n access.businessIds = partner?.businessIds || [];\n access.partnerBusinessId = partner?.partnerBusinessId || null;\n } catch (err) {\n console.error('partnerAccess: failed to load partner for scoping:', err);\n access.businessIds = [];\n access.partnerBusinessId = null;\n }\n return access;\n}\n","import { DynamoDBDocument } from '@aws-sdk/lib-dynamodb';\nimport { DynamoDB } from '@aws-sdk/client-dynamodb';\n\nconst dynamoUtil = {\n get: (params) => get(params)\n};\n\n/**\n * @param {{TableName:string, Key:{key:string}}} params\n */\nasync function get(params) {\n const dynamoDb = DynamoDBDocument.from(new DynamoDB());\n return dynamoDb.get(params);\n}\n\nexport default dynamoUtil;","import { handleFile } from './handleFile.js';\nimport _ from 'lodash';\nimport Promise from 'bluebird';\n\nexport function handleEvents(event, transformer, errorHandlerPerFile, shouldSkipFailedFolders = false, userImportTypes) {\n if (!event || !event.Records) {\n return Promise.resolve();\n }\n\n let hasErrors = false;\n\n return Promise.map(event.Records, (record) => {\n const snsInfo = JSON.parse(_.get(record, 'Sns.Message', '{}'));\n const s3Bucket = snsInfo.bucket;\n const files = snsInfo.files || [];\n\n return Promise.map(files, (file) => {\n let path = decodeURIComponent(file);\n if (path) {\n return handleFile(path, s3Bucket, transformer, { shouldSkipFailedFolders, userImportTypes }).catch((err) => {\n if (errorHandlerPerFile && !errorHandlerPerFile(err, path)) {\n console.error('HANDLE-FILE-CATCH: ', err);\n hasErrors = true;\n }\n });\n }\n });\n }).then(() => {\n if (hasErrors) {\n throw new Error('ERROR: HANDLE-FILE');\n }\n });\n}\n\nexport function handleDirectS3WriteEvent(event, transformer, errorHandlerPerFile, shouldSkipFailedFolders = false, userImportTypes) {\n if (!event || !event.Records) {\n return Promise.resolve();\n }\n\n let hasErrors = false;\n\n return Promise.map(event.Records, (record) => {\n const s3Bucket = record.s3.bucket.name;\n const file = record.s3.object.key || [];\n\n let path = decodeURIComponent(file);\n if (path) {\n return handleFile(path, s3Bucket, transformer, { shouldSkipFailedFolders, userImportTypes }).catch((err) => {\n if (errorHandlerPerFile && !errorHandlerPerFile(err, path)) {\n console.error('HANDLE-FILE-CATCH:', err);\n hasErrors = true;\n }\n });\n }\n\n }).then(() => {\n if (hasErrors) {\n throw new Error('ERROR: HANDLE-FILE (DIRECT S3 EVENT)');\n }\n });\n}\n","module.exports = require(\"dayjs/plugin/utc.js\");","import _ from 'lodash';\nimport { ensurePartnerScope } from './accessContext.js';\nimport { errorList } from '../../../requestResponse/errorCodes.js';\n\n/**\n * Assert the caller can write to their own business.\n * For partner: businessId must equal partnerBusinessId.\n *\n * global → allow\n * partner → businessId must equal partnerBusinessId; throws if not\n * standard → throws (CRM routes gate standard users before reaching this)\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {string} businessId - The businessId being written to.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function assertCanWriteOwnBusiness(access, businessId, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n return;\n }\n if (access.level === 'partner') {\n await ensurePartnerScope(access, { getPartnerById });\n if (!access.partnerBusinessId) {\n throw { ...errorList.partnerNotConfigured };\n }\n if (businessId !== access.partnerBusinessId) {\n throw errorList.unauthorized;\n }\n return;\n }\n throw errorList.unauthorized;\n}\n\n/**\n * Assert the caller can write to a business in their portfolio.\n * For partner: businessId must be in the businessIds array.\n *\n * global → allow\n * standard → allow (handled elsewhere via checkWriteAccess)\n * partner → businessId must be in portfolio; throws if not\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {string} businessId - The businessId being written to.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function assertCanWriteBookBusiness(access, businessId, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n return;\n }\n if (access.level === 'standard') {\n return;\n }\n if (access.level === 'partner') {\n if (!businessId) {\n throw { ...errorList.invalidRequest, message: 'businessId is required' };\n }\n await ensurePartnerScope(access, { getPartnerById });\n if (!(access.businessIds || []).includes(businessId)) {\n throw errorList.unauthorized;\n }\n return;\n }\n throw errorList.unauthorized;\n}\n\n/**\n * Assert the caller can write to a business in the union of own + portfolio.\n * For partner: businessId must be partnerBusinessId OR in businessIds[].\n * Used by ticket write paths.\n *\n * global → allow\n * standard → allow (handled elsewhere via checkWriteAccess)\n * partner → businessId must be in [partnerBusinessId, ...businessIds]\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {string} businessId - The businessId being written to.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function assertCanWriteBookUnionOwn(access, businessId, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n return;\n }\n if (access.level === 'standard') {\n return;\n }\n if (access.level === 'partner') {\n if (!businessId) {\n throw { ...errorList.invalidRequest, message: 'businessId is required' };\n }\n await ensurePartnerScope(access, { getPartnerById });\n const allowed = _.uniq(\n [access.partnerBusinessId, ...(access.businessIds || [])].filter(Boolean)\n );\n if (!allowed.includes(businessId)) {\n throw errorList.unauthorized;\n }\n return;\n }\n throw errorList.unauthorized;\n}\n\n/**\n * Auto-stamp body.businessId from the partner's own business if missing.\n * No-op for non-partner users or if body.businessId is already set.\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {object} body - Request body to mutate.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function stampOwnBusinessId(access, body, { getPartnerById } = {}) {\n if (!access || access.level !== 'partner') {\n return;\n }\n if (body.businessId) {\n return;\n }\n await ensurePartnerScope(access, { getPartnerById });\n body.businessId = access.partnerBusinessId;\n}\n","import { publishEvents } from './publishEvents.js';\nimport { handleEvents, handleDirectS3WriteEvent } from './handleEvents.js';\nimport _ from 'lodash';\n\n/**\n * bucket watcher watches a s3 bucket and publishes events to a sns topic, this allows you to process files in s3 with a some transformer function\n * prefix objects with DIRECT to listen to direct s3 events\n *\n * @param {object} params - The parameters for watchBucket, see below\n * @param {object} params.event - The event of the lambda\n * @param {string} params.dynamoConfigTable - The Dynamo DB table where to get the chunkSize and maxMessage size\n * @param {string} params.dynamoConfigKey - The key to the item in the Dynamo DB table that holds the chunkSize and maxMessage size\n * @param {string} params.s3Bucket - The name of the s3 bucket to watch, when you drop items into this table events will be created\n * @param {string} params.snsTopic - The name of the snsEvent to publish\n * @param {function} params.transformer - the function to run on each file\n * @param {function} [params.errorHandlerPerFile] - the function to run on as a catch on each file\n * @param {boolean} [params.shouldSkipFailedFolders] - whether to use the failed-once, failed-twice, error or just error folders\n * @param {object} [params.userImportTypes] - user import subdirectories object map\n */\nexport function watchBucket({\n event,\n dynamoConfigTable,\n dynamoConfigKey,\n s3Bucket,\n snsTopic,\n transformer,\n errorHandlerPerFile = _.noop,\n shouldSkipFailedFolders = false,\n userImportTypes\n }) {\n if (!event || !dynamoConfigTable || !dynamoConfigKey || !s3Bucket || !snsTopic || !transformer) {\n throw new Error('Missing required parameters. Need event, dynamoConfigTable, dynamoConfigKey, s3Bucket, snsTopic, transformer');\n }\n\n const EventSource = _.get(event, 'Records[0].eventSource') || _.get(event, 'Records[0].EventSource');\n\n if (_.isEqual(EventSource, 'aws:sns')) {\n return handleEvents(event, transformer, errorHandlerPerFile, shouldSkipFailedFolders, userImportTypes);\n } else if (_.isEqual(EventSource, 'aws:s3')) {\n const failedOnce = 'failed-once';\n const failedTwice = 'failed-twice';\n const error = 'error';\n const direct = 'DIRECT';\n const key = _.get(event, 'Records[0].s3.object.key') || '';\n const startsWithDirect = _.startsWith(key, direct);\n if (key.includes(failedOnce) || key.includes(failedTwice) || key.includes(error)) {\n // this used to throw, but the throw raised useless alarms, I believed turing throw in to a return was ok\n return;\n }\n\n if (startsWithDirect) {\n console.log('------->DIRECT WRITE FIRE');\n return handleDirectS3WriteEvent(event, transformer, errorHandlerPerFile, shouldSkipFailedFolders, userImportTypes);\n }\n\n } else {\n // the function is being run from the cron job so publish SNS events\n return publishEvents(dynamoConfigTable, dynamoConfigKey, s3Bucket, snsTopic, userImportTypes);\n }\n}\n","import { errorList } from '../../../requestResponse/errorCodes.js';\n\n/**\n * Gate: CRM routes — rejects standard users. Super and partner pass.\n * @param {object} access - Access object from resolveAccess.\n */\nexport function requireCrmAccess(access) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'standard') {\n throw errorList.unauthorized;\n }\n}\n\n/**\n * Gate: Ticket routes — all three user types pass. Only rejects null access.\n * @param {object} access - Access object from resolveAccess.\n */\nexport function requireTicketAccess(access) {\n if (!access) {\n throw errorList.unauthorized;\n }\n}\n\n/**\n * Gate: Super-only routes — throws unless global.\n * @param {object} access - Access object from resolveAccess.\n */\nexport function requireSuper(access) {\n if (!access || access.level !== 'global') {\n throw errorList.unauthorized;\n }\n}\n","import _ from 'lodash';\nimport DB from 'sequelize';\n\n/**\n * Create an object with default filters for a given sequeliaze Schema Object, and set of sub schemas\n *\n * @param {object} schema - type is sequelize data type\n * @param {object} subSchemas - An object with alias as the key and sequelize schema as the value http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-method-define\n * sub schema can be {location: locationSchema} or {location: {as: \"asAlias\", schema: schema}}\n * @returns {object} An Object with a default filter for each dataType CHAR and TEXT will get a $like operator, INTEGER, DECIMAL and BOOLEAN will get a $eq.\n */\nexport function defaultFilters(schema, subSchemas = {}) {\n schema = _.clone(schema);\n\n const filters = {};\n\n addFiltersFromSchema(schema, filters);\n Object.keys(subSchemas).forEach((key) => {\n addFiltersFromSchema(subSchemas[key], filters, key);\n });\n\n return filters;\n}\n\nexport function addFiltersFromSchema(schema, filters, keyPrefix = '') {\n const asLinkAlias = _.get(schema, 'as', null);\n schema = _.get(schema, 'schema') || schema;\n\n return Object.keys(schema).reduce((acc, item) => {\n let key = item;\n\n if (asLinkAlias) {\n acc[asLinkAlias] = { type: DB.STRING, filterType: DB.Op.eq };\n }\n\n if (keyPrefix) {\n key = `${keyPrefix}.${item}`;\n }\n\n if (schema[item].filterType) {\n acc[key] = { filterType: schema[item].filterType };\n\n return acc;\n }\n\n const itemType = schema[item].type;\n\n //new sequelize uses class symbols instead of objects\n if (itemType instanceof DB.STRING) {\n acc[key] = { filterType: DB.Op.iLike };\n } else if (itemType instanceof DB.CHAR) {\n acc[key] = { filterType: DB.Op.iLike };\n } else if (itemType instanceof DB.TEXT) {\n acc[key] = { filterType: DB.Op.iLike };\n } else if (itemType instanceof DB.DECIMAL) {\n acc[key] = { filterType: DB.Op.or };\n } else if (itemType instanceof DB.INTEGER) {\n acc[key] = { filterType: DB.Op.or };\n } else if (itemType instanceof DB.BIGINT) {\n acc[key] = { filterType: DB.Op.or };\n } else if (itemType instanceof DB.BOOLEAN) {\n acc[key] = { type: DB.BOOLEAN, filterType: DB.Op.eq };\n } else if (itemType instanceof DB.JSONB || itemType === DB.JSONB) {\n acc[key] = { type: 'jsonb', field: item };\n } else if (itemType instanceof DB.DATE) {\n acc[key] = { filterType: DB.Op.between };\n } else if (itemType instanceof DB.DATEONLY) {\n acc[key] = { filterType: DB.Op.eq };\n }\n\n //these are automatically part of the models, so add them always\n acc['createdAt'] = { type: DB.DATE, filterType: DB.Op.between };\n acc['updatedAt'] = { type: DB.DATE, filterType: DB.Op.between };\n acc['id'] = { type: DB.INTEGER, filterType: DB.Op.eq };\n\n return acc;\n }, filters);\n}\n","import _ from 'lodash';\nimport DB from 'sequelize';\nimport dayjs from 'dayjs';\nimport utc from 'dayjs/plugin/utc.js';\nimport { errorList } from '../../../requestResponse/errorCodes.js';\nimport { accessRightsUtils } from './accessRightsUtils.js';\n\ndayjs.extend(utc);\n\n/**\n * Create sequelize where clause from query string parameters and default sort object\n *\n * Translates URL query string parameters into a Sequelize-compatible WHERE object\n * by matching each param against a filter definition (objectFilters).\n *\n * Filter definitions come from defaultFilters() which maps schema data types to operators:\n * STRING / CHAR / TEXT -> Op.iLike (case-insensitive LIKE)\n * INTEGER / DECIMAL -> Op.or (positive or negative match)\n * BOOLEAN -> Op.eq (exact match with string-to-boolean coercion)\n * JSONB -> case-insensitive search via jsonb_extract_path_text\n * DATE -> Op.between\n *\n * Three convenience params are handled automatically:\n * - searchString: searches a single value across all iLike and eq fields using OR\n * - startDate + endDate: filters createdAt with a BETWEEN range\n *\n * @param {object} event - the Lambda event containing queryStringParameters\n * @param {object} objectFilters - filter definitions created by defaultFilters()\n * @returns {object} A Sequelize where clause object\n */\nexport const createFilters = function (event, objectFilters) {\n let query = _.get(event, 'queryStringParameters', {}) || {};\n\n // Extract the three convenience params before iterating.\n // These are handled separately from the per-field filter logic below.\n const searchString = _.get(query, 'searchString');\n const startDate = _.get(query, 'startDate');\n const endDate = _.get(query, 'endDate');\n\n // ──────────────────────────────────────────────────────────────────────\n // STEP 1 — Build per-field WHERE conditions\n //\n // Each query param is looked up in objectFilters. If a matching filter\n // definition exists, we create the appropriate Sequelize condition.\n //\n // String-type fields (Op.iLike) are collected into a separate array\n // because they use DB.where(DB.fn('LOWER', DB.col(...))) which cannot\n // be expressed as a simple { column: { operator: value } } key.\n // Instead they are merged into WHERE via Op.and after the reduce.\n //\n // This approach replaces the Postgres-only Op.iLike with\n // LOWER(column) LIKE '%lowered_value%' which works across all\n // database dialects (Postgres, MySQL, MSSQL, SQLite).\n // ──────────────────────────────────────────────────────────────────────\n const caseInsensitiveConditions = [];\n const where = Object.keys(query).reduce((acc, item) => {\n const val = _.get(objectFilters, item, null);\n\n if (val) {\n // JSONB fields are handled entirely in Step 4 below.\n // Skip them here so they don't fall into the catch-all else branch.\n if (val.type === 'jsonb') {\n return acc;\n }\n\n // Dot-notation keys (e.g. \"snowman.snowmanType\") reference columns\n // on joined/included models. Sequelize requires these to be wrapped\n // in $...$ syntax in the WHERE object so it can resolve them.\n const itemName = item.includes('.')\n ? `$${item}$`\n : item;\n\n // STRING / CHAR / TEXT fields — case-insensitive partial match\n // Generates: WHERE LOWER(\"column\") LIKE '%lowered_value%'\n if (val.filterType === DB.Op.iLike) {\n caseInsensitiveConditions.push(\n DB.where(\n DB.fn('LOWER', DB.col(item)),\n { [DB.Op.like]: `%${query[item]?.toLowerCase()}%` }\n )\n );\n\n // INTEGER / DECIMAL fields — match positive or negative value\n // Generates: WHERE \"column\" IN (-value, value)\n // Useful for fields like amounts where sign may vary.\n } else if (val.filterType === DB.Op.or) {\n acc[itemName] = {};\n acc[itemName][val.filterType] = [ -1 * +query[item], +query[item] ];\n\n // ENUM / multi-value fields — match any value in a comma-separated list\n // Query: ?status=open,closed -> WHERE \"status\" IN ('open','closed')\n } else if (val.filterType === DB.Op.in) {\n acc[itemName] = {};\n acc[itemName][val.filterType] = query[item].split(',');\n\n // Catch-all for other operators (Op.eq, Op.contains, Op.between, etc.)\n // Attempts JSON.parse first so structured values (objects, arrays, numbers)\n // are passed as their parsed type rather than raw strings.\n } else {\n acc[itemName] = {};\n let parsedJson;\n try {\n parsedJson = JSON.parse(query[item]);\n } catch (e) {\n parsedJson = query[item];\n }\n acc[itemName][val.filterType] = parsedJson;\n }\n\n // BOOLEAN override — runs after the block above so it can replace\n // the value set by the catch-all. Query strings are always strings\n // (\"true\", \"false\", \"null\"), so we coerce them to actual booleans/null.\n if (val.type === DB.BOOLEAN) {\n const queryValue = _.get(query, item, '').toLowerCase();\n\n const booleanMap = {\n 'false': false,\n 'null': null,\n 'true': true\n };\n\n acc[itemName][val.filterType] = booleanMap[queryValue];\n }\n }\n\n return acc;\n }, {});\n\n // Merge the case-insensitive string conditions into WHERE using Op.and.\n // This keeps them alongside the key-based conditions built above.\n // Example result: WHERE decimal = 100 AND LOWER(\"name\") LIKE '%john%'\n if (caseInsensitiveConditions.length) {\n where[DB.Op.and] = [ ...(where[DB.Op.and] || []), ...caseInsensitiveConditions ];\n }\n\n // ──────────────────────────────────────────────────────────────────────\n // STEP 2 — Apply automatic filters (active flag, businessId, dates)\n //\n // These are appended to every query regardless of what the caller sent.\n // ──────────────────────────────────────────────────────────────────────\n\n // If the model has an \"active\" column and the caller did not explicitly\n // filter by it, default to only returning active records.\n if (objectFilters?.active && !where?.active) {\n where.active = true;\n }\n\n // Scope every query to the caller's authorized business IDs.\n // accessRightsUtils extracts them from the JWT claims on the event.\n const businessIds = accessRightsUtils(event);\n const filterAdds = {\n businessId: businessIds\n };\n\n // Date range filter — when both startDate and endDate are provided,\n // automatically filter createdAt with a BETWEEN clause.\n // Generates: WHERE \"createdAt\" BETWEEN '2024-01-01' AND '2024-12-31'\n if (startDate && endDate) {\n const s = dayjs.utc(startDate);\n const e = dayjs.utc(endDate);\n const dates = {\n [DB.Op.between]: [ s.toDate(), e.toDate() ]\n };\n if (!s.isValid()) {\n throw { ...errorList.invalidStartDate };\n }\n\n if (!e.isValid()) {\n throw { ...errorList.invalidEndDate };\n }\n\n filterAdds.createdAt = dates;\n }\n\n // ──────────────────────────────────────────────────────────────────────\n // STEP 3 — searchString: search one value across many fields with OR\n //\n // When ?searchString=john is provided, we build an OR array that checks\n // every filterable field for a match. This lets a single search box\n // query across name, title, email, etc. simultaneously.\n //\n // String fields (Op.iLike) get a case-insensitive LOWER + LIKE condition.\n // Numeric fields (Op.eq) get an exact match, but only when the search\n // value is a valid number (and the field is not a boolean).\n //\n // Generates: WHERE (LOWER(\"name\") LIKE '%john%'\n // OR LOWER(\"title\") LIKE '%john%'\n // OR \"id\" = 123)\n // ──────────────────────────────────────────────────────────────────────\n if (searchString) {\n const adds = Object.keys(objectFilters).reduce((acc, item) => {\n const type = objectFilters[item].filterType;\n const dataType = objectFilters[item].type;\n\n // String fields — case-insensitive partial match via LOWER + LIKE\n if (type === DB.Op.iLike) {\n acc.push(\n DB.where(\n DB.fn('LOWER', DB.col(item)),\n { [DB.Op.like]: `%${query['searchString'].toLowerCase()}%` }\n )\n );\n }\n\n // Numeric fields — exact match only when the search value is numeric.\n // Booleans are excluded because a search for \"1\" should not match\n // boolean true.\n if (!_.isNaN(Number(query['searchString'])) && !(dataType instanceof DB.BOOLEAN)) {\n\n if (type === DB.Op.eq) {\n const newOr = {};\n const itemName = item.includes('.') ? `$${item}$` : item;\n newOr[itemName] = {\n [DB.Op.eq]: `${query['searchString']}`\n };\n acc.push(newOr);\n }\n }\n\n return acc;\n }, []);\n\n filterAdds[DB.Op.or] = adds;\n }\n\n // Merge the automatic filters (businessId, createdAt, searchString OR)\n // into the where object built in Step 1.\n const withDate = Object.assign(where, filterAdds);\n\n // ──────────────────────────────────────────────────────────────────────\n // STEP 4 — JSONB field filters: case-insensitive search inside JSON columns\n //\n // JSONB columns store structured data (e.g. a \"token\" column containing\n // { cardType: \"mastercard\", cardHolderName: \"GREGORY HERBERT\" }).\n //\n // Query params use dot-notation to target nested keys:\n // ?token.cardHolderName=gregory\n // ?paymentProviderData.payment.result.message=approved\n //\n // For each matching param we:\n // 1. Split the path after the column prefix into individual key segments\n // 2. Use jsonb_extract_path_text(column, key1, key2, ...) to pull the\n // value out of the JSON as plain text\n // 3. Wrap it in LOWER() and compare with Op.like for case-insensitive match\n //\n // Generates: WHERE LOWER(jsonb_extract_path_text(\"token\", 'cardHolderName'))\n // LIKE '%gregory%'\n //\n // jsonb_extract_path_text is used via DB.fn() so Sequelize parameterizes\n // the path arguments, keeping it safe from SQL injection.\n // ──────────────────────────────────────────────────────────────────────\n Object.keys(objectFilters || {}).forEach((k) => {\n const def = objectFilters[k];\n if (def && def.type === 'jsonb' && def.field) {\n const prefix = `${def.field}.`;\n\n Object.keys(query).forEach((qKey) => {\n if (qKey.startsWith(prefix)) {\n // Dot-notation: ?token.cardHolderName=gregory\n // e.g. \"token.cardHolderName\" -> pathParts = [\"cardHolderName\"]\n // e.g. \"data.payment.result.message\" -> pathParts = [\"payment\",\"result\",\"message\"]\n const pathParts = qKey.substring(prefix.length).split('.');\n const value = query[qKey];\n\n if (!withDate[DB.Op.and]) {\n withDate[DB.Op.and] = [];\n }\n withDate[DB.Op.and].push(\n DB.where(\n DB.fn('LOWER', DB.fn('jsonb_extract_path_text', DB.col(def.field), ...pathParts)),\n { [DB.Op.like]: `%${value?.toLowerCase()}%` }\n )\n );\n } else if (qKey === def.field) {\n // JSON-object-as-value: ?token={\"cardHolderName\":\"Test\"}\n // Parse the JSON and create a condition for each key-value pair.\n // Nested objects are flattened recursively into deeper path segments.\n let parsed;\n try {\n parsed = JSON.parse(query[qKey]);\n } catch (e) {\n return;\n }\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n const addJsonbConditions = (obj, pathParts) => {\n Object.entries(obj).forEach(([key, value]) => {\n const currentPath = [...pathParts, key];\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n addJsonbConditions(value, currentPath);\n } else if (value !== null && !Array.isArray(value)) {\n if (!withDate[DB.Op.and]) {\n withDate[DB.Op.and] = [];\n }\n withDate[DB.Op.and].push(\n DB.where(\n DB.fn('LOWER', DB.fn('jsonb_extract_path_text', DB.col(def.field), ...currentPath)),\n { [DB.Op.like]: `%${String(value)?.toLowerCase()}%` }\n )\n );\n }\n });\n };\n addJsonbConditions(parsed, []);\n }\n }\n });\n }\n });\n\n return withDate;\n};\n","module.exports = require(\"dayjs\");","import { SNS } from '@aws-sdk/client-sns';\n\nconst SNSUtil = {\n publish: (params) => publish(params),\n createTopic: (params) => createTopic(params)\n};\n\nasync function publish(params) {\n const sns = new SNS();\n return await sns.publish(params);\n}\n\nasync function createTopic(params) {\n const sns = new SNS();\n return await sns.createTopic(params);\n}\n\nexport default SNSUtil;\n","module.exports = require(\"dayjs/plugin/isSameOrBefore\");","import _ from 'lodash';\nimport { ensurePartnerScope } from './accessContext.js';\nimport { errorList } from '../../../requestResponse/errorCodes.js';\n\n/**\n * Scope a WHERE clause to the partner's own business (partnerBusinessId).\n * Use for \"mine\" resources: deal, activity, application, template.\n *\n * global → deletes where.businessId (super sees everything)\n * partner → sets where.businessId = partnerBusinessId\n * throws partnerNotConfigured if partnerBusinessId is missing\n * standard → no-op (createFilters already handled)\n *\n * @param {object} where - Sequelize WHERE clause to mutate.\n * @param {object} access - Access object from resolveAccess.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function scopeToOwnBusiness(where, access, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n delete where.businessId;\n return;\n }\n if (access.level === 'partner') {\n await ensurePartnerScope(access, { getPartnerById });\n if (!access.partnerBusinessId) {\n throw errorList.partnerNotConfigured;\n }\n where.businessId = access.partnerBusinessId;\n return;\n }\n // standard → no-op (createFilters already injected from JWT)\n}\n\n/**\n * Scope a WHERE clause to the partner's portfolio (businessIds array).\n * Use for \"book\" resources (future transaction lists, merchant inbox views).\n *\n * global → deletes where.businessId\n * partner → sets where.businessId = businessIds[]\n * standard → no-op\n *\n * @param {object} where - Sequelize WHERE clause to mutate.\n * @param {object} access - Access object from resolveAccess.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function scopeToPartnerBook(where, access, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n delete where.businessId;\n return;\n }\n if (access.level === 'partner') {\n await ensurePartnerScope(access, { getPartnerById });\n where.businessId = access.businessIds || [];\n return;\n }\n // standard → no-op\n}\n\n/**\n * Scope to the union of partnerBusinessId + businessIds.\n * Use for tickets — partner sees own tickets + portfolio merchants' tickets.\n *\n * global → deletes where.businessId\n * partner → sets where.businessId = [partnerBusinessId, ...businessIds]\n * standard → sets where.businessId = access.businessIds\n * (explicitly handled here because ticket routes may not call\n * createFilters before scoping, e.g. delete/resolve handlers)\n *\n * @param {object} where - Sequelize WHERE clause to mutate.\n * @param {object} access - Access object from resolveAccess.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function scopeToBookUnionOwn(where, access, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n delete where.businessId;\n return;\n }\n if (access.level === 'partner') {\n await ensurePartnerScope(access, { getPartnerById });\n const ids = _.uniq(\n [access.partnerBusinessId, ...(access.businessIds || [])].filter(Boolean)\n );\n where.businessId = ids;\n return;\n }\n if (access.level === 'standard') {\n where.businessId = access.businessIds;\n return;\n }\n}\n","module.exports = require(\"@aws-sdk/lib-dynamodb\");","import { ensurePartnerScope } from './accessContext.js';\nimport { scopeToOwnBusiness, scopeToPartnerBook, scopeToBookUnionOwn } from './accessScope.js';\nimport {\n assertCanWriteOwnBusiness,\n assertCanWriteBookBusiness,\n assertCanWriteBookUnionOwn,\n stampOwnBusinessId\n} from './accessWrites.js';\n\n/**\n * Factory that pre-binds getPartnerById into all scope/assert/stamp helpers.\n * Bind once at module level, then call without repeating the injection:\n *\n * import { createAccessHelpers } from 'piper-utils';\n * import { getPartnerById } from '../partner/partner.js';\n *\n * const {\n * scopeToOwnBusiness,\n * stampOwnBusinessId,\n * assertCanWriteOwnBusiness\n * } = createAccessHelpers({ getPartnerById });\n *\n * @param {{ getPartnerById: Function }} deps\n * @returns {object} Pre-bound helpers.\n */\nexport function createAccessHelpers({ getPartnerById }) {\n const deps = { getPartnerById };\n return {\n ensurePartnerScope: (access) => ensurePartnerScope(access, deps),\n scopeToOwnBusiness: (where, access) => scopeToOwnBusiness(where, access, deps),\n scopeToPartnerBook: (where, access) => scopeToPartnerBook(where, access, deps),\n scopeToBookUnionOwn: (where, access) => scopeToBookUnionOwn(where, access, deps),\n assertCanWriteOwnBusiness: (access, businessId) => assertCanWriteOwnBusiness(access, businessId, deps),\n assertCanWriteBookBusiness: (access, businessId) => assertCanWriteBookBusiness(access, businessId, deps),\n assertCanWriteBookUnionOwn: (access, businessId) => assertCanWriteBookUnionOwn(access, businessId, deps),\n stampOwnBusinessId: (access, body) => stampOwnBusinessId(access, body, deps)\n };\n}\n","module.exports = require(\"bluebird\");","import _, { isEmpty } from 'lodash';\r\nimport { errorList } from '../../../requestResponse/errorCodes.js';\r\nimport { parseBody } from '../../../requestResponse/requestResponse.js';\r\n\r\nexport function isSystemUser(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:SYSTEM') ||\r\n _.get(event, 'requestContext.authorizer.custom:SYSTEM') ||\r\n 'false';\r\n let isSys = false;\r\n try {\r\n isSys = JSON.parse(jsonToParse);\r\n return isSys;\r\n } catch (e) {\r\n console.error('error with system user:', e);\r\n\r\n return false;\r\n }\r\n}\r\n\r\nexport function isSuperUser(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:SUPER') ||\r\n _.get(event, 'requestContext.authorizer.custom:SUPER') ||\r\n 'false';\r\n let isSys = false;\r\n\r\n try {\r\n isSys = JSON.parse(jsonToParse);\r\n\r\n return isSys;\r\n } catch (e) {\r\n\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Throws unauthorized error if the user is not a super user.\r\n * Mirrors the behavior and style of checkModule but focused on SUPER role.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n */\r\nexport function checkIsSuper(event) {\r\n // Super or System users are always allowed\r\n if (isSuperUser(event)) {\r\n return;\r\n }\r\n if (isSystemUser(event)) {\r\n return;\r\n }\r\n\r\n // In local builds allow bypass to ease development and tests\r\n if (process.env.BUILD_ENV === 'local') {\r\n return;\r\n }\r\n\r\n throw errorList.unauthorized;\r\n}\r\n\r\n/**\r\n * Get the allowed businessIds for a user from the lambda event, compare it to businessIds, return what user has access to.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @param {{useCognitoBid:boolean}} [options] - An object with options, useCognitoBid prefers the businessId set in cognito if set and does not return the local bid of 1 if a bid is in the claim.\r\n * @returns {array} A list of businessIds that have been requested and are allowed to for some user.\r\n */\r\nexport function accessRightsUtils(event, options) {\r\n const useCognitoBid = _.get(options, 'useCognitoBid', false);\r\n const requestedBusinessIds = getRequestedBusinessIds(event);\r\n const allowedBusinessIds = getAllowedBusinessIds(event, useCognitoBid);\r\n\r\n if (isSuperUser(event)) {\r\n let v = requestedBusinessIds;\r\n if (_.isEmpty(requestedBusinessIds)) {\r\n v = allowedBusinessIds;\r\n }\r\n\r\n return v;\r\n }\r\n if (isSystemUser(event)) {\r\n return requestedBusinessIds;\r\n }\r\n\r\n if (requestedBusinessIds.length === 0) {\r\n return allowedBusinessIds;\r\n }\r\n\r\n return _.intersection(requestedBusinessIds, allowedBusinessIds);\r\n}\r\n\r\n/**\r\n * Get the businessID set in cognito as custom:DBI.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {string} The businessID set in cognito as custom:DBI\r\n */\r\nexport function userDefaultBid(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:DBI') ||\r\n _.get(event, 'requestContext.authorizer.custom:DBI') ||\r\n '{}';\r\n\r\n const dbi = JSON.parse(jsonToParse);\r\n return _.get(dbi, 'defaultBid', '') || '1';\r\n}\r\n\r\n/**\r\n * Get requested businessIds from the query string.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {array} The businessID requested by the query string\r\n */\r\nexport function getRequestedBusinessIds(event) {\r\n let requestedBusinessIds = _.get(event, 'queryStringParameters.businessIds', null);\r\n const body = parseBody(event);\r\n const bodyBid = body?.businessId;\r\n if (requestedBusinessIds) {\r\n return requestedBusinessIds ? requestedBusinessIds.split(',') : [];\r\n } else if (bodyBid) {\r\n return [ bodyBid ];\r\n } else {\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Get the allowed businessIds for a user from cognito custom:AR property.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @param useCognitoBid\r\n * @returns {array} The businessID requested by the query string\r\n */\r\nfunction getAllowedBusinessIds(event, useCognitoBid) {\r\n const businesses = getBusinessesInfo(event, useCognitoBid);\r\n return Object.keys(businesses);\r\n}\r\n\r\nexport function getAccessRightsInfo(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:AR') ||\r\n _.get(event, 'requestContext.authorizer.custom:AR') ||\r\n '{}';\r\n const accessRights = JSON.parse(jsonToParse);\r\n return _.get(accessRights, 'businessIds', {});\r\n}\r\n\r\nexport function getDefaultBusinessIDInfo(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:DBI') ||\r\n _.get(event, 'requestContext.authorizer.custom:DBI') ||\r\n '{}';\r\n const dbi = JSON.parse(jsonToParse);\r\n\r\n return _.get(dbi, 'defaultBid', '1');\r\n}\r\n\r\nexport function getBusinessesInfo(event, useCognitoBid = false) {\r\n const json = _.get(event, 'requestContext.authorizer.claims.custom:AR') ||\r\n _.get(event, 'requestContext.authorizer.custom:AR') ||\r\n '{}';\r\n\r\n let businessIds = _.get(JSON.parse(json), 'businessIds', {});\r\n\r\n // Local environment tweaks\r\n if (process.env.BUILD_ENV === 'local') {\r\n let b;\r\n try {\r\n b = JSON.parse(event?.body);\r\n } catch (e) {\r\n }\r\n const bodyBid = b?.businessId;\r\n // Always inject the default local BID “1” unless the caller explicitly wants\r\n // what Cognito says **and** Cognito actually returned something.\r\n if (!useCognitoBid) {\r\n businessIds = { ...businessIds, '1': 'A' };\r\n }\r\n\r\n // If Cognito gave no BIDs at all, fall back to the local default.\r\n if (isEmpty(businessIds)) {\r\n businessIds = { '1': 'A' };\r\n }\r\n // a businessId is found on the body for local allow it\r\n if (bodyBid) {\r\n businessIds[bodyBid] = 'A';\r\n }\r\n }\r\n\r\n return businessIds;\r\n}\r\n\r\n/**\r\n * Get the modules listed in custom:MOD.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {array} The Module access list\r\n */\r\nexport function getModuleInfo(event) {\r\n let jsonToParse =\r\n _.get(event, 'requestContext.authorizer.claims.custom:MOD') ||\r\n _.get(event, 'requestContext.authorizer.custom:MOD') ||\r\n _.get(event, 'requestContext.authorizer.claims.custom:AR') ||\r\n _.get(event, 'requestContext.authorizer.custom:AR') ||\r\n\r\n '{}';\r\n\r\n const moduleRights = JSON.parse(jsonToParse);\r\n return _.get(moduleRights, 'module', {});\r\n}\r\n\r\n/**\r\n * Get the modules listed in custom:MOD.\r\n *\r\n * @param {string} moduleName - A sting name for a module.\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {array} The Module access list\r\n */\r\nexport function checkModule(moduleName, event) {\r\n const moduleRights = getModuleInfo(event);\r\n let allowAccess = _.get(moduleRights, moduleName, false);\r\n\r\n if (isSuperUser(event)) {\r\n return;\r\n }\r\n if (isSystemUser(event)) {\r\n return;\r\n }\r\n\r\n if (process.env.BUILD_ENV === 'local') {\r\n return;\r\n }\r\n if (!allowAccess) {\r\n throw errorList.unauthorized;\r\n }\r\n}\r\n\r\nexport const userRoles = {\r\n admin: 'A',\r\n read: 'R',\r\n write: 'W'\r\n};\r\n\r\n/**\r\n * Get the partner ID from custom:PID if the user is a partner admin.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {string|false} The partner ID or false if not a partner user.\r\n */\r\nexport function isPartnerUser(event) {\r\n const partnerId = _.get(event, 'requestContext.authorizer.claims.custom:PID') ||\r\n _.get(event, 'requestContext.authorizer.custom:PID') ||\r\n '';\r\n return partnerId || false;\r\n}\r\n\r\n/**\r\n * Get the partner ID from custom:BPID if the user's business belongs to a partner.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {string|false} The partner ID or false if not associated with a partner.\r\n */\r\nexport function getBelongsToPartnerId(event) {\r\n const partnerId = _.get(event, 'requestContext.authorizer.claims.custom:BPID') ||\r\n _.get(event, 'requestContext.authorizer.custom:BPID') ||\r\n '';\r\n return partnerId || false;\r\n}\r\n\r\n/**\r\n * Get the effective partner ID from either custom:PID or custom:BPID.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {string|false} The partner ID or false.\r\n */\r\nexport function getEffectivePartnerId(event) {\r\n return isPartnerUser(event) || getBelongsToPartnerId(event);\r\n}\r\n\r\n/**\r\n * Enrich the event's custom:AR with partner business IDs in-memory.\r\n * Call this BEFORE accessRightsUtils() or getBusinessesInfo() so that\r\n * partner admins (custom:PID) get access to their partner's merchants.\r\n *\r\n * This keeps accessRightsUtils synchronous — the DB lookup is done by the caller.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @param {string[]} partnerBusinessIds - Array of business IDs from the partner record.\r\n * @param {string} [role='R'] - Access role to assign (default: Read).\r\n */\r\nexport function enrichEventWithPartnerAccess(event, partnerBusinessIds, role = 'R') {\r\n if (!partnerBusinessIds || partnerBusinessIds.length === 0) return;\r\n\r\n const arPath = event?.requestContext?.authorizer?.claims\r\n ? 'requestContext.authorizer.claims.custom:AR'\r\n : 'requestContext.authorizer.custom:AR';\r\n\r\n const json = _.get(event, arPath) || '{}';\r\n const accessRights = JSON.parse(json);\r\n const businessIds = accessRights.businessIds || {};\r\n\r\n for (const bid of partnerBusinessIds) {\r\n if (!businessIds[bid]) {\r\n businessIds[bid] = role;\r\n }\r\n }\r\n\r\n accessRights.businessIds = businessIds;\r\n _.set(event, arPath, JSON.stringify(accessRights));\r\n}\r\n\r\n/**\r\n * @param {{body: string}} event\r\n * @param {{useCognitoBid:boolean}} [options] - An object with options, useCognitoBid prefers the businessId set in cognito if set and does not return the local bid of 1 if a bid is in the claim.\r\n * @returns {string} businessId\r\n */\r\nexport function checkWriteAccess(event, options) {\r\n const eventBody = parseBody(event);\r\n const businessIds = accessRightsUtils(event, options) || [];\r\n const businessId = businessIds.find((id) => id === eventBody.businessId);\r\n const raw = getBusinessesInfo(event);\r\n const userRight = raw[businessId];\r\n\r\n if (isSuperUser(event)) {\r\n return eventBody.businessId;\r\n }\r\n\r\n if (isSystemUser(event)) {\r\n return eventBody.businessId;\r\n }\r\n\r\n if (process.env.BUILD_ENV === 'local') {\r\n return eventBody.businessId;\r\n }\r\n\r\n if ((userRight !== userRoles.admin && userRight !== userRoles.write) || (!userRight)) {\r\n throw errorList.unauthorized;\r\n }\r\n return businessId;\r\n}\r\n\r\n/**\r\n * Get the company-level cached settings from custom:SET.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {object} The company settings object (e.g. { auditEnabled: true })\r\n */\r\nexport function getCompanySettings(event) {\r\n const jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:SET')\r\n || _.get(event, 'requestContext.authorizer.custom:SET')\r\n || '{}';\r\n try {\r\n return JSON.parse(jsonToParse);\r\n } catch (e) {\r\n return {};\r\n }\r\n}\r\n\r\n","module.exports = require(\"@aws-sdk/client-sns\");","module.exports = require(\"lodash\");","import _ from 'lodash';\n\n/**\n * Create sequelize order clause from query string parameters and default sort object\n *\n * @param {object} event - the event created AWS lambda, it will contain queryStringParameters with sort property a comma seperated list of sortable fields * @param {object} objectFilters - the default filters object created by createDefaultFilters\n * @param {object} defaultFilter - A default filter object as built by createDefault Filters, if items are not on the schema they will not be in the order by\n * @returns {object} An sequelize order by object\n */\nexport const createSort = function (event, defaultFilter) {\n let copyOfDefaultFilter = _.clone(defaultFilter);\n let query = _.get(event, 'queryStringParameters', {}) || {};\n let sort = _.get(query, 'sort', '-updatedAt') || '-updatedAt';\n\n return sort.split(',').reduce((acc, item) => {\n\n const testItem = item.indexOf('-') === 0 ? item.substr(1) : item;\n\n if (_.get(copyOfDefaultFilter, testItem, null)) {\n const sortItem = [];\n\n testItem.split('.').forEach((parentChildList) => {\n sortItem.push(parentChildList);\n });\n\n if (item.indexOf('-') === 0) {\n sortItem.push('DESC');\n } else {\n sortItem.push('ASC');\n }\n acc.push(sortItem);\n }\n\n return acc;\n }, []);\n};\n","import _ from 'lodash';\r\nimport { errorList } from './errorCodes.js';\r\n\r\nconst securityHeaders = {\r\n 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',\r\n 'X-Content-Type-Options': 'nosniff',\r\n 'X-Frame-Options': 'DENY',\r\n 'Referrer-Policy': 'strict-origin-when-cross-origin',\r\n 'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',\r\n 'Cache-Control': 'no-store',\r\n 'Content-Security-Policy': \"default-src 'none'; frame-ancestors 'none'\"\r\n};\r\n\r\nconst htmlSecurityHeaders = {\r\n 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',\r\n 'X-Content-Type-Options': 'nosniff',\r\n 'Referrer-Policy': 'strict-origin-when-cross-origin',\r\n 'Permissions-Policy': 'camera=(), microphone=(), geolocation=(), payment=*',\r\n 'Cache-Control': 'no-store',\r\n 'Content-Security-Policy': [\r\n \"default-src 'self'\",\r\n \"script-src 'self' 'unsafe-inline' https://browser.sentry-cdn.com https://test-htp.tokenex.com https://htp.tokenex.com https://sandbox.nmi.com https://secure.nmi.com https://applepay.cdn-apple.com\",\r\n \"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://sandbox.nmi.com https://secure.nmi.com\",\r\n \"font-src 'self' https://fonts.gstatic.com\",\r\n \"frame-src https:\",\r\n \"connect-src 'self' https://*.tokenex.com https://*.sentry.io https://*.nmi.com https://*.apple.com\",\r\n \"img-src 'self' data:\",\r\n \"frame-ancestors *\"\r\n ].join('; ')\r\n};\r\n\r\n/**\r\n * @param {Object} body\r\n * @param {{dbClose?:function}} [options]\r\n */\r\nexport function success(body, options) {\r\n const dbClose = _.get(options, 'dbClose', _.noop);\r\n dbClose();\r\n\r\n return buildResponse(200, body);\r\n}\r\n\r\n/**\r\n * @param {string} html\r\n * @param {{dbClose:function|undefined}} options\r\n */\r\nexport function successHtml(html, options) {\r\n const dbClose = _.get(options, 'dbClose', _.noop);\r\n\r\n dbClose();\r\n return {\r\n statusCode: 200,\r\n headers: {\r\n 'Content-Type': 'text/html',\r\n 'Access-Control-Allow-Origin': '*',\r\n 'Access-Control-Allow-Credentials': true,\r\n ...htmlSecurityHeaders\r\n },\r\n body: html\r\n };\r\n}\r\n\r\n/**\r\n * @param {string} event\r\n * @returns string\r\n */\r\nexport function getCurrentUserNameFromCognitoEvent(event) {\r\n const attributes = _.get(event, 'request.userAttributes');\r\n\r\n return attributes['cognito:email_alias'] || attributes['email'] || 'UNKNOWN USER';\r\n}\r\n\r\n/**\r\n * Get the user information from the event object\r\n *\r\n * @param event {Object} an event object\r\n * @returns {{username: string, id: number}}\r\n */\r\nexport function getCurrentUser(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:UID') ||\r\n _.get(event, 'requestContext.authorizer.custom:UID') ||\r\n '0';\r\n\r\n const username = _.get(event, 'requestContext.authorizer.claims.email') || _.get(event, 'requestContext.authorizer.email') || 'localtestuser@gexample.com';\r\n const id = process.env.BUILD_ENV === 'local' ? 1 : JSON.parse(jsonToParse);\r\n\r\n return {\r\n username,\r\n id\r\n };\r\n}\r\n\r\n/**\r\n * Create a failure response\r\n *\r\n * @param body {Object} an event object\r\n * @param options {Object} an options object\r\n * @returns {{statusCode:number, headers:object, body:string}} a response object\r\n */\r\nexport function failure(body = {}, options) {\r\n const dbClose = _.get(options, 'dbClose', _.noop);\r\n dbClose();\r\n let cleanedErrorBody;\r\n\r\n if (process.env.UTIL_LOG === 'LOG_ALL' || process.env.BUILD_ENV === 'test') {\r\n if (_.isObject(body)) {\r\n console.error('------->ALL UTIL ERROR:', JSON.stringify(body, null, 2));\r\n }\r\n }\r\n\r\n const NORMAL_ERROR = { statusCode: 500, errorCode: '5XX', message: 'INTERNAL UTIL ERROR' };\r\n cleanedErrorBody = body;\r\n if (!_.isUndefined(body.details)) {\r\n cleanedErrorBody = detectJoyError(body);\r\n } else if (_.isUndefined(body.errorCode) || _.isUndefined(body.statusCode)) {\r\n cleanedErrorBody = detectSequelizeError(body);\r\n }\r\n if (_.get(body, 'response.data.message')) {\r\n const err = _.get(body, 'response.data.message');\r\n if (_.isObject(body)) {\r\n if (process.env.UTIL_LOG === 'LOG_ALL' || process.env.BUILD_ENV === 'test') {\r\n console.error('------->MSG UTIL ERROR:', JSON.stringify(err, null, 2));\r\n }\r\n }\r\n }\r\n const newBody = _.merge(NORMAL_ERROR, cleanedErrorBody);\r\n\r\n return buildResponse(newBody.statusCode, newBody);\r\n}\r\n\r\n/**\r\n * Create a failure response object\r\n *\r\n * @param statusCode {Number} a status code\r\n * @param body {Object} an event object\r\n * @returns {{statusCode:number, headers:object, body:string}} a response object\r\n */\r\nfunction buildResponse(statusCode, body) {\r\n return {\r\n statusCode: statusCode,\r\n headers: {\r\n 'Access-Control-Allow-Origin': '*',\r\n 'Access-Control-Allow-Credentials': true,\r\n ...securityHeaders\r\n },\r\n body: JSON.stringify(body)\r\n };\r\n}\r\n\r\n/**\r\n * parse the body of the event object\r\n *\r\n * @param requestEvent {{body:string}} an event object\r\n * @returns event {*} the json object of the body\r\n */\r\nexport function parseBody(requestEvent) {\r\n\r\n let eventBody = {};\r\n if (_.isString(requestEvent.body)) {\r\n try {\r\n eventBody = JSON.parse(requestEvent.body);\r\n } catch (e) {\r\n // Invalid JSON\r\n eventBody = null;\r\n\r\n throw errorList.invalidJson;\r\n }\r\n } else if (_.isObject(requestEvent.body)) {\r\n eventBody = requestEvent.body;\r\n }\r\n\r\n return eventBody;\r\n}\r\n\r\n/**\r\n * parse the body of the event object\r\n *\r\n * @param requestEvent {string|object} an event object\r\n * @param [callback] {function} undefined a call back function\r\n * @returns event {*} the json object of the body\r\n */\r\nexport function parseEvent(requestEvent, callback) {\r\n let event = {};\r\n if (_.isString(requestEvent)) {\r\n try {\r\n event = JSON.parse(requestEvent);\r\n } catch (e) {\r\n // Invalid JSON\r\n event = null;\r\n\r\n if (callback) {\r\n callback(Error(e));\r\n }\r\n }\r\n } else if (_.isObject(requestEvent)) {\r\n event = requestEvent;\r\n }\r\n\r\n return event;\r\n}\r\n\r\n/**\r\n * parse the body of the event object\r\n * look for sequelize errors and return a message\r\n * ERRORS should not be caught here this is a fallback for unknown database errors\r\n *\r\n * @param body {object} part of a body response\r\n * @returns error message object {message:string}\r\n */\r\nexport function detectSequelizeError(body) {\r\n const errorBody = {};\r\n const errorName = _.get(body, 'name', '');\r\n\r\n if (errorName === 'SequelizeForeignKeyConstraintError') {\r\n const detail = _.get(body, 'parent.detail') || _.get(body, 'original.detail') || '';\r\n const notPresent = detail.match(/Key \\((\\w+)\\)=\\((.+?)\\) is not present in table \"(\\w+)\"/);\r\n const stillReferenced = detail.match(/Key \\((\\w+)\\)=\\((.+?)\\) is still referenced from table \"(\\w+)\"/);\r\n if (notPresent) {\r\n errorBody.message = 'The referenced ' + notPresent[3] + ' does not exist (' + notPresent[1] + ': ' + notPresent[2] + ')';\r\n } else if (stillReferenced) {\r\n errorBody.message = 'This item cannot be removed because it is referenced by ' + stillReferenced[3];\r\n } else {\r\n errorBody.message = 'A referenced item does not exist or is still in use';\r\n }\r\n errorBody.statusCode = 409;\r\n errorBody.errorCode = '4090';\r\n return errorBody;\r\n }\r\n\r\n if (errorName === 'SequelizeUniqueConstraintError') {\r\n const fields = _.get(body, 'errors', []).map(err => _.get(err, 'path')).filter(Boolean);\r\n errorBody.message = fields.length\r\n ? 'A record with this ' + fields.join(', ') + ' already exists'\r\n : 'A record with this value already exists';\r\n errorBody.statusCode = 409;\r\n errorBody.errorCode = '4091';\r\n return errorBody;\r\n }\r\n\r\n if (errorName === 'SequelizeValidationError') {\r\n const messages = _.get(body, 'errors', []).map(err => _.get(err, 'message')).filter(Boolean);\r\n errorBody.message = messages.length ? messages.join(', ') : 'Validation error';\r\n errorBody.statusCode = 400;\r\n errorBody.errorCode = '4001';\r\n return errorBody;\r\n }\r\n\r\n let sequelizeError = _.get(body, 'errors', []).reduce((acc, err) => {\r\n acc = acc + ' ' + _.get(err, 'message');\r\n return acc;\r\n }, '');\r\n const parentError = _.get(body, 'parent', '');\r\n\r\n sequelizeError = sequelizeError + _.get(body, 'original.detail', '') + _.get(body, 'TypeError', '') + parentError;\r\n errorBody.message = sequelizeError.trim();\r\n return errorBody;\r\n}\r\n\r\nexport function detectJoyError(body) {\r\n const errorBody = {};\r\n const joyError = _.get(body, 'details[0]', {});\r\n const additionalMessages = _.get(body, 'details[0].context.details') || [];\r\n\r\n const v = additionalMessages.reduce((acc, contextItem) => {\r\n acc = acc + ' ' + contextItem?.message || '';\r\n return acc;\r\n }, '');\r\n\r\n console.error('USER VALIDATION ERROR:', body);\r\n const msg = (joyError?.message || '') + v;\r\n\r\n if (msg) {\r\n errorBody.message = _.trim(msg);\r\n }\r\n\r\n errorBody.statusCode = 400;\r\n errorBody.errorCode = '4000';\r\n return errorBody;\r\n}\r\n\r\n/**\r\n * Parse the body of a Dynamoose error response.\r\n * Attempts to extract a human-readable error message from Dynamoose errors.\r\n * This is a fallback for unknown database errors.\r\n *\r\n * @param {object} body - Part of a body response containing error details.\r\n * @returns {object} - Error message object { message: string }\r\n */\r\nexport function detectDynamooseError(body) {\r\n const errorBody = {};\r\n\r\n // Start with an empty message string.\r\n let dynamooseError = '';\r\n\r\n // If the error body contains an array of errors, concatenate their messages.\r\n if (Array.isArray(body.errors)) {\r\n dynamooseError += body.errors.reduce((acc, err) => {\r\n return acc + ' ' + (err.message || '');\r\n }, '');\r\n }\r\n\r\n // If there's a top-level message, add it.\r\n if (body.message) {\r\n dynamooseError += ' ' + body.message;\r\n }\r\n\r\n // If there is any additional detail provided, append it.\r\n if (body.detail) {\r\n dynamooseError += ' ' + body.detail;\r\n }\r\n\r\n // Trim the message to remove extra spaces.\r\n errorBody.message = dynamooseError.trim();\r\n\r\n return errorBody;\r\n}","import _ from 'lodash';\nimport dayjs from 'dayjs';\nimport customParseFormat from 'dayjs/plugin/customParseFormat';\nimport isSameOrBefore from 'dayjs/plugin/isSameOrBefore';\nimport Promise from 'bluebird';\nimport S3Utils from '../s3/S3Utils/S3Utils.js';\nimport SNSUtil from '../sns/SNSUtils.js';\nimport dynamoUtil from '../dynamo/dynamoUtils.js';\n\ndayjs.extend(customParseFormat);\ndayjs.extend(isSameOrBefore);\n\n/**\n * @param {string} bucket\n * @param {number} maxKeys\n * @param {Object} userImportTypes\n */\nexport async function loop(bucket, maxKeys, userImportTypes) {\n let bucketResult = {};\n let fileList = [];\n\n const currentTime = dayjs();\n\n do {\n bucketResult = await S3Utils.listObjectsV2({\n Bucket: bucket,\n MaxKeys: maxKeys,\n ContinuationToken: _.get(bucketResult, 'NextContinuationToken')\n });\n\n let newFiles = _.filter(bucketResult.Contents, (file) => {\n if (_.startsWith(_.get(file, 'Key'), 'delayUntil/')) {\n const fileDelayTime = _.get(file, 'Key').split('/')[1];\n return dayjs(fileDelayTime, 'YYYYMMDDHHmm').isSameOrBefore(currentTime);\n }\n if (userImportTypes) {\n // look for items in the userImportTypes\n const usersImports = Object.values(userImportTypes);\n const items = file.Key.split('/');\n const fileName = _.last(items);\n const folderName = _.first(items);\n if (_.isEmpty(fileName)) {\n return false;\n\n } else if (usersImports.indexOf(folderName) === -1) {\n return false;\n }\n\n return !_.startsWith(file.Key, `${folderName}/error`);\n }\n return !_.startsWith(file.Key, 'error');\n });\n\n fileList = _.concat(fileList, newFiles);\n } while (bucketResult.IsTruncated && bucketResult.NextContinuationToken && fileList.length < maxKeys);\n\n return fileList;\n}\n\n/**\n * Published SNS events at a steady pace for data in a particular bucket. Should be executed via a cloud watch cron job as a part of a micro service\n *\n * @param {string} configTable - The Dynamo DB table where to get the chunk-size and maxMessage size\n * @param {string} tableKey - The key to the item in the Dynamo DB table that holds the chunk-size and maxMessage size\n * @param {string} bucket - The name of the s3 bucket to watch, when you drop items into this table events will be created\n * @param {string} snsTopic - The name of the snsEvent to publish\n * @param {object} userImportTypes - import types to filter on\n */\nexport async function publishEvents(configTable, tableKey, bucket, snsTopic, userImportTypes) {\n let result;\n try {\n result = await dynamoUtil.get({\n TableName: configTable,\n Key: { key: tableKey }\n });\n } catch (e) {\n console.error(`Cannot get config for key: ${tableKey} table: ${configTable} falling back to defaults of 2 and 10`, e);\n }\n let chunkSize = _.get(result, 'Item.snsChunkSize', 2);\n let maxMessages = _.get(result, 'Item.snsMaxMessages', 10);\n\n const snsCreateTopicResponse = await SNSUtil.createTopic({ Name: snsTopic });\n const topicArn = snsCreateTopicResponse.TopicArn;\n const maxKeys = chunkSize * maxMessages;\n\n const fileList = await loop(bucket, maxKeys, userImportTypes);\n\n const messageList = _.chain(fileList)\n .map('Key')\n .chunk(chunkSize)\n .slice(0, maxMessages)\n .value()\n ;\n\n return Promise.map(messageList, (files) => {\n return SNSUtil.publish({\n Message: JSON.stringify({\n bucket: bucket,\n files: files\n }),\n TopicArn: topicArn\n });\n });\n}","import _ from 'lodash';\nimport { SequelizeStorage, Umzug } from 'umzug';\n\n/**\n * Execute database migrations\n * @param {string} databaseName - name of database to create (or verify existence)\n * @param {object} sequelizeInstance - instance of Sequelize (must be initialized)\n * @param {function} initializeModels - function to run to sync Sequelize models with database\n * @param {string} pathToMigrationFolder - pass in the path if using windows. windows and linux PWD will be different\n */\nexport async function runMigrations(databaseName,\n sequelizeInstance,\n initializeModels,\n pathToMigrationFolder = `${process.env.PWD}/migrations/*.js`) {\n const umzug = new Umzug({\n migrations: { glob: pathToMigrationFolder },\n context: sequelizeInstance.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize: sequelizeInstance }),\n logger: console\n });\n\n const pendingMigrations = await umzug.pending();\n console.log('------->UTIL Pending Migrations:', pendingMigrations, pathToMigrationFolder);\n await umzug.up().catch((upError) => {\n console.error('Migration Error: ', upError);\n return umzug.down({\n migrations: _.chain(pendingMigrations)\n .map('file')\n .reverse()\n .value()\n }).then(() => {\n const msg = 'UTIL Error: Error with migrating up:' + upError;\n console.error(msg);\n throw new Error(msg);\n }, (downError) => {\n const msg = 'UTIL Error: Error with migrating down:' + downError;\n console.error(msg);\n throw new Error(msg);\n });\n });\n\n // The following line is needed to sync (create) tables, but not to database updates\n // in the past it worked to leave it in, but now the tags module causes foreign key problems\n // The tables are still initiated by being passed in to run migrations\n await initializeModels();\n}","import _ from 'lodash';\nimport S3Util from '../s3/S3Utils/S3Utils.js';\n\nexport async function handleFile(path, s3Bucket, transformer, options) {\n const shouldSkipFailedFolders = _.get(options, 'shouldSkipFailedFolders');\n const userImportTypes = _.get(options, 'userImportTypes');\n const params = {\n Bucket: s3Bucket,\n Key: path\n };\n let body;\n\n try {\n body = await S3Util.getObject(params);\n } catch (e) {\n if (e.Code === 'NoSuchKey' || e.code === 'NoSuchKey' || e.name === 'NoSuchKey') {\n return;\n }\n console.error('S3 getObject error:', e);\n throw e;\n }\n\n try {\n // exit early for null/undefined or blank string bodies\n if (_.isNil(body) || (_.isString(body) && _.isEmpty(body.trim()))) {\n await S3Util.deleteObject(params);\n return;\n }\n\n const parsedBody = JSON.parse(body);\n\n // exit early for objects like {} or []\n if (_.isEmpty(parsedBody)) {\n await S3Util.deleteObject(params);\n return;\n }\n\n const returnedValue = await transformer(parsedBody);\n await S3Util.deleteObject(params);\n\n return returnedValue;\n } catch (error) {\n console.error('HANDLE-FILE-ERROR', error);\n\n if (!body) {\n return;\n }\n\n let newPath = '';\n\n if (userImportTypes) {\n console.log('USER IMPORT');\n // look for items in the userImportTypes\n const usersImports = Object.values(userImportTypes);\n const items = path.split('/');\n const fileName = _.last(items);\n const folderName = _.first(items);\n\n if (usersImports.indexOf(folderName) > -1) {\n if (shouldSkipFailedFolders) {\n newPath = `${folderName}/error/${fileName}`;\n } else if (_.startsWith(path, `${folderName}/failed-once/`)) {\n newPath = _.replace(path, `${folderName}/failed-once/`, `${folderName}/failed-twice/`);\n } else if (_.startsWith(path, `${folderName}/failed-twice/`)) {\n newPath = _.replace(path, `${folderName}/failed-twice/`, `${folderName}/error/`);\n } else {\n newPath = `${folderName}/failed-once/${fileName}`;\n }\n } else {\n newPath = `pathAndEventMisMatchError/${path}`;\n }\n\n } else {\n if (shouldSkipFailedFolders) {\n newPath = `error/${path}`;\n } else if (_.startsWith(path, 'failed-once/')) {\n newPath = _.replace(path, 'failed-once/', 'failed-twice/');\n } else if (_.startsWith(path, 'failed-twice/')) {\n newPath = _.replace(path, 'failed-twice/', 'error/');\n } else {\n if (_.includes(path, 'delayUntil/')) {\n path = _.last(path.split('/'));\n }\n\n newPath = `failed-once/${path}`;\n }\n }\n\n const newParams = {\n Bucket: s3Bucket,\n Key: newPath,\n Body: body\n };\n\n if (\n containsError(newPath, 'failed-once') ||\n containsError(newPath, 'failed-twice') ||\n containsError(newPath, 'error')\n ) {\n throw new Error('NESTING ERROR');\n }\n\n await S3Util.putObject(newParams);\n await S3Util.deleteObject(params);\n\n throw error;\n }\n}\n\nexport function containsError(str, val) {\n const firstIndex = str.toLowerCase().indexOf(val);\n if (firstIndex === -1) return false;\n const secondIndex = str.toLowerCase().indexOf(val, firstIndex + 1);\n return secondIndex !== -1;\n}\n","import { S3 } from '@aws-sdk/client-s3';\n\nexport function s3Utils(action, params) {\n const s3 = new S3();\n return s3[action](params);\n}\n\nconst S3Util = {\n getObject: (params) => getS3(params),\n deleteObject: (params) => s3Utils('deleteObject', params),\n putObject: (params) => s3Utils('putObject', params),\n listObjectsV2: (params) => s3Utils('listObjectsV2', params)\n};\nexport default S3Util;\n\nasync function getS3(params) {\n const s3 = new S3();\n const response = await s3.getObject(params);\n return response?.Body.transformToString('utf-8');\n}","module.exports = require(\"umzug\");","module.exports = require(\"@aws-sdk/client-dynamodb\");","export const errorList = {\n invalidInventoryReleaseRequest: {\n message: 'NOT ENOUGH INVENTORY TO FULFILL RELEASE',\n errorCode: '4010',\n statusCode: 400\n },\n alreadyReleased: {\n message: 'ALREADY RELEASED',\n errorCode: '4011',\n statusCode: 400\n },\n alreadyReceived: {\n message: 'RECEIVABLE ALREADY RECEIVED',\n errorCode: '4012',\n statusCode: 400\n },\n invalidItemsRequest: {\n message: 'VALID ITEMS MUST BE INCLUDED',\n errorCode: '4013',\n statusCode: 400\n },\n invalidID: {\n message: 'ID is invalid',\n errorCode: '4014',\n statusCode: 400\n },\n invalidReceivable: {\n message: 'MUST CONTAIN AT LEAST ONE RECEIVABLE',\n errorCode: '4015',\n statusCode: 400\n },\n invalidRequest: {\n message: 'INVALID REQUEST DATA',\n errorCode: '4016',\n statusCode: 400\n },\n invalidAPIKey: {\n message: 'INVALID REQUEST - API MAY KEY INVALID',\n errorCode: '4017',\n statusCode: 400\n },\n qbCreationError: {\n message: 'QUICKBOOKS ERROR - ERROR CREATING OBJECT IN QUICKBOOKS',\n errorCode: '4018',\n statusCode: 400\n },\n cannotReopen: {\n message: 'CANNOT REOPEN - THE ORDER HAS ALREADY BEEN OPENED',\n errorCode: '4018',\n statusCode: 400\n },\n invalidDateFormat: {\n message: 'INVALID DATE FORMAT',\n errorCode: '4019',\n statusCode: 400\n },\n invalidStartDate: {\n message: 'INVALID START DATE',\n errorCode: '4020',\n statusCode: 400\n },\n invalidEndDate: {\n message: 'INVALID END DATE',\n errorCode: '4021',\n statusCode: 400\n },\n invalidOrderStatus: {\n message: 'UNABLE TO EDIT ORDER ITEMS UNLESS THE ORDER IS IN ESTIMATE STATUS',\n errorCode: '4022',\n statusCode: 400\n },\n invalidPaymentStatus: {\n message: 'UNABLE TO UPDATE PAYMENT STATUS PAYMENT MUST BE OPEN',\n errorCode: '4023',\n statusCode: 400\n },\n invalidReleaseStatus: {\n message: 'UNABLE TO UPDATE RELEASE, STATUS RELEASE MUST BE OPEN',\n errorCode: '4024',\n statusCode: 400\n },\n invalidReceivableStatus: {\n message: 'UNABLE TO UPDATE RECEIVABLE, STATUS RECEIVABLE MUST BE OPEN',\n errorCode: '40025',\n statusCode: 400\n },\n invalidJson:{\n message: 'INVALID JSON',\n errorCode: '4005',\n statusCode: 400\n },\n invalidFilter:{\n message: 'INVALID FILTER',\n errorCode: '4026',\n statusCode: 400\n },\n invalidUserNameUpdate:{\n message: 'UNABLE TO UPDATE USERNAME',\n errorCode: '4027',\n statusCode: 400\n },\n imageSizeLimit:{\n message: 'IMAGE SIZE LIMIT 100KB EXCEEDED',\n errorCode: '4028',\n statusCode: 400\n },\n unauthorized:{\n message: 'UNAUTHORIZED',\n errorCode: '4111',\n statusCode: 401\n },\n notFound:{\n message: 'ITEM NOT FOUND',\n errorCode: '4004',\n statusCode: 404\n },\n emailRequired:{\n message: 'NO EMAIL PROVIDED, CHECK CUSTOMER EMAIL',\n errorCode: '4004',\n statusCode: 404\n },\n mobilePhoneRequired:{\n message: 'NO MOBILE PHONE PROVIDED, CHECK CUSTOMER CONTACTS',\n errorCode: '4004',\n statusCode: 404\n },\n invalidCadenceType: {\n message: 'INVALID CADENCE TYPE',\n errorCode: '5001',\n statusCode: 500\n },\n partnerNotConfigured: {\n message: 'Partner has no partnerBusinessId configured. Contact support.',\n errorCode: '4310',\n statusCode: 400\n },\n};","/**\n * create pagination object from Sequelize findAll\n * @param {object} result - sequelize result\n * @param {number} limit - max number of results to return\n * @param {number} offset - page offset\n */\nexport function getPaginationFromFindAll(result, limit, offset) {\n result = result || [];\n limit = limit || 0;\n offset = offset || 0;\n\n const hasMore = result.length > limit;\n if (hasMore) {\n result.splice(-1, 1);\n }\n const pageObject = {\n offset: offset,\n limit: limit,\n rows: result,\n hasMore: hasMore\n };\n\n return pageObject;\n}\n\n/**\n * wrapper for Sequelize findAll\n * @param {object} model - instance of Sequelize (must be initialized)\n * @param {*&{include: [{model: *}], where: {businessId: Array}, order: [string[]]}} options - instance of Sequelize (must be initialized)\n */\nexport async function findAll(model, options) {\n\n const limit = options.limit || 0;\n const includes = options.includes || { all: true, nested: true };\n const findArgs = Object.assign({include: includes}, options, { limit: limit + 1 });\n const results = await model.findAll(findArgs);\n return getPaginationFromFindAll(results, limit, options.offset);\n}\n\nconst findUtils = {\n findAll\n};\nexport default findUtils;","import _ from 'lodash';\n\n/**\n * Create sequelize includes array from query string parameters and default sequelize model\n *\n * @param {object} event - the query parameters from the event passed by lambda\n * @param {object} objectFilters - the default filters object created by createDefaultFilters\n * @returns {object} A sequelize includes array\n */\n\nexport function createIncludes(event, objectFilters) {\n const query = _.get(event, 'queryStringParameters', {}) || {};\n\n const keys = Object.keys(objectFilters);\n\n const canBeIncluded = keys.reduce((acc, item) => {\n acc = includeSubItem(item, acc);\n\n return acc;\n }, []);\n\n const askedForInQuery = Object.keys(query).reduce((acc, item) => {\n if (item === 'sort') {\n query[item].split(',').forEach((sortItem) => {\n sortItem = sortItem.indexOf('-') === 0 ? sortItem.substr(1) : sortItem;\n acc = includeSubItem(sortItem, acc);\n });\n }\n\n acc = includeSubItem(item, acc);\n\n return acc;\n }, []);\n\n return _.intersection(canBeIncluded, askedForInQuery);\n}\n\nexport function includeSubItem(queryStringItem, acc = []) {\n const dot = queryStringItem.indexOf('.');\n if (dot > 0) {\n acc.push(queryStringItem.substring(0, dot));\n }\n\n return acc;\n}","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","import { handleFile as handleFileImport } from './eventManager/handleFile.js';\r\nimport { watchBucket as watchBucketImport } from './eventManager/watchBucket.js';\r\nimport { publishEvents as publishEventsImport } from './eventManager/publishEvents.js';\r\nimport { createIncludes as createIncludesImport } from './database/dbUtils/queryStringUtils/createIncludes.js';\r\nimport { createFilters as createFiltersImport } from './database/dbUtils/queryStringUtils/createFilters.js';\r\nimport { createSort as createSortImport } from './database/dbUtils/queryStringUtils/createSort.js';\r\nimport { findAll as findAllImport } from './database/dbUtils/queryStringUtils/findAll.js';\r\nimport { checkModule as checkModuleImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { checkIsSuper as checkIsSuperImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getModuleInfo as getModuleInfoImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getAccessRightsInfo as getAccessRightsInfoImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getDefaultBusinessIDInfo as getDefaultBusinessIDInfoImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { failure as failureImport, success as successImport } from './requestResponse/requestResponse.js';\r\nimport { runMigrations as runMigrationsImport } from './database/dbSetup/migrations.js';\r\nimport { getCurrentUser as getCurrentUserImport } from './requestResponse/requestResponse.js';\r\nimport { successHtml as successHtmlImport } from './requestResponse/requestResponse.js';\r\nimport { getCurrentUserNameFromCognitoEvent as getCurrentUserNameFromCognitoEventImport } from './requestResponse/requestResponse.js';\r\nimport { defaultFilters as defaultFiltersImport } from './database/dbUtils/queryStringUtils/defaultFilters.js';\r\nimport { accessRightsUtils as accessRightsUtilsImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { parseBody as parseBodyImport } from './requestResponse/requestResponse.js';\r\nimport { parseEvent as parseEventImport } from './requestResponse/requestResponse.js';\r\nimport { getBusinessesInfo as getBusinessesInfoImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { userDefaultBid as userDefaultBidImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { checkWriteAccess as checkWriteAccessImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { isSystemUser as isSystemUserImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { isSuperUser as isSuperUserImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { isPartnerUser as isPartnerUserImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getBelongsToPartnerId as getBelongsToPartnerIdImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getEffectivePartnerId as getEffectivePartnerIdImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { enrichEventWithPartnerAccess as enrichEventWithPartnerAccessImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getCompanySettings as getCompanySettingsImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { resolveAccess as resolveAccessImport, ensurePartnerScope as ensurePartnerScopeImport } from './database/dbUtils/partnerAccess/accessContext.js';\r\nimport { requireCrmAccess as requireCrmAccessImport, requireTicketAccess as requireTicketAccessImport, requireSuper as requireSuperImport } from './database/dbUtils/partnerAccess/accessGates.js';\r\nimport { scopeToOwnBusiness as scopeToOwnBusinessImport, scopeToPartnerBook as scopeToPartnerBookImport, scopeToBookUnionOwn as scopeToBookUnionOwnImport } from './database/dbUtils/partnerAccess/accessScope.js';\r\nimport { assertCanWriteOwnBusiness as assertCanWriteOwnBusinessImport, assertCanWriteBookBusiness as assertCanWriteBookBusinessImport, assertCanWriteBookUnionOwn as assertCanWriteBookUnionOwnImport, stampOwnBusinessId as stampOwnBusinessIdImport } from './database/dbUtils/partnerAccess/accessWrites.js';\r\nimport { createAccessHelpers as createAccessHelpersImport } from './database/dbUtils/partnerAccess/createAccessHelpers.js';\r\n\r\nexport const handleFile = handleFileImport;\r\nexport const watchBucket = watchBucketImport;\r\nexport const publishEvents = publishEventsImport;\r\nexport const createFilters = createFiltersImport;\r\nexport const createIncludes = createIncludesImport;\r\nexport const createSort = createSortImport;\r\nexport const findAll = findAllImport;\r\nexport const checkModule = checkModuleImport;\r\nexport const checkIsSuper = checkIsSuperImport;\r\nexport const getAccessRightsInfo = getAccessRightsInfoImport;\r\nexport const getDefaultBusinessIDInfo = getDefaultBusinessIDInfoImport;\r\nexport const getModuleInfo = getModuleInfoImport;\r\nexport const failure = failureImport;\r\nexport const success = successImport;\r\nexport const runMigrations = runMigrationsImport;\r\nexport const getCurrentUser = getCurrentUserImport;\r\nexport const successHtml = successHtmlImport;\r\nexport const getCurrentUserNameFromCognitoEvent = getCurrentUserNameFromCognitoEventImport;\r\nexport const defaultFilters = defaultFiltersImport;\r\nexport const accessRightsUtils = accessRightsUtilsImport;\r\nexport const parseBody = parseBodyImport;\r\nexport const parseEvent = parseEventImport;\r\nexport const getBusinessesInfo = getBusinessesInfoImport;\r\nexport const userDefaultBid = userDefaultBidImport;\r\nexport const checkWriteAccess = checkWriteAccessImport;\r\nexport const isSystemUser = isSystemUserImport;\r\nexport const isSuperUser = isSuperUserImport;\r\nexport const isPartnerUser = isPartnerUserImport;\r\nexport const getBelongsToPartnerId = getBelongsToPartnerIdImport;\r\nexport const getEffectivePartnerId = getEffectivePartnerIdImport;\r\nexport const enrichEventWithPartnerAccess = enrichEventWithPartnerAccessImport;\r\nexport const getCompanySettings = getCompanySettingsImport;\r\nexport const resolveAccess = resolveAccessImport;\r\nexport const ensurePartnerScope = ensurePartnerScopeImport;\r\nexport const requireCrmAccess = requireCrmAccessImport;\r\nexport const requireTicketAccess = requireTicketAccessImport;\r\nexport const requireSuper = requireSuperImport;\r\nexport const scopeToOwnBusiness = scopeToOwnBusinessImport;\r\nexport const scopeToPartnerBook = scopeToPartnerBookImport;\r\nexport const scopeToBookUnionOwn = scopeToBookUnionOwnImport;\r\nexport const assertCanWriteOwnBusiness = assertCanWriteOwnBusinessImport;\r\nexport const assertCanWriteBookBusiness = assertCanWriteBookBusinessImport;\r\nexport const assertCanWriteBookUnionOwn = assertCanWriteBookUnionOwnImport;\r\nexport const stampOwnBusinessId = stampOwnBusinessIdImport;\r\nexport const createAccessHelpers = createAccessHelpersImport;\r\n"],"names":["module","exports","require","async","ensurePartnerScope","access","level","businessIds","undefined","partner","getPartnerById","partnerId","partnerBusinessId","err","console","error","resolveAccess","event","isSuperUser","env","process","BUILD_ENV","isPartnerUser","arBusinessIds","getAccessRightsInfo","Object","keys","length","errorList","unauthorized","_accessRightsUtils","_errorCodes","_libDynamodb","_clientDynamodb","dynamoUtil","get","params","DynamoDBDocument","from","DynamoDB","handleDirectS3WriteEvent","transformer","errorHandlerPerFile","shouldSkipFailedFolders","userImportTypes","Records","Promise","resolve","hasErrors","map","record","s3Bucket","s3","bucket","name","file","object","key","path","decodeURIComponent","handleFile","catch","then","Error","handleEvents","snsInfo","JSON","parse","_","files","_handleFile","_lodash","_interopRequireDefault","_bluebird","e","__esModule","default","assertCanWriteBookBusiness","businessId","invalidRequest","message","includes","assertCanWriteBookUnionOwn","uniq","filter","Boolean","assertCanWriteOwnBusiness","partnerNotConfigured","stampOwnBusinessId","body","_accessContext","watchBucket","noop","dynamoConfigTable","dynamoConfigKey","snsTopic","EventSource","isEqual","publishEvents","failedOnce","failedTwice","direct","startsWithDirect","startsWith","log","_publishEvents","_handleEvents","requireCrmAccess","requireSuper","requireTicketAccess","defaultFilters","schema","subSchemas","clone","filters","addFiltersFromSchema","forEach","_sequelize","keyPrefix","asLinkAlias","reduce","acc","item","type","DB","STRING","filterType","Op","eq","itemType","CHAR","TEXT","iLike","DECIMAL","INTEGER","BIGINT","or","BOOLEAN","JSONB","field","DATE","between","DATEONLY","_dayjs","_utc","dayjs","extend","utc","objectFilters","query","searchString","startDate","endDate","caseInsensitiveConditions","where","val","itemName","push","fn","col","like","toLowerCase","in","split","parsedJson","queryValue","booleanMap","and","active","filterAdds","accessRightsUtils","s","dates","toDate","isValid","invalidStartDate","invalidEndDate","createdAt","adds","dataType","isNaN","Number","newOr","withDate","assign","k","def","prefix","qKey","pathParts","substring","value","parsed","Array","isArray","addJsonbConditions","obj","entries","currentPath","String","_clientSns","SNSUtil","publish","sns","SNS","createTopic","scopeToBookUnionOwn","ids","scopeToOwnBusiness","scopeToPartnerBook","createAccessHelpers","deps","_accessScope","_accessWrites","checkIsSuper","isSystemUser","checkModule","moduleName","moduleRights","getModuleInfo","allowAccess","checkWriteAccess","options","eventBody","parseBody","find","id","userRight","getBusinessesInfo","userRoles","admin","write","enrichEventWithPartnerAccess","partnerBusinessIds","role","arPath","requestContext","authorizer","claims","json","accessRights","bid","set","stringify","jsonToParse","getCompanySettings","getDefaultBusinessIDInfo","dbi","getEffectivePartnerId","getBelongsToPartnerId","userDefaultBid","_interopRequireWildcard","t","WeakMap","r","n","o","i","f","__proto__","has","hasOwnProperty","call","defineProperty","getOwnPropertyDescriptor","_requestResponse","isSys","useCognitoBid","requestedBusinessIds","getRequestedBusinessIds","allowedBusinessIds","getAllowedBusinessIds","businesses","v","isEmpty","intersection","bodyBid","b","read","defaultFilter","copyOfDefaultFilter","testItem","indexOf","substr","sortItem","parentChildList","detectDynamooseError","errorBody","dynamooseError","errors","detail","trim","failure","cleanedErrorBody","dbClose","UTIL_LOG","isObject","isUndefined","details","errorCode","statusCode","detectSequelizeError","detectJoyError","newBody","merge","buildResponse","getCurrentUser","username","getCurrentUserNameFromCognitoEvent","attributes","requestEvent","isString","invalidJson","parseEvent","callback","success","successHtml","html","headers","htmlSecurityHeaders","securityHeaders","join","errorName","notPresent","match","stillReferenced","fields","messages","sequelizeError","parentError","joyError","contextItem","msg","configTable","tableKey","result","TableName","Key","chunkSize","maxMessages","topicArn","Name","TopicArn","maxKeys","fileList","loop","messageList","chain","chunk","slice","Message","_customParseFormat","_isSameOrBefore","_S3Utils","_SNSUtils","_dynamoUtils","bucketResult","currentTime","S3Utils","listObjectsV2","Bucket","MaxKeys","ContinuationToken","newFiles","Contents","fileDelayTime","isSameOrBefore","usersImports","values","items","fileName","last","folderName","first","concat","IsTruncated","NextContinuationToken","customParseFormat","runMigrations","databaseName","sequelizeInstance","initializeModels","pathToMigrationFolder","PWD","umzug","Umzug","migrations","glob","context","getQueryInterface","storage","SequelizeStorage","sequelize","logger","pendingMigrations","pending","up","upError","down","reverse","downError","_umzug","S3Util","getObject","Code","code","isNil","deleteObject","parsedBody","returnedValue","newPath","replace","newParams","Body","containsError","putObject","str","firstIndex","_clientS","s3Utils","action","S3","getS3","response","transformToString","invalidInventoryReleaseRequest","alreadyReleased","alreadyReceived","invalidItemsRequest","invalidID","invalidReceivable","invalidAPIKey","qbCreationError","cannotReopen","invalidDateFormat","invalidOrderStatus","invalidPaymentStatus","invalidReleaseStatus","invalidReceivableStatus","invalidFilter","invalidUserNameUpdate","imageSizeLimit","notFound","emailRequired","mobilePhoneRequired","invalidCadenceType","getPaginationFromFindAll","limit","offset","hasMore","splice","rows","findAll","model","all","nested","findArgs","include","findUtils","createIncludes","canBeIncluded","includeSubItem","askedForInQuery","queryStringItem","dot","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","_watchBucket","_createIncludes","_createFilters","_createSort","_findAll","_migrations","_defaultFilters","_accessGates","_createAccessHelpers","handleFileImport","watchBucketImport","publishEventsImport","createFiltersImport","createIncludesImport","createSortImport","findAllImport","checkModuleImport","checkIsSuperImport","getAccessRightsInfoImport","getDefaultBusinessIDInfoImport","getModuleInfoImport","failureImport","successImport","runMigrationsImport","getCurrentUserImport","successHtmlImport","getCurrentUserNameFromCognitoEventImport","defaultFiltersImport","accessRightsUtilsImport","parseBodyImport","parseEventImport","getBusinessesInfoImport","userDefaultBidImport","checkWriteAccessImport","isSystemUserImport","isSuperUserImport","isPartnerUserImport","getBelongsToPartnerIdImport","getEffectivePartnerIdImport","enrichEventWithPartnerAccessImport","getCompanySettingsImport","resolveAccessImport","ensurePartnerScopeImport","requireCrmAccessImport","requireTicketAccessImport","requireSuperImport","scopeToOwnBusinessImport","scopeToPartnerBookImport","scopeToBookUnionOwnImport","assertCanWriteOwnBusinessImport","assertCanWriteBookBusinessImport","assertCanWriteBookUnionOwnImport","stampOwnBusinessIdImport","createAccessHelpersImport"],"ignoreList":[],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"main.js","mappings":"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","sources":["webpack://piper-utils/external commonjs \"sequelize\"","webpack://piper-utils/external commonjs \"@aws-sdk/client-s3\"","webpack://piper-utils/external commonjs \"dayjs/plugin/customParseFormat\"","webpack://piper-utils/./src/database/dbUtils/partnerAccess/accessContext.js","webpack://piper-utils/./src/dynamo/dynamoUtils.js","webpack://piper-utils/./src/eventManager/handleEvents.js","webpack://piper-utils/external commonjs \"dayjs/plugin/utc.js\"","webpack://piper-utils/./src/database/dbUtils/partnerAccess/accessWrites.js","webpack://piper-utils/./src/audit/audit.js","webpack://piper-utils/./src/eventManager/watchBucket.js","webpack://piper-utils/./src/database/dbUtils/partnerAccess/accessGates.js","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/defaultFilters.js","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/createFilters.js","webpack://piper-utils/external commonjs \"dayjs\"","webpack://piper-utils/./src/sns/SNSUtils.js","webpack://piper-utils/external commonjs \"dayjs/plugin/isSameOrBefore\"","webpack://piper-utils/./src/database/dbUtils/partnerAccess/accessScope.js","webpack://piper-utils/external commonjs \"@aws-sdk/lib-dynamodb\"","webpack://piper-utils/./src/database/dbUtils/partnerAccess/createAccessHelpers.js","webpack://piper-utils/external commonjs \"bluebird\"","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/accessRightsUtils.js","webpack://piper-utils/external commonjs \"@aws-sdk/client-sns\"","webpack://piper-utils/external commonjs \"lodash\"","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/createSort.js","webpack://piper-utils/./src/requestResponse/requestResponse.js","webpack://piper-utils/./src/eventManager/publishEvents.js","webpack://piper-utils/./src/database/dbSetup/migrations.js","webpack://piper-utils/./src/eventManager/handleFile.js","webpack://piper-utils/./src/s3/S3Utils/S3Utils.js","webpack://piper-utils/external commonjs \"umzug\"","webpack://piper-utils/external commonjs \"@aws-sdk/client-dynamodb\"","webpack://piper-utils/./src/requestResponse/errorCodes.js","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/findAll.js","webpack://piper-utils/./src/database/dbUtils/queryStringUtils/createIncludes.js","webpack://piper-utils/webpack/bootstrap","webpack://piper-utils/./src/index.js"],"sourcesContent":["module.exports = require(\"sequelize\");","module.exports = require(\"@aws-sdk/client-s3\");","module.exports = require(\"dayjs/plugin/customParseFormat\");","import { isSuperUser, isPartnerUser, getAccessRightsInfo } from '../queryStringUtils/accessRightsUtils.js';\nimport { errorList } from '../../../requestResponse/errorCodes.js';\n\n/**\n * Resolve the caller's access level from the Lambda event.\n * Synchronous — reads JWT claims only, no Dynamo lookups.\n *\n * Returns an access object:\n * { level: 'global' } — super user or local/test env\n * { level: 'partner', partnerId, partnerBusinessId: null, businessIds: null }\n * { level: 'standard', businessIds: string[] }\n *\n * Partner fields (partnerBusinessId, businessIds) start null and are\n * lazy-loaded by ensurePartnerScope on first use.\n *\n * @param {object} event - Lambda event with Cognito authorizer claims.\n * @returns {object} Access object.\n */\nexport function resolveAccess(event) {\n if (isSuperUser(event)) {\n return { level: 'global' };\n }\n\n const env = process.env.BUILD_ENV;\n if (env === 'local' || env === 'test') {\n return { level: 'global' };\n }\n\n const partnerId = isPartnerUser(event);\n if (partnerId) {\n return { level: 'partner', partnerId, partnerBusinessId: null, businessIds: null };\n }\n\n const arBusinessIds = getAccessRightsInfo(event);\n const businessIds = Object.keys(arBusinessIds);\n if (businessIds.length > 0) {\n return { level: 'standard', businessIds };\n }\n\n throw errorList.unauthorized;\n}\n\n/**\n * Lazy-load partner scope from Dynamo. Populates partnerBusinessId and\n * businessIds on the access object, then caches for the request lifetime.\n *\n * No-op for non-partner access objects or if already loaded.\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {{ getPartnerById: Function }} deps - Injected so piper-utils stays DB-agnostic.\n * @returns {object} The same access object, now populated.\n */\nexport async function ensurePartnerScope(access, { getPartnerById }) {\n if (!access || access.level !== 'partner') {\n return access;\n }\n if (access.businessIds !== null && access.businessIds !== undefined) {\n return access;\n }\n try {\n const partner = await getPartnerById(access.partnerId);\n access.businessIds = partner?.businessIds || [];\n access.partnerBusinessId = partner?.partnerBusinessId || null;\n } catch (err) {\n console.error('partnerAccess: failed to load partner for scoping:', err);\n access.businessIds = [];\n access.partnerBusinessId = null;\n }\n return access;\n}\n","import { DynamoDBDocument } from '@aws-sdk/lib-dynamodb';\nimport { DynamoDB } from '@aws-sdk/client-dynamodb';\n\nconst dynamoUtil = {\n get: (params) => get(params)\n};\n\n/**\n * @param {{TableName:string, Key:{key:string}}} params\n */\nasync function get(params) {\n const dynamoDb = DynamoDBDocument.from(new DynamoDB());\n return dynamoDb.get(params);\n}\n\nexport default dynamoUtil;","import { handleFile } from './handleFile.js';\nimport _ from 'lodash';\nimport Promise from 'bluebird';\n\nexport function handleEvents(event, transformer, errorHandlerPerFile, shouldSkipFailedFolders = false, userImportTypes) {\n if (!event || !event.Records) {\n return Promise.resolve();\n }\n\n let hasErrors = false;\n\n return Promise.map(event.Records, (record) => {\n const snsInfo = JSON.parse(_.get(record, 'Sns.Message', '{}'));\n const s3Bucket = snsInfo.bucket;\n const files = snsInfo.files || [];\n\n return Promise.map(files, (file) => {\n let path = decodeURIComponent(file);\n if (path) {\n return handleFile(path, s3Bucket, transformer, { shouldSkipFailedFolders, userImportTypes }).catch((err) => {\n if (errorHandlerPerFile && !errorHandlerPerFile(err, path)) {\n console.error('HANDLE-FILE-CATCH: ', err);\n hasErrors = true;\n }\n });\n }\n });\n }).then(() => {\n if (hasErrors) {\n throw new Error('ERROR: HANDLE-FILE');\n }\n });\n}\n\nexport function handleDirectS3WriteEvent(event, transformer, errorHandlerPerFile, shouldSkipFailedFolders = false, userImportTypes) {\n if (!event || !event.Records) {\n return Promise.resolve();\n }\n\n let hasErrors = false;\n\n return Promise.map(event.Records, (record) => {\n const s3Bucket = record.s3.bucket.name;\n const file = record.s3.object.key || [];\n\n let path = decodeURIComponent(file);\n if (path) {\n return handleFile(path, s3Bucket, transformer, { shouldSkipFailedFolders, userImportTypes }).catch((err) => {\n if (errorHandlerPerFile && !errorHandlerPerFile(err, path)) {\n console.error('HANDLE-FILE-CATCH:', err);\n hasErrors = true;\n }\n });\n }\n\n }).then(() => {\n if (hasErrors) {\n throw new Error('ERROR: HANDLE-FILE (DIRECT S3 EVENT)');\n }\n });\n}\n","module.exports = require(\"dayjs/plugin/utc.js\");","import _ from 'lodash';\nimport { ensurePartnerScope } from './accessContext.js';\nimport { errorList } from '../../../requestResponse/errorCodes.js';\n\n/**\n * Assert the caller can write to their own business.\n * For partner: businessId must equal partnerBusinessId.\n *\n * global → allow\n * partner → businessId must equal partnerBusinessId; throws if not\n * standard → throws (CRM routes gate standard users before reaching this)\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {string} businessId - The businessId being written to.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function assertCanWriteOwnBusiness(access, businessId, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n return;\n }\n if (access.level === 'partner') {\n await ensurePartnerScope(access, { getPartnerById });\n if (!access.partnerBusinessId) {\n throw { ...errorList.partnerNotConfigured };\n }\n if (businessId !== access.partnerBusinessId) {\n throw errorList.unauthorized;\n }\n return;\n }\n throw errorList.unauthorized;\n}\n\n/**\n * Assert the caller can write to a business in their portfolio.\n * For partner: businessId must be in the businessIds array.\n *\n * global → allow\n * standard → allow (handled elsewhere via checkWriteAccess)\n * partner → businessId must be in portfolio; throws if not\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {string} businessId - The businessId being written to.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function assertCanWriteBookBusiness(access, businessId, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n return;\n }\n if (access.level === 'standard') {\n return;\n }\n if (access.level === 'partner') {\n if (!businessId) {\n throw { ...errorList.invalidRequest, message: 'businessId is required' };\n }\n await ensurePartnerScope(access, { getPartnerById });\n if (!(access.businessIds || []).includes(businessId)) {\n throw errorList.unauthorized;\n }\n return;\n }\n throw errorList.unauthorized;\n}\n\n/**\n * Assert the caller can write to a business in the union of own + portfolio.\n * For partner: businessId must be partnerBusinessId OR in businessIds[].\n * Used by ticket write paths.\n *\n * global → allow\n * standard → allow (handled elsewhere via checkWriteAccess)\n * partner → businessId must be in [partnerBusinessId, ...businessIds]\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {string} businessId - The businessId being written to.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function assertCanWriteBookUnionOwn(access, businessId, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n return;\n }\n if (access.level === 'standard') {\n return;\n }\n if (access.level === 'partner') {\n if (!businessId) {\n throw { ...errorList.invalidRequest, message: 'businessId is required' };\n }\n await ensurePartnerScope(access, { getPartnerById });\n const allowed = _.uniq(\n [access.partnerBusinessId, ...(access.businessIds || [])].filter(Boolean)\n );\n if (!allowed.includes(businessId)) {\n throw errorList.unauthorized;\n }\n return;\n }\n throw errorList.unauthorized;\n}\n\n/**\n * Auto-stamp body.businessId from the partner's own business if missing.\n * No-op for non-partner users or if body.businessId is already set.\n *\n * @param {object} access - Access object from resolveAccess.\n * @param {object} body - Request body to mutate.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function stampOwnBusinessId(access, body, { getPartnerById } = {}) {\n if (!access || access.level !== 'partner') {\n return;\n }\n if (body.businessId) {\n return;\n }\n await ensurePartnerScope(access, { getPartnerById });\n body.businessId = access.partnerBusinessId;\n}\n","import _ from 'lodash';\nimport Promise from 'bluebird';\nimport { getCurrentUser } from '../requestResponse/requestResponse.js';\nimport { accessRightsUtils, getCompanySettings } from '../database/dbUtils/queryStringUtils/accessRightsUtils.js';\n\n/**\n * @file Audit logging for Sequelize models. Each parent model gets a sibling\n * `<ModelName>Audit` table that records every field-level change made through\n * Sequelize hooks (afterCreate / afterUpsert / afterUpdate / afterDestroy).\n *\n * Typical wiring in a domain service:\n *\n * 1. At model `dbSetup` (one-time, at boot):\n * `await attachAudit(MyModel);`\n *\n * 2. At the top of each route handler that mutates the model:\n * `bindAuditRequest(event, businessId, [MyModel]);`\n *\n * 3. To list audit history for a record:\n * `const filter = getAuditFilter(MyModel, id, { event, offset, limit });`\n * `const audits = await findAll(getAuditModel(MyModel), filter);`\n *\n * Audit is **off by default** for any model whose request hasn't been bound —\n * so cron lambdas, untouched endpoints, and unit tests will not write audit\n * rows unless they explicitly opt in. The on/off switch comes from the\n * `custom:SET.auditEnabled` JWT claim resolved by {@link getCompanySettings}.\n *\n * The user identity stamped on each row is read from the JWT via\n * {@link getCurrentUser}; `changedByUser` stores `claims.email`. There is\n * intentionally no foreign key back to a User table — domain services must\n * not read across other services' databases.\n */\n\n/**\n * Registry of `<ModelName>Audit` Sequelize models, keyed by parent model name.\n * Populated by {@link attachAudit}. Exported for tests; do not mutate from app code.\n *\n * @type {Object<string, import('sequelize').ModelStatic<any>>}\n */\nexport const auditModels = {};\n\n/**\n * Per-model per-request audit context, keyed by parent model name. Populated by\n * {@link bindAuditRequest} or {@link bindAuditRequestForUser}. A model with no\n * entry here (or with `auditEnabled === false`) will not write any audit rows.\n * Exported for tests; do not mutate from app code.\n *\n * @type {Object<string, { user: { username: string, id?: number }, businessId: string|number, auditEnabled: boolean }>}\n */\nexport const modelOptions = {};\n\nconst SENSITIVE_FIELDS_PATTERN = /\"(token|password|secret|key|credential|auth|securityCode|cvv|pin|ssn)\":\\s*\"[^\"]*\"/gi;\n\nfunction getAuditSchema(model) {\n const DataTypes = model.sequelize.Sequelize;\n return {\n field: { type: DataTypes.STRING, allowNull: false },\n type: DataTypes.STRING,\n valueOld: DataTypes.STRING,\n valueNew: DataTypes.STRING,\n changedByUser: { type: DataTypes.STRING, allowNull: false },\n businessId: { type: DataTypes.STRING, allowNull: false }\n };\n}\n\n/**\n * Internal hook factory. Returns the async function that Sequelize invokes on\n * each create/upsert/update/destroy. Reads its per-request state from\n * {@link modelOptions}; emits zero rows when audit is disabled for the model.\n *\n * Sensitive fields inside JSON values (token, password, secret, key,\n * credential, auth, securityCode, cvv, pin, ssn) are masked as\n * `***************` before being persisted. String values longer than 255\n * characters are truncated.\n *\n * Exported only so tests can drive the hook directly. Application code should\n * never call this — use {@link attachAudit}.\n *\n * @param {string} modelName name of the parent Sequelize model\n * @returns {(modelInfo: any, options: { type?: string, transaction?: import('sequelize').Transaction }) => Promise<void>}\n * the hook function Sequelize will call on each lifecycle event\n */\nfunction auditMe(modelName) {\n return async (modelInfo, options) => {\n if (_.isArray(modelInfo)) {\n modelInfo = modelInfo[0];\n }\n\n const opts = modelOptions[modelName];\n if (!opts || !opts.auditEnabled) {\n return;\n }\n\n const auditModel = auditModels[modelName];\n\n const writeAuditRow = async (field, type, valueOld, valueNew) => {\n const data = {\n field,\n type,\n valueOld: String(valueOld).substring(0, 255),\n valueNew: String(valueNew).substring(0, 255),\n businessId: opts.businessId,\n changedByUser: opts.user.username\n };\n data[modelName + 'Id'] = modelInfo.dataValues.id;\n\n const newOptions = {};\n if (options.transaction) {\n newOptions.transaction = options.transaction;\n }\n return auditModel.create(data, newOptions);\n };\n\n const checkAudit = async (field, type = 'INITIAL', valueOld, valueNew) => {\n if (_.isEqual(valueOld, valueNew)) {\n return;\n }\n if (_.isString(valueOld) && _.isString(valueNew)) {\n type = 'INSERT';\n }\n\n if (_.isArray(valueOld) || _.isArray(valueNew)) {\n let oldString = JSON.stringify(valueOld || []);\n let newString = JSON.stringify(valueNew || []);\n oldString = oldString.replace(SENSITIVE_FIELDS_PATTERN, '\"$1\":\"***************\"').substring(0, 255);\n newString = newString.replace(SENSITIVE_FIELDS_PATTERN, '\"$1\":\"***************\"').substring(0, 255);\n return writeAuditRow(field, 'UPDATE', oldString, newString);\n }\n\n if (_.isObject(valueOld) || _.isObject(valueNew)) {\n _.forEach(valueOld, (valueSub, keySub) => {\n checkAudit(field + ' ' + keySub, 'DELETED', valueSub || '', (valueNew || {})[keySub] || '');\n });\n _.forEach(valueNew, (valueSub, keySub) => {\n checkAudit(field + ' ' + keySub, 'INSERT', (valueOld || {})[keySub] || '', valueSub || '');\n });\n return;\n }\n\n return writeAuditRow(field, type, valueOld, valueNew);\n };\n\n return Promise.map([...modelInfo._changed], async (field) => {\n const valueOld = modelInfo._previousDataValues[field] || '';\n const valueNew = modelInfo.dataValues[field] || '';\n await checkAudit(field, options.type, valueOld, valueNew);\n });\n };\n}\n\n/**\n * Define a sibling `<ModelName>Audit` table for the given Sequelize model and\n * wire the four lifecycle hooks (`afterCreate`, `afterUpsert`, `afterUpdate`,\n * `afterDestroy`) that record changes into it.\n *\n * Call this **once per model at boot time** from inside the model's\n * `dbSetup()` function. It is idempotent — calling it again for a model that\n * already has an audit table attached is a no-op.\n *\n * The audit table has no foreign key into any user table; the username of the\n * person who made the change is stamped onto each row from the JWT (set by\n * {@link bindAuditRequest}). This keeps the audit util portable across domain\n * services that own different user models.\n *\n * @example\n * // src/customer/customer.js\n * Customer.dbSetup = async function () {\n * await attachAudit(Customer);\n * };\n *\n * @param {import('sequelize').ModelStatic<any>} model the Sequelize model to audit\n * @returns {Promise<void>} resolves when the audit table's `sync()` completes\n * @see {@link bindAuditRequest} - per-request setup that turns audit on\n * @see {@link getAuditModel} - retrieve the audit model from the parent\n * @see {@link getAuditFilter} - build a filter for an audit history query\n */\nexport async function attachAudit(model) {\n if (auditModels[model.name]) {\n return;\n }\n\n const auditModel = model.sequelize.define(model.name + 'Audit', getAuditSchema(model), {\n updatedAt: false,\n freezeTableName: true\n });\n auditModel.belongsTo(model, {\n foreignKey: { allowNull: true },\n onDelete: 'SET NULL'\n });\n auditModels[model.name] = auditModel;\n\n model.addHook('afterCreate', auditMe(model.name));\n model.addHook('afterUpsert', auditMe(model.name));\n model.addHook('afterUpdate', auditMe(model.name));\n model.addHook('afterDestroy', auditMe(model.name));\n\n return auditModel.sync();\n}\n\n/**\n * Bind per-request audit context for one or more models. Call this **once at\n * the top of each route handler** that mutates an audited model.\n *\n * Resolves the acting user from the JWT claims on the event\n * (via {@link getCurrentUser}) and reads the company `auditEnabled` flag from\n * the `custom:SET` claim (via {@link getCompanySettings}). If the company has\n * `auditEnabled: false` then no rows will be written for the bound models on\n * this request.\n *\n * Audit is **off by default** for any model that has not been bound this\n * request — a route that omits this call writes no audit rows.\n *\n * @example\n * // src/customer/customerRoutes.js\n * export async function updateCustomer(event) {\n * checkModule('customer', event);\n * const businessId = checkWriteAccess(event);\n * bindAuditRequest(event, businessId, [Customer]);\n * // ...mutate Customer here; rows are written automatically by hooks\n * }\n *\n * @example\n * // Bind several models in one call when a handler touches more than one\n * bindAuditRequest(event, businessId, [Order, Payment, Receivable]);\n *\n * @param {import('aws-lambda').APIGatewayProxyEvent} event API Gateway event\n * with `requestContext.authorizer.claims` (must include `email` and\n * optionally `custom:UID`, `custom:SET`)\n * @param {string|number} businessId business id this request acts on; stamped\n * onto every audit row written for the bound models\n * @param {Array<import('sequelize').ModelStatic<any>>} models Sequelize models\n * to enable audit on for the duration of this request\n * @returns {void}\n * @see {@link bindAuditRequestForUser} - the equivalent for non-JWT contexts\n * (webhooks, integration crons, Cognito triggers)\n * @see {@link attachAudit} - one-time setup that creates the audit table\n */\nexport function bindAuditRequest(event, businessId, models) {\n const user = getCurrentUser(event);\n const auditEnabled = !!(getCompanySettings(event) || {}).auditEnabled;\n _.forEach(models, (model) => {\n // Lazily ensure the audit table model + hooks are wired in this Lambda\n // process. `attachAudit` is idempotent — first call registers, subsequent\n // calls are no-ops. The returned sync() promise is intentionally not\n // awaited; the table is expected to already exist from the migration\n // Lambda, and the synchronous registration is what the request needs.\n const attachPromise = attachAudit(model);\n if (attachPromise && typeof attachPromise.catch === 'function') {\n attachPromise.catch((err) => console.error('attachAudit sync failed for', model.name, err));\n }\n modelOptions[model.name] = { user, businessId, auditEnabled };\n });\n}\n\n/**\n * Bind per-request audit context for **system-driven flows** that do not carry\n * an API Gateway JWT — for example, payment-gateway webhooks, integration\n * crons (QuickBooks/Inbox/etc.), Cognito triggers, or batch jobs.\n *\n * Use {@link bindAuditRequest} instead whenever you have a JWT-authenticated\n * API event; that path automatically resolves the user and the company's\n * `auditEnabled` flag from claims.\n *\n * @example\n * // payment webhook from the gateway — no JWT, but we still want audit\n * import { systemUser } from '../user/user.js';\n *\n * export async function webhook(event) {\n * const businessId = event.queryStringParameters.businessId;\n * bindAuditRequestForUser(systemUser, businessId, [Order, Payment]);\n * // ...mutate Order/Payment; audit rows are written by hooks\n * }\n *\n * @example\n * // turn audit OFF explicitly for a system flow that should not be audited\n * bindAuditRequestForUser(systemUser, businessId, [Order], { auditEnabled: false });\n *\n * @param {{ username: string, id?: number }} user identity stamped onto each\n * audit row's `changedByUser` field. Conventionally the `systemUser`\n * constant exported from your service's user model\n * @param {string|number} businessId business id this flow is acting on\n * @param {Array<import('sequelize').ModelStatic<any>>} models Sequelize models\n * to enable audit on\n * @param {{ auditEnabled?: boolean }} [opts] when `auditEnabled` is `false`,\n * binds context but suppresses writes; defaults to `true`\n * @returns {void}\n * @see {@link bindAuditRequest} - the JWT-driven equivalent for API handlers\n */\nexport function bindAuditRequestForUser(user, businessId, models, opts = {}) {\n const auditEnabled = opts.auditEnabled !== false;\n _.forEach(models, (model) => {\n // See bindAuditRequest for why this is here.\n const attachPromise = attachAudit(model);\n if (attachPromise && typeof attachPromise.catch === 'function') {\n attachPromise.catch((err) => console.error('attachAudit sync failed for', model.name, err));\n }\n modelOptions[model.name] = { user, businessId, auditEnabled };\n });\n}\n\n/**\n * Get the `<ModelName>Audit` Sequelize model that {@link attachAudit} created\n * for a parent model. Returns `undefined` if audit was never attached.\n *\n * @example\n * const audits = await findAll(getAuditModel(Customer), filter);\n *\n * @param {import('sequelize').ModelStatic<any>} model parent Sequelize model\n * @returns {import('sequelize').ModelStatic<any> | undefined} the audit model,\n * or `undefined` if {@link attachAudit} has not been called for this model\n * @see {@link getAuditFilter} - companion filter builder for history queries\n */\nexport function getAuditModel(model) {\n return auditModels[model.name];\n}\n\n/**\n * Build a Sequelize `findAll`-style filter for an audit-history query, scoped\n * to the businesses the caller is allowed to read (resolved from\n * {@link accessRightsUtils}).\n *\n * The returned filter joins the parent model so callers can render `oldValue`\n * → `newValue` rows in the UI alongside the parent record.\n *\n * @example\n * // GET /customer/{id}/audit\n * export async function getCustomerAudit(event) {\n * bindAuditRequest(event, userDefaultBid(event), [Customer]);\n * const filter = getAuditFilter(Customer, event.pathParameters.id, {\n * event,\n * offset: 0,\n * limit: 10\n * });\n * const audits = await findAll(getAuditModel(Customer), filter);\n * return success(audits);\n * }\n *\n * @param {import('sequelize').ModelStatic<any>} modelToFilter the parent model\n * whose history is being fetched\n * @param {string|number} id parent record id\n * @param {{ event: import('aws-lambda').APIGatewayProxyEvent, offset?: number, limit?: number }} options\n * `event` is required (drives business-id scoping); `offset` and `limit`\n * are pagination passthroughs\n * @returns {{ where: Object, include: Array<{ model: Object }>, order: Array, offset?: number, limit?: number }}\n * a Sequelize `findAll`-compatible filter\n * @see {@link getAuditModel} - call to get the audit model to query against\n */\nexport function getAuditFilter(modelToFilter, id, options) {\n const businessIds = accessRightsUtils(options.event);\n const filter = {\n where: {\n businessId: businessIds\n },\n include: [{\n model: modelToFilter\n }],\n order: [\n ['createdAt', 'DESC']\n ]\n };\n filter.where[modelToFilter.name + 'Id'] = id;\n\n return { ...filter, ...options };\n}\n\n/**\n * Decrement an integer field on a Sequelize instance and write a matching\n * audit row in the same call. Useful for inventory adjustments and other\n * counter-style fields where Sequelize's plain `model.decrement()` would\n * bypass the `afterUpdate` hook.\n *\n * The acting user and businessId come from whatever\n * {@link bindAuditRequest} / {@link bindAuditRequestForUser} was called for\n * this request. If audit is disabled for the model, the decrement still\n * happens but no audit row is written.\n *\n * @example\n * // release inventory on order release\n * await decrementWithAudit('inventory', inventoryEntry, 'quantity', {\n * by: item.quantity,\n * transaction: t\n * });\n *\n * @param {string} modelName name of the parent model (e.g. `'inventory'`)\n * @param {import('sequelize').Model} model the Sequelize instance to mutate\n * @param {string} field the integer/decimal field to decrement\n * @param {{ by?: number, transaction?: import('sequelize').Transaction }} args\n * passed straight through to Sequelize's `decrement()`; transaction is also\n * propagated to the audit write\n * @returns {Promise<import('sequelize').Model>} the updated instance (with\n * `_changed` set on it so internal hooks can observe the change)\n * @see {@link incrementWithAudit} - the +1 counterpart\n */\nexport async function decrementWithAudit(modelName, model, field, args) {\n const r = await model.decrement(field, args);\n r._changed = [field];\n const options = {};\n if (args.transaction) {\n options.transaction = args.transaction;\n }\n await auditMe(modelName)(r, options);\n return r;\n}\n\n/**\n * Increment an integer field on a Sequelize instance and write a matching\n * audit row in the same call. The mirror of {@link decrementWithAudit}.\n *\n * @example\n * // restock from a receivable\n * await incrementWithAudit('inventory', inventoryEntry, 'quantity', {\n * by: item.quantity,\n * transaction: t\n * });\n *\n * @param {string} modelName name of the parent model (e.g. `'inventory'`)\n * @param {import('sequelize').Model} model the Sequelize instance to mutate\n * @param {string} field the integer/decimal field to increment\n * @param {{ by?: number, transaction?: import('sequelize').Transaction }} args\n * passed straight through to Sequelize's `increment()`; transaction is also\n * propagated to the audit write\n * @returns {Promise<import('sequelize').Model>} the updated instance\n * @see {@link decrementWithAudit} - the -1 counterpart\n */\nexport async function incrementWithAudit(modelName, model, field, args) {\n const r = await model.increment(field, args);\n r._changed = [field];\n const options = {};\n if (args.transaction) {\n options.transaction = args.transaction;\n }\n await auditMe(modelName)(r, options);\n return r;\n}\n\nexport { auditMe };\n","import { publishEvents } from './publishEvents.js';\nimport { handleEvents, handleDirectS3WriteEvent } from './handleEvents.js';\nimport _ from 'lodash';\n\n/**\n * bucket watcher watches a s3 bucket and publishes events to a sns topic, this allows you to process files in s3 with a some transformer function\n * prefix objects with DIRECT to listen to direct s3 events\n *\n * @param {object} params - The parameters for watchBucket, see below\n * @param {object} params.event - The event of the lambda\n * @param {string} params.dynamoConfigTable - The Dynamo DB table where to get the chunkSize and maxMessage size\n * @param {string} params.dynamoConfigKey - The key to the item in the Dynamo DB table that holds the chunkSize and maxMessage size\n * @param {string} params.s3Bucket - The name of the s3 bucket to watch, when you drop items into this table events will be created\n * @param {string} params.snsTopic - The name of the snsEvent to publish\n * @param {function} params.transformer - the function to run on each file\n * @param {function} [params.errorHandlerPerFile] - the function to run on as a catch on each file\n * @param {boolean} [params.shouldSkipFailedFolders] - whether to use the failed-once, failed-twice, error or just error folders\n * @param {object} [params.userImportTypes] - user import subdirectories object map\n */\nexport function watchBucket({\n event,\n dynamoConfigTable,\n dynamoConfigKey,\n s3Bucket,\n snsTopic,\n transformer,\n errorHandlerPerFile = _.noop,\n shouldSkipFailedFolders = false,\n userImportTypes\n }) {\n if (!event || !dynamoConfigTable || !dynamoConfigKey || !s3Bucket || !snsTopic || !transformer) {\n throw new Error('Missing required parameters. Need event, dynamoConfigTable, dynamoConfigKey, s3Bucket, snsTopic, transformer');\n }\n\n const EventSource = _.get(event, 'Records[0].eventSource') || _.get(event, 'Records[0].EventSource');\n\n if (_.isEqual(EventSource, 'aws:sns')) {\n return handleEvents(event, transformer, errorHandlerPerFile, shouldSkipFailedFolders, userImportTypes);\n } else if (_.isEqual(EventSource, 'aws:s3')) {\n const failedOnce = 'failed-once';\n const failedTwice = 'failed-twice';\n const error = 'error';\n const direct = 'DIRECT';\n const key = _.get(event, 'Records[0].s3.object.key') || '';\n const startsWithDirect = _.startsWith(key, direct);\n if (key.includes(failedOnce) || key.includes(failedTwice) || key.includes(error)) {\n // this used to throw, but the throw raised useless alarms, I believed turing throw in to a return was ok\n return;\n }\n\n if (startsWithDirect) {\n console.log('------->DIRECT WRITE FIRE');\n return handleDirectS3WriteEvent(event, transformer, errorHandlerPerFile, shouldSkipFailedFolders, userImportTypes);\n }\n\n } else {\n // the function is being run from the cron job so publish SNS events\n return publishEvents(dynamoConfigTable, dynamoConfigKey, s3Bucket, snsTopic, userImportTypes);\n }\n}\n","import { errorList } from '../../../requestResponse/errorCodes.js';\n\n/**\n * Gate: CRM routes — rejects standard users. Super and partner pass.\n * @param {object} access - Access object from resolveAccess.\n */\nexport function requireCrmAccess(access) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'standard') {\n throw errorList.unauthorized;\n }\n}\n\n/**\n * Gate: Ticket routes — all three user types pass. Only rejects null access.\n * @param {object} access - Access object from resolveAccess.\n */\nexport function requireTicketAccess(access) {\n if (!access) {\n throw errorList.unauthorized;\n }\n}\n\n/**\n * Gate: Super-only routes — throws unless global.\n * @param {object} access - Access object from resolveAccess.\n */\nexport function requireSuper(access) {\n if (!access || access.level !== 'global') {\n throw errorList.unauthorized;\n }\n}\n","import _ from 'lodash';\nimport DB from 'sequelize';\n\n/**\n * Create an object with default filters for a given sequeliaze Schema Object, and set of sub schemas\n *\n * @param {object} schema - type is sequelize data type\n * @param {object} subSchemas - An object with alias as the key and sequelize schema as the value http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-method-define\n * sub schema can be {location: locationSchema} or {location: {as: \"asAlias\", schema: schema}}\n * @returns {object} An Object with a default filter for each dataType CHAR and TEXT will get a $like operator, INTEGER, DECIMAL and BOOLEAN will get a $eq.\n */\nexport function defaultFilters(schema, subSchemas = {}) {\n schema = _.clone(schema);\n\n const filters = {};\n\n addFiltersFromSchema(schema, filters);\n Object.keys(subSchemas).forEach((key) => {\n addFiltersFromSchema(subSchemas[key], filters, key);\n });\n\n return filters;\n}\n\nexport function addFiltersFromSchema(schema, filters, keyPrefix = '') {\n const asLinkAlias = _.get(schema, 'as', null);\n schema = _.get(schema, 'schema') || schema;\n\n return Object.keys(schema).reduce((acc, item) => {\n let key = item;\n\n if (asLinkAlias) {\n acc[asLinkAlias] = { type: DB.STRING, filterType: DB.Op.eq };\n }\n\n if (keyPrefix) {\n key = `${keyPrefix}.${item}`;\n }\n\n if (schema[item].filterType) {\n acc[key] = { filterType: schema[item].filterType };\n\n return acc;\n }\n\n const itemType = schema[item].type;\n\n //new sequelize uses class symbols instead of objects\n if (itemType instanceof DB.STRING) {\n acc[key] = { filterType: DB.Op.iLike };\n } else if (itemType instanceof DB.CHAR) {\n acc[key] = { filterType: DB.Op.iLike };\n } else if (itemType instanceof DB.TEXT) {\n acc[key] = { filterType: DB.Op.iLike };\n } else if (itemType instanceof DB.DECIMAL) {\n acc[key] = { filterType: DB.Op.or };\n } else if (itemType instanceof DB.INTEGER) {\n acc[key] = { filterType: DB.Op.or };\n } else if (itemType instanceof DB.BIGINT) {\n acc[key] = { filterType: DB.Op.or };\n } else if (itemType instanceof DB.BOOLEAN) {\n acc[key] = { type: DB.BOOLEAN, filterType: DB.Op.eq };\n } else if (itemType instanceof DB.JSONB || itemType === DB.JSONB) {\n acc[key] = { type: 'jsonb', field: item };\n } else if (itemType instanceof DB.DATE) {\n acc[key] = { filterType: DB.Op.between };\n } else if (itemType instanceof DB.DATEONLY) {\n acc[key] = { filterType: DB.Op.eq };\n }\n\n //these are automatically part of the models, so add them always\n acc['createdAt'] = { type: DB.DATE, filterType: DB.Op.between };\n acc['updatedAt'] = { type: DB.DATE, filterType: DB.Op.between };\n acc['id'] = { type: DB.INTEGER, filterType: DB.Op.eq };\n\n return acc;\n }, filters);\n}\n","import _ from 'lodash';\nimport DB from 'sequelize';\nimport dayjs from 'dayjs';\nimport utc from 'dayjs/plugin/utc.js';\nimport { errorList } from '../../../requestResponse/errorCodes.js';\nimport { accessRightsUtils } from './accessRightsUtils.js';\n\ndayjs.extend(utc);\n\n/**\n * Create sequelize where clause from query string parameters and default sort object\n *\n * Translates URL query string parameters into a Sequelize-compatible WHERE object\n * by matching each param against a filter definition (objectFilters).\n *\n * Filter definitions come from defaultFilters() which maps schema data types to operators:\n * STRING / CHAR / TEXT -> Op.iLike (case-insensitive LIKE)\n * INTEGER / DECIMAL -> Op.or (positive or negative match)\n * BOOLEAN -> Op.eq (exact match with string-to-boolean coercion)\n * JSONB -> case-insensitive search via jsonb_extract_path_text\n * DATE -> Op.between\n *\n * Three convenience params are handled automatically:\n * - searchString: searches a single value across all iLike and eq fields using OR\n * - startDate + endDate: filters createdAt with a BETWEEN range\n *\n * @param {object} event - the Lambda event containing queryStringParameters\n * @param {object} objectFilters - filter definitions created by defaultFilters()\n * @returns {object} A Sequelize where clause object\n */\nexport const createFilters = function (event, objectFilters) {\n let query = _.get(event, 'queryStringParameters', {}) || {};\n\n // Extract the three convenience params before iterating.\n // These are handled separately from the per-field filter logic below.\n const searchString = _.get(query, 'searchString');\n const startDate = _.get(query, 'startDate');\n const endDate = _.get(query, 'endDate');\n\n // ──────────────────────────────────────────────────────────────────────\n // STEP 1 — Build per-field WHERE conditions\n //\n // Each query param is looked up in objectFilters. If a matching filter\n // definition exists, we create the appropriate Sequelize condition.\n //\n // String-type fields (Op.iLike) are collected into a separate array\n // because they use DB.where(DB.fn('LOWER', DB.col(...))) which cannot\n // be expressed as a simple { column: { operator: value } } key.\n // Instead they are merged into WHERE via Op.and after the reduce.\n //\n // This approach replaces the Postgres-only Op.iLike with\n // LOWER(column) LIKE '%lowered_value%' which works across all\n // database dialects (Postgres, MySQL, MSSQL, SQLite).\n // ──────────────────────────────────────────────────────────────────────\n const caseInsensitiveConditions = [];\n const where = Object.keys(query).reduce((acc, item) => {\n const val = _.get(objectFilters, item, null);\n\n if (val) {\n // JSONB fields are handled entirely in Step 4 below.\n // Skip them here so they don't fall into the catch-all else branch.\n if (val.type === 'jsonb') {\n return acc;\n }\n\n // Dot-notation keys (e.g. \"snowman.snowmanType\") reference columns\n // on joined/included models. Sequelize requires these to be wrapped\n // in $...$ syntax in the WHERE object so it can resolve them.\n const itemName = item.includes('.')\n ? `$${item}$`\n : item;\n\n // STRING / CHAR / TEXT fields — case-insensitive partial match\n // Generates: WHERE LOWER(\"column\") LIKE '%lowered_value%'\n if (val.filterType === DB.Op.iLike) {\n caseInsensitiveConditions.push(\n DB.where(\n DB.fn('LOWER', DB.col(item)),\n { [DB.Op.like]: `%${query[item]?.toLowerCase()}%` }\n )\n );\n\n // INTEGER / DECIMAL fields — match positive or negative value\n // Generates: WHERE \"column\" IN (-value, value)\n // Useful for fields like amounts where sign may vary.\n } else if (val.filterType === DB.Op.or) {\n acc[itemName] = {};\n acc[itemName][val.filterType] = [ -1 * +query[item], +query[item] ];\n\n // ENUM / multi-value fields — match any value in a comma-separated list\n // Query: ?status=open,closed -> WHERE \"status\" IN ('open','closed')\n } else if (val.filterType === DB.Op.in) {\n acc[itemName] = {};\n acc[itemName][val.filterType] = query[item].split(',');\n\n // Catch-all for other operators (Op.eq, Op.contains, Op.between, etc.)\n // Attempts JSON.parse first so structured values (objects, arrays, numbers)\n // are passed as their parsed type rather than raw strings.\n } else {\n acc[itemName] = {};\n let parsedJson;\n try {\n parsedJson = JSON.parse(query[item]);\n } catch (e) {\n parsedJson = query[item];\n }\n acc[itemName][val.filterType] = parsedJson;\n }\n\n // BOOLEAN override — runs after the block above so it can replace\n // the value set by the catch-all. Query strings are always strings\n // (\"true\", \"false\", \"null\"), so we coerce them to actual booleans/null.\n if (val.type === DB.BOOLEAN) {\n const queryValue = _.get(query, item, '').toLowerCase();\n\n const booleanMap = {\n 'false': false,\n 'null': null,\n 'true': true\n };\n\n acc[itemName][val.filterType] = booleanMap[queryValue];\n }\n }\n\n return acc;\n }, {});\n\n // Merge the case-insensitive string conditions into WHERE using Op.and.\n // This keeps them alongside the key-based conditions built above.\n // Example result: WHERE decimal = 100 AND LOWER(\"name\") LIKE '%john%'\n if (caseInsensitiveConditions.length) {\n where[DB.Op.and] = [ ...(where[DB.Op.and] || []), ...caseInsensitiveConditions ];\n }\n\n // ──────────────────────────────────────────────────────────────────────\n // STEP 2 — Apply automatic filters (active flag, businessId, dates)\n //\n // These are appended to every query regardless of what the caller sent.\n // ──────────────────────────────────────────────────────────────────────\n\n // If the model has an \"active\" column and the caller did not explicitly\n // filter by it, default to only returning active records.\n if (objectFilters?.active && !where?.active) {\n where.active = true;\n }\n\n // Scope every query to the caller's authorized business IDs.\n // accessRightsUtils extracts them from the JWT claims on the event.\n const businessIds = accessRightsUtils(event);\n const filterAdds = {\n businessId: businessIds\n };\n\n // Date range filter — when both startDate and endDate are provided,\n // automatically filter createdAt with a BETWEEN clause.\n // Generates: WHERE \"createdAt\" BETWEEN '2024-01-01' AND '2024-12-31'\n if (startDate && endDate) {\n const s = dayjs.utc(startDate);\n const e = dayjs.utc(endDate);\n const dates = {\n [DB.Op.between]: [ s.toDate(), e.toDate() ]\n };\n if (!s.isValid()) {\n throw { ...errorList.invalidStartDate };\n }\n\n if (!e.isValid()) {\n throw { ...errorList.invalidEndDate };\n }\n\n filterAdds.createdAt = dates;\n }\n\n // ──────────────────────────────────────────────────────────────────────\n // STEP 3 — searchString: search one value across many fields with OR\n //\n // When ?searchString=john is provided, we build an OR array that checks\n // every filterable field for a match. This lets a single search box\n // query across name, title, email, etc. simultaneously.\n //\n // String fields (Op.iLike) get a case-insensitive LOWER + LIKE condition.\n // Numeric fields (Op.eq) get an exact match, but only when the search\n // value is a valid number (and the field is not a boolean).\n //\n // Generates: WHERE (LOWER(\"name\") LIKE '%john%'\n // OR LOWER(\"title\") LIKE '%john%'\n // OR \"id\" = 123)\n // ──────────────────────────────────────────────────────────────────────\n if (searchString) {\n const adds = Object.keys(objectFilters).reduce((acc, item) => {\n const type = objectFilters[item].filterType;\n const dataType = objectFilters[item].type;\n\n // String fields — case-insensitive partial match via LOWER + LIKE\n if (type === DB.Op.iLike) {\n acc.push(\n DB.where(\n DB.fn('LOWER', DB.col(item)),\n { [DB.Op.like]: `%${query['searchString'].toLowerCase()}%` }\n )\n );\n }\n\n // Numeric fields — exact match only when the search value is numeric.\n // Booleans are excluded because a search for \"1\" should not match\n // boolean true.\n if (!_.isNaN(Number(query['searchString'])) && !(dataType instanceof DB.BOOLEAN)) {\n\n if (type === DB.Op.eq) {\n const newOr = {};\n const itemName = item.includes('.') ? `$${item}$` : item;\n newOr[itemName] = {\n [DB.Op.eq]: `${query['searchString']}`\n };\n acc.push(newOr);\n }\n }\n\n return acc;\n }, []);\n\n filterAdds[DB.Op.or] = adds;\n }\n\n // Merge the automatic filters (businessId, createdAt, searchString OR)\n // into the where object built in Step 1.\n const withDate = Object.assign(where, filterAdds);\n\n // ──────────────────────────────────────────────────────────────────────\n // STEP 4 — JSONB field filters: case-insensitive search inside JSON columns\n //\n // JSONB columns store structured data (e.g. a \"token\" column containing\n // { cardType: \"mastercard\", cardHolderName: \"GREGORY HERBERT\" }).\n //\n // Query params use dot-notation to target nested keys:\n // ?token.cardHolderName=gregory\n // ?paymentProviderData.payment.result.message=approved\n //\n // For each matching param we:\n // 1. Split the path after the column prefix into individual key segments\n // 2. Use jsonb_extract_path_text(column, key1, key2, ...) to pull the\n // value out of the JSON as plain text\n // 3. Wrap it in LOWER() and compare with Op.like for case-insensitive match\n //\n // Generates: WHERE LOWER(jsonb_extract_path_text(\"token\", 'cardHolderName'))\n // LIKE '%gregory%'\n //\n // jsonb_extract_path_text is used via DB.fn() so Sequelize parameterizes\n // the path arguments, keeping it safe from SQL injection.\n // ──────────────────────────────────────────────────────────────────────\n Object.keys(objectFilters || {}).forEach((k) => {\n const def = objectFilters[k];\n if (def && def.type === 'jsonb' && def.field) {\n const prefix = `${def.field}.`;\n\n Object.keys(query).forEach((qKey) => {\n if (qKey.startsWith(prefix)) {\n // Dot-notation: ?token.cardHolderName=gregory\n // e.g. \"token.cardHolderName\" -> pathParts = [\"cardHolderName\"]\n // e.g. \"data.payment.result.message\" -> pathParts = [\"payment\",\"result\",\"message\"]\n const pathParts = qKey.substring(prefix.length).split('.');\n const value = query[qKey];\n\n if (!withDate[DB.Op.and]) {\n withDate[DB.Op.and] = [];\n }\n withDate[DB.Op.and].push(\n DB.where(\n DB.fn('LOWER', DB.fn('jsonb_extract_path_text', DB.col(def.field), ...pathParts)),\n { [DB.Op.like]: `%${value?.toLowerCase()}%` }\n )\n );\n } else if (qKey === def.field) {\n // JSON-object-as-value: ?token={\"cardHolderName\":\"Test\"}\n // Parse the JSON and create a condition for each key-value pair.\n // Nested objects are flattened recursively into deeper path segments.\n let parsed;\n try {\n parsed = JSON.parse(query[qKey]);\n } catch (e) {\n return;\n }\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n const addJsonbConditions = (obj, pathParts) => {\n Object.entries(obj).forEach(([key, value]) => {\n const currentPath = [...pathParts, key];\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n addJsonbConditions(value, currentPath);\n } else if (value !== null && !Array.isArray(value)) {\n if (!withDate[DB.Op.and]) {\n withDate[DB.Op.and] = [];\n }\n withDate[DB.Op.and].push(\n DB.where(\n DB.fn('LOWER', DB.fn('jsonb_extract_path_text', DB.col(def.field), ...currentPath)),\n { [DB.Op.like]: `%${String(value)?.toLowerCase()}%` }\n )\n );\n }\n });\n };\n addJsonbConditions(parsed, []);\n }\n }\n });\n }\n });\n\n return withDate;\n};\n","module.exports = require(\"dayjs\");","import { SNS } from '@aws-sdk/client-sns';\n\nconst SNSUtil = {\n publish: (params) => publish(params),\n createTopic: (params) => createTopic(params)\n};\n\nasync function publish(params) {\n const sns = new SNS();\n return await sns.publish(params);\n}\n\nasync function createTopic(params) {\n const sns = new SNS();\n return await sns.createTopic(params);\n}\n\nexport default SNSUtil;\n","module.exports = require(\"dayjs/plugin/isSameOrBefore\");","import _ from 'lodash';\nimport { ensurePartnerScope } from './accessContext.js';\nimport { errorList } from '../../../requestResponse/errorCodes.js';\n\n/**\n * Scope a WHERE clause to the partner's own business (partnerBusinessId).\n * Use for \"mine\" resources: deal, activity, application, template.\n *\n * global → deletes where.businessId (super sees everything)\n * partner → sets where.businessId = partnerBusinessId\n * throws partnerNotConfigured if partnerBusinessId is missing\n * standard → no-op (createFilters already handled)\n *\n * @param {object} where - Sequelize WHERE clause to mutate.\n * @param {object} access - Access object from resolveAccess.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function scopeToOwnBusiness(where, access, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n delete where.businessId;\n return;\n }\n if (access.level === 'partner') {\n await ensurePartnerScope(access, { getPartnerById });\n if (!access.partnerBusinessId) {\n throw errorList.partnerNotConfigured;\n }\n where.businessId = access.partnerBusinessId;\n return;\n }\n // standard → no-op (createFilters already injected from JWT)\n}\n\n/**\n * Scope a WHERE clause to the partner's portfolio (businessIds array).\n * Use for \"book\" resources (future transaction lists, merchant inbox views).\n *\n * global → deletes where.businessId\n * partner → sets where.businessId = businessIds[]\n * standard → no-op\n *\n * @param {object} where - Sequelize WHERE clause to mutate.\n * @param {object} access - Access object from resolveAccess.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function scopeToPartnerBook(where, access, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n delete where.businessId;\n return;\n }\n if (access.level === 'partner') {\n await ensurePartnerScope(access, { getPartnerById });\n where.businessId = access.businessIds || [];\n return;\n }\n // standard → no-op\n}\n\n/**\n * Scope to the union of partnerBusinessId + businessIds.\n * Use for tickets — partner sees own tickets + portfolio merchants' tickets.\n *\n * global → deletes where.businessId\n * partner → sets where.businessId = [partnerBusinessId, ...businessIds]\n * standard → sets where.businessId = access.businessIds\n * (explicitly handled here because ticket routes may not call\n * createFilters before scoping, e.g. delete/resolve handlers)\n *\n * @param {object} where - Sequelize WHERE clause to mutate.\n * @param {object} access - Access object from resolveAccess.\n * @param {{ getPartnerById: Function }} deps\n */\nexport async function scopeToBookUnionOwn(where, access, { getPartnerById } = {}) {\n if (!access) {\n throw errorList.unauthorized;\n }\n if (access.level === 'global') {\n delete where.businessId;\n return;\n }\n if (access.level === 'partner') {\n await ensurePartnerScope(access, { getPartnerById });\n const ids = _.uniq(\n [access.partnerBusinessId, ...(access.businessIds || [])].filter(Boolean)\n );\n where.businessId = ids;\n return;\n }\n if (access.level === 'standard') {\n where.businessId = access.businessIds;\n return;\n }\n}\n","module.exports = require(\"@aws-sdk/lib-dynamodb\");","import { ensurePartnerScope } from './accessContext.js';\nimport { scopeToOwnBusiness, scopeToPartnerBook, scopeToBookUnionOwn } from './accessScope.js';\nimport {\n assertCanWriteOwnBusiness,\n assertCanWriteBookBusiness,\n assertCanWriteBookUnionOwn,\n stampOwnBusinessId\n} from './accessWrites.js';\n\n/**\n * Factory that pre-binds getPartnerById into all scope/assert/stamp helpers.\n * Bind once at module level, then call without repeating the injection:\n *\n * import { createAccessHelpers } from 'piper-utils';\n * import { getPartnerById } from '../partner/partner.js';\n *\n * const {\n * scopeToOwnBusiness,\n * stampOwnBusinessId,\n * assertCanWriteOwnBusiness\n * } = createAccessHelpers({ getPartnerById });\n *\n * @param {{ getPartnerById: Function }} deps\n * @returns {object} Pre-bound helpers.\n */\nexport function createAccessHelpers({ getPartnerById }) {\n const deps = { getPartnerById };\n return {\n ensurePartnerScope: (access) => ensurePartnerScope(access, deps),\n scopeToOwnBusiness: (where, access) => scopeToOwnBusiness(where, access, deps),\n scopeToPartnerBook: (where, access) => scopeToPartnerBook(where, access, deps),\n scopeToBookUnionOwn: (where, access) => scopeToBookUnionOwn(where, access, deps),\n assertCanWriteOwnBusiness: (access, businessId) => assertCanWriteOwnBusiness(access, businessId, deps),\n assertCanWriteBookBusiness: (access, businessId) => assertCanWriteBookBusiness(access, businessId, deps),\n assertCanWriteBookUnionOwn: (access, businessId) => assertCanWriteBookUnionOwn(access, businessId, deps),\n stampOwnBusinessId: (access, body) => stampOwnBusinessId(access, body, deps)\n };\n}\n","module.exports = require(\"bluebird\");","import _, { isEmpty } from 'lodash';\r\nimport { errorList } from '../../../requestResponse/errorCodes.js';\r\nimport { parseBody } from '../../../requestResponse/requestResponse.js';\r\n\r\nexport function isSystemUser(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:SYSTEM') ||\r\n _.get(event, 'requestContext.authorizer.custom:SYSTEM') ||\r\n 'false';\r\n let isSys = false;\r\n try {\r\n isSys = JSON.parse(jsonToParse);\r\n return isSys;\r\n } catch (e) {\r\n console.error('error with system user:', e);\r\n\r\n return false;\r\n }\r\n}\r\n\r\nexport function isSuperUser(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:SUPER') ||\r\n _.get(event, 'requestContext.authorizer.custom:SUPER') ||\r\n 'false';\r\n let isSys = false;\r\n\r\n try {\r\n isSys = JSON.parse(jsonToParse);\r\n\r\n return isSys;\r\n } catch (e) {\r\n\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Throws unauthorized error if the user is not a super user.\r\n * Mirrors the behavior and style of checkModule but focused on SUPER role.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n */\r\nexport function checkIsSuper(event) {\r\n // Super or System users are always allowed\r\n if (isSuperUser(event)) {\r\n return;\r\n }\r\n if (isSystemUser(event)) {\r\n return;\r\n }\r\n\r\n // In local builds allow bypass to ease development and tests\r\n if (process.env.BUILD_ENV === 'local') {\r\n return;\r\n }\r\n\r\n throw errorList.unauthorized;\r\n}\r\n\r\n/**\r\n * Get the allowed businessIds for a user from the lambda event, compare it to businessIds, return what user has access to.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @param {{useCognitoBid:boolean}} [options] - An object with options, useCognitoBid prefers the businessId set in cognito if set and does not return the local bid of 1 if a bid is in the claim.\r\n * @returns {array} A list of businessIds that have been requested and are allowed to for some user.\r\n */\r\nexport function accessRightsUtils(event, options) {\r\n const useCognitoBid = _.get(options, 'useCognitoBid', false);\r\n const requestedBusinessIds = getRequestedBusinessIds(event);\r\n const allowedBusinessIds = getAllowedBusinessIds(event, useCognitoBid);\r\n\r\n if (isSuperUser(event)) {\r\n let v = requestedBusinessIds;\r\n if (_.isEmpty(requestedBusinessIds)) {\r\n v = allowedBusinessIds;\r\n }\r\n\r\n return v;\r\n }\r\n if (isSystemUser(event)) {\r\n return requestedBusinessIds;\r\n }\r\n\r\n if (requestedBusinessIds.length === 0) {\r\n return allowedBusinessIds;\r\n }\r\n\r\n return _.intersection(requestedBusinessIds, allowedBusinessIds);\r\n}\r\n\r\n/**\r\n * Get the businessID set in cognito as custom:DBI.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {string} The businessID set in cognito as custom:DBI\r\n */\r\nexport function userDefaultBid(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:DBI') ||\r\n _.get(event, 'requestContext.authorizer.custom:DBI') ||\r\n '{}';\r\n\r\n const dbi = JSON.parse(jsonToParse);\r\n return _.get(dbi, 'defaultBid', '') || '1';\r\n}\r\n\r\n/**\r\n * Get requested businessIds from the query string.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {array} The businessID requested by the query string\r\n */\r\nexport function getRequestedBusinessIds(event) {\r\n let requestedBusinessIds = _.get(event, 'queryStringParameters.businessIds', null);\r\n const body = parseBody(event);\r\n const bodyBid = body?.businessId;\r\n if (requestedBusinessIds) {\r\n return requestedBusinessIds ? requestedBusinessIds.split(',') : [];\r\n } else if (bodyBid) {\r\n return [ bodyBid ];\r\n } else {\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Get the allowed businessIds for a user from cognito custom:AR property.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @param useCognitoBid\r\n * @returns {array} The businessID requested by the query string\r\n */\r\nfunction getAllowedBusinessIds(event, useCognitoBid) {\r\n const businesses = getBusinessesInfo(event, useCognitoBid);\r\n return Object.keys(businesses);\r\n}\r\n\r\nexport function getAccessRightsInfo(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:AR') ||\r\n _.get(event, 'requestContext.authorizer.custom:AR') ||\r\n '{}';\r\n const accessRights = JSON.parse(jsonToParse);\r\n return _.get(accessRights, 'businessIds', {});\r\n}\r\n\r\nexport function getDefaultBusinessIDInfo(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:DBI') ||\r\n _.get(event, 'requestContext.authorizer.custom:DBI') ||\r\n '{}';\r\n const dbi = JSON.parse(jsonToParse);\r\n\r\n return _.get(dbi, 'defaultBid', '1');\r\n}\r\n\r\nexport function getBusinessesInfo(event, useCognitoBid = false) {\r\n const json = _.get(event, 'requestContext.authorizer.claims.custom:AR') ||\r\n _.get(event, 'requestContext.authorizer.custom:AR') ||\r\n '{}';\r\n\r\n let businessIds = _.get(JSON.parse(json), 'businessIds', {});\r\n\r\n // Local environment tweaks\r\n if (process.env.BUILD_ENV === 'local') {\r\n let b;\r\n try {\r\n b = JSON.parse(event?.body);\r\n } catch (e) {\r\n }\r\n const bodyBid = b?.businessId;\r\n // Always inject the default local BID “1” unless the caller explicitly wants\r\n // what Cognito says **and** Cognito actually returned something.\r\n if (!useCognitoBid) {\r\n businessIds = { ...businessIds, '1': 'A' };\r\n }\r\n\r\n // If Cognito gave no BIDs at all, fall back to the local default.\r\n if (isEmpty(businessIds)) {\r\n businessIds = { '1': 'A' };\r\n }\r\n // a businessId is found on the body for local allow it\r\n if (bodyBid) {\r\n businessIds[bodyBid] = 'A';\r\n }\r\n }\r\n\r\n return businessIds;\r\n}\r\n\r\n/**\r\n * Get the modules listed in custom:MOD.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {array} The Module access list\r\n */\r\nexport function getModuleInfo(event) {\r\n let jsonToParse =\r\n _.get(event, 'requestContext.authorizer.claims.custom:MOD') ||\r\n _.get(event, 'requestContext.authorizer.custom:MOD') ||\r\n _.get(event, 'requestContext.authorizer.claims.custom:AR') ||\r\n _.get(event, 'requestContext.authorizer.custom:AR') ||\r\n\r\n '{}';\r\n\r\n const moduleRights = JSON.parse(jsonToParse);\r\n return _.get(moduleRights, 'module', {});\r\n}\r\n\r\n/**\r\n * Get the modules listed in custom:MOD.\r\n *\r\n * @param {string} moduleName - A sting name for a module.\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {array} The Module access list\r\n */\r\nexport function checkModule(moduleName, event) {\r\n const moduleRights = getModuleInfo(event);\r\n let allowAccess = _.get(moduleRights, moduleName, false);\r\n\r\n if (isSuperUser(event)) {\r\n return;\r\n }\r\n if (isSystemUser(event)) {\r\n return;\r\n }\r\n\r\n if (process.env.BUILD_ENV === 'local') {\r\n return;\r\n }\r\n if (!allowAccess) {\r\n throw errorList.unauthorized;\r\n }\r\n}\r\n\r\nexport const userRoles = {\r\n admin: 'A',\r\n read: 'R',\r\n write: 'W'\r\n};\r\n\r\n/**\r\n * Get the partner ID from custom:PID if the user is a partner admin.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {string|false} The partner ID or false if not a partner user.\r\n */\r\nexport function isPartnerUser(event) {\r\n const partnerId = _.get(event, 'requestContext.authorizer.claims.custom:PID') ||\r\n _.get(event, 'requestContext.authorizer.custom:PID') ||\r\n '';\r\n return partnerId || false;\r\n}\r\n\r\n/**\r\n * Get the partner ID from custom:BPID if the user's business belongs to a partner.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {string|false} The partner ID or false if not associated with a partner.\r\n */\r\nexport function getBelongsToPartnerId(event) {\r\n const partnerId = _.get(event, 'requestContext.authorizer.claims.custom:BPID') ||\r\n _.get(event, 'requestContext.authorizer.custom:BPID') ||\r\n '';\r\n return partnerId || false;\r\n}\r\n\r\n/**\r\n * Get the effective partner ID from either custom:PID or custom:BPID.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {string|false} The partner ID or false.\r\n */\r\nexport function getEffectivePartnerId(event) {\r\n return isPartnerUser(event) || getBelongsToPartnerId(event);\r\n}\r\n\r\n/**\r\n * Enrich the event's custom:AR with partner business IDs in-memory.\r\n * Call this BEFORE accessRightsUtils() or getBusinessesInfo() so that\r\n * partner admins (custom:PID) get access to their partner's merchants.\r\n *\r\n * This keeps accessRightsUtils synchronous — the DB lookup is done by the caller.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @param {string[]} partnerBusinessIds - Array of business IDs from the partner record.\r\n * @param {string} [role='R'] - Access role to assign (default: Read).\r\n */\r\nexport function enrichEventWithPartnerAccess(event, partnerBusinessIds, role = 'R') {\r\n if (!partnerBusinessIds || partnerBusinessIds.length === 0) return;\r\n\r\n const arPath = event?.requestContext?.authorizer?.claims\r\n ? 'requestContext.authorizer.claims.custom:AR'\r\n : 'requestContext.authorizer.custom:AR';\r\n\r\n const json = _.get(event, arPath) || '{}';\r\n const accessRights = JSON.parse(json);\r\n const businessIds = accessRights.businessIds || {};\r\n\r\n for (const bid of partnerBusinessIds) {\r\n if (!businessIds[bid]) {\r\n businessIds[bid] = role;\r\n }\r\n }\r\n\r\n accessRights.businessIds = businessIds;\r\n _.set(event, arPath, JSON.stringify(accessRights));\r\n}\r\n\r\n/**\r\n * @param {{body: string}} event\r\n * @param {{useCognitoBid:boolean}} [options] - An object with options, useCognitoBid prefers the businessId set in cognito if set and does not return the local bid of 1 if a bid is in the claim.\r\n * @returns {string} businessId\r\n */\r\nexport function checkWriteAccess(event, options) {\r\n const eventBody = parseBody(event);\r\n const businessIds = accessRightsUtils(event, options) || [];\r\n const businessId = businessIds.find((id) => id === eventBody.businessId);\r\n const raw = getBusinessesInfo(event);\r\n const userRight = raw[businessId];\r\n\r\n if (isSuperUser(event)) {\r\n return eventBody.businessId;\r\n }\r\n\r\n if (isSystemUser(event)) {\r\n return eventBody.businessId;\r\n }\r\n\r\n if (process.env.BUILD_ENV === 'local') {\r\n return eventBody.businessId;\r\n }\r\n\r\n if ((userRight !== userRoles.admin && userRight !== userRoles.write) || (!userRight)) {\r\n throw errorList.unauthorized;\r\n }\r\n return businessId;\r\n}\r\n\r\n/**\r\n * Get the company-level cached settings from custom:SET.\r\n *\r\n * @param {object} event - The lambda event passed in by a validated api request.\r\n * @returns {object} The company settings object (e.g. { auditEnabled: true })\r\n */\r\nexport function getCompanySettings(event) {\r\n const jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:SET')\r\n || _.get(event, 'requestContext.authorizer.custom:SET')\r\n || '{}';\r\n try {\r\n return JSON.parse(jsonToParse);\r\n } catch (e) {\r\n return {};\r\n }\r\n}\r\n\r\n","module.exports = require(\"@aws-sdk/client-sns\");","module.exports = require(\"lodash\");","import _ from 'lodash';\n\n/**\n * Create sequelize order clause from query string parameters and default sort object\n *\n * @param {object} event - the event created AWS lambda, it will contain queryStringParameters with sort property a comma seperated list of sortable fields * @param {object} objectFilters - the default filters object created by createDefaultFilters\n * @param {object} defaultFilter - A default filter object as built by createDefault Filters, if items are not on the schema they will not be in the order by\n * @returns {object} An sequelize order by object\n */\nexport const createSort = function (event, defaultFilter) {\n let copyOfDefaultFilter = _.clone(defaultFilter);\n let query = _.get(event, 'queryStringParameters', {}) || {};\n let sort = _.get(query, 'sort', '-updatedAt') || '-updatedAt';\n\n return sort.split(',').reduce((acc, item) => {\n\n const testItem = item.indexOf('-') === 0 ? item.substr(1) : item;\n\n if (_.get(copyOfDefaultFilter, testItem, null)) {\n const sortItem = [];\n\n testItem.split('.').forEach((parentChildList) => {\n sortItem.push(parentChildList);\n });\n\n if (item.indexOf('-') === 0) {\n sortItem.push('DESC');\n } else {\n sortItem.push('ASC');\n }\n acc.push(sortItem);\n }\n\n return acc;\n }, []);\n};\n","import _ from 'lodash';\r\nimport { errorList } from './errorCodes.js';\r\n\r\nconst securityHeaders = {\r\n 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',\r\n 'X-Content-Type-Options': 'nosniff',\r\n 'X-Frame-Options': 'DENY',\r\n 'Referrer-Policy': 'strict-origin-when-cross-origin',\r\n 'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',\r\n 'Cache-Control': 'no-store',\r\n 'Content-Security-Policy': \"default-src 'none'; frame-ancestors 'none'\"\r\n};\r\n\r\nconst htmlSecurityHeaders = {\r\n 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',\r\n 'X-Content-Type-Options': 'nosniff',\r\n 'Referrer-Policy': 'strict-origin-when-cross-origin',\r\n 'Permissions-Policy': 'camera=(), microphone=(), geolocation=(), payment=*',\r\n 'Cache-Control': 'no-store',\r\n 'Content-Security-Policy': [\r\n \"default-src 'self'\",\r\n \"script-src 'self' 'unsafe-inline' https://browser.sentry-cdn.com https://test-htp.tokenex.com https://htp.tokenex.com https://sandbox.nmi.com https://secure.nmi.com https://applepay.cdn-apple.com\",\r\n \"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://sandbox.nmi.com https://secure.nmi.com\",\r\n \"font-src 'self' https://fonts.gstatic.com\",\r\n \"frame-src https:\",\r\n \"connect-src 'self' https://*.tokenex.com https://*.sentry.io https://*.nmi.com https://*.apple.com\",\r\n \"img-src 'self' data:\",\r\n \"frame-ancestors *\"\r\n ].join('; ')\r\n};\r\n\r\n/**\r\n * @param {Object} body\r\n * @param {{dbClose?:function}} [options]\r\n */\r\nexport function success(body, options) {\r\n const dbClose = _.get(options, 'dbClose', _.noop);\r\n dbClose();\r\n\r\n return buildResponse(200, body);\r\n}\r\n\r\n/**\r\n * @param {string} html\r\n * @param {{dbClose:function|undefined}} options\r\n */\r\nexport function successHtml(html, options) {\r\n const dbClose = _.get(options, 'dbClose', _.noop);\r\n\r\n dbClose();\r\n return {\r\n statusCode: 200,\r\n headers: {\r\n 'Content-Type': 'text/html',\r\n 'Access-Control-Allow-Origin': '*',\r\n 'Access-Control-Allow-Credentials': true,\r\n ...htmlSecurityHeaders\r\n },\r\n body: html\r\n };\r\n}\r\n\r\n/**\r\n * @param {string} event\r\n * @returns string\r\n */\r\nexport function getCurrentUserNameFromCognitoEvent(event) {\r\n const attributes = _.get(event, 'request.userAttributes');\r\n\r\n return attributes['cognito:email_alias'] || attributes['email'] || 'UNKNOWN USER';\r\n}\r\n\r\n/**\r\n * Get the user information from the event object\r\n *\r\n * @param event {Object} an event object\r\n * @returns {{username: string, id: number}}\r\n */\r\nexport function getCurrentUser(event) {\r\n let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:UID') ||\r\n _.get(event, 'requestContext.authorizer.custom:UID') ||\r\n '0';\r\n\r\n const username = _.get(event, 'requestContext.authorizer.claims.email') || _.get(event, 'requestContext.authorizer.email') || 'localtestuser@gexample.com';\r\n const id = process.env.BUILD_ENV === 'local' ? 1 : JSON.parse(jsonToParse);\r\n\r\n return {\r\n username,\r\n id\r\n };\r\n}\r\n\r\n/**\r\n * Create a failure response\r\n *\r\n * @param body {Object} an event object\r\n * @param options {Object} an options object\r\n * @returns {{statusCode:number, headers:object, body:string}} a response object\r\n */\r\nexport function failure(body = {}, options) {\r\n const dbClose = _.get(options, 'dbClose', _.noop);\r\n dbClose();\r\n let cleanedErrorBody;\r\n\r\n if (process.env.UTIL_LOG === 'LOG_ALL' || process.env.BUILD_ENV === 'test') {\r\n if (_.isObject(body)) {\r\n console.error('------->ALL UTIL ERROR:', JSON.stringify(body, null, 2));\r\n }\r\n }\r\n\r\n const NORMAL_ERROR = { statusCode: 500, errorCode: '5XX', message: 'INTERNAL UTIL ERROR' };\r\n cleanedErrorBody = body;\r\n if (!_.isUndefined(body.details)) {\r\n cleanedErrorBody = detectJoyError(body);\r\n } else if (_.isUndefined(body.errorCode) || _.isUndefined(body.statusCode)) {\r\n cleanedErrorBody = detectSequelizeError(body);\r\n }\r\n if (_.get(body, 'response.data.message')) {\r\n const err = _.get(body, 'response.data.message');\r\n if (_.isObject(body)) {\r\n if (process.env.UTIL_LOG === 'LOG_ALL' || process.env.BUILD_ENV === 'test') {\r\n console.error('------->MSG UTIL ERROR:', JSON.stringify(err, null, 2));\r\n }\r\n }\r\n }\r\n const newBody = _.merge(NORMAL_ERROR, cleanedErrorBody);\r\n\r\n return buildResponse(newBody.statusCode, newBody);\r\n}\r\n\r\n/**\r\n * Create a failure response object\r\n *\r\n * @param statusCode {Number} a status code\r\n * @param body {Object} an event object\r\n * @returns {{statusCode:number, headers:object, body:string}} a response object\r\n */\r\nfunction buildResponse(statusCode, body) {\r\n return {\r\n statusCode: statusCode,\r\n headers: {\r\n 'Access-Control-Allow-Origin': '*',\r\n 'Access-Control-Allow-Credentials': true,\r\n ...securityHeaders\r\n },\r\n body: JSON.stringify(body)\r\n };\r\n}\r\n\r\n/**\r\n * parse the body of the event object\r\n *\r\n * @param requestEvent {{body:string}} an event object\r\n * @returns event {*} the json object of the body\r\n */\r\nexport function parseBody(requestEvent) {\r\n\r\n let eventBody = {};\r\n if (_.isString(requestEvent.body)) {\r\n try {\r\n eventBody = JSON.parse(requestEvent.body);\r\n } catch (e) {\r\n // Invalid JSON\r\n eventBody = null;\r\n\r\n throw errorList.invalidJson;\r\n }\r\n } else if (_.isObject(requestEvent.body)) {\r\n eventBody = requestEvent.body;\r\n }\r\n\r\n return eventBody;\r\n}\r\n\r\n/**\r\n * parse the body of the event object\r\n *\r\n * @param requestEvent {string|object} an event object\r\n * @param [callback] {function} undefined a call back function\r\n * @returns event {*} the json object of the body\r\n */\r\nexport function parseEvent(requestEvent, callback) {\r\n let event = {};\r\n if (_.isString(requestEvent)) {\r\n try {\r\n event = JSON.parse(requestEvent);\r\n } catch (e) {\r\n // Invalid JSON\r\n event = null;\r\n\r\n if (callback) {\r\n callback(Error(e));\r\n }\r\n }\r\n } else if (_.isObject(requestEvent)) {\r\n event = requestEvent;\r\n }\r\n\r\n return event;\r\n}\r\n\r\n/**\r\n * parse the body of the event object\r\n * look for sequelize errors and return a message\r\n * ERRORS should not be caught here this is a fallback for unknown database errors\r\n *\r\n * @param body {object} part of a body response\r\n * @returns error message object {message:string}\r\n */\r\nexport function detectSequelizeError(body) {\r\n const errorBody = {};\r\n const errorName = _.get(body, 'name', '');\r\n\r\n if (errorName === 'SequelizeForeignKeyConstraintError') {\r\n const detail = _.get(body, 'parent.detail') || _.get(body, 'original.detail') || '';\r\n const notPresent = detail.match(/Key \\((\\w+)\\)=\\((.+?)\\) is not present in table \"(\\w+)\"/);\r\n const stillReferenced = detail.match(/Key \\((\\w+)\\)=\\((.+?)\\) is still referenced from table \"(\\w+)\"/);\r\n if (notPresent) {\r\n errorBody.message = 'The referenced ' + notPresent[3] + ' does not exist (' + notPresent[1] + ': ' + notPresent[2] + ')';\r\n } else if (stillReferenced) {\r\n errorBody.message = 'This item cannot be removed because it is referenced by ' + stillReferenced[3];\r\n } else {\r\n errorBody.message = 'A referenced item does not exist or is still in use';\r\n }\r\n errorBody.statusCode = 409;\r\n errorBody.errorCode = '4090';\r\n return errorBody;\r\n }\r\n\r\n if (errorName === 'SequelizeUniqueConstraintError') {\r\n const fields = _.get(body, 'errors', []).map(err => _.get(err, 'path')).filter(Boolean);\r\n errorBody.message = fields.length\r\n ? 'A record with this ' + fields.join(', ') + ' already exists'\r\n : 'A record with this value already exists';\r\n errorBody.statusCode = 409;\r\n errorBody.errorCode = '4091';\r\n return errorBody;\r\n }\r\n\r\n if (errorName === 'SequelizeValidationError') {\r\n const messages = _.get(body, 'errors', []).map(err => _.get(err, 'message')).filter(Boolean);\r\n errorBody.message = messages.length ? messages.join(', ') : 'Validation error';\r\n errorBody.statusCode = 400;\r\n errorBody.errorCode = '4001';\r\n return errorBody;\r\n }\r\n\r\n let sequelizeError = _.get(body, 'errors', []).reduce((acc, err) => {\r\n acc = acc + ' ' + _.get(err, 'message');\r\n return acc;\r\n }, '');\r\n const parentError = _.get(body, 'parent', '');\r\n\r\n sequelizeError = sequelizeError + _.get(body, 'original.detail', '') + _.get(body, 'TypeError', '') + parentError;\r\n errorBody.message = sequelizeError.trim();\r\n return errorBody;\r\n}\r\n\r\nexport function detectJoyError(body) {\r\n const errorBody = {};\r\n const joyError = _.get(body, 'details[0]', {});\r\n const additionalMessages = _.get(body, 'details[0].context.details') || [];\r\n\r\n const v = additionalMessages.reduce((acc, contextItem) => {\r\n acc = acc + ' ' + contextItem?.message || '';\r\n return acc;\r\n }, '');\r\n\r\n console.error('USER VALIDATION ERROR:', body);\r\n const msg = (joyError?.message || '') + v;\r\n\r\n if (msg) {\r\n errorBody.message = _.trim(msg);\r\n }\r\n\r\n errorBody.statusCode = 400;\r\n errorBody.errorCode = '4000';\r\n return errorBody;\r\n}\r\n\r\n/**\r\n * Parse the body of a Dynamoose error response.\r\n * Attempts to extract a human-readable error message from Dynamoose errors.\r\n * This is a fallback for unknown database errors.\r\n *\r\n * @param {object} body - Part of a body response containing error details.\r\n * @returns {object} - Error message object { message: string }\r\n */\r\nexport function detectDynamooseError(body) {\r\n const errorBody = {};\r\n\r\n // Start with an empty message string.\r\n let dynamooseError = '';\r\n\r\n // If the error body contains an array of errors, concatenate their messages.\r\n if (Array.isArray(body.errors)) {\r\n dynamooseError += body.errors.reduce((acc, err) => {\r\n return acc + ' ' + (err.message || '');\r\n }, '');\r\n }\r\n\r\n // If there's a top-level message, add it.\r\n if (body.message) {\r\n dynamooseError += ' ' + body.message;\r\n }\r\n\r\n // If there is any additional detail provided, append it.\r\n if (body.detail) {\r\n dynamooseError += ' ' + body.detail;\r\n }\r\n\r\n // Trim the message to remove extra spaces.\r\n errorBody.message = dynamooseError.trim();\r\n\r\n return errorBody;\r\n}","import _ from 'lodash';\nimport dayjs from 'dayjs';\nimport customParseFormat from 'dayjs/plugin/customParseFormat';\nimport isSameOrBefore from 'dayjs/plugin/isSameOrBefore';\nimport Promise from 'bluebird';\nimport S3Utils from '../s3/S3Utils/S3Utils.js';\nimport SNSUtil from '../sns/SNSUtils.js';\nimport dynamoUtil from '../dynamo/dynamoUtils.js';\n\ndayjs.extend(customParseFormat);\ndayjs.extend(isSameOrBefore);\n\n/**\n * @param {string} bucket\n * @param {number} maxKeys\n * @param {Object} userImportTypes\n */\nexport async function loop(bucket, maxKeys, userImportTypes) {\n let bucketResult = {};\n let fileList = [];\n\n const currentTime = dayjs();\n\n do {\n bucketResult = await S3Utils.listObjectsV2({\n Bucket: bucket,\n MaxKeys: maxKeys,\n ContinuationToken: _.get(bucketResult, 'NextContinuationToken')\n });\n\n let newFiles = _.filter(bucketResult.Contents, (file) => {\n if (_.startsWith(_.get(file, 'Key'), 'delayUntil/')) {\n const fileDelayTime = _.get(file, 'Key').split('/')[1];\n return dayjs(fileDelayTime, 'YYYYMMDDHHmm').isSameOrBefore(currentTime);\n }\n if (userImportTypes) {\n // look for items in the userImportTypes\n const usersImports = Object.values(userImportTypes);\n const items = file.Key.split('/');\n const fileName = _.last(items);\n const folderName = _.first(items);\n if (_.isEmpty(fileName)) {\n return false;\n\n } else if (usersImports.indexOf(folderName) === -1) {\n return false;\n }\n\n return !_.startsWith(file.Key, `${folderName}/error`);\n }\n return !_.startsWith(file.Key, 'error');\n });\n\n fileList = _.concat(fileList, newFiles);\n } while (bucketResult.IsTruncated && bucketResult.NextContinuationToken && fileList.length < maxKeys);\n\n return fileList;\n}\n\n/**\n * Published SNS events at a steady pace for data in a particular bucket. Should be executed via a cloud watch cron job as a part of a micro service\n *\n * @param {string} configTable - The Dynamo DB table where to get the chunk-size and maxMessage size\n * @param {string} tableKey - The key to the item in the Dynamo DB table that holds the chunk-size and maxMessage size\n * @param {string} bucket - The name of the s3 bucket to watch, when you drop items into this table events will be created\n * @param {string} snsTopic - The name of the snsEvent to publish\n * @param {object} userImportTypes - import types to filter on\n */\nexport async function publishEvents(configTable, tableKey, bucket, snsTopic, userImportTypes) {\n let result;\n try {\n result = await dynamoUtil.get({\n TableName: configTable,\n Key: { key: tableKey }\n });\n } catch (e) {\n console.error(`Cannot get config for key: ${tableKey} table: ${configTable} falling back to defaults of 2 and 10`, e);\n }\n let chunkSize = _.get(result, 'Item.snsChunkSize', 2);\n let maxMessages = _.get(result, 'Item.snsMaxMessages', 10);\n\n const snsCreateTopicResponse = await SNSUtil.createTopic({ Name: snsTopic });\n const topicArn = snsCreateTopicResponse.TopicArn;\n const maxKeys = chunkSize * maxMessages;\n\n const fileList = await loop(bucket, maxKeys, userImportTypes);\n\n const messageList = _.chain(fileList)\n .map('Key')\n .chunk(chunkSize)\n .slice(0, maxMessages)\n .value()\n ;\n\n return Promise.map(messageList, (files) => {\n return SNSUtil.publish({\n Message: JSON.stringify({\n bucket: bucket,\n files: files\n }),\n TopicArn: topicArn\n });\n });\n}","import _ from 'lodash';\nimport { SequelizeStorage, Umzug } from 'umzug';\n\n/**\n * Execute database migrations\n * @param {string} databaseName - name of database to create (or verify existence)\n * @param {object} sequelizeInstance - instance of Sequelize (must be initialized)\n * @param {function} initializeModels - function to run to sync Sequelize models with database\n * @param {string} pathToMigrationFolder - pass in the path if using windows. windows and linux PWD will be different\n */\nexport async function runMigrations(databaseName,\n sequelizeInstance,\n initializeModels,\n pathToMigrationFolder = `${process.env.PWD}/migrations/*.js`) {\n const umzug = new Umzug({\n migrations: { glob: pathToMigrationFolder },\n context: sequelizeInstance.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize: sequelizeInstance }),\n logger: console\n });\n\n const pendingMigrations = await umzug.pending();\n console.log('------->UTIL Pending Migrations:', pendingMigrations, pathToMigrationFolder);\n await umzug.up().catch((upError) => {\n console.error('Migration Error: ', upError);\n return umzug.down({\n migrations: _.chain(pendingMigrations)\n .map('file')\n .reverse()\n .value()\n }).then(() => {\n const msg = 'UTIL Error: Error with migrating up:' + upError;\n console.error(msg);\n throw new Error(msg);\n }, (downError) => {\n const msg = 'UTIL Error: Error with migrating down:' + downError;\n console.error(msg);\n throw new Error(msg);\n });\n });\n\n // The following line is needed to sync (create) tables, but not to database updates\n // in the past it worked to leave it in, but now the tags module causes foreign key problems\n // The tables are still initiated by being passed in to run migrations\n await initializeModels();\n}","import _ from 'lodash';\nimport S3Util from '../s3/S3Utils/S3Utils.js';\n\nexport async function handleFile(path, s3Bucket, transformer, options) {\n const shouldSkipFailedFolders = _.get(options, 'shouldSkipFailedFolders');\n const userImportTypes = _.get(options, 'userImportTypes');\n const params = {\n Bucket: s3Bucket,\n Key: path\n };\n let body;\n\n try {\n body = await S3Util.getObject(params);\n } catch (e) {\n if (e.Code === 'NoSuchKey' || e.code === 'NoSuchKey' || e.name === 'NoSuchKey') {\n return;\n }\n console.error('S3 getObject error:', e);\n throw e;\n }\n\n try {\n // exit early for null/undefined or blank string bodies\n if (_.isNil(body) || (_.isString(body) && _.isEmpty(body.trim()))) {\n await S3Util.deleteObject(params);\n return;\n }\n\n const parsedBody = JSON.parse(body);\n\n // exit early for objects like {} or []\n if (_.isEmpty(parsedBody)) {\n await S3Util.deleteObject(params);\n return;\n }\n\n const returnedValue = await transformer(parsedBody);\n await S3Util.deleteObject(params);\n\n return returnedValue;\n } catch (error) {\n console.error('HANDLE-FILE-ERROR', error);\n\n if (!body) {\n return;\n }\n\n let newPath = '';\n\n if (userImportTypes) {\n console.log('USER IMPORT');\n // look for items in the userImportTypes\n const usersImports = Object.values(userImportTypes);\n const items = path.split('/');\n const fileName = _.last(items);\n const folderName = _.first(items);\n\n if (usersImports.indexOf(folderName) > -1) {\n if (shouldSkipFailedFolders) {\n newPath = `${folderName}/error/${fileName}`;\n } else if (_.startsWith(path, `${folderName}/failed-once/`)) {\n newPath = _.replace(path, `${folderName}/failed-once/`, `${folderName}/failed-twice/`);\n } else if (_.startsWith(path, `${folderName}/failed-twice/`)) {\n newPath = _.replace(path, `${folderName}/failed-twice/`, `${folderName}/error/`);\n } else {\n newPath = `${folderName}/failed-once/${fileName}`;\n }\n } else {\n newPath = `pathAndEventMisMatchError/${path}`;\n }\n\n } else {\n if (shouldSkipFailedFolders) {\n newPath = `error/${path}`;\n } else if (_.startsWith(path, 'failed-once/')) {\n newPath = _.replace(path, 'failed-once/', 'failed-twice/');\n } else if (_.startsWith(path, 'failed-twice/')) {\n newPath = _.replace(path, 'failed-twice/', 'error/');\n } else {\n if (_.includes(path, 'delayUntil/')) {\n path = _.last(path.split('/'));\n }\n\n newPath = `failed-once/${path}`;\n }\n }\n\n const newParams = {\n Bucket: s3Bucket,\n Key: newPath,\n Body: body\n };\n\n if (\n containsError(newPath, 'failed-once') ||\n containsError(newPath, 'failed-twice') ||\n containsError(newPath, 'error')\n ) {\n throw new Error('NESTING ERROR');\n }\n\n await S3Util.putObject(newParams);\n await S3Util.deleteObject(params);\n\n throw error;\n }\n}\n\nexport function containsError(str, val) {\n const firstIndex = str.toLowerCase().indexOf(val);\n if (firstIndex === -1) return false;\n const secondIndex = str.toLowerCase().indexOf(val, firstIndex + 1);\n return secondIndex !== -1;\n}\n","import { S3 } from '@aws-sdk/client-s3';\n\nexport function s3Utils(action, params) {\n const s3 = new S3();\n return s3[action](params);\n}\n\nconst S3Util = {\n getObject: (params) => getS3(params),\n deleteObject: (params) => s3Utils('deleteObject', params),\n putObject: (params) => s3Utils('putObject', params),\n listObjectsV2: (params) => s3Utils('listObjectsV2', params)\n};\nexport default S3Util;\n\nasync function getS3(params) {\n const s3 = new S3();\n const response = await s3.getObject(params);\n return response?.Body.transformToString('utf-8');\n}","module.exports = require(\"umzug\");","module.exports = require(\"@aws-sdk/client-dynamodb\");","export const errorList = {\n invalidInventoryReleaseRequest: {\n message: 'NOT ENOUGH INVENTORY TO FULFILL RELEASE',\n errorCode: '4010',\n statusCode: 400\n },\n alreadyReleased: {\n message: 'ALREADY RELEASED',\n errorCode: '4011',\n statusCode: 400\n },\n alreadyReceived: {\n message: 'RECEIVABLE ALREADY RECEIVED',\n errorCode: '4012',\n statusCode: 400\n },\n invalidItemsRequest: {\n message: 'VALID ITEMS MUST BE INCLUDED',\n errorCode: '4013',\n statusCode: 400\n },\n invalidID: {\n message: 'ID is invalid',\n errorCode: '4014',\n statusCode: 400\n },\n invalidReceivable: {\n message: 'MUST CONTAIN AT LEAST ONE RECEIVABLE',\n errorCode: '4015',\n statusCode: 400\n },\n invalidRequest: {\n message: 'INVALID REQUEST DATA',\n errorCode: '4016',\n statusCode: 400\n },\n invalidAPIKey: {\n message: 'INVALID REQUEST - API MAY KEY INVALID',\n errorCode: '4017',\n statusCode: 400\n },\n qbCreationError: {\n message: 'QUICKBOOKS ERROR - ERROR CREATING OBJECT IN QUICKBOOKS',\n errorCode: '4018',\n statusCode: 400\n },\n cannotReopen: {\n message: 'CANNOT REOPEN - THE ORDER HAS ALREADY BEEN OPENED',\n errorCode: '4018',\n statusCode: 400\n },\n invalidDateFormat: {\n message: 'INVALID DATE FORMAT',\n errorCode: '4019',\n statusCode: 400\n },\n invalidStartDate: {\n message: 'INVALID START DATE',\n errorCode: '4020',\n statusCode: 400\n },\n invalidEndDate: {\n message: 'INVALID END DATE',\n errorCode: '4021',\n statusCode: 400\n },\n invalidOrderStatus: {\n message: 'UNABLE TO EDIT ORDER ITEMS UNLESS THE ORDER IS IN ESTIMATE STATUS',\n errorCode: '4022',\n statusCode: 400\n },\n invalidPaymentStatus: {\n message: 'UNABLE TO UPDATE PAYMENT STATUS PAYMENT MUST BE OPEN',\n errorCode: '4023',\n statusCode: 400\n },\n invalidReleaseStatus: {\n message: 'UNABLE TO UPDATE RELEASE, STATUS RELEASE MUST BE OPEN',\n errorCode: '4024',\n statusCode: 400\n },\n invalidReceivableStatus: {\n message: 'UNABLE TO UPDATE RECEIVABLE, STATUS RECEIVABLE MUST BE OPEN',\n errorCode: '40025',\n statusCode: 400\n },\n invalidJson:{\n message: 'INVALID JSON',\n errorCode: '4005',\n statusCode: 400\n },\n invalidFilter:{\n message: 'INVALID FILTER',\n errorCode: '4026',\n statusCode: 400\n },\n invalidUserNameUpdate:{\n message: 'UNABLE TO UPDATE USERNAME',\n errorCode: '4027',\n statusCode: 400\n },\n imageSizeLimit:{\n message: 'IMAGE SIZE LIMIT 100KB EXCEEDED',\n errorCode: '4028',\n statusCode: 400\n },\n unauthorized:{\n message: 'UNAUTHORIZED',\n errorCode: '4111',\n statusCode: 401\n },\n notFound:{\n message: 'ITEM NOT FOUND',\n errorCode: '4004',\n statusCode: 404\n },\n emailRequired:{\n message: 'NO EMAIL PROVIDED, CHECK CUSTOMER EMAIL',\n errorCode: '4004',\n statusCode: 404\n },\n mobilePhoneRequired:{\n message: 'NO MOBILE PHONE PROVIDED, CHECK CUSTOMER CONTACTS',\n errorCode: '4004',\n statusCode: 404\n },\n invalidCadenceType: {\n message: 'INVALID CADENCE TYPE',\n errorCode: '5001',\n statusCode: 500\n },\n partnerNotConfigured: {\n message: 'Partner has no partnerBusinessId configured. Contact support.',\n errorCode: '4310',\n statusCode: 400\n },\n};","/**\n * create pagination object from Sequelize findAll\n * @param {object} result - sequelize result\n * @param {number} limit - max number of results to return\n * @param {number} offset - page offset\n */\nexport function getPaginationFromFindAll(result, limit, offset) {\n result = result || [];\n limit = limit || 0;\n offset = offset || 0;\n\n const hasMore = result.length > limit;\n if (hasMore) {\n result.splice(-1, 1);\n }\n const pageObject = {\n offset: offset,\n limit: limit,\n rows: result,\n hasMore: hasMore\n };\n\n return pageObject;\n}\n\n/**\n * wrapper for Sequelize findAll\n * @param {object} model - instance of Sequelize (must be initialized)\n * @param {*&{include: [{model: *}], where: {businessId: Array}, order: [string[]]}} options - instance of Sequelize (must be initialized)\n */\nexport async function findAll(model, options) {\n\n const limit = options.limit || 0;\n const includes = options.includes || { all: true, nested: true };\n const findArgs = Object.assign({include: includes}, options, { limit: limit + 1 });\n const results = await model.findAll(findArgs);\n return getPaginationFromFindAll(results, limit, options.offset);\n}\n\nconst findUtils = {\n findAll\n};\nexport default findUtils;","import _ from 'lodash';\n\n/**\n * Create sequelize includes array from query string parameters and default sequelize model\n *\n * @param {object} event - the query parameters from the event passed by lambda\n * @param {object} objectFilters - the default filters object created by createDefaultFilters\n * @returns {object} A sequelize includes array\n */\n\nexport function createIncludes(event, objectFilters) {\n const query = _.get(event, 'queryStringParameters', {}) || {};\n\n const keys = Object.keys(objectFilters);\n\n const canBeIncluded = keys.reduce((acc, item) => {\n acc = includeSubItem(item, acc);\n\n return acc;\n }, []);\n\n const askedForInQuery = Object.keys(query).reduce((acc, item) => {\n if (item === 'sort') {\n query[item].split(',').forEach((sortItem) => {\n sortItem = sortItem.indexOf('-') === 0 ? sortItem.substr(1) : sortItem;\n acc = includeSubItem(sortItem, acc);\n });\n }\n\n acc = includeSubItem(item, acc);\n\n return acc;\n }, []);\n\n return _.intersection(canBeIncluded, askedForInQuery);\n}\n\nexport function includeSubItem(queryStringItem, acc = []) {\n const dot = queryStringItem.indexOf('.');\n if (dot > 0) {\n acc.push(queryStringItem.substring(0, dot));\n }\n\n return acc;\n}","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","import { handleFile as handleFileImport } from './eventManager/handleFile.js';\r\nimport { watchBucket as watchBucketImport } from './eventManager/watchBucket.js';\r\nimport { publishEvents as publishEventsImport } from './eventManager/publishEvents.js';\r\nimport { createIncludes as createIncludesImport } from './database/dbUtils/queryStringUtils/createIncludes.js';\r\nimport { createFilters as createFiltersImport } from './database/dbUtils/queryStringUtils/createFilters.js';\r\nimport { createSort as createSortImport } from './database/dbUtils/queryStringUtils/createSort.js';\r\nimport { findAll as findAllImport } from './database/dbUtils/queryStringUtils/findAll.js';\r\nimport { checkModule as checkModuleImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { checkIsSuper as checkIsSuperImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getModuleInfo as getModuleInfoImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getAccessRightsInfo as getAccessRightsInfoImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getDefaultBusinessIDInfo as getDefaultBusinessIDInfoImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { failure as failureImport, success as successImport } from './requestResponse/requestResponse.js';\r\nimport { runMigrations as runMigrationsImport } from './database/dbSetup/migrations.js';\r\nimport { getCurrentUser as getCurrentUserImport } from './requestResponse/requestResponse.js';\r\nimport { successHtml as successHtmlImport } from './requestResponse/requestResponse.js';\r\nimport { getCurrentUserNameFromCognitoEvent as getCurrentUserNameFromCognitoEventImport } from './requestResponse/requestResponse.js';\r\nimport { defaultFilters as defaultFiltersImport } from './database/dbUtils/queryStringUtils/defaultFilters.js';\r\nimport { accessRightsUtils as accessRightsUtilsImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { parseBody as parseBodyImport } from './requestResponse/requestResponse.js';\r\nimport { parseEvent as parseEventImport } from './requestResponse/requestResponse.js';\r\nimport { getBusinessesInfo as getBusinessesInfoImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { userDefaultBid as userDefaultBidImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { checkWriteAccess as checkWriteAccessImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { isSystemUser as isSystemUserImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { isSuperUser as isSuperUserImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { isPartnerUser as isPartnerUserImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getBelongsToPartnerId as getBelongsToPartnerIdImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getEffectivePartnerId as getEffectivePartnerIdImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { enrichEventWithPartnerAccess as enrichEventWithPartnerAccessImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { getCompanySettings as getCompanySettingsImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';\r\nimport { resolveAccess as resolveAccessImport, ensurePartnerScope as ensurePartnerScopeImport } from './database/dbUtils/partnerAccess/accessContext.js';\r\nimport { requireCrmAccess as requireCrmAccessImport, requireTicketAccess as requireTicketAccessImport, requireSuper as requireSuperImport } from './database/dbUtils/partnerAccess/accessGates.js';\r\nimport { scopeToOwnBusiness as scopeToOwnBusinessImport, scopeToPartnerBook as scopeToPartnerBookImport, scopeToBookUnionOwn as scopeToBookUnionOwnImport } from './database/dbUtils/partnerAccess/accessScope.js';\r\nimport { assertCanWriteOwnBusiness as assertCanWriteOwnBusinessImport, assertCanWriteBookBusiness as assertCanWriteBookBusinessImport, assertCanWriteBookUnionOwn as assertCanWriteBookUnionOwnImport, stampOwnBusinessId as stampOwnBusinessIdImport } from './database/dbUtils/partnerAccess/accessWrites.js';\r\nimport { createAccessHelpers as createAccessHelpersImport } from './database/dbUtils/partnerAccess/createAccessHelpers.js';\r\nimport {\r\n attachAudit as attachAuditImport,\r\n bindAuditRequest as bindAuditRequestImport,\r\n bindAuditRequestForUser as bindAuditRequestForUserImport,\r\n decrementWithAudit as decrementWithAuditImport,\r\n getAuditFilter as getAuditFilterImport,\r\n getAuditModel as getAuditModelImport,\r\n incrementWithAudit as incrementWithAuditImport\r\n} from './audit/audit.js';\r\n\r\nexport const handleFile = handleFileImport;\r\nexport const watchBucket = watchBucketImport;\r\nexport const publishEvents = publishEventsImport;\r\nexport const createFilters = createFiltersImport;\r\nexport const createIncludes = createIncludesImport;\r\nexport const createSort = createSortImport;\r\nexport const findAll = findAllImport;\r\nexport const checkModule = checkModuleImport;\r\nexport const checkIsSuper = checkIsSuperImport;\r\nexport const getAccessRightsInfo = getAccessRightsInfoImport;\r\nexport const getDefaultBusinessIDInfo = getDefaultBusinessIDInfoImport;\r\nexport const getModuleInfo = getModuleInfoImport;\r\nexport const failure = failureImport;\r\nexport const success = successImport;\r\nexport const runMigrations = runMigrationsImport;\r\nexport const getCurrentUser = getCurrentUserImport;\r\nexport const successHtml = successHtmlImport;\r\nexport const getCurrentUserNameFromCognitoEvent = getCurrentUserNameFromCognitoEventImport;\r\nexport const defaultFilters = defaultFiltersImport;\r\nexport const accessRightsUtils = accessRightsUtilsImport;\r\nexport const parseBody = parseBodyImport;\r\nexport const parseEvent = parseEventImport;\r\nexport const getBusinessesInfo = getBusinessesInfoImport;\r\nexport const userDefaultBid = userDefaultBidImport;\r\nexport const checkWriteAccess = checkWriteAccessImport;\r\nexport const isSystemUser = isSystemUserImport;\r\nexport const isSuperUser = isSuperUserImport;\r\nexport const isPartnerUser = isPartnerUserImport;\r\nexport const getBelongsToPartnerId = getBelongsToPartnerIdImport;\r\nexport const getEffectivePartnerId = getEffectivePartnerIdImport;\r\nexport const enrichEventWithPartnerAccess = enrichEventWithPartnerAccessImport;\r\nexport const getCompanySettings = getCompanySettingsImport;\r\nexport const resolveAccess = resolveAccessImport;\r\nexport const ensurePartnerScope = ensurePartnerScopeImport;\r\nexport const requireCrmAccess = requireCrmAccessImport;\r\nexport const requireTicketAccess = requireTicketAccessImport;\r\nexport const requireSuper = requireSuperImport;\r\nexport const scopeToOwnBusiness = scopeToOwnBusinessImport;\r\nexport const scopeToPartnerBook = scopeToPartnerBookImport;\r\nexport const scopeToBookUnionOwn = scopeToBookUnionOwnImport;\r\nexport const assertCanWriteOwnBusiness = assertCanWriteOwnBusinessImport;\r\nexport const assertCanWriteBookBusiness = assertCanWriteBookBusinessImport;\r\nexport const assertCanWriteBookUnionOwn = assertCanWriteBookUnionOwnImport;\r\nexport const stampOwnBusinessId = stampOwnBusinessIdImport;\r\nexport const createAccessHelpers = createAccessHelpersImport;\r\nexport const attachAudit = attachAuditImport;\r\nexport const bindAuditRequest = bindAuditRequestImport;\r\nexport const bindAuditRequestForUser = bindAuditRequestForUserImport;\r\nexport const decrementWithAudit = decrementWithAuditImport;\r\nexport const getAuditFilter = getAuditFilterImport;\r\nexport const getAuditModel = getAuditModelImport;\r\nexport const incrementWithAudit = incrementWithAuditImport;\r\n"],"names":["module","exports","require","async","ensurePartnerScope","access","level","businessIds","undefined","partner","getPartnerById","partnerId","partnerBusinessId","err","console","error","resolveAccess","event","isSuperUser","env","process","BUILD_ENV","isPartnerUser","arBusinessIds","getAccessRightsInfo","Object","keys","length","errorList","unauthorized","_accessRightsUtils","_errorCodes","_libDynamodb","_clientDynamodb","dynamoUtil","get","params","DynamoDBDocument","from","DynamoDB","handleDirectS3WriteEvent","transformer","errorHandlerPerFile","shouldSkipFailedFolders","userImportTypes","Records","Promise","resolve","hasErrors","map","record","s3Bucket","s3","bucket","name","file","object","key","path","decodeURIComponent","handleFile","catch","then","Error","handleEvents","snsInfo","JSON","parse","_","files","_handleFile","_lodash","_interopRequireDefault","_bluebird","e","__esModule","default","assertCanWriteBookBusiness","businessId","invalidRequest","message","includes","assertCanWriteBookUnionOwn","uniq","filter","Boolean","assertCanWriteOwnBusiness","partnerNotConfigured","stampOwnBusinessId","body","_accessContext","bindAuditRequest","models","user","getCurrentUser","auditEnabled","getCompanySettings","forEach","model","attachPromise","attachAudit","modelOptions","bindAuditRequestForUser","opts","decrementWithAudit","modelName","field","args","r","decrement","_changed","options","transaction","auditMe","getAuditFilter","modelToFilter","id","where","accessRightsUtils","include","order","getAuditModel","auditModels","incrementWithAudit","increment","_requestResponse","SENSITIVE_FIELDS_PATTERN","modelInfo","isArray","auditModel","writeAuditRow","type","valueOld","valueNew","data","String","substring","changedByUser","username","dataValues","newOptions","create","checkAudit","isEqual","isString","oldString","stringify","newString","replace","isObject","valueSub","keySub","_previousDataValues","sequelize","define","getAuditSchema","DataTypes","Sequelize","STRING","allowNull","updatedAt","freezeTableName","belongsTo","foreignKey","onDelete","addHook","sync","watchBucket","noop","dynamoConfigTable","dynamoConfigKey","snsTopic","EventSource","publishEvents","failedOnce","failedTwice","direct","startsWithDirect","startsWith","log","_publishEvents","_handleEvents","requireCrmAccess","requireSuper","requireTicketAccess","defaultFilters","schema","subSchemas","clone","filters","addFiltersFromSchema","_sequelize","keyPrefix","asLinkAlias","reduce","acc","item","DB","filterType","Op","eq","itemType","CHAR","TEXT","iLike","DECIMAL","INTEGER","BIGINT","or","BOOLEAN","JSONB","DATE","between","DATEONLY","_dayjs","_utc","dayjs","extend","utc","objectFilters","query","searchString","startDate","endDate","caseInsensitiveConditions","val","itemName","push","fn","col","like","toLowerCase","in","split","parsedJson","queryValue","booleanMap","and","active","filterAdds","s","dates","toDate","isValid","invalidStartDate","invalidEndDate","createdAt","adds","dataType","isNaN","Number","newOr","withDate","assign","k","def","prefix","qKey","pathParts","value","parsed","Array","addJsonbConditions","obj","entries","currentPath","_clientSns","SNSUtil","publish","sns","SNS","createTopic","scopeToBookUnionOwn","ids","scopeToOwnBusiness","scopeToPartnerBook","createAccessHelpers","deps","_accessScope","_accessWrites","checkIsSuper","isSystemUser","checkModule","moduleName","moduleRights","getModuleInfo","allowAccess","checkWriteAccess","eventBody","parseBody","find","userRight","getBusinessesInfo","userRoles","admin","write","enrichEventWithPartnerAccess","partnerBusinessIds","role","arPath","requestContext","authorizer","claims","json","accessRights","bid","set","jsonToParse","getDefaultBusinessIDInfo","dbi","getEffectivePartnerId","getBelongsToPartnerId","userDefaultBid","_interopRequireWildcard","t","WeakMap","n","o","i","f","__proto__","has","hasOwnProperty","call","defineProperty","getOwnPropertyDescriptor","isSys","useCognitoBid","requestedBusinessIds","getRequestedBusinessIds","allowedBusinessIds","getAllowedBusinessIds","businesses","v","isEmpty","intersection","bodyBid","b","read","defaultFilter","copyOfDefaultFilter","testItem","indexOf","substr","sortItem","parentChildList","detectDynamooseError","errorBody","dynamooseError","errors","detail","trim","failure","cleanedErrorBody","dbClose","UTIL_LOG","isUndefined","details","errorCode","statusCode","detectSequelizeError","detectJoyError","newBody","merge","buildResponse","getCurrentUserNameFromCognitoEvent","attributes","requestEvent","invalidJson","parseEvent","callback","success","successHtml","html","headers","htmlSecurityHeaders","securityHeaders","join","errorName","notPresent","match","stillReferenced","fields","messages","sequelizeError","parentError","joyError","contextItem","msg","configTable","tableKey","result","TableName","Key","chunkSize","maxMessages","topicArn","Name","TopicArn","maxKeys","fileList","loop","messageList","chain","chunk","slice","Message","_customParseFormat","_isSameOrBefore","_S3Utils","_SNSUtils","_dynamoUtils","bucketResult","currentTime","S3Utils","listObjectsV2","Bucket","MaxKeys","ContinuationToken","newFiles","Contents","fileDelayTime","isSameOrBefore","usersImports","values","items","fileName","last","folderName","first","concat","IsTruncated","NextContinuationToken","customParseFormat","runMigrations","databaseName","sequelizeInstance","initializeModels","pathToMigrationFolder","PWD","umzug","Umzug","migrations","glob","context","getQueryInterface","storage","SequelizeStorage","logger","pendingMigrations","pending","up","upError","down","reverse","downError","_umzug","S3Util","getObject","Code","code","isNil","deleteObject","parsedBody","returnedValue","newPath","newParams","Body","containsError","putObject","str","firstIndex","_clientS","s3Utils","action","S3","getS3","response","transformToString","invalidInventoryReleaseRequest","alreadyReleased","alreadyReceived","invalidItemsRequest","invalidID","invalidReceivable","invalidAPIKey","qbCreationError","cannotReopen","invalidDateFormat","invalidOrderStatus","invalidPaymentStatus","invalidReleaseStatus","invalidReceivableStatus","invalidFilter","invalidUserNameUpdate","imageSizeLimit","notFound","emailRequired","mobilePhoneRequired","invalidCadenceType","getPaginationFromFindAll","limit","offset","hasMore","splice","rows","findAll","all","nested","findArgs","findUtils","createIncludes","canBeIncluded","includeSubItem","askedForInQuery","queryStringItem","dot","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","_watchBucket","_createIncludes","_createFilters","_createSort","_findAll","_migrations","_defaultFilters","_accessGates","_createAccessHelpers","_audit","handleFileImport","watchBucketImport","publishEventsImport","createFiltersImport","createIncludesImport","createSortImport","findAllImport","checkModuleImport","checkIsSuperImport","getAccessRightsInfoImport","getDefaultBusinessIDInfoImport","getModuleInfoImport","failureImport","successImport","runMigrationsImport","getCurrentUserImport","successHtmlImport","getCurrentUserNameFromCognitoEventImport","defaultFiltersImport","accessRightsUtilsImport","parseBodyImport","parseEventImport","getBusinessesInfoImport","userDefaultBidImport","checkWriteAccessImport","isSystemUserImport","isSuperUserImport","isPartnerUserImport","getBelongsToPartnerIdImport","getEffectivePartnerIdImport","enrichEventWithPartnerAccessImport","getCompanySettingsImport","resolveAccessImport","ensurePartnerScopeImport","requireCrmAccessImport","requireTicketAccessImport","requireSuperImport","scopeToOwnBusinessImport","scopeToPartnerBookImport","scopeToBookUnionOwnImport","assertCanWriteOwnBusinessImport","assertCanWriteBookBusinessImport","assertCanWriteBookUnionOwnImport","stampOwnBusinessIdImport","createAccessHelpersImport","attachAuditImport","bindAuditRequestImport","bindAuditRequestForUserImport","decrementWithAuditImport","getAuditFilterImport","getAuditModelImport","incrementWithAuditImport"],"ignoreList":[],"sourceRoot":""}
|