@openfin/cloud-notification-core-api 0.0.1-alpha.d138264 → 0.0.1-alpha.d19c912
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/README.md +2 -2
- package/bundle.d.ts +602 -286
- package/index.cjs +484 -186
- package/index.mjs +482 -186
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
|
-
import z from 'zod';
|
|
3
2
|
import mqtt from 'mqtt';
|
|
4
3
|
|
|
4
|
+
var d$1=Object.defineProperty;var e$1=(c,a)=>{for(var b in a)d$1(c,b,{get:a[b],enumerable:true});};
|
|
5
|
+
|
|
6
|
+
var g;(function(r){r.assertEqual=a=>{};function e(a){}r.assertIs=e;function t(a){throw new Error}r.assertNever=t,r.arrayToEnum=a=>{let n={};for(let i of a)n[i]=i;return n},r.getValidEnumValues=a=>{let n=r.objectKeys(a).filter(o=>typeof a[a[o]]!="number"),i={};for(let o of n)i[o]=a[o];return r.objectValues(i)},r.objectValues=a=>r.objectKeys(a).map(function(n){return a[n]}),r.objectKeys=typeof Object.keys=="function"?a=>Object.keys(a):a=>{let n=[];for(let i in a)Object.prototype.hasOwnProperty.call(a,i)&&n.push(i);return n},r.find=(a,n)=>{for(let i of a)if(n(i))return i},r.isInteger=typeof Number.isInteger=="function"?a=>Number.isInteger(a):a=>typeof a=="number"&&Number.isFinite(a)&&Math.floor(a)===a;function s(a,n=" | "){return a.map(i=>typeof i=="string"?`'${i}'`:i).join(n)}r.joinValues=s,r.jsonStringifyReplacer=(a,n)=>typeof n=="bigint"?n.toString():n;})(g||(g={}));var ve;(function(r){r.mergeShapes=(e,t)=>({...e,...t});})(ve||(ve={}));var u=g.arrayToEnum(["string","nan","number","integer","float","boolean","date","bigint","symbol","function","undefined","null","array","object","unknown","promise","void","never","map","set"]),R=r=>{switch(typeof r){case "undefined":return u.undefined;case "string":return u.string;case "number":return Number.isNaN(r)?u.nan:u.number;case "boolean":return u.boolean;case "function":return u.function;case "bigint":return u.bigint;case "symbol":return u.symbol;case "object":return Array.isArray(r)?u.array:r===null?u.null:r.then&&typeof r.then=="function"&&r.catch&&typeof r.catch=="function"?u.promise:typeof Map<"u"&&r instanceof Map?u.map:typeof Set<"u"&&r instanceof Set?u.set:typeof Date<"u"&&r instanceof Date?u.date:u.object;default:return u.unknown}};var c=g.arrayToEnum(["invalid_type","invalid_literal","custom","invalid_union","invalid_union_discriminator","invalid_enum_value","unrecognized_keys","invalid_arguments","invalid_return_type","invalid_date","invalid_string","too_small","too_big","invalid_intersection_types","not_multiple_of","not_finite"]),Me=r=>JSON.stringify(r,null,2).replace(/"([^"]+)":/g,"$1:"),b=class r extends Error{get errors(){return this.issues}constructor(e){super(),this.issues=[],this.addIssue=s=>{this.issues=[...this.issues,s];},this.addIssues=(s=[])=>{this.issues=[...this.issues,...s];};let t=new.target.prototype;Object.setPrototypeOf?Object.setPrototypeOf(this,t):this.__proto__=t,this.name="ZodError",this.issues=e;}format(e){let t=e||function(n){return n.message},s={_errors:[]},a=n=>{for(let i of n.issues)if(i.code==="invalid_union")i.unionErrors.map(a);else if(i.code==="invalid_return_type")a(i.returnTypeError);else if(i.code==="invalid_arguments")a(i.argumentsError);else if(i.path.length===0)s._errors.push(t(i));else {let o=s,f=0;for(;f<i.path.length;){let l=i.path[f];f===i.path.length-1?(o[l]=o[l]||{_errors:[]},o[l]._errors.push(t(i))):o[l]=o[l]||{_errors:[]},o=o[l],f++;}}};return a(this),s}static assert(e){if(!(e instanceof r))throw new Error(`Not a ZodError: ${e}`)}toString(){return this.message}get message(){return JSON.stringify(this.issues,g.jsonStringifyReplacer,2)}get isEmpty(){return this.issues.length===0}flatten(e=t=>t.message){let t={},s=[];for(let a of this.issues)if(a.path.length>0){let n=a.path[0];t[n]=t[n]||[],t[n].push(e(a));}else s.push(e(a));return {formErrors:s,fieldErrors:t}}get formErrors(){return this.flatten()}};b.create=r=>new b(r);var Ve=(r,e)=>{let t;switch(r.code){case c.invalid_type:r.received===u.undefined?t="Required":t=`Expected ${r.expected}, received ${r.received}`;break;case c.invalid_literal:t=`Invalid literal value, expected ${JSON.stringify(r.expected,g.jsonStringifyReplacer)}`;break;case c.unrecognized_keys:t=`Unrecognized key(s) in object: ${g.joinValues(r.keys,", ")}`;break;case c.invalid_union:t="Invalid input";break;case c.invalid_union_discriminator:t=`Invalid discriminator value. Expected ${g.joinValues(r.options)}`;break;case c.invalid_enum_value:t=`Invalid enum value. Expected ${g.joinValues(r.options)}, received '${r.received}'`;break;case c.invalid_arguments:t="Invalid function arguments";break;case c.invalid_return_type:t="Invalid function return type";break;case c.invalid_date:t="Invalid date";break;case c.invalid_string:typeof r.validation=="object"?"includes"in r.validation?(t=`Invalid input: must include "${r.validation.includes}"`,typeof r.validation.position=="number"&&(t=`${t} at one or more positions greater than or equal to ${r.validation.position}`)):"startsWith"in r.validation?t=`Invalid input: must start with "${r.validation.startsWith}"`:"endsWith"in r.validation?t=`Invalid input: must end with "${r.validation.endsWith}"`:g.assertNever(r.validation):r.validation!=="regex"?t=`Invalid ${r.validation}`:t="Invalid";break;case c.too_small:r.type==="array"?t=`Array must contain ${r.exact?"exactly":r.inclusive?"at least":"more than"} ${r.minimum} element(s)`:r.type==="string"?t=`String must contain ${r.exact?"exactly":r.inclusive?"at least":"over"} ${r.minimum} character(s)`:r.type==="number"?t=`Number must be ${r.exact?"exactly equal to ":r.inclusive?"greater than or equal to ":"greater than "}${r.minimum}`:r.type==="bigint"?t=`Number must be ${r.exact?"exactly equal to ":r.inclusive?"greater than or equal to ":"greater than "}${r.minimum}`:r.type==="date"?t=`Date must be ${r.exact?"exactly equal to ":r.inclusive?"greater than or equal to ":"greater than "}${new Date(Number(r.minimum))}`:t="Invalid input";break;case c.too_big:r.type==="array"?t=`Array must contain ${r.exact?"exactly":r.inclusive?"at most":"less than"} ${r.maximum} element(s)`:r.type==="string"?t=`String must contain ${r.exact?"exactly":r.inclusive?"at most":"under"} ${r.maximum} character(s)`:r.type==="number"?t=`Number must be ${r.exact?"exactly":r.inclusive?"less than or equal to":"less than"} ${r.maximum}`:r.type==="bigint"?t=`BigInt must be ${r.exact?"exactly":r.inclusive?"less than or equal to":"less than"} ${r.maximum}`:r.type==="date"?t=`Date must be ${r.exact?"exactly":r.inclusive?"smaller than or equal to":"smaller than"} ${new Date(Number(r.maximum))}`:t="Invalid input";break;case c.custom:t="Invalid input";break;case c.invalid_intersection_types:t="Intersection results could not be merged";break;case c.not_multiple_of:t=`Number must be a multiple of ${r.multipleOf}`;break;case c.not_finite:t="Number must be finite";break;default:t=e.defaultError,g.assertNever(r);}return {message:t}},I=Ve;var we=I;function Pe(r){we=r;}function re(){return we}var h$1;(function(r){r.errToObj=e=>typeof e=="string"?{message:e}:e||{},r.toString=e=>typeof e=="string"?e:e?.message;})(h$1||(h$1={}));var ue=r=>{let{data:e,path:t,errorMaps:s,issueData:a}=r,n=[...t,...a.path||[]],i={...a,path:n};if(a.message!==void 0)return {...a,path:n,message:a.message};let o="",f=s.filter(l=>!!l).slice().reverse();for(let l of f)o=l(i,{data:e,defaultError:o}).message;return {...a,path:n,message:o}},ze=[];function d(r,e){let t=re(),s=ue({issueData:e,data:r.data,path:r.path,errorMaps:[r.common.contextualErrorMap,r.schemaErrorMap,t,t===I?void 0:I].filter(a=>!!a)});r.common.issues.push(s);}var x=class r{constructor(){this.value="valid";}dirty(){this.value==="valid"&&(this.value="dirty");}abort(){this.value!=="aborted"&&(this.value="aborted");}static mergeArray(e,t){let s=[];for(let a of t){if(a.status==="aborted")return p;a.status==="dirty"&&e.dirty(),s.push(a.value);}return {status:e.value,value:s}}static async mergeObjectAsync(e,t){let s=[];for(let a of t){let n=await a.key,i=await a.value;s.push({key:n,value:i});}return r.mergeObjectSync(e,s)}static mergeObjectSync(e,t){let s={};for(let a of t){let{key:n,value:i}=a;if(n.status==="aborted"||i.status==="aborted")return p;n.status==="dirty"&&e.dirty(),i.status==="dirty"&&e.dirty(),n.value!=="__proto__"&&(typeof i.value<"u"||a.alwaysSet)&&(s[n.value]=i.value);}return {status:e.value,value:s}}},p=Object.freeze({status:"aborted"}),D=r=>({status:"dirty",value:r}),k=r=>({status:"valid",value:r}),he=r=>r.status==="aborted",pe=r=>r.status==="dirty",M=r=>r.status==="valid",se=r=>typeof Promise<"u"&&r instanceof Promise;var O=class{constructor(e,t,s,a){this._cachedPath=[],this.parent=e,this.data=t,this._path=s,this._key=a;}get path(){return this._cachedPath.length||(Array.isArray(this._key)?this._cachedPath.push(...this._path,...this._key):this._cachedPath.push(...this._path,this._key)),this._cachedPath}},Te=(r,e)=>{if(M(e))return {success:true,data:e.value};if(!r.common.issues.length)throw new Error("Validation failed but no issues detected.");return {success:false,get error(){if(this._error)return this._error;let t=new b(r.common.issues);return this._error=t,this._error}}};function y$1(r){if(!r)return {};let{errorMap:e,invalid_type_error:t,required_error:s,description:a}=r;if(e&&(t||s))throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`);return e?{errorMap:e,description:a}:{errorMap:(i,o)=>{let{message:f}=r;return i.code==="invalid_enum_value"?{message:f??o.defaultError}:typeof o.data>"u"?{message:f??s??o.defaultError}:i.code!=="invalid_type"?{message:o.defaultError}:{message:f??t??o.defaultError}},description:a}}var _=class{get description(){return this._def.description}_getType(e){return R(e.data)}_getOrReturnCtx(e,t){return t||{common:e.parent.common,data:e.data,parsedType:R(e.data),schemaErrorMap:this._def.errorMap,path:e.path,parent:e.parent}}_processInputParams(e){return {status:new x,ctx:{common:e.parent.common,data:e.data,parsedType:R(e.data),schemaErrorMap:this._def.errorMap,path:e.path,parent:e.parent}}}_parseSync(e){let t=this._parse(e);if(se(t))throw new Error("Synchronous parse encountered promise.");return t}_parseAsync(e){let t=this._parse(e);return Promise.resolve(t)}parse(e,t){let s=this.safeParse(e,t);if(s.success)return s.data;throw s.error}safeParse(e,t){let s={common:{issues:[],async:t?.async??false,contextualErrorMap:t?.errorMap},path:t?.path||[],schemaErrorMap:this._def.errorMap,parent:null,data:e,parsedType:R(e)},a=this._parseSync({data:e,path:s.path,parent:s});return Te(s,a)}"~validate"(e){let t={common:{issues:[],async:!!this["~standard"].async},path:[],schemaErrorMap:this._def.errorMap,parent:null,data:e,parsedType:R(e)};if(!this["~standard"].async)try{let s=this._parseSync({data:e,path:[],parent:t});return M(s)?{value:s.value}:{issues:t.common.issues}}catch(s){s?.message?.toLowerCase()?.includes("encountered")&&(this["~standard"].async=true),t.common={issues:[],async:true};}return this._parseAsync({data:e,path:[],parent:t}).then(s=>M(s)?{value:s.value}:{issues:t.common.issues})}async parseAsync(e,t){let s=await this.safeParseAsync(e,t);if(s.success)return s.data;throw s.error}async safeParseAsync(e,t){let s={common:{issues:[],contextualErrorMap:t?.errorMap,async:true},path:t?.path||[],schemaErrorMap:this._def.errorMap,parent:null,data:e,parsedType:R(e)},a=this._parse({data:e,path:s.path,parent:s}),n=await(se(a)?a:Promise.resolve(a));return Te(s,n)}refine(e,t){let s=a=>typeof t=="string"||typeof t>"u"?{message:t}:typeof t=="function"?t(a):t;return this._refinement((a,n)=>{let i=e(a),o=()=>n.addIssue({code:c.custom,...s(a)});return typeof Promise<"u"&&i instanceof Promise?i.then(f=>f?true:(o(),false)):i?true:(o(),false)})}refinement(e,t){return this._refinement((s,a)=>e(s)?true:(a.addIssue(typeof t=="function"?t(s,a):t),false))}_refinement(e){return new S({schema:this,typeName:m.ZodEffects,effect:{type:"refinement",refinement:e}})}superRefine(e){return this._refinement(e)}constructor(e){this.spa=this.safeParseAsync,this._def=e,this.parse=this.parse.bind(this),this.safeParse=this.safeParse.bind(this),this.parseAsync=this.parseAsync.bind(this),this.safeParseAsync=this.safeParseAsync.bind(this),this.spa=this.spa.bind(this),this.refine=this.refine.bind(this),this.refinement=this.refinement.bind(this),this.superRefine=this.superRefine.bind(this),this.optional=this.optional.bind(this),this.nullable=this.nullable.bind(this),this.nullish=this.nullish.bind(this),this.array=this.array.bind(this),this.promise=this.promise.bind(this),this.or=this.or.bind(this),this.and=this.and.bind(this),this.transform=this.transform.bind(this),this.brand=this.brand.bind(this),this.default=this.default.bind(this),this.catch=this.catch.bind(this),this.describe=this.describe.bind(this),this.pipe=this.pipe.bind(this),this.readonly=this.readonly.bind(this),this.isNullable=this.isNullable.bind(this),this.isOptional=this.isOptional.bind(this),this["~standard"]={version:1,vendor:"zod",validate:t=>this["~validate"](t)};}optional(){return C.create(this,this._def)}nullable(){return j.create(this,this._def)}nullish(){return this.nullable().optional()}array(){return $.create(this)}promise(){return z.create(this,this._def)}or(e){return J.create([this,e],this._def)}and(e){return Y.create(this,e,this._def)}transform(e){return new S({...y$1(this._def),schema:this,typeName:m.ZodEffects,effect:{type:"transform",transform:e}})}default(e){let t=typeof e=="function"?e:()=>e;return new K({...y$1(this._def),innerType:this,defaultValue:t,typeName:m.ZodDefault})}brand(){return new le({typeName:m.ZodBranded,type:this,...y$1(this._def)})}catch(e){let t=typeof e=="function"?e:()=>e;return new ee({...y$1(this._def),innerType:this,catchValue:t,typeName:m.ZodCatch})}describe(e){let t=this.constructor;return new t({...this._def,description:e})}pipe(e){return fe.create(this,e)}readonly(){return te.create(this)}isOptional(){return this.safeParse(void 0).success}isNullable(){return this.safeParse(null).success}},De=/^c[^\s-]{8,}$/i,Le=/^[0-9a-z]+$/,Ue=/^[0-9A-HJKMNP-TV-Z]{26}$/i,Fe=/^[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,Be=/^[a-z0-9_-]{21}$/i,We=/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,qe=/^[-+]?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)?)??$/,Je=/^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i,Ye="^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$",xe,He=/^(?:(?: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])$/,Ge=/^(?:(?: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])$/,Qe=/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/,Xe=/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,Ke=/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,et=/^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/,Oe="((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))",tt=new RegExp(`^${Oe}$`);function Se(r){let e="[0-5]\\d";r.precision?e=`${e}\\.\\d{${r.precision}}`:r.precision==null&&(e=`${e}(\\.\\d+)?`);let t=r.precision?"+":"?";return `([01]\\d|2[0-3]):[0-5]\\d(:${e})${t}`}function rt(r){return new RegExp(`^${Se(r)}$`)}function Ae(r){let e=`${Oe}T${Se(r)}`,t=[];return t.push(r.local?"Z?":"Z"),r.offset&&t.push("([+-]\\d{2}:?\\d{2})"),e=`${e}(${t.join("|")})`,new RegExp(`^${e}$`)}function st(r,e){return !!((e==="v4"||!e)&&He.test(r)||(e==="v6"||!e)&&Qe.test(r))}function at(r,e){if(!We.test(r))return false;try{let[t]=r.split(".");if(!t)return !1;let s=t.replace(/-/g,"+").replace(/_/g,"/").padEnd(t.length+(4-t.length%4)%4,"="),a=JSON.parse(atob(s));return !(typeof a!="object"||a===null||"typ"in a&&a?.typ!=="JWT"||!a.alg||e&&a.alg!==e)}catch{return false}}function nt(r,e){return !!((e==="v4"||!e)&&Ge.test(r)||(e==="v6"||!e)&&Xe.test(r))}var V=class r extends _{_parse(e){if(this._def.coerce&&(e.data=String(e.data)),this._getType(e)!==u.string){let n=this._getOrReturnCtx(e);return d(n,{code:c.invalid_type,expected:u.string,received:n.parsedType}),p}let s=new x,a;for(let n of this._def.checks)if(n.kind==="min")e.data.length<n.value&&(a=this._getOrReturnCtx(e,a),d(a,{code:c.too_small,minimum:n.value,type:"string",inclusive:true,exact:false,message:n.message}),s.dirty());else if(n.kind==="max")e.data.length>n.value&&(a=this._getOrReturnCtx(e,a),d(a,{code:c.too_big,maximum:n.value,type:"string",inclusive:true,exact:false,message:n.message}),s.dirty());else if(n.kind==="length"){let i=e.data.length>n.value,o=e.data.length<n.value;(i||o)&&(a=this._getOrReturnCtx(e,a),i?d(a,{code:c.too_big,maximum:n.value,type:"string",inclusive:true,exact:true,message:n.message}):o&&d(a,{code:c.too_small,minimum:n.value,type:"string",inclusive:true,exact:true,message:n.message}),s.dirty());}else if(n.kind==="email")Je.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"email",code:c.invalid_string,message:n.message}),s.dirty());else if(n.kind==="emoji")xe||(xe=new RegExp(Ye,"u")),xe.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"emoji",code:c.invalid_string,message:n.message}),s.dirty());else if(n.kind==="uuid")Fe.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"uuid",code:c.invalid_string,message:n.message}),s.dirty());else if(n.kind==="nanoid")Be.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"nanoid",code:c.invalid_string,message:n.message}),s.dirty());else if(n.kind==="cuid")De.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"cuid",code:c.invalid_string,message:n.message}),s.dirty());else if(n.kind==="cuid2")Le.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"cuid2",code:c.invalid_string,message:n.message}),s.dirty());else if(n.kind==="ulid")Ue.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"ulid",code:c.invalid_string,message:n.message}),s.dirty());else if(n.kind==="url")try{new URL(e.data);}catch{a=this._getOrReturnCtx(e,a),d(a,{validation:"url",code:c.invalid_string,message:n.message}),s.dirty();}else n.kind==="regex"?(n.regex.lastIndex=0,n.regex.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"regex",code:c.invalid_string,message:n.message}),s.dirty())):n.kind==="trim"?e.data=e.data.trim():n.kind==="includes"?e.data.includes(n.value,n.position)||(a=this._getOrReturnCtx(e,a),d(a,{code:c.invalid_string,validation:{includes:n.value,position:n.position},message:n.message}),s.dirty()):n.kind==="toLowerCase"?e.data=e.data.toLowerCase():n.kind==="toUpperCase"?e.data=e.data.toUpperCase():n.kind==="startsWith"?e.data.startsWith(n.value)||(a=this._getOrReturnCtx(e,a),d(a,{code:c.invalid_string,validation:{startsWith:n.value},message:n.message}),s.dirty()):n.kind==="endsWith"?e.data.endsWith(n.value)||(a=this._getOrReturnCtx(e,a),d(a,{code:c.invalid_string,validation:{endsWith:n.value},message:n.message}),s.dirty()):n.kind==="datetime"?Ae(n).test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{code:c.invalid_string,validation:"datetime",message:n.message}),s.dirty()):n.kind==="date"?tt.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{code:c.invalid_string,validation:"date",message:n.message}),s.dirty()):n.kind==="time"?rt(n).test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{code:c.invalid_string,validation:"time",message:n.message}),s.dirty()):n.kind==="duration"?qe.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"duration",code:c.invalid_string,message:n.message}),s.dirty()):n.kind==="ip"?st(e.data,n.version)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"ip",code:c.invalid_string,message:n.message}),s.dirty()):n.kind==="jwt"?at(e.data,n.alg)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"jwt",code:c.invalid_string,message:n.message}),s.dirty()):n.kind==="cidr"?nt(e.data,n.version)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"cidr",code:c.invalid_string,message:n.message}),s.dirty()):n.kind==="base64"?Ke.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"base64",code:c.invalid_string,message:n.message}),s.dirty()):n.kind==="base64url"?et.test(e.data)||(a=this._getOrReturnCtx(e,a),d(a,{validation:"base64url",code:c.invalid_string,message:n.message}),s.dirty()):g.assertNever(n);return {status:s.value,value:e.data}}_regex(e,t,s){return this.refinement(a=>e.test(a),{validation:t,code:c.invalid_string,...h$1.errToObj(s)})}_addCheck(e){return new r({...this._def,checks:[...this._def.checks,e]})}email(e){return this._addCheck({kind:"email",...h$1.errToObj(e)})}url(e){return this._addCheck({kind:"url",...h$1.errToObj(e)})}emoji(e){return this._addCheck({kind:"emoji",...h$1.errToObj(e)})}uuid(e){return this._addCheck({kind:"uuid",...h$1.errToObj(e)})}nanoid(e){return this._addCheck({kind:"nanoid",...h$1.errToObj(e)})}cuid(e){return this._addCheck({kind:"cuid",...h$1.errToObj(e)})}cuid2(e){return this._addCheck({kind:"cuid2",...h$1.errToObj(e)})}ulid(e){return this._addCheck({kind:"ulid",...h$1.errToObj(e)})}base64(e){return this._addCheck({kind:"base64",...h$1.errToObj(e)})}base64url(e){return this._addCheck({kind:"base64url",...h$1.errToObj(e)})}jwt(e){return this._addCheck({kind:"jwt",...h$1.errToObj(e)})}ip(e){return this._addCheck({kind:"ip",...h$1.errToObj(e)})}cidr(e){return this._addCheck({kind:"cidr",...h$1.errToObj(e)})}datetime(e){return typeof e=="string"?this._addCheck({kind:"datetime",precision:null,offset:false,local:false,message:e}):this._addCheck({kind:"datetime",precision:typeof e?.precision>"u"?null:e?.precision,offset:e?.offset??false,local:e?.local??false,...h$1.errToObj(e?.message)})}date(e){return this._addCheck({kind:"date",message:e})}time(e){return typeof e=="string"?this._addCheck({kind:"time",precision:null,message:e}):this._addCheck({kind:"time",precision:typeof e?.precision>"u"?null:e?.precision,...h$1.errToObj(e?.message)})}duration(e){return this._addCheck({kind:"duration",...h$1.errToObj(e)})}regex(e,t){return this._addCheck({kind:"regex",regex:e,...h$1.errToObj(t)})}includes(e,t){return this._addCheck({kind:"includes",value:e,position:t?.position,...h$1.errToObj(t?.message)})}startsWith(e,t){return this._addCheck({kind:"startsWith",value:e,...h$1.errToObj(t)})}endsWith(e,t){return this._addCheck({kind:"endsWith",value:e,...h$1.errToObj(t)})}min(e,t){return this._addCheck({kind:"min",value:e,...h$1.errToObj(t)})}max(e,t){return this._addCheck({kind:"max",value:e,...h$1.errToObj(t)})}length(e,t){return this._addCheck({kind:"length",value:e,...h$1.errToObj(t)})}nonempty(e){return this.min(1,h$1.errToObj(e))}trim(){return new r({...this._def,checks:[...this._def.checks,{kind:"trim"}]})}toLowerCase(){return new r({...this._def,checks:[...this._def.checks,{kind:"toLowerCase"}]})}toUpperCase(){return new r({...this._def,checks:[...this._def.checks,{kind:"toUpperCase"}]})}get isDatetime(){return !!this._def.checks.find(e=>e.kind==="datetime")}get isDate(){return !!this._def.checks.find(e=>e.kind==="date")}get isTime(){return !!this._def.checks.find(e=>e.kind==="time")}get isDuration(){return !!this._def.checks.find(e=>e.kind==="duration")}get isEmail(){return !!this._def.checks.find(e=>e.kind==="email")}get isURL(){return !!this._def.checks.find(e=>e.kind==="url")}get isEmoji(){return !!this._def.checks.find(e=>e.kind==="emoji")}get isUUID(){return !!this._def.checks.find(e=>e.kind==="uuid")}get isNANOID(){return !!this._def.checks.find(e=>e.kind==="nanoid")}get isCUID(){return !!this._def.checks.find(e=>e.kind==="cuid")}get isCUID2(){return !!this._def.checks.find(e=>e.kind==="cuid2")}get isULID(){return !!this._def.checks.find(e=>e.kind==="ulid")}get isIP(){return !!this._def.checks.find(e=>e.kind==="ip")}get isCIDR(){return !!this._def.checks.find(e=>e.kind==="cidr")}get isBase64(){return !!this._def.checks.find(e=>e.kind==="base64")}get isBase64url(){return !!this._def.checks.find(e=>e.kind==="base64url")}get minLength(){let e=null;for(let t of this._def.checks)t.kind==="min"&&(e===null||t.value>e)&&(e=t.value);return e}get maxLength(){let e=null;for(let t of this._def.checks)t.kind==="max"&&(e===null||t.value<e)&&(e=t.value);return e}};V.create=r=>new V({checks:[],typeName:m.ZodString,coerce:r?.coerce??false,...y$1(r)});function it(r,e){let t=(r.toString().split(".")[1]||"").length,s=(e.toString().split(".")[1]||"").length,a=t>s?t:s,n=Number.parseInt(r.toFixed(a).replace(".","")),i=Number.parseInt(e.toFixed(a).replace(".",""));return n%i/10**a}var L=class r extends _{constructor(){super(...arguments),this.min=this.gte,this.max=this.lte,this.step=this.multipleOf;}_parse(e){if(this._def.coerce&&(e.data=Number(e.data)),this._getType(e)!==u.number){let n=this._getOrReturnCtx(e);return d(n,{code:c.invalid_type,expected:u.number,received:n.parsedType}),p}let s,a=new x;for(let n of this._def.checks)n.kind==="int"?g.isInteger(e.data)||(s=this._getOrReturnCtx(e,s),d(s,{code:c.invalid_type,expected:"integer",received:"float",message:n.message}),a.dirty()):n.kind==="min"?(n.inclusive?e.data<n.value:e.data<=n.value)&&(s=this._getOrReturnCtx(e,s),d(s,{code:c.too_small,minimum:n.value,type:"number",inclusive:n.inclusive,exact:false,message:n.message}),a.dirty()):n.kind==="max"?(n.inclusive?e.data>n.value:e.data>=n.value)&&(s=this._getOrReturnCtx(e,s),d(s,{code:c.too_big,maximum:n.value,type:"number",inclusive:n.inclusive,exact:false,message:n.message}),a.dirty()):n.kind==="multipleOf"?it(e.data,n.value)!==0&&(s=this._getOrReturnCtx(e,s),d(s,{code:c.not_multiple_of,multipleOf:n.value,message:n.message}),a.dirty()):n.kind==="finite"?Number.isFinite(e.data)||(s=this._getOrReturnCtx(e,s),d(s,{code:c.not_finite,message:n.message}),a.dirty()):g.assertNever(n);return {status:a.value,value:e.data}}gte(e,t){return this.setLimit("min",e,true,h$1.toString(t))}gt(e,t){return this.setLimit("min",e,false,h$1.toString(t))}lte(e,t){return this.setLimit("max",e,true,h$1.toString(t))}lt(e,t){return this.setLimit("max",e,false,h$1.toString(t))}setLimit(e,t,s,a){return new r({...this._def,checks:[...this._def.checks,{kind:e,value:t,inclusive:s,message:h$1.toString(a)}]})}_addCheck(e){return new r({...this._def,checks:[...this._def.checks,e]})}int(e){return this._addCheck({kind:"int",message:h$1.toString(e)})}positive(e){return this._addCheck({kind:"min",value:0,inclusive:false,message:h$1.toString(e)})}negative(e){return this._addCheck({kind:"max",value:0,inclusive:false,message:h$1.toString(e)})}nonpositive(e){return this._addCheck({kind:"max",value:0,inclusive:true,message:h$1.toString(e)})}nonnegative(e){return this._addCheck({kind:"min",value:0,inclusive:true,message:h$1.toString(e)})}multipleOf(e,t){return this._addCheck({kind:"multipleOf",value:e,message:h$1.toString(t)})}finite(e){return this._addCheck({kind:"finite",message:h$1.toString(e)})}safe(e){return this._addCheck({kind:"min",inclusive:true,value:Number.MIN_SAFE_INTEGER,message:h$1.toString(e)})._addCheck({kind:"max",inclusive:true,value:Number.MAX_SAFE_INTEGER,message:h$1.toString(e)})}get minValue(){let e=null;for(let t of this._def.checks)t.kind==="min"&&(e===null||t.value>e)&&(e=t.value);return e}get maxValue(){let e=null;for(let t of this._def.checks)t.kind==="max"&&(e===null||t.value<e)&&(e=t.value);return e}get isInt(){return !!this._def.checks.find(e=>e.kind==="int"||e.kind==="multipleOf"&&g.isInteger(e.value))}get isFinite(){let e=null,t=null;for(let s of this._def.checks){if(s.kind==="finite"||s.kind==="int"||s.kind==="multipleOf")return true;s.kind==="min"?(t===null||s.value>t)&&(t=s.value):s.kind==="max"&&(e===null||s.value<e)&&(e=s.value);}return Number.isFinite(t)&&Number.isFinite(e)}};L.create=r=>new L({checks:[],typeName:m.ZodNumber,coerce:r?.coerce||false,...y$1(r)});var U=class r extends _{constructor(){super(...arguments),this.min=this.gte,this.max=this.lte;}_parse(e){if(this._def.coerce)try{e.data=BigInt(e.data);}catch{return this._getInvalidInput(e)}if(this._getType(e)!==u.bigint)return this._getInvalidInput(e);let s,a=new x;for(let n of this._def.checks)n.kind==="min"?(n.inclusive?e.data<n.value:e.data<=n.value)&&(s=this._getOrReturnCtx(e,s),d(s,{code:c.too_small,type:"bigint",minimum:n.value,inclusive:n.inclusive,message:n.message}),a.dirty()):n.kind==="max"?(n.inclusive?e.data>n.value:e.data>=n.value)&&(s=this._getOrReturnCtx(e,s),d(s,{code:c.too_big,type:"bigint",maximum:n.value,inclusive:n.inclusive,message:n.message}),a.dirty()):n.kind==="multipleOf"?e.data%n.value!==BigInt(0)&&(s=this._getOrReturnCtx(e,s),d(s,{code:c.not_multiple_of,multipleOf:n.value,message:n.message}),a.dirty()):g.assertNever(n);return {status:a.value,value:e.data}}_getInvalidInput(e){let t=this._getOrReturnCtx(e);return d(t,{code:c.invalid_type,expected:u.bigint,received:t.parsedType}),p}gte(e,t){return this.setLimit("min",e,true,h$1.toString(t))}gt(e,t){return this.setLimit("min",e,false,h$1.toString(t))}lte(e,t){return this.setLimit("max",e,true,h$1.toString(t))}lt(e,t){return this.setLimit("max",e,false,h$1.toString(t))}setLimit(e,t,s,a){return new r({...this._def,checks:[...this._def.checks,{kind:e,value:t,inclusive:s,message:h$1.toString(a)}]})}_addCheck(e){return new r({...this._def,checks:[...this._def.checks,e]})}positive(e){return this._addCheck({kind:"min",value:BigInt(0),inclusive:false,message:h$1.toString(e)})}negative(e){return this._addCheck({kind:"max",value:BigInt(0),inclusive:false,message:h$1.toString(e)})}nonpositive(e){return this._addCheck({kind:"max",value:BigInt(0),inclusive:true,message:h$1.toString(e)})}nonnegative(e){return this._addCheck({kind:"min",value:BigInt(0),inclusive:true,message:h$1.toString(e)})}multipleOf(e,t){return this._addCheck({kind:"multipleOf",value:e,message:h$1.toString(t)})}get minValue(){let e=null;for(let t of this._def.checks)t.kind==="min"&&(e===null||t.value>e)&&(e=t.value);return e}get maxValue(){let e=null;for(let t of this._def.checks)t.kind==="max"&&(e===null||t.value<e)&&(e=t.value);return e}};U.create=r=>new U({checks:[],typeName:m.ZodBigInt,coerce:r?.coerce??false,...y$1(r)});var F=class extends _{_parse(e){if(this._def.coerce&&(e.data=!!e.data),this._getType(e)!==u.boolean){let s=this._getOrReturnCtx(e);return d(s,{code:c.invalid_type,expected:u.boolean,received:s.parsedType}),p}return k(e.data)}};F.create=r=>new F({typeName:m.ZodBoolean,coerce:r?.coerce||false,...y$1(r)});var B=class r extends _{_parse(e){if(this._def.coerce&&(e.data=new Date(e.data)),this._getType(e)!==u.date){let n=this._getOrReturnCtx(e);return d(n,{code:c.invalid_type,expected:u.date,received:n.parsedType}),p}if(Number.isNaN(e.data.getTime())){let n=this._getOrReturnCtx(e);return d(n,{code:c.invalid_date}),p}let s=new x,a;for(let n of this._def.checks)n.kind==="min"?e.data.getTime()<n.value&&(a=this._getOrReturnCtx(e,a),d(a,{code:c.too_small,message:n.message,inclusive:true,exact:false,minimum:n.value,type:"date"}),s.dirty()):n.kind==="max"?e.data.getTime()>n.value&&(a=this._getOrReturnCtx(e,a),d(a,{code:c.too_big,message:n.message,inclusive:true,exact:false,maximum:n.value,type:"date"}),s.dirty()):g.assertNever(n);return {status:s.value,value:new Date(e.data.getTime())}}_addCheck(e){return new r({...this._def,checks:[...this._def.checks,e]})}min(e,t){return this._addCheck({kind:"min",value:e.getTime(),message:h$1.toString(t)})}max(e,t){return this._addCheck({kind:"max",value:e.getTime(),message:h$1.toString(t)})}get minDate(){let e=null;for(let t of this._def.checks)t.kind==="min"&&(e===null||t.value>e)&&(e=t.value);return e!=null?new Date(e):null}get maxDate(){let e=null;for(let t of this._def.checks)t.kind==="max"&&(e===null||t.value<e)&&(e=t.value);return e!=null?new Date(e):null}};B.create=r=>new B({checks:[],coerce:r?.coerce||false,typeName:m.ZodDate,...y$1(r)});var ne=class extends _{_parse(e){if(this._getType(e)!==u.symbol){let s=this._getOrReturnCtx(e);return d(s,{code:c.invalid_type,expected:u.symbol,received:s.parsedType}),p}return k(e.data)}};ne.create=r=>new ne({typeName:m.ZodSymbol,...y$1(r)});var W=class extends _{_parse(e){if(this._getType(e)!==u.undefined){let s=this._getOrReturnCtx(e);return d(s,{code:c.invalid_type,expected:u.undefined,received:s.parsedType}),p}return k(e.data)}};W.create=r=>new W({typeName:m.ZodUndefined,...y$1(r)});var q=class extends _{_parse(e){if(this._getType(e)!==u.null){let s=this._getOrReturnCtx(e);return d(s,{code:c.invalid_type,expected:u.null,received:s.parsedType}),p}return k(e.data)}};q.create=r=>new q({typeName:m.ZodNull,...y$1(r)});var P=class extends _{constructor(){super(...arguments),this._any=true;}_parse(e){return k(e.data)}};P.create=r=>new P({typeName:m.ZodAny,...y$1(r)});var Z=class extends _{constructor(){super(...arguments),this._unknown=true;}_parse(e){return k(e.data)}};Z.create=r=>new Z({typeName:m.ZodUnknown,...y$1(r)});var A=class extends _{_parse(e){let t=this._getOrReturnCtx(e);return d(t,{code:c.invalid_type,expected:u.never,received:t.parsedType}),p}};A.create=r=>new A({typeName:m.ZodNever,...y$1(r)});var ie=class extends _{_parse(e){if(this._getType(e)!==u.undefined){let s=this._getOrReturnCtx(e);return d(s,{code:c.invalid_type,expected:u.void,received:s.parsedType}),p}return k(e.data)}};ie.create=r=>new ie({typeName:m.ZodVoid,...y$1(r)});var $=class r extends _{_parse(e){let{ctx:t,status:s}=this._processInputParams(e),a=this._def;if(t.parsedType!==u.array)return d(t,{code:c.invalid_type,expected:u.array,received:t.parsedType}),p;if(a.exactLength!==null){let i=t.data.length>a.exactLength.value,o=t.data.length<a.exactLength.value;(i||o)&&(d(t,{code:i?c.too_big:c.too_small,minimum:o?a.exactLength.value:void 0,maximum:i?a.exactLength.value:void 0,type:"array",inclusive:true,exact:true,message:a.exactLength.message}),s.dirty());}if(a.minLength!==null&&t.data.length<a.minLength.value&&(d(t,{code:c.too_small,minimum:a.minLength.value,type:"array",inclusive:true,exact:false,message:a.minLength.message}),s.dirty()),a.maxLength!==null&&t.data.length>a.maxLength.value&&(d(t,{code:c.too_big,maximum:a.maxLength.value,type:"array",inclusive:true,exact:false,message:a.maxLength.message}),s.dirty()),t.common.async)return Promise.all([...t.data].map((i,o)=>a.type._parseAsync(new O(t,i,t.path,o)))).then(i=>x.mergeArray(s,i));let n=[...t.data].map((i,o)=>a.type._parseSync(new O(t,i,t.path,o)));return x.mergeArray(s,n)}get element(){return this._def.type}min(e,t){return new r({...this._def,minLength:{value:e,message:h$1.toString(t)}})}max(e,t){return new r({...this._def,maxLength:{value:e,message:h$1.toString(t)}})}length(e,t){return new r({...this._def,exactLength:{value:e,message:h$1.toString(t)}})}nonempty(e){return this.min(1,e)}};$.create=(r,e)=>new $({type:r,minLength:null,maxLength:null,exactLength:null,typeName:m.ZodArray,...y$1(e)});function ae(r){if(r instanceof w){let e={};for(let t in r.shape){let s=r.shape[t];e[t]=C.create(ae(s));}return new w({...r._def,shape:()=>e})}else return r instanceof $?new $({...r._def,type:ae(r.element)}):r instanceof C?C.create(ae(r.unwrap())):r instanceof j?j.create(ae(r.unwrap())):r instanceof N?N.create(r.items.map(e=>ae(e))):r}var w=class r extends _{constructor(){super(...arguments),this._cached=null,this.nonstrict=this.passthrough,this.augment=this.extend;}_getCached(){if(this._cached!==null)return this._cached;let e=this._def.shape(),t=g.objectKeys(e);return this._cached={shape:e,keys:t},this._cached}_parse(e){if(this._getType(e)!==u.object){let l=this._getOrReturnCtx(e);return d(l,{code:c.invalid_type,expected:u.object,received:l.parsedType}),p}let{status:s,ctx:a}=this._processInputParams(e),{shape:n,keys:i}=this._getCached(),o=[];if(!(this._def.catchall instanceof A&&this._def.unknownKeys==="strip"))for(let l in a.data)i.includes(l)||o.push(l);let f=[];for(let l of i){let v=n[l],T=a.data[l];f.push({key:{status:"valid",value:l},value:v._parse(new O(a,T,a.path,l)),alwaysSet:l in a.data});}if(this._def.catchall instanceof A){let l=this._def.unknownKeys;if(l==="passthrough")for(let v of o)f.push({key:{status:"valid",value:v},value:{status:"valid",value:a.data[v]}});else if(l==="strict")o.length>0&&(d(a,{code:c.unrecognized_keys,keys:o}),s.dirty());else if(l!=="strip")throw new Error("Internal ZodObject error: invalid unknownKeys value.")}else {let l=this._def.catchall;for(let v of o){let T=a.data[v];f.push({key:{status:"valid",value:v},value:l._parse(new O(a,T,a.path,v)),alwaysSet:v in a.data});}}return a.common.async?Promise.resolve().then(async()=>{let l=[];for(let v of f){let T=await v.key,be=await v.value;l.push({key:T,value:be,alwaysSet:v.alwaysSet});}return l}).then(l=>x.mergeObjectSync(s,l)):x.mergeObjectSync(s,f)}get shape(){return this._def.shape()}strict(e){return h$1.errToObj,new r({...this._def,unknownKeys:"strict",...e!==void 0?{errorMap:(t,s)=>{let a=this._def.errorMap?.(t,s).message??s.defaultError;return t.code==="unrecognized_keys"?{message:h$1.errToObj(e).message??a}:{message:a}}}:{}})}strip(){return new r({...this._def,unknownKeys:"strip"})}passthrough(){return new r({...this._def,unknownKeys:"passthrough"})}extend(e){return new r({...this._def,shape:()=>({...this._def.shape(),...e})})}merge(e){return new r({unknownKeys:e._def.unknownKeys,catchall:e._def.catchall,shape:()=>({...this._def.shape(),...e._def.shape()}),typeName:m.ZodObject})}setKey(e,t){return this.augment({[e]:t})}catchall(e){return new r({...this._def,catchall:e})}pick(e){let t={};for(let s of g.objectKeys(e))e[s]&&this.shape[s]&&(t[s]=this.shape[s]);return new r({...this._def,shape:()=>t})}omit(e){let t={};for(let s of g.objectKeys(this.shape))e[s]||(t[s]=this.shape[s]);return new r({...this._def,shape:()=>t})}deepPartial(){return ae(this)}partial(e){let t={};for(let s of g.objectKeys(this.shape)){let a=this.shape[s];e&&!e[s]?t[s]=a:t[s]=a.optional();}return new r({...this._def,shape:()=>t})}required(e){let t={};for(let s of g.objectKeys(this.shape))if(e&&!e[s])t[s]=this.shape[s];else {let n=this.shape[s];for(;n instanceof C;)n=n._def.innerType;t[s]=n;}return new r({...this._def,shape:()=>t})}keyof(){return Re(g.objectKeys(this.shape))}};w.create=(r,e)=>new w({shape:()=>r,unknownKeys:"strip",catchall:A.create(),typeName:m.ZodObject,...y$1(e)});w.strictCreate=(r,e)=>new w({shape:()=>r,unknownKeys:"strict",catchall:A.create(),typeName:m.ZodObject,...y$1(e)});w.lazycreate=(r,e)=>new w({shape:r,unknownKeys:"strip",catchall:A.create(),typeName:m.ZodObject,...y$1(e)});var J=class extends _{_parse(e){let{ctx:t}=this._processInputParams(e),s=this._def.options;function a(n){for(let o of n)if(o.result.status==="valid")return o.result;for(let o of n)if(o.result.status==="dirty")return t.common.issues.push(...o.ctx.common.issues),o.result;let i=n.map(o=>new b(o.ctx.common.issues));return d(t,{code:c.invalid_union,unionErrors:i}),p}if(t.common.async)return Promise.all(s.map(async n=>{let i={...t,common:{...t.common,issues:[]},parent:null};return {result:await n._parseAsync({data:t.data,path:t.path,parent:i}),ctx:i}})).then(a);{let n,i=[];for(let f of s){let l={...t,common:{...t.common,issues:[]},parent:null},v=f._parseSync({data:t.data,path:t.path,parent:l});if(v.status==="valid")return v;v.status==="dirty"&&!n&&(n={result:v,ctx:l}),l.common.issues.length&&i.push(l.common.issues);}if(n)return t.common.issues.push(...n.ctx.common.issues),n.result;let o=i.map(f=>new b(f));return d(t,{code:c.invalid_union,unionErrors:o}),p}}get options(){return this._def.options}};J.create=(r,e)=>new J({options:r,typeName:m.ZodUnion,...y$1(e)});var E=r=>r instanceof H?E(r.schema):r instanceof S?E(r.innerType()):r instanceof G?[r.value]:r instanceof Q?r.options:r instanceof X?g.objectValues(r.enum):r instanceof K?E(r._def.innerType):r instanceof W?[void 0]:r instanceof q?[null]:r instanceof C?[void 0,...E(r.unwrap())]:r instanceof j?[null,...E(r.unwrap())]:r instanceof le||r instanceof te?E(r.unwrap()):r instanceof ee?E(r._def.innerType):[],me=class r extends _{_parse(e){let{ctx:t}=this._processInputParams(e);if(t.parsedType!==u.object)return d(t,{code:c.invalid_type,expected:u.object,received:t.parsedType}),p;let s=this.discriminator,a=t.data[s],n=this.optionsMap.get(a);return n?t.common.async?n._parseAsync({data:t.data,path:t.path,parent:t}):n._parseSync({data:t.data,path:t.path,parent:t}):(d(t,{code:c.invalid_union_discriminator,options:Array.from(this.optionsMap.keys()),path:[s]}),p)}get discriminator(){return this._def.discriminator}get options(){return this._def.options}get optionsMap(){return this._def.optionsMap}static create(e,t,s){let a=new Map;for(let n of t){let i=E(n.shape[e]);if(!i.length)throw new Error(`A discriminator value for key \`${e}\` could not be extracted from all schema options`);for(let o of i){if(a.has(o))throw new Error(`Discriminator property ${String(e)} has duplicate value ${String(o)}`);a.set(o,n);}}return new r({typeName:m.ZodDiscriminatedUnion,discriminator:e,options:t,optionsMap:a,...y$1(s)})}};function ke(r,e){let t=R(r),s=R(e);if(r===e)return {valid:true,data:r};if(t===u.object&&s===u.object){let a=g.objectKeys(e),n=g.objectKeys(r).filter(o=>a.indexOf(o)!==-1),i={...r,...e};for(let o of n){let f=ke(r[o],e[o]);if(!f.valid)return {valid:false};i[o]=f.data;}return {valid:true,data:i}}else if(t===u.array&&s===u.array){if(r.length!==e.length)return {valid:false};let a=[];for(let n=0;n<r.length;n++){let i=r[n],o=e[n],f=ke(i,o);if(!f.valid)return {valid:false};a.push(f.data);}return {valid:true,data:a}}else return t===u.date&&s===u.date&&+r==+e?{valid:true,data:r}:{valid:false}}var Y=class extends _{_parse(e){let{status:t,ctx:s}=this._processInputParams(e),a=(n,i)=>{if(he(n)||he(i))return p;let o=ke(n.value,i.value);return o.valid?((pe(n)||pe(i))&&t.dirty(),{status:t.value,value:o.data}):(d(s,{code:c.invalid_intersection_types}),p)};return s.common.async?Promise.all([this._def.left._parseAsync({data:s.data,path:s.path,parent:s}),this._def.right._parseAsync({data:s.data,path:s.path,parent:s})]).then(([n,i])=>a(n,i)):a(this._def.left._parseSync({data:s.data,path:s.path,parent:s}),this._def.right._parseSync({data:s.data,path:s.path,parent:s}))}};Y.create=(r,e,t)=>new Y({left:r,right:e,typeName:m.ZodIntersection,...y$1(t)});var N=class r extends _{_parse(e){let{status:t,ctx:s}=this._processInputParams(e);if(s.parsedType!==u.array)return d(s,{code:c.invalid_type,expected:u.array,received:s.parsedType}),p;if(s.data.length<this._def.items.length)return d(s,{code:c.too_small,minimum:this._def.items.length,inclusive:true,exact:false,type:"array"}),p;!this._def.rest&&s.data.length>this._def.items.length&&(d(s,{code:c.too_big,maximum:this._def.items.length,inclusive:true,exact:false,type:"array"}),t.dirty());let n=[...s.data].map((i,o)=>{let f=this._def.items[o]||this._def.rest;return f?f._parse(new O(s,i,s.path,o)):null}).filter(i=>!!i);return s.common.async?Promise.all(n).then(i=>x.mergeArray(t,i)):x.mergeArray(t,n)}get items(){return this._def.items}rest(e){return new r({...this._def,rest:e})}};N.create=(r,e)=>{if(!Array.isArray(r))throw new Error("You must pass an array of schemas to z.tuple([ ... ])");return new N({items:r,typeName:m.ZodTuple,rest:null,...y$1(e)})};var ye=class r extends _{get keySchema(){return this._def.keyType}get valueSchema(){return this._def.valueType}_parse(e){let{status:t,ctx:s}=this._processInputParams(e);if(s.parsedType!==u.object)return d(s,{code:c.invalid_type,expected:u.object,received:s.parsedType}),p;let a=[],n=this._def.keyType,i=this._def.valueType;for(let o in s.data)a.push({key:n._parse(new O(s,o,s.path,o)),value:i._parse(new O(s,s.data[o],s.path,o)),alwaysSet:o in s.data});return s.common.async?x.mergeObjectAsync(t,a):x.mergeObjectSync(t,a)}get element(){return this._def.valueType}static create(e,t,s){return t instanceof _?new r({keyType:e,valueType:t,typeName:m.ZodRecord,...y$1(s)}):new r({keyType:V.create(),valueType:e,typeName:m.ZodRecord,...y$1(t)})}},oe=class extends _{get keySchema(){return this._def.keyType}get valueSchema(){return this._def.valueType}_parse(e){let{status:t,ctx:s}=this._processInputParams(e);if(s.parsedType!==u.map)return d(s,{code:c.invalid_type,expected:u.map,received:s.parsedType}),p;let a=this._def.keyType,n=this._def.valueType,i=[...s.data.entries()].map(([o,f],l)=>({key:a._parse(new O(s,o,s.path,[l,"key"])),value:n._parse(new O(s,f,s.path,[l,"value"]))}));if(s.common.async){let o=new Map;return Promise.resolve().then(async()=>{for(let f of i){let l=await f.key,v=await f.value;if(l.status==="aborted"||v.status==="aborted")return p;(l.status==="dirty"||v.status==="dirty")&&t.dirty(),o.set(l.value,v.value);}return {status:t.value,value:o}})}else {let o=new Map;for(let f of i){let l=f.key,v=f.value;if(l.status==="aborted"||v.status==="aborted")return p;(l.status==="dirty"||v.status==="dirty")&&t.dirty(),o.set(l.value,v.value);}return {status:t.value,value:o}}}};oe.create=(r,e,t)=>new oe({valueType:e,keyType:r,typeName:m.ZodMap,...y$1(t)});var ce=class r extends _{_parse(e){let{status:t,ctx:s}=this._processInputParams(e);if(s.parsedType!==u.set)return d(s,{code:c.invalid_type,expected:u.set,received:s.parsedType}),p;let a=this._def;a.minSize!==null&&s.data.size<a.minSize.value&&(d(s,{code:c.too_small,minimum:a.minSize.value,type:"set",inclusive:true,exact:false,message:a.minSize.message}),t.dirty()),a.maxSize!==null&&s.data.size>a.maxSize.value&&(d(s,{code:c.too_big,maximum:a.maxSize.value,type:"set",inclusive:true,exact:false,message:a.maxSize.message}),t.dirty());let n=this._def.valueType;function i(f){let l=new Set;for(let v of f){if(v.status==="aborted")return p;v.status==="dirty"&&t.dirty(),l.add(v.value);}return {status:t.value,value:l}}let o=[...s.data.values()].map((f,l)=>n._parse(new O(s,f,s.path,l)));return s.common.async?Promise.all(o).then(f=>i(f)):i(o)}min(e,t){return new r({...this._def,minSize:{value:e,message:h$1.toString(t)}})}max(e,t){return new r({...this._def,maxSize:{value:e,message:h$1.toString(t)}})}size(e,t){return this.min(e,t).max(e,t)}nonempty(e){return this.min(1,e)}};ce.create=(r,e)=>new ce({valueType:r,minSize:null,maxSize:null,typeName:m.ZodSet,...y$1(e)});var _e=class r extends _{constructor(){super(...arguments),this.validate=this.implement;}_parse(e){let{ctx:t}=this._processInputParams(e);if(t.parsedType!==u.function)return d(t,{code:c.invalid_type,expected:u.function,received:t.parsedType}),p;function s(o,f){return ue({data:o,path:t.path,errorMaps:[t.common.contextualErrorMap,t.schemaErrorMap,re(),I].filter(l=>!!l),issueData:{code:c.invalid_arguments,argumentsError:f}})}function a(o,f){return ue({data:o,path:t.path,errorMaps:[t.common.contextualErrorMap,t.schemaErrorMap,re(),I].filter(l=>!!l),issueData:{code:c.invalid_return_type,returnTypeError:f}})}let n={errorMap:t.common.contextualErrorMap},i=t.data;if(this._def.returns instanceof z){let o=this;return k(async function(...f){let l=new b([]),v=await o._def.args.parseAsync(f,n).catch(ge=>{throw l.addIssue(s(f,ge)),l}),T=await Reflect.apply(i,this,v);return await o._def.returns._def.type.parseAsync(T,n).catch(ge=>{throw l.addIssue(a(T,ge)),l})})}else {let o=this;return k(function(...f){let l=o._def.args.safeParse(f,n);if(!l.success)throw new b([s(f,l.error)]);let v=Reflect.apply(i,this,l.data),T=o._def.returns.safeParse(v,n);if(!T.success)throw new b([a(v,T.error)]);return T.data})}}parameters(){return this._def.args}returnType(){return this._def.returns}args(...e){return new r({...this._def,args:N.create(e).rest(Z.create())})}returns(e){return new r({...this._def,returns:e})}implement(e){return this.parse(e)}strictImplement(e){return this.parse(e)}static create(e,t,s){return new r({args:e||N.create([]).rest(Z.create()),returns:t||Z.create(),typeName:m.ZodFunction,...y$1(s)})}},H=class extends _{get schema(){return this._def.getter()}_parse(e){let{ctx:t}=this._processInputParams(e);return this._def.getter()._parse({data:t.data,path:t.path,parent:t})}};H.create=(r,e)=>new H({getter:r,typeName:m.ZodLazy,...y$1(e)});var G=class extends _{_parse(e){if(e.data!==this._def.value){let t=this._getOrReturnCtx(e);return d(t,{received:t.data,code:c.invalid_literal,expected:this._def.value}),p}return {status:"valid",value:e.data}}get value(){return this._def.value}};G.create=(r,e)=>new G({value:r,typeName:m.ZodLiteral,...y$1(e)});function Re(r,e){return new Q({values:r,typeName:m.ZodEnum,...y$1(e)})}var Q=class r extends _{_parse(e){if(typeof e.data!="string"){let t=this._getOrReturnCtx(e),s=this._def.values;return d(t,{expected:g.joinValues(s),received:t.parsedType,code:c.invalid_type}),p}if(this._cache||(this._cache=new Set(this._def.values)),!this._cache.has(e.data)){let t=this._getOrReturnCtx(e),s=this._def.values;return d(t,{received:t.data,code:c.invalid_enum_value,options:s}),p}return k(e.data)}get options(){return this._def.values}get enum(){let e={};for(let t of this._def.values)e[t]=t;return e}get Values(){let e={};for(let t of this._def.values)e[t]=t;return e}get Enum(){let e={};for(let t of this._def.values)e[t]=t;return e}extract(e,t=this._def){return r.create(e,{...this._def,...t})}exclude(e,t=this._def){return r.create(this.options.filter(s=>!e.includes(s)),{...this._def,...t})}};Q.create=Re;var X=class extends _{_parse(e){let t=g.getValidEnumValues(this._def.values),s=this._getOrReturnCtx(e);if(s.parsedType!==u.string&&s.parsedType!==u.number){let a=g.objectValues(t);return d(s,{expected:g.joinValues(a),received:s.parsedType,code:c.invalid_type}),p}if(this._cache||(this._cache=new Set(g.getValidEnumValues(this._def.values))),!this._cache.has(e.data)){let a=g.objectValues(t);return d(s,{received:s.data,code:c.invalid_enum_value,options:a}),p}return k(e.data)}get enum(){return this._def.values}};X.create=(r,e)=>new X({values:r,typeName:m.ZodNativeEnum,...y$1(e)});var z=class extends _{unwrap(){return this._def.type}_parse(e){let{ctx:t}=this._processInputParams(e);if(t.parsedType!==u.promise&&t.common.async===false)return d(t,{code:c.invalid_type,expected:u.promise,received:t.parsedType}),p;let s=t.parsedType===u.promise?t.data:Promise.resolve(t.data);return k(s.then(a=>this._def.type.parseAsync(a,{path:t.path,errorMap:t.common.contextualErrorMap})))}};z.create=(r,e)=>new z({type:r,typeName:m.ZodPromise,...y$1(e)});var S=class extends _{innerType(){return this._def.schema}sourceType(){return this._def.schema._def.typeName===m.ZodEffects?this._def.schema.sourceType():this._def.schema}_parse(e){let{status:t,ctx:s}=this._processInputParams(e),a=this._def.effect||null,n={addIssue:i=>{d(s,i),i.fatal?t.abort():t.dirty();},get path(){return s.path}};if(n.addIssue=n.addIssue.bind(n),a.type==="preprocess"){let i=a.transform(s.data,n);if(s.common.async)return Promise.resolve(i).then(async o=>{if(t.value==="aborted")return p;let f=await this._def.schema._parseAsync({data:o,path:s.path,parent:s});return f.status==="aborted"?p:f.status==="dirty"?D(f.value):t.value==="dirty"?D(f.value):f});{if(t.value==="aborted")return p;let o=this._def.schema._parseSync({data:i,path:s.path,parent:s});return o.status==="aborted"?p:o.status==="dirty"?D(o.value):t.value==="dirty"?D(o.value):o}}if(a.type==="refinement"){let i=o=>{let f=a.refinement(o,n);if(s.common.async)return Promise.resolve(f);if(f instanceof Promise)throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.");return o};if(s.common.async===false){let o=this._def.schema._parseSync({data:s.data,path:s.path,parent:s});return o.status==="aborted"?p:(o.status==="dirty"&&t.dirty(),i(o.value),{status:t.value,value:o.value})}else return this._def.schema._parseAsync({data:s.data,path:s.path,parent:s}).then(o=>o.status==="aborted"?p:(o.status==="dirty"&&t.dirty(),i(o.value).then(()=>({status:t.value,value:o.value}))))}if(a.type==="transform")if(s.common.async===false){let i=this._def.schema._parseSync({data:s.data,path:s.path,parent:s});if(!M(i))return p;let o=a.transform(i.value,n);if(o instanceof Promise)throw new Error("Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.");return {status:t.value,value:o}}else return this._def.schema._parseAsync({data:s.data,path:s.path,parent:s}).then(i=>M(i)?Promise.resolve(a.transform(i.value,n)).then(o=>({status:t.value,value:o})):p);g.assertNever(a);}};S.create=(r,e,t)=>new S({schema:r,typeName:m.ZodEffects,effect:e,...y$1(t)});S.createWithPreprocess=(r,e,t)=>new S({schema:e,effect:{type:"preprocess",transform:r},typeName:m.ZodEffects,...y$1(t)});var C=class extends _{_parse(e){return this._getType(e)===u.undefined?k(void 0):this._def.innerType._parse(e)}unwrap(){return this._def.innerType}};C.create=(r,e)=>new C({innerType:r,typeName:m.ZodOptional,...y$1(e)});var j=class extends _{_parse(e){return this._getType(e)===u.null?k(null):this._def.innerType._parse(e)}unwrap(){return this._def.innerType}};j.create=(r,e)=>new j({innerType:r,typeName:m.ZodNullable,...y$1(e)});var K=class extends _{_parse(e){let{ctx:t}=this._processInputParams(e),s=t.data;return t.parsedType===u.undefined&&(s=this._def.defaultValue()),this._def.innerType._parse({data:s,path:t.path,parent:t})}removeDefault(){return this._def.innerType}};K.create=(r,e)=>new K({innerType:r,typeName:m.ZodDefault,defaultValue:typeof e.default=="function"?e.default:()=>e.default,...y$1(e)});var ee=class extends _{_parse(e){let{ctx:t}=this._processInputParams(e),s={...t,common:{...t.common,issues:[]}},a=this._def.innerType._parse({data:s.data,path:s.path,parent:{...s}});return se(a)?a.then(n=>({status:"valid",value:n.status==="valid"?n.value:this._def.catchValue({get error(){return new b(s.common.issues)},input:s.data})})):{status:"valid",value:a.status==="valid"?a.value:this._def.catchValue({get error(){return new b(s.common.issues)},input:s.data})}}removeCatch(){return this._def.innerType}};ee.create=(r,e)=>new ee({innerType:r,typeName:m.ZodCatch,catchValue:typeof e.catch=="function"?e.catch:()=>e.catch,...y$1(e)});var de=class extends _{_parse(e){if(this._getType(e)!==u.nan){let s=this._getOrReturnCtx(e);return d(s,{code:c.invalid_type,expected:u.nan,received:s.parsedType}),p}return {status:"valid",value:e.data}}};de.create=r=>new de({typeName:m.ZodNaN,...y$1(r)});var ot=Symbol("zod_brand"),le=class extends _{_parse(e){let{ctx:t}=this._processInputParams(e),s=t.data;return this._def.type._parse({data:s,path:t.path,parent:t})}unwrap(){return this._def.type}},fe=class r extends _{_parse(e){let{status:t,ctx:s}=this._processInputParams(e);if(s.common.async)return (async()=>{let n=await this._def.in._parseAsync({data:s.data,path:s.path,parent:s});return n.status==="aborted"?p:n.status==="dirty"?(t.dirty(),D(n.value)):this._def.out._parseAsync({data:n.value,path:s.path,parent:s})})();{let a=this._def.in._parseSync({data:s.data,path:s.path,parent:s});return a.status==="aborted"?p:a.status==="dirty"?(t.dirty(),{status:"dirty",value:a.value}):this._def.out._parseSync({data:a.value,path:s.path,parent:s})}}static create(e,t){return new r({in:e,out:t,typeName:m.ZodPipeline})}},te=class extends _{_parse(e){let t=this._def.innerType._parse(e),s=a=>(M(a)&&(a.value=Object.freeze(a.value)),a);return se(t)?t.then(a=>s(a)):s(t)}unwrap(){return this._def.innerType}};te.create=(r,e)=>new te({innerType:r,typeName:m.ZodReadonly,...y$1(e)});function Ce(r,e){let t=typeof r=="function"?r(e):typeof r=="string"?{message:r}:r;return typeof t=="string"?{message:t}:t}function Ne(r,e={},t){return r?P.create().superRefine((s,a)=>{let n=r(s);if(n instanceof Promise)return n.then(i=>{if(!i){let o=Ce(e,s),f=o.fatal??t??true;a.addIssue({code:"custom",...o,fatal:f});}});if(!n){let i=Ce(e,s),o=i.fatal??t??true;a.addIssue({code:"custom",...i,fatal:o});}}):P.create()}var ct={object:w.lazycreate},m;(function(r){r.ZodString="ZodString",r.ZodNumber="ZodNumber",r.ZodNaN="ZodNaN",r.ZodBigInt="ZodBigInt",r.ZodBoolean="ZodBoolean",r.ZodDate="ZodDate",r.ZodSymbol="ZodSymbol",r.ZodUndefined="ZodUndefined",r.ZodNull="ZodNull",r.ZodAny="ZodAny",r.ZodUnknown="ZodUnknown",r.ZodNever="ZodNever",r.ZodVoid="ZodVoid",r.ZodArray="ZodArray",r.ZodObject="ZodObject",r.ZodUnion="ZodUnion",r.ZodDiscriminatedUnion="ZodDiscriminatedUnion",r.ZodIntersection="ZodIntersection",r.ZodTuple="ZodTuple",r.ZodRecord="ZodRecord",r.ZodMap="ZodMap",r.ZodSet="ZodSet",r.ZodFunction="ZodFunction",r.ZodLazy="ZodLazy",r.ZodLiteral="ZodLiteral",r.ZodEnum="ZodEnum",r.ZodEffects="ZodEffects",r.ZodNativeEnum="ZodNativeEnum",r.ZodOptional="ZodOptional",r.ZodNullable="ZodNullable",r.ZodDefault="ZodDefault",r.ZodCatch="ZodCatch",r.ZodPromise="ZodPromise",r.ZodBranded="ZodBranded",r.ZodPipeline="ZodPipeline",r.ZodReadonly="ZodReadonly";})(m||(m={}));var dt=(r,e={message:`Input not instance of ${r.name}`})=>Ne(t=>t instanceof r,e),je=V.create,Ie=L.create,ut=de.create,lt=U.create,Ee=F.create,ft=B.create,ht=ne.create,pt=W.create,mt=q.create,yt=P.create,_t=Z.create,gt=A.create,vt=ie.create,xt=$.create,kt=w.create,bt=w.strictCreate,wt=J.create,Tt=me.create,Ct=Y.create,Ot=N.create,St=ye.create,At=oe.create,Rt=ce.create,Nt=_e.create,jt=H.create,It=G.create,Et=Q.create,Zt=X.create,$t=z.create,Mt=S.create,Vt=C.create,Pt=j.create,zt=S.createWithPreprocess,Dt=fe.create,Lt=()=>je().optional(),Ut=()=>Ie().optional(),Ft=()=>Ee().optional(),Bt={string:(r=>V.create({...r,coerce:true})),number:(r=>L.create({...r,coerce:true})),boolean:(r=>F.create({...r,coerce:true})),bigint:(r=>U.create({...r,coerce:true})),date:(r=>B.create({...r,coerce:true}))};var Wt=p;var Ze={};e$1(Ze,{BRAND:()=>ot,DIRTY:()=>D,EMPTY_PATH:()=>ze,INVALID:()=>p,NEVER:()=>Wt,OK:()=>k,ParseStatus:()=>x,Schema:()=>_,ZodAny:()=>P,ZodArray:()=>$,ZodBigInt:()=>U,ZodBoolean:()=>F,ZodBranded:()=>le,ZodCatch:()=>ee,ZodDate:()=>B,ZodDefault:()=>K,ZodDiscriminatedUnion:()=>me,ZodEffects:()=>S,ZodEnum:()=>Q,ZodError:()=>b,ZodFirstPartyTypeKind:()=>m,ZodFunction:()=>_e,ZodIntersection:()=>Y,ZodIssueCode:()=>c,ZodLazy:()=>H,ZodLiteral:()=>G,ZodMap:()=>oe,ZodNaN:()=>de,ZodNativeEnum:()=>X,ZodNever:()=>A,ZodNull:()=>q,ZodNullable:()=>j,ZodNumber:()=>L,ZodObject:()=>w,ZodOptional:()=>C,ZodParsedType:()=>u,ZodPipeline:()=>fe,ZodPromise:()=>z,ZodReadonly:()=>te,ZodRecord:()=>ye,ZodSchema:()=>_,ZodSet:()=>ce,ZodString:()=>V,ZodSymbol:()=>ne,ZodTransformer:()=>S,ZodTuple:()=>N,ZodType:()=>_,ZodUndefined:()=>W,ZodUnion:()=>J,ZodUnknown:()=>Z,ZodVoid:()=>ie,addIssueToContext:()=>d,any:()=>yt,array:()=>xt,bigint:()=>lt,boolean:()=>Ee,coerce:()=>Bt,custom:()=>Ne,date:()=>ft,datetimeRegex:()=>Ae,defaultErrorMap:()=>I,discriminatedUnion:()=>Tt,effect:()=>Mt,enum:()=>Et,function:()=>Nt,getErrorMap:()=>re,getParsedType:()=>R,instanceof:()=>dt,intersection:()=>Ct,isAborted:()=>he,isAsync:()=>se,isDirty:()=>pe,isValid:()=>M,late:()=>ct,lazy:()=>jt,literal:()=>It,makeIssue:()=>ue,map:()=>At,nan:()=>ut,nativeEnum:()=>Zt,never:()=>gt,null:()=>mt,nullable:()=>Pt,number:()=>Ie,object:()=>kt,objectUtil:()=>ve,oboolean:()=>Ft,onumber:()=>Ut,optional:()=>Vt,ostring:()=>Lt,pipeline:()=>Dt,preprocess:()=>zt,promise:()=>$t,quotelessJson:()=>Me,record:()=>St,set:()=>Rt,setErrorMap:()=>Pe,strictObject:()=>bt,string:()=>je,symbol:()=>ht,transformer:()=>Mt,tuple:()=>Ot,undefined:()=>pt,union:()=>wt,unknown:()=>_t,util:()=>g,void:()=>vt});
|
|
7
|
+
|
|
8
|
+
Ze.object({sessionId:Ze.string().uuid()});Ze.object({platformId:Ze.string(),sourceId:Ze.string(),isFullApi:Ze.boolean().optional().default(false),timeOffset:Ze.number().default(0)});var o=Ze.object({uuid:Ze.string(),name:Ze.string(),notificationTopic:Ze.string().optional(),eventTopic:Ze.string().optional()});Ze.object({sessionId:Ze.string(),orgId:Ze.string(),userId:Ze.string(),platformId:Ze.string(),sourceId:Ze.string(),groups:Ze.array(o),mqtt:Ze.object({sessionRootTopic:Ze.string(),userNotificationEventsTopic:Ze.string(),allNotificationEventsTopic:Ze.string().optional(),notificationsRootTopic:Ze.string(),lastWillTopic:Ze.string(),url:Ze.string(),token:Ze.string(),userNotificationTopic:Ze.string(),localSessionExpiryHandling:Ze.boolean()}).optional()}).strict();Ze.object({title:Ze.string().optional(),date:Ze.number().optional(),appId:Ze.string().optional(),stream:Ze.object({appId:Ze.string().optional()}).optional()}).passthrough();var e=Ze.object({groups:Ze.array(Ze.string()).default([]),users:Ze.array(Ze.string().min(1).max(255).regex(/^[\w+.@-]+$/)).default([])});Ze.object({action:Ze.literal("forward"),actionData:Ze.object({id:Ze.string().min(1),forwardTargets:e})});Ze.object({forwardActionId:Ze.string().min(1)});var i=Ze.enum(["new","update","delete"]),n=Ze.object({correlationId:Ze.string().optional(),targets:e,ttlSeconds:Ze.number().optional(),notificationClass:Ze.string().default("interactive").optional(),payload:Ze.unknown()});Ze.object({sessionId:Ze.string().uuid(),timeOffset:Ze.number(),notification:n});Ze.object({sessionId:Ze.string().uuid(),timeOffset:Ze.number().optional().default(0),ttlSeconds:Ze.number().optional(),payload:Ze.unknown()});var a=Ze.enum(["users","groups"]),y=Ze.object({notificationId:Ze.string().uuid(),category:Ze.string(),type:Ze.string(),sourceId:Ze.string(),originatingSessionId:Ze.string().uuid(),platformId:Ze.string(),userId:Ze.string().uuid(),userName:Ze.string().optional(),payload:Ze.unknown().optional(),correlationId:Ze.string().optional()}),h=Ze.object({action:i,notificationId:Ze.string().uuid(),originatingSessionId:Ze.string().uuid(),correlationId:Ze.string().optional(),target:Ze.string(),targetType:a,payload:Ze.unknown(),txInstanceId:Ze.string().uuid()}),r=Ze.object({category:Ze.string(),type:Ze.string(),payload:Ze.unknown().optional()});Ze.object({sessionId:Ze.string().uuid(),timeOffset:Ze.number().optional().default(0),event:r,targets:e.nullable().optional()});Ze.object({userId:Ze.string().uuid(),platformId:Ze.string(),sourceId:Ze.string(),notificationId:Ze.string().uuid(),category:Ze.string(),type:Ze.string(),sessionId:Ze.string().uuid(),payload:Ze.unknown().optional(),timestamp:Ze.date(),cursor:Ze.string().base64(),correlationId:Ze.string().nullish(),targets:e.optional()});
|
|
9
|
+
|
|
10
|
+
var l=t=>{let e=t.replaceAll("-","+").replaceAll("_","/");return e.padEnd(e.length+(4-e.length%4)%4,"=")};
|
|
11
|
+
|
|
5
12
|
class CloudNotificationAPIError extends Error {
|
|
6
13
|
code;
|
|
7
14
|
constructor(message = 'An unexpected error has occurred', code = 'UNEXPECTED_ERROR', cause) {
|
|
@@ -21,7 +28,12 @@ class SessionNotConnectedError extends CloudNotificationAPIError {
|
|
|
21
28
|
}
|
|
22
29
|
}
|
|
23
30
|
class PublishError extends CloudNotificationAPIError {
|
|
24
|
-
constructor(message = '
|
|
31
|
+
constructor(message = 'Error publishing notification', code = 'ERR_PUBLISH_ERROR', cause) {
|
|
32
|
+
super(message, code, cause);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
class EventPublishError extends CloudNotificationAPIError {
|
|
36
|
+
constructor(message = 'Error posting notification event', code = 'ERR_EVENT_PUBLISH_ERROR', cause) {
|
|
25
37
|
super(message, code, cause);
|
|
26
38
|
}
|
|
27
39
|
}
|
|
@@ -30,12 +42,20 @@ class EventRetrievalError extends CloudNotificationAPIError {
|
|
|
30
42
|
super(message, code, cause);
|
|
31
43
|
}
|
|
32
44
|
}
|
|
45
|
+
class NotificationRetrievalError extends CloudNotificationAPIError {
|
|
46
|
+
constructor(message = 'Notification Retrieval error', code = 'ERR_NOTIFICATION_RETRIEVAL_ERROR', cause) {
|
|
47
|
+
super(message, code, cause);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
33
50
|
class InvalidMessageFormatError extends CloudNotificationAPIError {
|
|
34
51
|
constructor(zodParseResult) {
|
|
35
52
|
super(`Message Format Error: ${zodParseResult.error?.toString()}`, 'ERR_MESSAGE_FORMAT_ERROR', undefined);
|
|
36
53
|
}
|
|
37
54
|
}
|
|
38
55
|
|
|
56
|
+
// Error codes as defined in https://docs.emqx.com/en/cloud/latest/connect_to_deployments/mqtt_client_error_codes.html
|
|
57
|
+
const BadUserNamePasswordError = 134;
|
|
58
|
+
|
|
39
59
|
class EventController {
|
|
40
60
|
#eventListeners = new Map();
|
|
41
61
|
addEventListener(type, callback) {
|
|
@@ -65,6 +85,41 @@ class EventController {
|
|
|
65
85
|
}
|
|
66
86
|
}
|
|
67
87
|
|
|
88
|
+
function validateConnectParameters(parameters) {
|
|
89
|
+
if (!parameters) {
|
|
90
|
+
throw new Error('Connect parameters must be provided');
|
|
91
|
+
}
|
|
92
|
+
if (!parameters.platformId) {
|
|
93
|
+
throw new Error('platformId must be provided');
|
|
94
|
+
}
|
|
95
|
+
if (parameters.authenticationType === 'jwt' &&
|
|
96
|
+
(!parameters.jwtAuthenticationParameters?.jwtRequestCallback || !parameters.jwtAuthenticationParameters?.authenticationId)) {
|
|
97
|
+
throw new Error('jwtAuthenticationParameters must be provided when using jwt authentication');
|
|
98
|
+
}
|
|
99
|
+
if (parameters.authenticationType === 'basic' &&
|
|
100
|
+
(!parameters.basicAuthenticationParameters?.username || !parameters.basicAuthenticationParameters?.password)) {
|
|
101
|
+
throw new Error('basicAuthenticationParameters must be provided when using basic authentication');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function handleAPIException(logger, error, message, exceptionConstructor) {
|
|
105
|
+
if (error instanceof Error) {
|
|
106
|
+
logger('error', `${message} - ${error.message}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
logger('error', `${message} - ${error}`);
|
|
110
|
+
}
|
|
111
|
+
throw new exceptionConstructor(undefined, undefined, error);
|
|
112
|
+
}
|
|
113
|
+
async function checkResponse(logger, response, failMessage, failCode) {
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
if (response.status === 401 || response.status === 403) {
|
|
116
|
+
throw new AuthorizationError();
|
|
117
|
+
}
|
|
118
|
+
const responseBody = await response.text();
|
|
119
|
+
logger('error', `Response check failure ${failMessage} - ${response.status}: ${response.statusText} : ${responseBody}`);
|
|
120
|
+
throw new CloudNotificationAPIError(`${failMessage} (HTTP ${response.status}: ${response.statusText})`, failCode, responseBody);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
68
123
|
function getRequestHeaders(connectionParameters) {
|
|
69
124
|
const headers = {};
|
|
70
125
|
headers['Content-Type'] = 'application/json';
|
|
@@ -144,7 +199,7 @@ class TimeDifferenceTracker {
|
|
|
144
199
|
#intervalMs;
|
|
145
200
|
#samples;
|
|
146
201
|
#connectionParams;
|
|
147
|
-
#currentOffset;
|
|
202
|
+
#currentOffset = 0;
|
|
148
203
|
#timerId;
|
|
149
204
|
#logger;
|
|
150
205
|
constructor(timeServerUrl, connectionParameters, logger, intervalMs = 60 * 60 * 1000, samples = 10) {
|
|
@@ -220,41 +275,9 @@ class TimeDifferenceTracker {
|
|
|
220
275
|
}
|
|
221
276
|
}
|
|
222
277
|
|
|
223
|
-
// Error codes as defined in https://docs.emqx.com/en/cloud/latest/connect_to_deployments/mqtt_client_error_codes.html
|
|
224
|
-
const BadUserNamePasswordError = 134;
|
|
225
|
-
const forwardedNotificationEventSchema = z.object({
|
|
226
|
-
notificationId: z.string().uuid(),
|
|
227
|
-
category: z.string(),
|
|
228
|
-
type: z.string(),
|
|
229
|
-
payload: z.unknown().optional(),
|
|
230
|
-
correlationId: z.string().optional(),
|
|
231
|
-
});
|
|
232
|
-
const forwardedMessageSchema = z.object({
|
|
233
|
-
action: z.enum(['new', 'update']),
|
|
234
|
-
notificationId: z.string().uuid(),
|
|
235
|
-
originatingSessionId: z.string().uuid(),
|
|
236
|
-
correlationId: z.string().optional(),
|
|
237
|
-
target: z.string(),
|
|
238
|
-
targetType: z.enum(['user', 'group']),
|
|
239
|
-
payload: z.unknown(),
|
|
240
|
-
});
|
|
241
|
-
const notificationEventDetailSchema = z.object({
|
|
242
|
-
userId: z.string().uuid(),
|
|
243
|
-
platformId: z.string(),
|
|
244
|
-
sourceId: z.string(),
|
|
245
|
-
notificationId: z.string().uuid(),
|
|
246
|
-
category: z.string(),
|
|
247
|
-
type: z.string(),
|
|
248
|
-
sessionId: z.string().uuid(),
|
|
249
|
-
payload: z.unknown().optional(),
|
|
250
|
-
correlationId: z.string().optional(),
|
|
251
|
-
timestamp: z.string().datetime(),
|
|
252
|
-
});
|
|
253
278
|
/**
|
|
254
|
-
* Represents a single connection to
|
|
279
|
+
* Represents a single connection to the Cloud Notification service
|
|
255
280
|
*
|
|
256
|
-
* @public
|
|
257
|
-
* @class
|
|
258
281
|
*/
|
|
259
282
|
class CloudNotificationAPI {
|
|
260
283
|
#cloudNotificationSettings;
|
|
@@ -262,177 +285,335 @@ class CloudNotificationAPI {
|
|
|
262
285
|
#mqttClient;
|
|
263
286
|
#reconnectRetryLimit = 30;
|
|
264
287
|
#keepAliveIntervalSeconds = 30;
|
|
288
|
+
#syncTime = true;
|
|
265
289
|
#timeDifferenceTracker;
|
|
266
|
-
#
|
|
267
|
-
#logger = (level, message) => {
|
|
268
|
-
console[level](message);
|
|
269
|
-
};
|
|
290
|
+
#deDuplicator;
|
|
270
291
|
#reconnectRetries = 0;
|
|
271
292
|
#connectionParams;
|
|
272
293
|
#attemptingToReconnect = false;
|
|
273
294
|
#events = new EventController();
|
|
274
295
|
#defaultSubscriptionOptions = { qos: 2, nl: true };
|
|
296
|
+
#logger = (level, message) => console[level](message);
|
|
297
|
+
#getCurrentTimeOffset = () => this.#timeDifferenceTracker?.currentOffset || 0;
|
|
298
|
+
#sessionTimer;
|
|
299
|
+
/**
|
|
300
|
+
* Constructs a new instance of the CloudNotificationAPI
|
|
301
|
+
*
|
|
302
|
+
* @param cloudNotificationSettings - The settings for the Cloud Notification API.
|
|
303
|
+
*/
|
|
275
304
|
constructor(cloudNotificationSettings) {
|
|
276
305
|
this.#cloudNotificationSettings = cloudNotificationSettings;
|
|
306
|
+
this.#deDuplicator = new SetWithTTL(cloudNotificationSettings?.deduplicationTTLms || 10_000);
|
|
307
|
+
this.#reconnectRetryLimit = cloudNotificationSettings.reconnectRetryLimit || this.#reconnectRetryLimit;
|
|
308
|
+
this.#keepAliveIntervalSeconds = cloudNotificationSettings.keepAliveIntervalSeconds || this.#keepAliveIntervalSeconds;
|
|
309
|
+
this.#logger = cloudNotificationSettings.logger || this.#logger;
|
|
310
|
+
this.#syncTime = cloudNotificationSettings.syncTime ?? true;
|
|
277
311
|
}
|
|
278
312
|
/**
|
|
279
|
-
* Connects and creates a session on the Cloud Notifications service
|
|
313
|
+
* Connects and creates a session on the Cloud Notifications service.
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```typescript
|
|
317
|
+
* const notificationApi = new CloudNotificationAPI({
|
|
318
|
+
* url: process.env.NOTIFICATION_SERVER_HOST
|
|
319
|
+
* });
|
|
280
320
|
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
321
|
+
* let connectionResult: ConnectionResult;
|
|
322
|
+
* try {
|
|
323
|
+
* connectionResult = await notificationApi.connect(connectSettings);
|
|
324
|
+
* } catch (errorConnect) {
|
|
325
|
+
* terminal.write(chalk.red(`\nError connecting to notification server: ${errorConnect}\n`));
|
|
326
|
+
* process.exit(1);
|
|
327
|
+
* }
|
|
328
|
+
* ```
|
|
329
|
+
*
|
|
330
|
+
* @param parameters - The parameters to use to connect.
|
|
331
|
+
* @returns A promise that resolves when the connection is established.
|
|
332
|
+
* @throws {@link CloudNotificationAPIError} If an error occurs during connection.
|
|
333
|
+
* @throws {@link AuthorizationError} If the connection is unauthorized.
|
|
286
334
|
*/
|
|
287
335
|
async connect(parameters) {
|
|
288
|
-
|
|
336
|
+
validateConnectParameters(parameters);
|
|
289
337
|
this.#connectionParams = parameters;
|
|
290
|
-
this.#
|
|
291
|
-
this.#keepAliveIntervalSeconds = parameters.keepAliveIntervalSeconds || this.#keepAliveIntervalSeconds;
|
|
292
|
-
this.#logger = parameters.logger || this.#logger;
|
|
338
|
+
this.#logger('info', 'Creating Notification service session');
|
|
293
339
|
if (this.#timeDifferenceTracker) {
|
|
294
340
|
this.#timeDifferenceTracker.stop();
|
|
295
341
|
this.#timeDifferenceTracker = undefined;
|
|
296
342
|
}
|
|
297
343
|
this.#timeDifferenceTracker = new TimeDifferenceTracker(this.#cloudNotificationSettings.url, parameters, this.#logger);
|
|
298
|
-
if (
|
|
344
|
+
if (this.#syncTime !== false) {
|
|
299
345
|
await this.#timeDifferenceTracker.start();
|
|
300
346
|
}
|
|
301
347
|
const { platformId, sourceId } = this.#connectionParams;
|
|
302
|
-
const timeOffset = Number.isFinite(this.#timeDifferenceTracker?.currentOffset) ? this.#timeDifferenceTracker.currentOffset : 0;
|
|
303
348
|
const createSessionResponse = await fetch(`${this.#cloudNotificationSettings.url}/api/sessions`, {
|
|
304
349
|
method: 'POST',
|
|
305
350
|
headers: getRequestHeaders(this.#connectionParams),
|
|
306
351
|
body: JSON.stringify({
|
|
307
352
|
platformId,
|
|
308
353
|
sourceId,
|
|
309
|
-
timeOffset,
|
|
354
|
+
timeOffset: this.#getCurrentTimeOffset(),
|
|
310
355
|
isFullApi: true,
|
|
311
356
|
}),
|
|
312
357
|
});
|
|
313
|
-
this.#
|
|
358
|
+
await checkResponse(this.#logger, createSessionResponse, 'Error creating session', 'ERR_CREATE_SESSION');
|
|
314
359
|
if (createSessionResponse.status !== 201) {
|
|
315
360
|
throw new CloudNotificationAPIError(`Failed to connect to the Cloud Notification service: ${this.#cloudNotificationSettings.url}`, 'ERR_CONNECT', new Error(createSessionResponse.statusText));
|
|
316
361
|
}
|
|
317
362
|
this.#sessionDetails = (await createSessionResponse.json());
|
|
363
|
+
const { mqtt: _, ...sessionDetailsWithoutMQTT } = this.#sessionDetails;
|
|
364
|
+
this.#logger('info', `Notification service session created: ${JSON.stringify(sessionDetailsWithoutMQTT, null, 2)}`);
|
|
318
365
|
// Now have the details from the server about where to connect to and a token to connect with
|
|
319
366
|
// we can go ahead and connect to the MQTT server
|
|
320
367
|
await this.#connectToMQTT();
|
|
368
|
+
// If local session expiry handling is enabled, start the session timer
|
|
369
|
+
if (this.#sessionDetails.mqtt?.localSessionExpiryHandling) {
|
|
370
|
+
this.#startSessionTimer();
|
|
371
|
+
}
|
|
321
372
|
return { sessionId: this.#sessionDetails.sessionId, platformId, sourceId, userId: this.#sessionDetails.userId, groups: this.#sessionDetails.groups };
|
|
322
373
|
}
|
|
323
374
|
/**
|
|
324
|
-
* Disconnects from the Cloud Notification service
|
|
375
|
+
* Disconnects from the Cloud Notification service.
|
|
325
376
|
*
|
|
326
|
-
* @returns
|
|
327
|
-
* @
|
|
328
|
-
* @throws {CloudNotificationAPIError} - If an error occurs during disconnection
|
|
377
|
+
* @returns A promise that resolves when disconnected.
|
|
378
|
+
* @throws {@link CloudNotificationAPIError} If an error occurs during disconnection.
|
|
329
379
|
*/
|
|
330
380
|
async disconnect() {
|
|
331
381
|
await this.#disconnect(true);
|
|
332
382
|
}
|
|
333
|
-
|
|
383
|
+
/**
|
|
384
|
+
* Posts a notification event to the Cloud Notification service.
|
|
385
|
+
*
|
|
386
|
+
* @param notificationId - The ID of the notification or an array of notification IDs.
|
|
387
|
+
* @param event - The event details, including category, type, and optional payload.
|
|
388
|
+
* @returns A promise that resolves when the event is posted.
|
|
389
|
+
* @throws {@link SessionNotConnectedError} If the session is not connected.
|
|
390
|
+
* @throws {@link PublishError} If an error occurs during publishing.
|
|
391
|
+
*/
|
|
392
|
+
async postNotificationEvent(notificationId, event, options) {
|
|
334
393
|
if (!this.#sessionDetails || !this.#connectionParams) {
|
|
335
394
|
this.#logger('error', 'Invalid Session');
|
|
336
395
|
throw new SessionNotConnectedError();
|
|
337
396
|
}
|
|
338
397
|
try {
|
|
339
|
-
const timeOffset = Number.isFinite(this.#timeDifferenceTracker?.currentOffset) ? this.#timeDifferenceTracker?.currentOffset : 0;
|
|
340
398
|
const publishPayload = {
|
|
341
399
|
sessionId: this.#sessionDetails.sessionId,
|
|
342
|
-
timeOffset,
|
|
400
|
+
timeOffset: this.#getCurrentTimeOffset(),
|
|
343
401
|
event,
|
|
402
|
+
targets: options?.targets,
|
|
344
403
|
};
|
|
345
|
-
const
|
|
404
|
+
const notificationIds = Array.isArray(notificationId) ? notificationId : [notificationId];
|
|
405
|
+
const notificationIdsString = notificationIds.join('&id=');
|
|
406
|
+
const publishResponse = await fetch(`${this.#cloudNotificationSettings.url}/api/publications/events?id=${notificationIdsString}`, {
|
|
346
407
|
method: 'POST',
|
|
347
408
|
headers: getRequestHeaders(this.#connectionParams),
|
|
348
409
|
body: JSON.stringify(publishPayload),
|
|
349
410
|
});
|
|
350
|
-
this.#
|
|
411
|
+
await checkResponse(this.#logger, publishResponse, 'Error posting notification event', 'ERR_POST_NOTIFICATION_EVENT');
|
|
351
412
|
}
|
|
352
413
|
catch (error) {
|
|
353
|
-
this.#
|
|
414
|
+
handleAPIException(this.#logger, error, 'Error posting notification event', PublishError);
|
|
354
415
|
}
|
|
355
416
|
}
|
|
356
|
-
|
|
417
|
+
/**
|
|
418
|
+
* Removes a notification from the notification center for a given set of users or user groups.
|
|
419
|
+
*
|
|
420
|
+
* @param notificationId - The ID of the notification to remove.
|
|
421
|
+
* @param targets - The targets to remove the notification from.
|
|
422
|
+
* @returns A promise that resolves when the notification is removed.
|
|
423
|
+
*/
|
|
424
|
+
async removeFromNotificationCenter(notificationId, targets) {
|
|
425
|
+
return this.postNotificationEvent(notificationId, { category: 'notification-center-event', type: 'notification-closed', payload: {} }, { targets });
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Post a notification-reminder-created event to the Cloud Notification service.
|
|
429
|
+
*
|
|
430
|
+
* @param notificationId - The ID of the notification or an array of notification IDs to mark as a reminder.
|
|
431
|
+
* @param payload - The payload of the reminder.
|
|
432
|
+
* @returns A promise that resolves when the notification-reminder-created event is posted.
|
|
433
|
+
* @throws {@link SessionNotConnectedError} If the session is not connected.
|
|
434
|
+
*/
|
|
435
|
+
async setReminder(notificationId, payload, targets) {
|
|
436
|
+
return this.postNotificationEvent(notificationId, { category: 'notification-center-event', type: 'notification-reminder-created', payload }, { targets });
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Post a notification-reminder-removed event to the Cloud Notification service.
|
|
440
|
+
*
|
|
441
|
+
* @param notificationId - The ID of the notification or an array of notification IDs to cancel the reminder for.
|
|
442
|
+
* @returns A promise that resolves when the notification-reminder-removed event is posted.
|
|
443
|
+
* @throws {@link SessionNotConnectedError} If the session is not connected.
|
|
444
|
+
*/
|
|
445
|
+
async cancelReminder(notificationId, targets) {
|
|
446
|
+
return this.postNotificationEvent(notificationId, { category: 'notification-center-event', type: 'notification-reminder-removed' }, { targets });
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Raises a notification to the Cloud Notification service.
|
|
450
|
+
*
|
|
451
|
+
* @param options - The options for the notification.
|
|
452
|
+
* @param payload - The payload of the notification which should generally conform to the notification center schema
|
|
453
|
+
* @returns A promise that resolves with the notification raise result.
|
|
454
|
+
* @throws {@link SessionNotConnectedError} If the session is not connected.
|
|
455
|
+
* @throws {@link PublishError} If an error occurs during publishing.
|
|
456
|
+
*/
|
|
457
|
+
async raiseNotification(options, payload) {
|
|
357
458
|
if (!this.#sessionDetails || !this.#connectionParams) {
|
|
358
459
|
this.#logger('error', 'Invalid Session');
|
|
359
460
|
throw new SessionNotConnectedError();
|
|
360
461
|
}
|
|
361
|
-
if (!Array.isArray(notificationIds) || notificationIds.length === 0) {
|
|
362
|
-
this.#logger('error', 'No notification IDs provided');
|
|
363
|
-
throw new EventRetrievalError('No notification IDs provided');
|
|
364
|
-
}
|
|
365
462
|
try {
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
const
|
|
372
|
-
method: '
|
|
463
|
+
const publishPayload = {
|
|
464
|
+
sessionId: this.#sessionDetails.sessionId,
|
|
465
|
+
timeOffset: this.#getCurrentTimeOffset(),
|
|
466
|
+
notification: { ...options, payload },
|
|
467
|
+
};
|
|
468
|
+
const publishResponse = await fetch(`${this.#cloudNotificationSettings.url}/api/publications`, {
|
|
469
|
+
method: 'POST',
|
|
373
470
|
headers: getRequestHeaders(this.#connectionParams),
|
|
471
|
+
body: JSON.stringify(publishPayload),
|
|
374
472
|
});
|
|
375
|
-
this.#
|
|
376
|
-
const
|
|
377
|
-
return
|
|
473
|
+
await checkResponse(this.#logger, publishResponse, 'Error publishing notification', 'ERR_PUBLISH_NOTIFICATION');
|
|
474
|
+
const publishResponseBody = (await publishResponse.json());
|
|
475
|
+
return publishResponseBody;
|
|
378
476
|
}
|
|
379
477
|
catch (error) {
|
|
380
|
-
this.#
|
|
478
|
+
handleAPIException(this.#logger, error, 'Error publishing notification', PublishError);
|
|
381
479
|
}
|
|
382
480
|
}
|
|
383
|
-
|
|
384
|
-
|
|
481
|
+
/**
|
|
482
|
+
* Raises a notification update to the Cloud Notification service.
|
|
483
|
+
*
|
|
484
|
+
* @param notificationId - The ID of the notification to update.
|
|
485
|
+
* @param options - The options for the notification update.
|
|
486
|
+
* @param payload - The new payload of the notification which should generally conform to the notification center update schema
|
|
487
|
+
* @throws {@link SessionNotConnectedError} If the session is not connected.
|
|
488
|
+
* @throws {@link PublishError} If an error occurs during publishing of the update.
|
|
489
|
+
*/
|
|
490
|
+
async updateNotification(notificationId, options, payload) {
|
|
385
491
|
if (!this.#sessionDetails || !this.#connectionParams) {
|
|
386
492
|
this.#logger('error', 'Invalid Session');
|
|
387
493
|
throw new SessionNotConnectedError();
|
|
388
494
|
}
|
|
389
495
|
try {
|
|
390
|
-
const
|
|
391
|
-
// NOTE: Will be strongly typed and moved to shared in a future PR
|
|
392
|
-
const publishPayload = {
|
|
496
|
+
const updatePayload = {
|
|
393
497
|
sessionId: this.#sessionDetails.sessionId,
|
|
394
|
-
timeOffset,
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
ttl: options.ttl,
|
|
398
|
-
targets: options.targets,
|
|
399
|
-
class: 'interactive',
|
|
400
|
-
payload,
|
|
401
|
-
},
|
|
498
|
+
timeOffset: this.#getCurrentTimeOffset(),
|
|
499
|
+
ttlSeconds: options.ttlSeconds,
|
|
500
|
+
payload,
|
|
402
501
|
};
|
|
403
|
-
const
|
|
404
|
-
method: '
|
|
502
|
+
const updateResponse = await fetch(`${this.#cloudNotificationSettings.url}/api/publications/${notificationId}`, {
|
|
503
|
+
method: 'PATCH',
|
|
405
504
|
headers: getRequestHeaders(this.#connectionParams),
|
|
406
|
-
body: JSON.stringify(
|
|
505
|
+
body: JSON.stringify(updatePayload),
|
|
407
506
|
});
|
|
408
|
-
this.#
|
|
409
|
-
const publishResponseBody = (await publishResponse.json());
|
|
410
|
-
return publishResponseBody;
|
|
507
|
+
await checkResponse(this.#logger, updateResponse, 'Error updating notification', 'ERR_UPDATING_NOTIFICATION');
|
|
411
508
|
}
|
|
412
509
|
catch (error) {
|
|
413
|
-
this.#
|
|
510
|
+
handleAPIException(this.#logger, error, 'Error updating notification', PublishError);
|
|
414
511
|
}
|
|
415
512
|
}
|
|
416
|
-
|
|
417
|
-
|
|
513
|
+
/**
|
|
514
|
+
* Marks a notification as deleted in the Cloud Notification service.
|
|
515
|
+
*
|
|
516
|
+
* This in turn causes notification events to be raised for the notification
|
|
517
|
+
*
|
|
518
|
+
* @param notificationId - The ID of the notification to delete.
|
|
519
|
+
* @returns A promise that resolves when the notification is deleted.
|
|
520
|
+
* @throws {@link SessionNotConnectedError} If the session is not connected.
|
|
521
|
+
*/
|
|
522
|
+
async deleteNotification(notificationId) {
|
|
523
|
+
if (!this.#sessionDetails || !this.#connectionParams) {
|
|
524
|
+
this.#logger('error', 'Invalid Session');
|
|
525
|
+
throw new SessionNotConnectedError();
|
|
526
|
+
}
|
|
527
|
+
try {
|
|
528
|
+
const notificationIds = Array.isArray(notificationId) ? notificationId : [notificationId];
|
|
529
|
+
const notificationIdsString = notificationIds.join('&id=');
|
|
530
|
+
const deleteResponse = await fetch(`${this.#cloudNotificationSettings.url}/api/publications?id=${notificationIdsString}&sessionId=${this.#sessionDetails.sessionId}`, {
|
|
531
|
+
method: 'DELETE',
|
|
532
|
+
headers: getRequestHeaders(this.#connectionParams),
|
|
533
|
+
});
|
|
534
|
+
await checkResponse(this.#logger, deleteResponse, 'Error deleting notification', 'ERR_DELETE_NOTIFICATION');
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
handleAPIException(this.#logger, error, 'Error deleting notification', PublishError);
|
|
538
|
+
}
|
|
418
539
|
}
|
|
419
|
-
|
|
420
|
-
|
|
540
|
+
/**
|
|
541
|
+
* Replays notifications from the Cloud Notification service.
|
|
542
|
+
*
|
|
543
|
+
* This is called at platform startup to populate the notification center with notifications that were missed since the last time the platform was started.
|
|
544
|
+
*
|
|
545
|
+
* @param pageItemLimit - The maximum number of items per page.
|
|
546
|
+
* @param pageStartCursor - The cursor to start the page from. This is retrieved from the pageInfo property.
|
|
547
|
+
* @returns A promise that resolves with the notifications replay details.
|
|
548
|
+
* @throws {@link SessionNotConnectedError} If the session is not connected.
|
|
549
|
+
* @throws {@link NotificationRetrievalError} If an error occurs during retrieval.
|
|
550
|
+
*/
|
|
551
|
+
async replayNotifications(pageItemLimit, pageStartCursor) {
|
|
552
|
+
if (!this.#sessionDetails || !this.#connectionParams) {
|
|
553
|
+
this.#logger('error', 'Invalid Session');
|
|
554
|
+
throw new SessionNotConnectedError();
|
|
555
|
+
}
|
|
556
|
+
try {
|
|
557
|
+
let replayUrl = `${this.#cloudNotificationSettings.url}/api/publications/replay`;
|
|
558
|
+
const parameters = new URLSearchParams();
|
|
559
|
+
if (pageItemLimit) {
|
|
560
|
+
parameters.set('pageItemLimit', pageItemLimit.toString());
|
|
561
|
+
}
|
|
562
|
+
if (pageStartCursor) {
|
|
563
|
+
parameters.set('pageStart', pageStartCursor);
|
|
564
|
+
}
|
|
565
|
+
if ([...parameters].length > 0) {
|
|
566
|
+
replayUrl += `?${parameters.toString()}`;
|
|
567
|
+
}
|
|
568
|
+
const replayResponse = await fetch(replayUrl, {
|
|
569
|
+
method: 'POST',
|
|
570
|
+
headers: getRequestHeaders(this.#connectionParams),
|
|
571
|
+
body: JSON.stringify({
|
|
572
|
+
sessionId: this.#sessionDetails.sessionId,
|
|
573
|
+
}),
|
|
574
|
+
});
|
|
575
|
+
await checkResponse(this.#logger, replayResponse, 'Error replaying notifications', 'ERR_REPLAY_NOTIFICATIONS');
|
|
576
|
+
const body = (await replayResponse.json());
|
|
577
|
+
return body;
|
|
578
|
+
}
|
|
579
|
+
catch (error) {
|
|
580
|
+
handleAPIException(this.#logger, error, 'Error replaying notifications', NotificationRetrievalError);
|
|
581
|
+
}
|
|
421
582
|
}
|
|
583
|
+
/**
|
|
584
|
+
* Adds an event listener for a specific event type.
|
|
585
|
+
*
|
|
586
|
+
* @param type - The event type.
|
|
587
|
+
* @param callback - The callback function to invoke when the event occurs.
|
|
588
|
+
*/
|
|
422
589
|
addEventListener(type, callback) {
|
|
423
590
|
this.#events.addEventListener(type, callback);
|
|
424
591
|
}
|
|
592
|
+
/**
|
|
593
|
+
* Removes an event listener for a specific event type.
|
|
594
|
+
*
|
|
595
|
+
* @param type - The event type.
|
|
596
|
+
* @param callback - The callback function to remove.
|
|
597
|
+
*/
|
|
425
598
|
removeEventListener(type, callback) {
|
|
426
599
|
this.#events.removeEventListener(type, callback);
|
|
427
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* Adds a one-time event listener for a specific event type.
|
|
603
|
+
*
|
|
604
|
+
* @param type - The event type.
|
|
605
|
+
* @param callback - The callback function to invoke once when the event occurs.
|
|
606
|
+
*/
|
|
428
607
|
once(type, callback) {
|
|
429
608
|
this.#events.once(type, callback);
|
|
430
609
|
}
|
|
431
610
|
async #connectToMQTT() {
|
|
432
|
-
if (!this.#sessionDetails) {
|
|
611
|
+
if (!this.#sessionDetails || !this.#sessionDetails.mqtt) {
|
|
433
612
|
this.#logger('error', 'Invalid Session');
|
|
434
613
|
throw new SessionNotConnectedError();
|
|
435
614
|
}
|
|
615
|
+
const { token: _, ...mqttDetailsWithoutToken } = this.#sessionDetails.mqtt;
|
|
616
|
+
this.#logger('info', `Connecting to MQTT server: ${JSON.stringify(mqttDetailsWithoutToken, null, 2)}`);
|
|
436
617
|
const clientOptions = {
|
|
437
618
|
keepalive: this.#keepAliveIntervalSeconds,
|
|
438
619
|
clientId: this.#sessionDetails.sessionId,
|
|
@@ -440,26 +621,25 @@ class CloudNotificationAPI {
|
|
|
440
621
|
protocolVersion: 5,
|
|
441
622
|
// The "will" message will automatically be published on an unexpected disconnection allowing the server to know that this client is no longer connected and to clean up its session
|
|
442
623
|
will: {
|
|
443
|
-
topic: this.#sessionDetails.lastWillTopic,
|
|
624
|
+
topic: this.#sessionDetails.mqtt.lastWillTopic,
|
|
444
625
|
payload: Buffer.from(JSON.stringify(this.#sessionDetails)),
|
|
445
626
|
qos: 2,
|
|
446
627
|
retain: false,
|
|
447
628
|
},
|
|
448
|
-
username: this.#sessionDetails.token,
|
|
629
|
+
username: this.#sessionDetails.mqtt.token,
|
|
449
630
|
};
|
|
450
|
-
this.#mqttClient = await mqtt.connectAsync(this.#sessionDetails.url, clientOptions);
|
|
451
|
-
this.#logger('debug', `Cloud Notifications successfully connected to notification backbone`);
|
|
631
|
+
this.#mqttClient = await mqtt.connectAsync(this.#sessionDetails.mqtt.url, clientOptions);
|
|
452
632
|
this.#mqttClient.on('error', async (error) => this.#mqttErrorHandler(error));
|
|
453
633
|
this.#mqttClient.on('reconnect', () => this.#mqttReconnectionHandler());
|
|
454
634
|
// Does not fire on initial connection, only successful reconnection attempts
|
|
455
635
|
this.#mqttClient.on('connect', () => this.#mqttConnectionHandler());
|
|
456
636
|
this.#mqttClient.on('message', (topic, message) => this.#mqttMessageHandler(topic, message));
|
|
457
637
|
// Subscribe any session specific topics
|
|
458
|
-
this.#mqttClient.subscribe(`${this.#sessionDetails.sessionRootTopic}/#`);
|
|
638
|
+
this.#mqttClient.subscribe(`${this.#sessionDetails.mqtt.sessionRootTopic}/#`);
|
|
639
|
+
this.#logger('info', 'Successfully connected to MQTT server');
|
|
459
640
|
// Subscribe to the user notification delivery topics for groups and users
|
|
460
641
|
await this.#subscribeToNotificationTopics();
|
|
461
642
|
}
|
|
462
|
-
// async #connect(parameters: ConnectParameters): Promise<ConnectionResult> {}
|
|
463
643
|
async #mqttConnectionHandler() {
|
|
464
644
|
this.#logger('debug', `Cloud Notifications successfully reconnected after ${this.#reconnectRetries} attempts`);
|
|
465
645
|
this.#reconnectRetries = 0;
|
|
@@ -490,7 +670,7 @@ class CloudNotificationAPI {
|
|
|
490
670
|
this.#logger('debug', `Session expired`);
|
|
491
671
|
this.#events.emitEvent('session-expired');
|
|
492
672
|
// TODO: Request new JWT if using JWT authentication
|
|
493
|
-
await this.#
|
|
673
|
+
await this.#extendSession();
|
|
494
674
|
this.#logger('debug', `Session extended`);
|
|
495
675
|
this.#events.emitEvent('session-extended');
|
|
496
676
|
return;
|
|
@@ -514,33 +694,45 @@ class CloudNotificationAPI {
|
|
|
514
694
|
}
|
|
515
695
|
}
|
|
516
696
|
async #sendNotificationDeliveredStatus(notificationId) {
|
|
517
|
-
return this.postNotificationEvent(
|
|
697
|
+
return this.postNotificationEvent(notificationId, { category: 'delivery', type: 'ack' });
|
|
518
698
|
}
|
|
519
699
|
async #subscribeToNotificationTopics() {
|
|
520
|
-
if (!this.#sessionDetails) {
|
|
700
|
+
if (!this.#sessionDetails || !this.#sessionDetails.mqtt) {
|
|
521
701
|
this.#logger('error', 'Invalid Session');
|
|
522
702
|
throw new SessionNotConnectedError();
|
|
523
703
|
}
|
|
524
|
-
// Group
|
|
704
|
+
// Group targeted notifications
|
|
525
705
|
const subscribePromises = this.#sessionDetails.groups.map((group) => {
|
|
526
|
-
if (group.
|
|
527
|
-
return this.#mqttClient?.subscribeAsync(group.
|
|
706
|
+
if (group.notificationTopic) {
|
|
707
|
+
return this.#mqttClient?.subscribeAsync(group.notificationTopic, this.#defaultSubscriptionOptions);
|
|
528
708
|
}
|
|
529
709
|
else {
|
|
530
|
-
this.#logger('warn', `Group ${group.uuid} does not have a topic to subscribe to`);
|
|
710
|
+
this.#logger('warn', `Group ${group.uuid} does not have a notification topic to subscribe to`);
|
|
531
711
|
return Promise.resolve();
|
|
532
712
|
}
|
|
533
713
|
});
|
|
534
714
|
subscribePromises.push(
|
|
715
|
+
// Group targeted events
|
|
716
|
+
...this.#sessionDetails.groups.map((group) => {
|
|
717
|
+
if (group.eventTopic) {
|
|
718
|
+
return this.#mqttClient?.subscribeAsync(group.eventTopic, this.#defaultSubscriptionOptions);
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
this.#logger('warn', `Group ${group.uuid} does not have an event topic to subscribe to`);
|
|
722
|
+
return Promise.resolve();
|
|
723
|
+
}
|
|
724
|
+
}),
|
|
535
725
|
// Notification directly to the user
|
|
536
|
-
this.#mqttClient?.subscribeAsync(this.#sessionDetails.userNotificationTopic, this.#defaultSubscriptionOptions),
|
|
726
|
+
this.#mqttClient?.subscribeAsync(this.#sessionDetails.mqtt.userNotificationTopic, this.#defaultSubscriptionOptions),
|
|
537
727
|
// The users notifications status updates
|
|
538
|
-
this.#mqttClient?.subscribeAsync(this.#sessionDetails.userNotificationEventsTopic, this.#defaultSubscriptionOptions)
|
|
539
|
-
//
|
|
540
|
-
|
|
728
|
+
this.#mqttClient?.subscribeAsync(this.#sessionDetails.mqtt.userNotificationEventsTopic, this.#defaultSubscriptionOptions));
|
|
729
|
+
// Global notification events
|
|
730
|
+
if (this.#sessionDetails.mqtt.allNotificationEventsTopic) {
|
|
731
|
+
subscribePromises.push(this.#mqttClient?.subscribeAsync(this.#sessionDetails.mqtt.allNotificationEventsTopic, this.#defaultSubscriptionOptions));
|
|
732
|
+
}
|
|
541
733
|
await Promise.all(subscribePromises);
|
|
542
734
|
}
|
|
543
|
-
async #
|
|
735
|
+
async #extendSession() {
|
|
544
736
|
if (!this.#sessionDetails) {
|
|
545
737
|
return;
|
|
546
738
|
}
|
|
@@ -566,6 +758,10 @@ class CloudNotificationAPI {
|
|
|
566
758
|
this.#sessionDetails = (await extendResponse.json());
|
|
567
759
|
this.#attemptingToReconnect = true;
|
|
568
760
|
await this.#connectToMQTT();
|
|
761
|
+
// If local session expiry handling is enabled, start the session timer
|
|
762
|
+
if (this.#sessionDetails.mqtt?.localSessionExpiryHandling) {
|
|
763
|
+
this.#startSessionTimer();
|
|
764
|
+
}
|
|
569
765
|
}
|
|
570
766
|
catch (error) {
|
|
571
767
|
throw new CloudNotificationAPIError('Error during session refresh', 'ERR_SESSION_EXTEND', error);
|
|
@@ -579,21 +775,31 @@ class CloudNotificationAPI {
|
|
|
579
775
|
if (!this.#connectionParams) {
|
|
580
776
|
throw new Error('Connect parameters must be provided');
|
|
581
777
|
}
|
|
778
|
+
// Cancel session timer if it's running
|
|
779
|
+
if (this.#sessionTimer) {
|
|
780
|
+
clearTimeout(this.#sessionTimer);
|
|
781
|
+
this.#sessionTimer = undefined;
|
|
782
|
+
}
|
|
582
783
|
// Clean up our session on the server
|
|
583
784
|
const disconnectResponse = await fetch(`${this.#cloudNotificationSettings.url}/api/sessions/${this.#sessionDetails.sessionId}`, {
|
|
584
785
|
method: 'DELETE',
|
|
585
786
|
headers: getRequestHeaders(this.#connectionParams),
|
|
586
787
|
});
|
|
587
|
-
if (disconnectResponse.status !==
|
|
588
|
-
throw new CloudNotificationAPIError(
|
|
788
|
+
if (disconnectResponse.status !== 204) {
|
|
789
|
+
throw new CloudNotificationAPIError(`Error during session tear down - unexpected status ${disconnectResponse.status}`, 'ERR_DISCONNECT', new Error(disconnectResponse.statusText));
|
|
589
790
|
}
|
|
590
791
|
}
|
|
591
792
|
catch (error) {
|
|
592
793
|
throw new CloudNotificationAPIError('Error during disconnection', 'ERR_DISCONNECT', error);
|
|
593
794
|
}
|
|
594
795
|
finally {
|
|
595
|
-
|
|
596
|
-
|
|
796
|
+
try {
|
|
797
|
+
this.#mqttClient?.removeAllListeners();
|
|
798
|
+
await this.#mqttClient?.endAsync(true);
|
|
799
|
+
}
|
|
800
|
+
catch (cleanupError) {
|
|
801
|
+
this.#logger('warn', `Error during MQTT client cleanup - ${cleanupError instanceof Error ? cleanupError.message : cleanupError}`);
|
|
802
|
+
}
|
|
597
803
|
this.#sessionDetails = undefined;
|
|
598
804
|
this.#mqttClient = undefined;
|
|
599
805
|
this.#reconnectRetries = 0;
|
|
@@ -603,22 +809,121 @@ class CloudNotificationAPI {
|
|
|
603
809
|
}
|
|
604
810
|
}
|
|
605
811
|
}
|
|
812
|
+
/**
|
|
813
|
+
* Extracts the expiration timestamp from a JWT token.
|
|
814
|
+
*
|
|
815
|
+
* @param token - The JWT token string
|
|
816
|
+
* @returns The expiration timestamp in seconds, or null if extraction fails
|
|
817
|
+
*/
|
|
818
|
+
#extractExpirationFromJwt(token) {
|
|
819
|
+
if (!token) {
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
try {
|
|
823
|
+
// JWT tokens have three parts separated by dots: header.payload.signature
|
|
824
|
+
// The exp claim is in the payload
|
|
825
|
+
const parts = token.split('.');
|
|
826
|
+
if (parts.length < 2) {
|
|
827
|
+
this.#logger('warn', 'Invalid JWT token format: expected at least 2 parts');
|
|
828
|
+
return null;
|
|
829
|
+
}
|
|
830
|
+
const payload = parts[1];
|
|
831
|
+
const decodedBytes = Buffer.from(l(payload), 'base64');
|
|
832
|
+
const payloadJson = decodedBytes.toString('utf8');
|
|
833
|
+
// Parse JSON to get the exp claim
|
|
834
|
+
const claims = JSON.parse(payloadJson);
|
|
835
|
+
const exp = claims.exp;
|
|
836
|
+
if (exp === undefined || exp === null) {
|
|
837
|
+
this.#logger('warn', "JWT token does not contain 'exp' claim");
|
|
838
|
+
return null;
|
|
839
|
+
}
|
|
840
|
+
if (typeof exp !== 'number') {
|
|
841
|
+
this.#logger('warn', `JWT token 'exp' claim is not a number: ${exp}`);
|
|
842
|
+
return null;
|
|
843
|
+
}
|
|
844
|
+
return exp;
|
|
845
|
+
}
|
|
846
|
+
catch (error) {
|
|
847
|
+
this.#logger('error', `Failed to extract expiration from JWT token: ${error instanceof Error ? error.message : error}`);
|
|
848
|
+
return null;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Start a session timer that will expire at the time specified in the JWT token's exp claim.
|
|
853
|
+
* On expiry, it will fire session expired event, extend the session, fire session extended event, and restart the timer.
|
|
854
|
+
*/
|
|
855
|
+
#startSessionTimer() {
|
|
856
|
+
if (!this.#sessionDetails?.mqtt?.token) {
|
|
857
|
+
this.#logger('warn', 'Cannot start session timer: session details or token not available');
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
// Extract expiration time from JWT token
|
|
861
|
+
const expTimestamp = this.#extractExpirationFromJwt(this.#sessionDetails.mqtt.token);
|
|
862
|
+
if (expTimestamp === null) {
|
|
863
|
+
this.#logger('warn', 'Cannot start session timer: could not extract expiration from JWT token');
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
const currentTimeSeconds = Math.floor(Date.now() / 1000);
|
|
867
|
+
const delaySeconds = expTimestamp - currentTimeSeconds;
|
|
868
|
+
if (delaySeconds <= 0) {
|
|
869
|
+
this.#logger('warn', 'JWT token has already expired or expires immediately');
|
|
870
|
+
this.#events.emitEvent('session-expired');
|
|
871
|
+
this.#extendSession()
|
|
872
|
+
.then(() => {
|
|
873
|
+
this.#logger('debug', 'Session extended');
|
|
874
|
+
this.#events.emitEvent('session-extended');
|
|
875
|
+
})
|
|
876
|
+
.catch((error) => {
|
|
877
|
+
this.#logger('error', `Error during session timer expiry: ${error instanceof Error ? error.message : error}`);
|
|
878
|
+
});
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
// Clear any existing timer
|
|
882
|
+
if (this.#sessionTimer) {
|
|
883
|
+
clearTimeout(this.#sessionTimer);
|
|
884
|
+
}
|
|
885
|
+
const expirationTimeString = new Date(expTimestamp * 1000).toISOString();
|
|
886
|
+
this.#logger('debug', `Starting session timer to expire in ${delaySeconds} seconds (at ${expirationTimeString})`);
|
|
887
|
+
this.#sessionTimer = setTimeout(async () => {
|
|
888
|
+
try {
|
|
889
|
+
this.#logger('debug', 'Session timer expired');
|
|
890
|
+
this.#events.emitEvent('session-expired');
|
|
891
|
+
await this.#extendSession();
|
|
892
|
+
this.#logger('debug', 'Session extended');
|
|
893
|
+
this.#events.emitEvent('session-extended');
|
|
894
|
+
}
|
|
895
|
+
catch (error) {
|
|
896
|
+
this.#logger('error', `Error during session timer expiry: ${error instanceof Error ? error.message : error}`);
|
|
897
|
+
}
|
|
898
|
+
}, delaySeconds * 1000);
|
|
899
|
+
}
|
|
900
|
+
#isGroupEventTopic(topic) {
|
|
901
|
+
if (!this.#sessionDetails) {
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
return this.#sessionDetails.groups.some((group) => group.eventTopic?.startsWith(topic));
|
|
905
|
+
}
|
|
606
906
|
#handleMessage(topic, message, sessionDetails) {
|
|
607
|
-
if (message.length === 0 || !sessionDetails) {
|
|
907
|
+
if (message.length === 0 || !sessionDetails || !sessionDetails.mqtt) {
|
|
608
908
|
// Ignore clean up messages
|
|
609
909
|
return;
|
|
610
910
|
}
|
|
611
911
|
try {
|
|
612
912
|
const messagePayload = JSON.parse(message.toString());
|
|
613
|
-
|
|
913
|
+
// NOTE: uncomment this to debug message payloads
|
|
914
|
+
// this.#logger('info', `Received message on topic ${topic} with payload ${JSON.stringify(messagePayload)}`);
|
|
915
|
+
if (topic.startsWith(sessionDetails.mqtt.notificationsRootTopic)) {
|
|
614
916
|
this.#handleNotificationMessage(messagePayload);
|
|
615
917
|
}
|
|
616
|
-
else if (topic === sessionDetails.userNotificationEventsTopic) {
|
|
918
|
+
else if (topic === sessionDetails.mqtt.userNotificationEventsTopic) {
|
|
617
919
|
this.#handleUserNotificationEventMessage(messagePayload);
|
|
618
920
|
}
|
|
619
|
-
else if (topic === sessionDetails.allNotificationEventsTopic) {
|
|
921
|
+
else if (topic === sessionDetails.mqtt.allNotificationEventsTopic) {
|
|
620
922
|
this.#handleAllNotificationEventMessage(messagePayload);
|
|
621
923
|
}
|
|
924
|
+
else if (this.#isGroupEventTopic(topic)) {
|
|
925
|
+
this.#handleGroupNotificationEventMessage(messagePayload);
|
|
926
|
+
}
|
|
622
927
|
else {
|
|
623
928
|
this.#logger('warn', `Received message on unknown topic ${topic}`);
|
|
624
929
|
this.#events.emitEvent('error', new CloudNotificationAPIError(`Received message on unknown topic ${topic}`, 'ERR_UNKNOWN_TOPIC'));
|
|
@@ -630,83 +935,74 @@ class CloudNotificationAPI {
|
|
|
630
935
|
}
|
|
631
936
|
}
|
|
632
937
|
#handleNotificationMessage(messagePayload) {
|
|
633
|
-
const parseResult =
|
|
938
|
+
const parseResult = h.safeParse(messagePayload);
|
|
634
939
|
if (!parseResult.success) {
|
|
635
940
|
this.#logger('warn', `Received invalid notification message payload format ${parseResult.error?.toString()}`);
|
|
636
941
|
throw new InvalidMessageFormatError(parseResult);
|
|
637
942
|
}
|
|
638
|
-
const { action, notificationId, originatingSessionId, correlationId, target, targetType, payload } = parseResult.data;
|
|
943
|
+
const { action, notificationId, originatingSessionId, correlationId, target, targetType, payload, txInstanceId } = parseResult.data;
|
|
639
944
|
// Ignore if its one we sent ourselves
|
|
640
945
|
if (originatingSessionId === this.#sessionDetails?.sessionId) {
|
|
641
946
|
return;
|
|
642
947
|
}
|
|
643
|
-
//
|
|
644
|
-
if (
|
|
645
|
-
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
this.#newNotificationsDeDuplicator.add(notificationId);
|
|
948
|
+
// We might have received this update from a different group or user topic so de-dupe
|
|
949
|
+
if (this.#deDuplicator.has(txInstanceId)) {
|
|
950
|
+
return;
|
|
649
951
|
}
|
|
952
|
+
this.#deDuplicator.add(txInstanceId);
|
|
650
953
|
this.#sendNotificationDeliveredStatus(notificationId);
|
|
651
954
|
let targetName = target;
|
|
652
|
-
if (targetType === '
|
|
955
|
+
if (targetType === 'groups') {
|
|
653
956
|
targetName = this.#lookupGroupNameByUuid(target);
|
|
654
957
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
958
|
+
const makePayload = (action) => ({ action, notificationId, correlationId, target, targetName, targetType, payload });
|
|
959
|
+
switch (action) {
|
|
960
|
+
case 'new': {
|
|
961
|
+
this.#events.emitEvent('new-notification', makePayload('new'));
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
case 'update': {
|
|
965
|
+
this.#events.emitEvent('update-notification', makePayload('update'));
|
|
966
|
+
break;
|
|
967
|
+
}
|
|
968
|
+
case 'delete': {
|
|
969
|
+
this.#events.emitEvent('delete-notification', makePayload('delete'));
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
// No default - Schema validation will prevent this
|
|
660
973
|
}
|
|
661
974
|
}
|
|
662
975
|
#handleUserNotificationEventMessage(messagePayload) {
|
|
663
|
-
const
|
|
664
|
-
if (
|
|
665
|
-
this.#logger('
|
|
666
|
-
|
|
976
|
+
const event = this.#parseNotificationEventMessage(messagePayload);
|
|
977
|
+
if (event.originatingSessionId === this.#sessionDetails?.sessionId) {
|
|
978
|
+
this.#logger('debug', `Received notification event from our own session, ignoring. (session id: ${event.originatingSessionId})`);
|
|
979
|
+
return;
|
|
667
980
|
}
|
|
668
|
-
this.#events.emitEvent('notification-event',
|
|
981
|
+
this.#events.emitEvent('notification-event', event);
|
|
669
982
|
}
|
|
670
|
-
#
|
|
671
|
-
const
|
|
672
|
-
if (
|
|
673
|
-
this.#logger('
|
|
674
|
-
|
|
983
|
+
#handleGroupNotificationEventMessage(messagePayload) {
|
|
984
|
+
const event = this.#parseNotificationEventMessage(messagePayload);
|
|
985
|
+
if (event.originatingSessionId === this.#sessionDetails?.sessionId) {
|
|
986
|
+
this.#logger('debug', `Received notification event from our own session, ignoring. (session id: ${event.originatingSessionId})`);
|
|
987
|
+
return;
|
|
675
988
|
}
|
|
676
|
-
this.#events.emitEvent('notification-event
|
|
989
|
+
this.#events.emitEvent('notification-event', event);
|
|
677
990
|
}
|
|
678
|
-
#
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
throw new Error('platformId must be provided');
|
|
684
|
-
}
|
|
685
|
-
if (parameters.authenticationType === 'jwt' &&
|
|
686
|
-
(!parameters.jwtAuthenticationParameters?.jwtRequestCallback || !parameters.jwtAuthenticationParameters?.authenticationId)) {
|
|
687
|
-
throw new Error('jwtAuthenticationParameters must be provided when using jwt authentication');
|
|
688
|
-
}
|
|
689
|
-
if (parameters.authenticationType === 'basic' &&
|
|
690
|
-
(!parameters.basicAuthenticationParameters?.username || !parameters.basicAuthenticationParameters?.password)) {
|
|
691
|
-
throw new Error('basicAuthenticationParameters must be provided when using basic authentication');
|
|
692
|
-
}
|
|
693
|
-
};
|
|
694
|
-
#handleAPIException(error, message, exceptionConstructor) {
|
|
695
|
-
if (error instanceof Error) {
|
|
696
|
-
this.#logger('error', `${message} - ${error.message}`);
|
|
697
|
-
}
|
|
698
|
-
else {
|
|
699
|
-
this.#logger('error', `${message} - ${error}`);
|
|
991
|
+
#handleAllNotificationEventMessage(messagePayload) {
|
|
992
|
+
const event = this.#parseNotificationEventMessage(messagePayload);
|
|
993
|
+
if (event.originatingSessionId === this.#sessionDetails?.sessionId) {
|
|
994
|
+
this.#logger('debug', `Received notification event from our own session, ignoring. (session id: ${event.originatingSessionId})`);
|
|
995
|
+
return;
|
|
700
996
|
}
|
|
701
|
-
|
|
997
|
+
this.#events.emitEvent('global-notification-event', event);
|
|
702
998
|
}
|
|
703
|
-
#
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
throw new CloudNotificationAPIError();
|
|
999
|
+
#parseNotificationEventMessage(messagePayload) {
|
|
1000
|
+
const parseResult = y.safeParse(messagePayload);
|
|
1001
|
+
if (!parseResult.success) {
|
|
1002
|
+
this.#logger('warn', `Received invalid notification event message payload format ${parseResult.error?.toString()}`);
|
|
1003
|
+
throw new InvalidMessageFormatError(parseResult);
|
|
709
1004
|
}
|
|
1005
|
+
return parseResult.data;
|
|
710
1006
|
}
|
|
711
1007
|
#lookupGroupNameByUuid(uuid) {
|
|
712
1008
|
if (!this.#sessionDetails) {
|
|
@@ -716,4 +1012,4 @@ class CloudNotificationAPI {
|
|
|
716
1012
|
}
|
|
717
1013
|
}
|
|
718
1014
|
|
|
719
|
-
export { AuthorizationError, CloudNotificationAPI, CloudNotificationAPIError, EventRetrievalError, InvalidMessageFormatError, PublishError, SessionNotConnectedError,
|
|
1015
|
+
export { AuthorizationError, CloudNotificationAPI, CloudNotificationAPIError, EventPublishError, EventRetrievalError, InvalidMessageFormatError, NotificationRetrievalError, PublishError, SessionNotConnectedError, a as targetTypeSchema };
|