UNPKG

@coursebuilder/core

Version:

Core package for Course Builder

1 lines 281 kB
{"version":3,"sources":["../../../src/lib/pricing/determine-coupon-to-apply.ts","../../../../../node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.mjs","../../../src/lib/pricing/bulk-coupon.ts","../../../src/lib/pricing/data/ppp.js","../../../src/lib/pricing/parity-coupon.ts"],"sourcesContent":["import { z } from 'zod'\n\nimport { CourseBuilderAdapter, MockCourseBuilderAdapter } from '../../adapters'\nimport { MerchantCoupon, Purchase } from '../../schemas'\nimport { MinimalMerchantCoupon } from '../../types'\nimport { getBulkDiscountPercent } from './bulk-coupon.js'\nimport { getPPPDiscountPercent } from './parity-coupon.js'\n\nconst PrismaCtxSchema: z.ZodType<CourseBuilderAdapter> = z.any()\nconst PurchaseSchema: z.ZodType<Purchase> = z.any()\n\nconst DetermineCouponToApplyParamsSchema = z.object({\n\tprismaCtx: PrismaCtxSchema,\n\tmerchantCouponId: z.string().optional(),\n\tcountry: z.string(),\n\tquantity: z.number(),\n\tuserId: z.string().optional(),\n\tproductId: z.string(),\n\tpurchaseToBeUpgraded: PurchaseSchema.nullable(),\n\tautoApplyPPP: z.boolean(),\n\tusedCoupon: z\n\t\t.object({\n\t\t\tmerchantCouponId: z.string().nullable().optional(),\n\t\t\trestrictedToProductId: z.string().nullable().optional(),\n\t\t})\n\t\t.nullable()\n\t\t.optional(),\n})\n\ntype DetermineCouponToApplyParams = z.infer<\n\ttypeof DetermineCouponToApplyParamsSchema\n>\n\nconst SPECIAL_TYPE = 'special' as const\nconst PPP_TYPE = 'ppp' as const\nconst BULK_TYPE = 'bulk' as const\nconst NONE_TYPE = 'none' as const\n\nexport const determineCouponToApply = async (\n\tparams: DetermineCouponToApplyParams,\n) => {\n\tconst {\n\t\tprismaCtx,\n\t\tmerchantCouponId,\n\t\tcountry,\n\t\tquantity,\n\t\tuserId,\n\t\tproductId,\n\t\tpurchaseToBeUpgraded,\n\t\tautoApplyPPP,\n\t\tusedCoupon,\n\t} = DetermineCouponToApplyParamsSchema.parse(params)\n\t// TODO: What are the lookups and logic checks we can\n\t// skip when there is no appliedMerchantCouponId?\n\n\tconst { getMerchantCoupon, getPurchasesForUser } = prismaCtx\n\n\t// if usedCoupon is restricted to a different product, we shouldn't apply it\n\tconst couponRestrictedToDifferentProduct =\n\t\tusedCoupon?.merchantCouponId === merchantCouponId &&\n\t\tusedCoupon?.restrictedToProductId &&\n\t\tusedCoupon?.restrictedToProductId !== productId\n\n\tconst candidateMerchantCoupon =\n\t\t!couponRestrictedToDifferentProduct && merchantCouponId\n\t\t\t? await getMerchantCoupon(merchantCouponId)\n\t\t\t: null\n\n\tconst specialMerchantCouponToApply =\n\t\tcandidateMerchantCoupon?.type === SPECIAL_TYPE\n\t\t\t? candidateMerchantCoupon\n\t\t\t: null\n\n\tconst userPurchases = await getPurchasesForUser(userId)\n\n\tconst pppDetails = await getPPPDetails({\n\t\tspecialMerchantCoupon: specialMerchantCouponToApply,\n\t\tappliedMerchantCoupon: candidateMerchantCoupon,\n\t\tcountry,\n\t\tquantity,\n\t\tpurchaseToBeUpgraded,\n\t\tuserPurchases,\n\t\tautoApplyPPP,\n\t\tprismaCtx,\n\t})\n\n\tconst { bulkCouponToBeApplied, consideredBulk } = await getBulkCouponDetails({\n\t\tprismaCtx,\n\t\tuserId,\n\t\tproductId,\n\t\tquantity,\n\t\tappliedMerchantCoupon: specialMerchantCouponToApply,\n\t\tpppApplied: pppDetails.pppApplied,\n\t})\n\n\tlet couponToApply: MinimalMerchantCoupon | null = null\n\tif (pppDetails.status === VALID_PPP) {\n\t\tcouponToApply = pppDetails.pppCouponToBeApplied\n\t} else if (bulkCouponToBeApplied) {\n\t\tcouponToApply = bulkCouponToBeApplied\n\t} else {\n\t\tcouponToApply = specialMerchantCouponToApply\n\t}\n\n\t// It is only every PPP that ends up in the Available Coupons\n\t// list because with Special and Bulk we auto-apply those if\n\t// they are the best discount.\n\tconst availableCoupons = pppDetails.availableCoupons\n\n\t// Narrow appliedCouponType to a union of consts\n\tconst appliedCouponType = z\n\t\t.string()\n\t\t.nullish()\n\t\t.transform((couponType) => {\n\t\t\tif (couponType === PPP_TYPE) {\n\t\t\t\treturn PPP_TYPE\n\t\t\t} else if (couponType === SPECIAL_TYPE) {\n\t\t\t\treturn SPECIAL_TYPE\n\t\t\t} else if (couponType === BULK_TYPE) {\n\t\t\t\treturn BULK_TYPE\n\t\t\t} else {\n\t\t\t\treturn NONE_TYPE\n\t\t\t}\n\t\t})\n\t\t.parse(couponToApply?.type)\n\n\treturn {\n\t\tappliedMerchantCoupon: couponToApply || undefined,\n\t\tappliedCouponType,\n\t\tavailableCoupons,\n\t\tbulk: consideredBulk,\n\t}\n}\n\ntype UserPurchases = Awaited<\n\tReturnType<CourseBuilderAdapter['getPurchasesForUser']>\n>\nconst UserPurchasesSchema: z.ZodType<UserPurchases> = z.any()\nconst MerchantCouponSchema: z.ZodType<MerchantCoupon> = z.any()\nconst GetPPPDetailsParamsSchema = z.object({\n\tspecialMerchantCoupon: MerchantCouponSchema.nullable(),\n\tappliedMerchantCoupon: MerchantCouponSchema.nullable(),\n\tquantity: z.number(),\n\tcountry: z.string(),\n\tpurchaseToBeUpgraded: PurchaseSchema.nullable(),\n\tuserPurchases: UserPurchasesSchema,\n\tautoApplyPPP: z.boolean(),\n\tprismaCtx: PrismaCtxSchema,\n})\ntype GetPPPDetailsParams = z.infer<typeof GetPPPDetailsParamsSchema>\n\nconst NO_PPP = 'NO_PPP' as const\nconst INVALID_PPP = 'INVALID_PPP' as const\nconst VALID_PPP = 'VALID_PPP' as const\n\nconst getPPPDetails = async ({\n\tspecialMerchantCoupon,\n\tappliedMerchantCoupon,\n\tcountry,\n\tquantity,\n\tpurchaseToBeUpgraded,\n\tuserPurchases,\n\tautoApplyPPP,\n\tprismaCtx,\n}: GetPPPDetailsParams) => {\n\tconst hasMadeNonPPPDiscountedPurchase = userPurchases.some(\n\t\t(purchase) => purchase.status === 'Valid',\n\t)\n\tconst hasOnlyPPPDiscountedPurchases = !hasMadeNonPPPDiscountedPurchase\n\n\tconst expectedPPPDiscountPercent = getPPPDiscountPercent(country)\n\n\tconst shouldLookupPPPMerchantCouponForUpgrade =\n\t\tappliedMerchantCoupon === null &&\n\t\tpurchaseToBeUpgraded !== null &&\n\t\thasOnlyPPPDiscountedPurchases &&\n\t\tautoApplyPPP\n\n\tlet pppMerchantCouponForUpgrade: MerchantCoupon | null = null\n\tif (shouldLookupPPPMerchantCouponForUpgrade) {\n\t\tpppMerchantCouponForUpgrade = await lookupApplicablePPPMerchantCoupon({\n\t\t\tprismaCtx,\n\t\t\tpppDiscountPercent: expectedPPPDiscountPercent,\n\t\t})\n\t}\n\n\tconst pppCouponToBeApplied =\n\t\tappliedMerchantCoupon?.type === PPP_TYPE\n\t\t\t? appliedMerchantCoupon\n\t\t\t: pppMerchantCouponForUpgrade\n\n\t// TODO: Move this sort of price comparison to the parent method, for the\n\t// purposes of this method we'll just assume that if the PPP looks\n\t// good and can be applied, then it is a candidate.\n\tconst pppDiscountIsBetter =\n\t\t(specialMerchantCoupon?.percentageDiscount || 0) <\n\t\texpectedPPPDiscountPercent\n\n\tconst pppConditionsMet =\n\t\texpectedPPPDiscountPercent > 0 &&\n\t\tquantity === 1 &&\n\t\thasOnlyPPPDiscountedPurchases &&\n\t\tpppDiscountIsBetter\n\n\t// Build `details` with all kinds of intermediate stuff as part of this refactoring\n\tconst pppApplied =\n\t\tquantity === 1 &&\n\t\tappliedMerchantCoupon?.type === 'ppp' &&\n\t\texpectedPPPDiscountPercent > 0\n\n\t// NOTE: PPP coupons are only *available* if the conditions are met\n\t// which includes that the PPP discount will be better than any\n\t// site-wide default coupon.\n\tlet availableCoupons: Awaited<ReturnType<typeof couponForType>> = []\n\tif (pppConditionsMet) {\n\t\tavailableCoupons = await couponForType(\n\t\t\tPPP_TYPE,\n\t\t\texpectedPPPDiscountPercent,\n\t\t\tprismaCtx,\n\t\t\tcountry,\n\t\t)\n\t}\n\n\tconst baseDetails = {\n\t\tpppApplied: false,\n\t\tpppCouponToBeApplied: null,\n\t\tavailableCoupons,\n\t}\n\tif (pppCouponToBeApplied === null) {\n\t\treturn {\n\t\t\t...baseDetails,\n\t\t\tstatus: NO_PPP,\n\t\t}\n\t}\n\n\t// Check *applied* PPP coupon validity\n\tconst couponPercentDoesNotMatchCountry =\n\t\texpectedPPPDiscountPercent !== pppCouponToBeApplied?.percentageDiscount\n\tconst couponPercentOutOfRange =\n\t\texpectedPPPDiscountPercent <= 0 || expectedPPPDiscountPercent >= 1\n\tconst pppAppliedToBulkPurchase = quantity > 1\n\tconst invalidCoupon =\n\t\tcouponPercentDoesNotMatchCountry ||\n\t\tcouponPercentOutOfRange ||\n\t\tpppAppliedToBulkPurchase\n\n\tif (invalidCoupon) {\n\t\treturn {\n\t\t\t...baseDetails,\n\t\t\tstatus: INVALID_PPP,\n\t\t\tavailableCoupons: [],\n\t\t}\n\t}\n\n\treturn {\n\t\t...baseDetails,\n\t\tstatus: VALID_PPP,\n\t\tpppApplied,\n\t\tpppCouponToBeApplied,\n\t}\n}\n\nconst LookupApplicablePPPMerchantCouponParamsSchema = z.object({\n\tprismaCtx: PrismaCtxSchema,\n\tpppDiscountPercent: z.number(),\n})\ntype LookupApplicablePPPMerchantCouponParams = z.infer<\n\ttypeof LookupApplicablePPPMerchantCouponParamsSchema\n>\n\n// TODO: Should we cross-check the incoming `pppDiscountPercent` with\n// the `discountPercentage` that was applied to the original purchase?\nconst lookupApplicablePPPMerchantCoupon = async (\n\tparams: LookupApplicablePPPMerchantCouponParams,\n) => {\n\tconst { prismaCtx, pppDiscountPercent } =\n\t\tLookupApplicablePPPMerchantCouponParamsSchema.parse(params)\n\n\tconst { getMerchantCouponForTypeAndPercent } = prismaCtx\n\tconst pppMerchantCoupon = await getMerchantCouponForTypeAndPercent({\n\t\ttype: PPP_TYPE,\n\t\tpercentageDiscount: pppDiscountPercent,\n\t})\n\n\t// early return if there is no PPP coupon that fits the bill\n\t// report this to Sentry? Seems like a bug if we aren't able to find one.\n\tif (pppMerchantCoupon === null) return null\n\n\treturn pppMerchantCoupon\n}\n\nconst GetBulkCouponDetailsParamsSchema = z.object({\n\tprismaCtx: PrismaCtxSchema,\n\tuserId: z.string().optional(),\n\tproductId: z.string(),\n\tquantity: z.number(),\n\tappliedMerchantCoupon: MerchantCouponSchema.nullable(),\n\tpppApplied: z.boolean(),\n})\ntype GetBulkCouponDetailsParams = z.infer<\n\ttypeof GetBulkCouponDetailsParamsSchema\n>\nconst getBulkCouponDetails = async (params: GetBulkCouponDetailsParams) => {\n\tconst {\n\t\tprismaCtx,\n\t\tuserId,\n\t\tproductId,\n\t\tquantity,\n\t\tappliedMerchantCoupon,\n\t\tpppApplied,\n\t} = GetBulkCouponDetailsParamsSchema.parse(params)\n\n\t// Determine if the user has an existing bulk purchase of this product.\n\t// If so, we can compute tiered pricing based on their existing seats purchased.\n\tconst seatCount = await getQualifyingSeatCount({\n\t\tuserId,\n\t\tproductId,\n\t\tnewPurchaseQuantity: quantity,\n\t\tprismaCtx,\n\t})\n\n\tconst consideredBulk = seatCount > 1\n\n\tconst bulkCouponPercent = getBulkDiscountPercent(seatCount)\n\n\tconst bulkDiscountIsBetter =\n\t\t(appliedMerchantCoupon?.percentageDiscount || 0) < bulkCouponPercent\n\n\tconst bulkDiscountAvailable =\n\t\tbulkCouponPercent > 0 && bulkDiscountIsBetter && !pppApplied // this condition seems irrelevant, if quantity > 1 OR seatCount > 1\n\n\tif (bulkDiscountAvailable) {\n\t\tconst bulkCoupons = await couponForType(\n\t\t\tBULK_TYPE,\n\t\t\tbulkCouponPercent,\n\t\t\tprismaCtx,\n\t\t)\n\t\tconst bulkCoupon = bulkCoupons[0]\n\n\t\treturn { bulkCouponToBeApplied: bulkCoupon, consideredBulk }\n\t} else {\n\t\treturn { bulkCouponToBeApplied: null, consideredBulk }\n\t}\n}\n\nconst getQualifyingSeatCount = async ({\n\tuserId,\n\tproductId: purchasingProductId,\n\tnewPurchaseQuantity,\n\tprismaCtx,\n}: {\n\tuserId: string | undefined\n\tproductId: string\n\tnewPurchaseQuantity: number\n\tprismaCtx: CourseBuilderAdapter\n}) => {\n\tconst { getPurchasesForUser } = prismaCtx\n\tconst userPurchases = await getPurchasesForUser(userId)\n\tconst bulkPurchase = userPurchases.find(\n\t\t({ productId, bulkCoupon }) =>\n\t\t\tproductId === purchasingProductId && Boolean(bulkCoupon),\n\t)\n\n\tconst existingSeatsPurchasedForThisProduct =\n\t\tbulkPurchase?.bulkCoupon?.maxUses || 0\n\n\treturn newPurchaseQuantity + existingSeatsPurchasedForThisProduct\n}\n\nasync function couponForType(\n\ttype: string,\n\tpercentageDiscount: number,\n\tprismaCtx: CourseBuilderAdapter,\n\tcountry?: string,\n) {\n\tconst { getMerchantCouponsForTypeAndPercent } = prismaCtx\n\tconst merchantCoupons =\n\t\t(await getMerchantCouponsForTypeAndPercent({ type, percentageDiscount })) ||\n\t\t[]\n\n\treturn merchantCoupons.map((coupon: MerchantCoupon) => {\n\t\t// for pricing we don't need the identifier so strip it here\n\t\tconst { identifier, ...rest } = coupon\n\t\treturn { ...rest, ...(country && { country }) }\n\t})\n}\n","var util;\n(function (util) {\n util.assertEqual = (val) => val;\n function assertIs(_arg) { }\n util.assertIs = assertIs;\n function assertNever(_x) {\n throw new Error();\n }\n util.assertNever = assertNever;\n util.arrayToEnum = (items) => {\n const obj = {};\n for (const item of items) {\n obj[item] = item;\n }\n return obj;\n };\n util.getValidEnumValues = (obj) => {\n const validKeys = util.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== \"number\");\n const filtered = {};\n for (const k of validKeys) {\n filtered[k] = obj[k];\n }\n return util.objectValues(filtered);\n };\n util.objectValues = (obj) => {\n return util.objectKeys(obj).map(function (e) {\n return obj[e];\n });\n };\n util.objectKeys = typeof Object.keys === \"function\" // eslint-disable-line ban/ban\n ? (obj) => Object.keys(obj) // eslint-disable-line ban/ban\n : (object) => {\n const keys = [];\n for (const key in object) {\n if (Object.prototype.hasOwnProperty.call(object, key)) {\n keys.push(key);\n }\n }\n return keys;\n };\n util.find = (arr, checker) => {\n for (const item of arr) {\n if (checker(item))\n return item;\n }\n return undefined;\n };\n util.isInteger = typeof Number.isInteger === \"function\"\n ? (val) => Number.isInteger(val) // eslint-disable-line ban/ban\n : (val) => typeof val === \"number\" && isFinite(val) && Math.floor(val) === val;\n function joinValues(array, separator = \" | \") {\n return array\n .map((val) => (typeof val === \"string\" ? `'${val}'` : val))\n .join(separator);\n }\n util.joinValues = joinValues;\n util.jsonStringifyReplacer = (_, value) => {\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n return value;\n };\n})(util || (util = {}));\nvar objectUtil;\n(function (objectUtil) {\n objectUtil.mergeShapes = (first, second) => {\n return {\n ...first,\n ...second, // second overwrites first\n };\n };\n})(objectUtil || (objectUtil = {}));\nconst ZodParsedType = util.arrayToEnum([\n \"string\",\n \"nan\",\n \"number\",\n \"integer\",\n \"float\",\n \"boolean\",\n \"date\",\n \"bigint\",\n \"symbol\",\n \"function\",\n \"undefined\",\n \"null\",\n \"array\",\n \"object\",\n \"unknown\",\n \"promise\",\n \"void\",\n \"never\",\n \"map\",\n \"set\",\n]);\nconst getParsedType = (data) => {\n const t = typeof data;\n switch (t) {\n case \"undefined\":\n return ZodParsedType.undefined;\n case \"string\":\n return ZodParsedType.string;\n case \"number\":\n return isNaN(data) ? ZodParsedType.nan : ZodParsedType.number;\n case \"boolean\":\n return ZodParsedType.boolean;\n case \"function\":\n return ZodParsedType.function;\n case \"bigint\":\n return ZodParsedType.bigint;\n case \"symbol\":\n return ZodParsedType.symbol;\n case \"object\":\n if (Array.isArray(data)) {\n return ZodParsedType.array;\n }\n if (data === null) {\n return ZodParsedType.null;\n }\n if (data.then &&\n typeof data.then === \"function\" &&\n data.catch &&\n typeof data.catch === \"function\") {\n return ZodParsedType.promise;\n }\n if (typeof Map !== \"undefined\" && data instanceof Map) {\n return ZodParsedType.map;\n }\n if (typeof Set !== \"undefined\" && data instanceof Set) {\n return ZodParsedType.set;\n }\n if (typeof Date !== \"undefined\" && data instanceof Date) {\n return ZodParsedType.date;\n }\n return ZodParsedType.object;\n default:\n return ZodParsedType.unknown;\n }\n};\n\nconst ZodIssueCode = util.arrayToEnum([\n \"invalid_type\",\n \"invalid_literal\",\n \"custom\",\n \"invalid_union\",\n \"invalid_union_discriminator\",\n \"invalid_enum_value\",\n \"unrecognized_keys\",\n \"invalid_arguments\",\n \"invalid_return_type\",\n \"invalid_date\",\n \"invalid_string\",\n \"too_small\",\n \"too_big\",\n \"invalid_intersection_types\",\n \"not_multiple_of\",\n \"not_finite\",\n]);\nconst quotelessJson = (obj) => {\n const json = JSON.stringify(obj, null, 2);\n return json.replace(/\"([^\"]+)\":/g, \"$1:\");\n};\nclass ZodError extends Error {\n get errors() {\n return this.issues;\n }\n constructor(issues) {\n super();\n this.issues = [];\n this.addIssue = (sub) => {\n this.issues = [...this.issues, sub];\n };\n this.addIssues = (subs = []) => {\n this.issues = [...this.issues, ...subs];\n };\n const actualProto = new.target.prototype;\n if (Object.setPrototypeOf) {\n // eslint-disable-next-line ban/ban\n Object.setPrototypeOf(this, actualProto);\n }\n else {\n this.__proto__ = actualProto;\n }\n this.name = \"ZodError\";\n this.issues = issues;\n }\n format(_mapper) {\n const mapper = _mapper ||\n function (issue) {\n return issue.message;\n };\n const fieldErrors = { _errors: [] };\n const processError = (error) => {\n for (const issue of error.issues) {\n if (issue.code === \"invalid_union\") {\n issue.unionErrors.map(processError);\n }\n else if (issue.code === \"invalid_return_type\") {\n processError(issue.returnTypeError);\n }\n else if (issue.code === \"invalid_arguments\") {\n processError(issue.argumentsError);\n }\n else if (issue.path.length === 0) {\n fieldErrors._errors.push(mapper(issue));\n }\n else {\n let curr = fieldErrors;\n let i = 0;\n while (i < issue.path.length) {\n const el = issue.path[i];\n const terminal = i === issue.path.length - 1;\n if (!terminal) {\n curr[el] = curr[el] || { _errors: [] };\n // if (typeof el === \"string\") {\n // curr[el] = curr[el] || { _errors: [] };\n // } else if (typeof el === \"number\") {\n // const errorArray: any = [];\n // errorArray._errors = [];\n // curr[el] = curr[el] || errorArray;\n // }\n }\n else {\n curr[el] = curr[el] || { _errors: [] };\n curr[el]._errors.push(mapper(issue));\n }\n curr = curr[el];\n i++;\n }\n }\n }\n };\n processError(this);\n return fieldErrors;\n }\n static assert(value) {\n if (!(value instanceof ZodError)) {\n throw new Error(`Not a ZodError: ${value}`);\n }\n }\n toString() {\n return this.message;\n }\n get message() {\n return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2);\n }\n get isEmpty() {\n return this.issues.length === 0;\n }\n flatten(mapper = (issue) => issue.message) {\n const fieldErrors = {};\n const formErrors = [];\n for (const sub of this.issues) {\n if (sub.path.length > 0) {\n fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || [];\n fieldErrors[sub.path[0]].push(mapper(sub));\n }\n else {\n formErrors.push(mapper(sub));\n }\n }\n return { formErrors, fieldErrors };\n }\n get formErrors() {\n return this.flatten();\n }\n}\nZodError.create = (issues) => {\n const error = new ZodError(issues);\n return error;\n};\n\nconst errorMap = (issue, _ctx) => {\n let message;\n switch (issue.code) {\n case ZodIssueCode.invalid_type:\n if (issue.received === ZodParsedType.undefined) {\n message = \"Required\";\n }\n else {\n message = `Expected ${issue.expected}, received ${issue.received}`;\n }\n break;\n case ZodIssueCode.invalid_literal:\n message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util.jsonStringifyReplacer)}`;\n break;\n case ZodIssueCode.unrecognized_keys:\n message = `Unrecognized key(s) in object: ${util.joinValues(issue.keys, \", \")}`;\n break;\n case ZodIssueCode.invalid_union:\n message = `Invalid input`;\n break;\n case ZodIssueCode.invalid_union_discriminator:\n message = `Invalid discriminator value. Expected ${util.joinValues(issue.options)}`;\n break;\n case ZodIssueCode.invalid_enum_value:\n message = `Invalid enum value. Expected ${util.joinValues(issue.options)}, received '${issue.received}'`;\n break;\n case ZodIssueCode.invalid_arguments:\n message = `Invalid function arguments`;\n break;\n case ZodIssueCode.invalid_return_type:\n message = `Invalid function return type`;\n break;\n case ZodIssueCode.invalid_date:\n message = `Invalid date`;\n break;\n case ZodIssueCode.invalid_string:\n if (typeof issue.validation === \"object\") {\n if (\"includes\" in issue.validation) {\n message = `Invalid input: must include \"${issue.validation.includes}\"`;\n if (typeof issue.validation.position === \"number\") {\n message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`;\n }\n }\n else if (\"startsWith\" in issue.validation) {\n message = `Invalid input: must start with \"${issue.validation.startsWith}\"`;\n }\n else if (\"endsWith\" in issue.validation) {\n message = `Invalid input: must end with \"${issue.validation.endsWith}\"`;\n }\n else {\n util.assertNever(issue.validation);\n }\n }\n else if (issue.validation !== \"regex\") {\n message = `Invalid ${issue.validation}`;\n }\n else {\n message = \"Invalid\";\n }\n break;\n case ZodIssueCode.too_small:\n if (issue.type === \"array\")\n message = `Array must contain ${issue.exact ? \"exactly\" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`;\n else if (issue.type === \"string\")\n message = `String must contain ${issue.exact ? \"exactly\" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`;\n else if (issue.type === \"number\")\n message = `Number must be ${issue.exact\n ? `exactly equal to `\n : issue.inclusive\n ? `greater than or equal to `\n : `greater than `}${issue.minimum}`;\n else if (issue.type === \"date\")\n message = `Date must be ${issue.exact\n ? `exactly equal to `\n : issue.inclusive\n ? `greater than or equal to `\n : `greater than `}${new Date(Number(issue.minimum))}`;\n else\n message = \"Invalid input\";\n break;\n case ZodIssueCode.too_big:\n if (issue.type === \"array\")\n message = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`;\n else if (issue.type === \"string\")\n message = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`;\n else if (issue.type === \"number\")\n message = `Number must be ${issue.exact\n ? `exactly`\n : issue.inclusive\n ? `less than or equal to`\n : `less than`} ${issue.maximum}`;\n else if (issue.type === \"bigint\")\n message = `BigInt must be ${issue.exact\n ? `exactly`\n : issue.inclusive\n ? `less than or equal to`\n : `less than`} ${issue.maximum}`;\n else if (issue.type === \"date\")\n message = `Date must be ${issue.exact\n ? `exactly`\n : issue.inclusive\n ? `smaller than or equal to`\n : `smaller than`} ${new Date(Number(issue.maximum))}`;\n else\n message = \"Invalid input\";\n break;\n case ZodIssueCode.custom:\n message = `Invalid input`;\n break;\n case ZodIssueCode.invalid_intersection_types:\n message = `Intersection results could not be merged`;\n break;\n case ZodIssueCode.not_multiple_of:\n message = `Number must be a multiple of ${issue.multipleOf}`;\n break;\n case ZodIssueCode.not_finite:\n message = \"Number must be finite\";\n break;\n default:\n message = _ctx.defaultError;\n util.assertNever(issue);\n }\n return { message };\n};\n\nlet overrideErrorMap = errorMap;\nfunction setErrorMap(map) {\n overrideErrorMap = map;\n}\nfunction getErrorMap() {\n return overrideErrorMap;\n}\n\nconst makeIssue = (params) => {\n const { data, path, errorMaps, issueData } = params;\n const fullPath = [...path, ...(issueData.path || [])];\n const fullIssue = {\n ...issueData,\n path: fullPath,\n };\n if (issueData.message !== undefined) {\n return {\n ...issueData,\n path: fullPath,\n message: issueData.message,\n };\n }\n let errorMessage = \"\";\n const maps = errorMaps\n .filter((m) => !!m)\n .slice()\n .reverse();\n for (const map of maps) {\n errorMessage = map(fullIssue, { data, defaultError: errorMessage }).message;\n }\n return {\n ...issueData,\n path: fullPath,\n message: errorMessage,\n };\n};\nconst EMPTY_PATH = [];\nfunction addIssueToContext(ctx, issueData) {\n const overrideMap = getErrorMap();\n const issue = makeIssue({\n issueData: issueData,\n data: ctx.data,\n path: ctx.path,\n errorMaps: [\n ctx.common.contextualErrorMap, // contextual error map is first priority\n ctx.schemaErrorMap, // then schema-bound map if available\n overrideMap, // then global override map\n overrideMap === errorMap ? undefined : errorMap, // then global default map\n ].filter((x) => !!x),\n });\n ctx.common.issues.push(issue);\n}\nclass ParseStatus {\n constructor() {\n this.value = \"valid\";\n }\n dirty() {\n if (this.value === \"valid\")\n this.value = \"dirty\";\n }\n abort() {\n if (this.value !== \"aborted\")\n this.value = \"aborted\";\n }\n static mergeArray(status, results) {\n const arrayValue = [];\n for (const s of results) {\n if (s.status === \"aborted\")\n return INVALID;\n if (s.status === \"dirty\")\n status.dirty();\n arrayValue.push(s.value);\n }\n return { status: status.value, value: arrayValue };\n }\n static async mergeObjectAsync(status, pairs) {\n const syncPairs = [];\n for (const pair of pairs) {\n const key = await pair.key;\n const value = await pair.value;\n syncPairs.push({\n key,\n value,\n });\n }\n return ParseStatus.mergeObjectSync(status, syncPairs);\n }\n static mergeObjectSync(status, pairs) {\n const finalObject = {};\n for (const pair of pairs) {\n const { key, value } = pair;\n if (key.status === \"aborted\")\n return INVALID;\n if (value.status === \"aborted\")\n return INVALID;\n if (key.status === \"dirty\")\n status.dirty();\n if (value.status === \"dirty\")\n status.dirty();\n if (key.value !== \"__proto__\" &&\n (typeof value.value !== \"undefined\" || pair.alwaysSet)) {\n finalObject[key.value] = value.value;\n }\n }\n return { status: status.value, value: finalObject };\n }\n}\nconst INVALID = Object.freeze({\n status: \"aborted\",\n});\nconst DIRTY = (value) => ({ status: \"dirty\", value });\nconst OK = (value) => ({ status: \"valid\", value });\nconst isAborted = (x) => x.status === \"aborted\";\nconst isDirty = (x) => x.status === \"dirty\";\nconst isValid = (x) => x.status === \"valid\";\nconst isAsync = (x) => typeof Promise !== \"undefined\" && x instanceof Promise;\n\n/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n\r\nfunction __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nfunction __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\n\nvar errorUtil;\n(function (errorUtil) {\n errorUtil.errToObj = (message) => typeof message === \"string\" ? { message } : message || {};\n errorUtil.toString = (message) => typeof message === \"string\" ? message : message === null || message === void 0 ? void 0 : message.message;\n})(errorUtil || (errorUtil = {}));\n\nvar _ZodEnum_cache, _ZodNativeEnum_cache;\nclass ParseInputLazyPath {\n constructor(parent, value, path, key) {\n this._cachedPath = [];\n this.parent = parent;\n this.data = value;\n this._path = path;\n this._key = key;\n }\n get path() {\n if (!this._cachedPath.length) {\n if (this._key instanceof Array) {\n this._cachedPath.push(...this._path, ...this._key);\n }\n else {\n this._cachedPath.push(...this._path, this._key);\n }\n }\n return this._cachedPath;\n }\n}\nconst handleResult = (ctx, result) => {\n if (isValid(result)) {\n return { success: true, data: result.value };\n }\n else {\n if (!ctx.common.issues.length) {\n throw new Error(\"Validation failed but no issues detected.\");\n }\n return {\n success: false,\n get error() {\n if (this._error)\n return this._error;\n const error = new ZodError(ctx.common.issues);\n this._error = error;\n return this._error;\n },\n };\n }\n};\nfunction processCreateParams(params) {\n if (!params)\n return {};\n const { errorMap, invalid_type_error, required_error, description } = params;\n if (errorMap && (invalid_type_error || required_error)) {\n throw new Error(`Can't use \"invalid_type_error\" or \"required_error\" in conjunction with custom error map.`);\n }\n if (errorMap)\n return { errorMap: errorMap, description };\n const customMap = (iss, ctx) => {\n var _a, _b;\n const { message } = params;\n if (iss.code === \"invalid_enum_value\") {\n return { message: message !== null && message !== void 0 ? message : ctx.defaultError };\n }\n if (typeof ctx.data === \"undefined\") {\n return { message: (_a = message !== null && message !== void 0 ? message : required_error) !== null && _a !== void 0 ? _a : ctx.defaultError };\n }\n if (iss.code !== \"invalid_type\")\n return { message: ctx.defaultError };\n return { message: (_b = message !== null && message !== void 0 ? message : invalid_type_error) !== null && _b !== void 0 ? _b : ctx.defaultError };\n };\n return { errorMap: customMap, description };\n}\nclass ZodType {\n get description() {\n return this._def.description;\n }\n _getType(input) {\n return getParsedType(input.data);\n }\n _getOrReturnCtx(input, ctx) {\n return (ctx || {\n common: input.parent.common,\n data: input.data,\n parsedType: getParsedType(input.data),\n schemaErrorMap: this._def.errorMap,\n path: input.path,\n parent: input.parent,\n });\n }\n _processInputParams(input) {\n return {\n status: new ParseStatus(),\n ctx: {\n common: input.parent.common,\n data: input.data,\n parsedType: getParsedType(input.data),\n schemaErrorMap: this._def.errorMap,\n path: input.path,\n parent: input.parent,\n },\n };\n }\n _parseSync(input) {\n const result = this._parse(input);\n if (isAsync(result)) {\n throw new Error(\"Synchronous parse encountered promise.\");\n }\n return result;\n }\n _parseAsync(input) {\n const result = this._parse(input);\n return Promise.resolve(result);\n }\n parse(data, params) {\n const result = this.safeParse(data, params);\n if (result.success)\n return result.data;\n throw result.error;\n }\n safeParse(data, params) {\n var _a;\n const ctx = {\n common: {\n issues: [],\n async: (_a = params === null || params === void 0 ? void 0 : params.async) !== null && _a !== void 0 ? _a : false,\n contextualErrorMap: params === null || params === void 0 ? void 0 : params.errorMap,\n },\n path: (params === null || params === void 0 ? void 0 : params.path) || [],\n schemaErrorMap: this._def.errorMap,\n parent: null,\n data,\n parsedType: getParsedType(data),\n };\n const result = this._parseSync({ data, path: ctx.path, parent: ctx });\n return handleResult(ctx, result);\n }\n \"~validate\"(data) {\n var _a, _b;\n const ctx = {\n common: {\n issues: [],\n async: !!this[\"~standard\"].async,\n },\n path: [],\n schemaErrorMap: this._def.errorMap,\n parent: null,\n data,\n parsedType: getParsedType(data),\n };\n if (!this[\"~standard\"].async) {\n try {\n const result = this._parseSync({ data, path: [], parent: ctx });\n return isValid(result)\n ? {\n value: result.value,\n }\n : {\n issues: ctx.common.issues,\n };\n }\n catch (err) {\n if ((_b = (_a = err === null || err === void 0 ? void 0 : err.message) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === null || _b === void 0 ? void 0 : _b.includes(\"encountered\")) {\n this[\"~standard\"].async = true;\n }\n ctx.common = {\n issues: [],\n async: true,\n };\n }\n }\n return this._parseAsync({ data, path: [], parent: ctx }).then((result) => isValid(result)\n ? {\n value: result.value,\n }\n : {\n issues: ctx.common.issues,\n });\n }\n async parseAsync(data, params) {\n const result = await this.safeParseAsync(data, params);\n if (result.success)\n return result.data;\n throw result.error;\n }\n async safeParseAsync(data, params) {\n const ctx = {\n common: {\n issues: [],\n contextualErrorMap: params === null || params === void 0 ? void 0 : params.errorMap,\n async: true,\n },\n path: (params === null || params === void 0 ? void 0 : params.path) || [],\n schemaErrorMap: this._def.errorMap,\n parent: null,\n data,\n parsedType: getParsedType(data),\n };\n const maybeAsyncResult = this._parse({ data, path: ctx.path, parent: ctx });\n const result = await (isAsync(maybeAsyncResult)\n ? maybeAsyncResult\n : Promise.resolve(maybeAsyncResult));\n return handleResult(ctx, result);\n }\n refine(check, message) {\n const getIssueProperties = (val) => {\n if (typeof message === \"string\" || typeof message === \"undefined\") {\n return { message };\n }\n else if (typeof message === \"function\") {\n return message(val);\n }\n else {\n return message;\n }\n };\n return this._refinement((val, ctx) => {\n const result = check(val);\n const setError = () => ctx.addIssue({\n code: ZodIssueCode.custom,\n ...getIssueProperties(val),\n });\n if (typeof Promise !== \"undefined\" && result instanceof Promise) {\n return result.then((data) => {\n if (!data) {\n setError();\n return false;\n }\n else {\n return true;\n }\n });\n }\n if (!result) {\n setError();\n return false;\n }\n else {\n return true;\n }\n });\n }\n refinement(check, refinementData) {\n return this._refinement((val, ctx) => {\n if (!check(val)) {\n ctx.addIssue(typeof refinementData === \"function\"\n ? refinementData(val, ctx)\n : refinementData);\n return false;\n }\n else {\n return true;\n }\n });\n }\n _refinement(refinement) {\n return new ZodEffects({\n schema: this,\n typeName: ZodFirstPartyTypeKind.ZodEffects,\n effect: { type: \"refinement\", refinement },\n });\n }\n superRefine(refinement) {\n return this._refinement(refinement);\n }\n constructor(def) {\n /** Alias of safeParseAsync */\n this.spa = this.safeParseAsync;\n this._def = def;\n this.parse = this.parse.bind(this);\n this.safeParse = this.safeParse.bind(this);\n this.parseAsync = this.parseAsync.bind(this);\n this.safeParseAsync = this.safeParseAsync.bind(this);\n this.spa = this.spa.bind(this);\n this.refine = this.refine.bind(this);\n this.refinement = this.refinement.bind(this);\n this.superRefine = this.superRefine.bind(this);\n this.optional = this.optional.bind(this);\n this.nullable = this.nullable.bind(this);\n this.nullish = this.nullish.bind(this);\n this.array = this.array.bind(this);\n this.promise = this.promise.bind(this);\n this.or = this.or.bind(this);\n this.and = this.and.bind(this);\n this.transform = this.transform.bind(this);\n this.brand = this.brand.bind(this);\n this.default = this.default.bind(this);\n this.catch = this.catch.bind(this);\n this.describe = this.describe.bind(this);\n this.pipe = this.pipe.bind(this);\n this.readonly = this.readonly.bind(this);\n this.isNullable = this.isNullable.bind(this);\n this.isOptional = this.isOptional.bind(this);\n this[\"~standard\"] = {\n version: 1,\n vendor: \"zod\",\n validate: (data) => this[\"~validate\"](data),\n };\n }\n optional() {\n return ZodOptional.create(this, this._def);\n }\n nullable() {\n return ZodNullable.create(this, this._def);\n }\n nullish() {\n return this.nullable().optional();\n }\n array() {\n return ZodArray.create(this);\n }\n promise() {\n return ZodPromise.create(this, this._def);\n }\n or(option) {\n return ZodUnion.create([this, option], this._def);\n }\n and(incoming) {\n return ZodIntersection.create(this, incoming, this._def);\n }\n transform(transform) {\n return new ZodEffects({\n ...processCreateParams(this._def),\n schema: this,\n typeName: ZodFirstPartyTypeKind.ZodEffects,\n effect: { type: \"transform\", transform },\n });\n }\n default(def) {\n const defaultValueFunc = typeof def === \"function\" ? def : () => def;\n return new ZodDefault({\n ...processCreateParams(this._def),\n innerType: this,\n defaultValue: defaultValueFunc,\n typeName: ZodFirstPartyTypeKind.ZodDefault,\n });\n }\n brand() {\n return new ZodBranded({\n typeName: ZodFirstPartyTypeKind.ZodBranded,\n type: this,\n ...processCreateParams(this._def),\n });\n }\n catch(def) {\n const catchValueFunc = typeof def === \"function\" ? def : () => def;\n return new ZodCatch({\n ...processCreateParams(this._def),\n innerType: this,\n catchValue: catchValueFunc,\n typeName: ZodFirstPartyTypeKind.ZodCatch,\n });\n }\n describe(description) {\n const This = this.constructor;\n return new This({\n ...this._def,\n description,\n });\n }\n pipe(target) {\n return ZodPipeline.create(this, target);\n }\n readonly() {\n return ZodReadonly.create(this);\n }\n isOptional() {\n return this.safeParse(undefined).success;\n }\n isNullable() {\n return this.safeParse(null).success;\n }\n}\nconst cuidRegex = /^c[^\\s-]{8,}$/i;\nconst cuid2Regex = /^[0-9a-z]+$/;\nconst ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/i;\n// const uuidRegex =\n// /^([a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[a-f0-9]{4}-[a-f0-9]{12}|00000000-0000-0000-0000-000000000000)$/i;\nconst uuidRegex = /^[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}$/i;\nconst nanoidRegex = /^[a-z0-9_-]{21}$/i;\nconst jwtRegex = /^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$/;\nconst durationRegex = /^[-+]?P(?!$)(?:(?:[-+]?\\d+Y)|(?:[-+]?\\d+[.,]\\d+Y$))?(?:(?:[-+]?\\d+M)|(?:[-+]?\\d+[.,]\\d+M$))?(?:(?:[-+]?\\d+W)|(?:[-+]?\\d+[.,]\\d+W$))?(?:(?:[-+]?\\d+D)|(?:[-+]?\\d+[.,]\\d+D$))?(?:T(?=[\\d+-])(?:(?:[-+]?\\d+H)|(?:[-+]?\\d+[.,]\\d+H$))?(?:(?:[-+]?\\d+M)|(?:[-+]?\\d+[.,]\\d+M$))?(?:[-+]?\\d+(?:[.,]\\d+)?S)?)??$/;\n// from https://stackoverflow.com/a/46181/1550155\n// old version: too slow, didn't support unicode\n// const emailRegex = /^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))$/i;\n//old email regex\n// const emailRegex = /^(([^<>()[\\].,;:\\s@\"]+(\\.[^<>()[\\].,;:\\s@\"]+)*)|(\".+\"))@((?!-)([^<>()[\\].,;:\\s@\"]+\\.)+[^<>()[\\].,;:\\s@\"]{1,})[^-<>()[\\].,;:\\s@\"]$/i;\n// eslint-disable-next-line\n// const emailRegex =\n// /^(([^<>()[\\]\\\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@((\\[(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\\])|(\\[IPv6:(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))\\])|([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])*(\\.[A-Za-z]{2,})+))$/;\n// const emailRegex =\n// /^[a-zA-Z0-9\\.\\!\\#\\$\\%\\&\\'\\*\\+\\/\\=\\?\\^\\_\\`\\{\\|\\}\\~\\-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;\n// const emailRegex =\n// /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])$/i;\nconst emailRegex = /^(?!\\.)(?!.*\\.\\.)([A-Z0-9_'+\\-\\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\\-]*\\.)+[A-Z]{2,}$/i;\n// const emailRegex =\n// /^[a-z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-z0-9-]+(?:\\.[a-z0-9\\-]+)*$/i;\n// from https://thekevinscott.com/emojis-in-javascript/#writing-a-regular-expression\nconst _emojiRegex = `^(\\\\p{Extended_Pictographic}|\\\\p{Emoji_Component})+$`;\nlet emojiRegex;\n// faster, simpler, safer\nconst ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;\nconst ipv4CidrRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/(3[0-2]|[12]?[0-9])$/;\n// const ipv6Regex =\n// /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:)