@everfur/sdk 0.9.2 → 0.10.0
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/CHANGELOG.md +71 -0
- package/README.md +17 -8
- package/dist/{Chat-Cugs9Dsl.d.ts → Chat-DwGk5APA.d.ts} +3 -3
- package/dist/{Chat-B7oN62ww.d.cts → Chat-Ml-HlOiV.d.cts} +3 -3
- package/dist/{DepthViews-GxV7wSzT.d.cts → DepthViews-DAJySZqL.d.cts} +1 -1
- package/dist/{DepthViews-CiYBIBEZ.d.ts → DepthViews-DwCS5KKh.d.ts} +1 -1
- package/dist/{DepthViews-CUNmy99u.d.cts → DepthViews-PgA2KvTE.d.cts} +1 -1
- package/dist/{DepthViews-C6qFJ3fV.d.ts → DepthViews-kM-_Mn2x.d.ts} +1 -1
- package/dist/animations/index.cjs +1 -1
- package/dist/animations/index.d.cts +3 -3
- package/dist/animations/index.d.ts +3 -3
- package/dist/animations/index.js +1 -1
- package/dist/{attachments-20X7Vuip.d.ts → attachments-BH0vdghi.d.ts} +2 -2
- package/dist/{attachments-HXFmzk-D.d.cts → attachments-BV1Mbqm-.d.cts} +5 -5
- package/dist/{attachments-DN2cNGwe.d.ts → attachments-DWv9stp1.d.ts} +5 -5
- package/dist/{attachments-CkaPnIUw.d.cts → attachments-DaWeeeBW.d.cts} +2 -2
- package/dist/{bookingCopy-B5igVNE0.d.ts → bookingCopy-Cc3Cl-IJ.d.ts} +2 -2
- package/dist/{bookingCopy-pJpizqgz.d.cts → bookingCopy-DRwrhDUe.d.cts} +2 -2
- package/dist/{casesRepository-DFoK5N1O.d.cts → casesRepository-BhfPDWhY.d.cts} +1 -1
- package/dist/{casesRepository-qAkKKgji.d.ts → casesRepository-DMkRRKr8.d.ts} +1 -1
- package/dist/chat/index.cjs +16 -15
- package/dist/chat/index.d.cts +9 -9
- package/dist/chat/index.d.ts +9 -9
- package/dist/chat/index.js +16 -15
- package/dist/client/index.cjs +2 -2
- package/dist/client/index.d.cts +6 -6
- package/dist/client/index.d.ts +6 -6
- package/dist/client/index.js +2 -2
- package/dist/{config-BB7e52FP.d.ts → config-CuOczZUI.d.ts} +1 -1
- package/dist/{config-u6rK4mKt.d.cts → config-lilR0260.d.cts} +1 -1
- package/dist/consent/index.cjs +1 -1
- package/dist/consent/index.d.cts +5 -5
- package/dist/consent/index.d.ts +5 -5
- package/dist/consent/index.js +1 -1
- package/dist/{context-BZ1k4qE3.d.cts → context-BA6X6ZHd.d.cts} +13 -5
- package/dist/{context-CJYmubjx.d.ts → context-CL3cR0MA.d.ts} +13 -5
- package/dist/{copy-CtfctY-J.d.ts → copy-A2n7xXsL.d.ts} +2 -2
- package/dist/{copy-DCO_lUXd.d.cts → copy-DkoUo0VR.d.cts} +2 -2
- package/dist/core/index.cjs +6 -7
- package/dist/core/index.d.cts +12 -12
- package/dist/core/index.d.ts +12 -12
- package/dist/core/index.js +6 -7
- package/dist/{depth-_vMRMm4x.d.ts → depth-6_BYIt0s.d.ts} +2 -2
- package/dist/{depth-C_ym3qyi.d.cts → depth-DOPtk0vF.d.cts} +2 -2
- package/dist/{entitlementRepository-tSY9WWad.d.ts → entitlementRepository-BE-L6vX1.d.ts} +2 -2
- package/dist/{entitlementRepository-DA04yM54.d.cts → entitlementRepository-Blh38A2b.d.cts} +2 -2
- package/dist/{identity-D5uywCtp.d.ts → identity-4lohfP2L.d.ts} +8 -2
- package/dist/{identity-CUynm8S2.d.cts → identity-YXqHjBln.d.cts} +8 -2
- package/dist/index.cjs +16 -16
- package/dist/index.d.cts +15 -14
- package/dist/index.d.ts +15 -14
- package/dist/index.js +16 -16
- package/dist/notifications/index.cjs +1 -1
- package/dist/notifications/index.d.cts +2 -2
- package/dist/notifications/index.d.ts +2 -2
- package/dist/notifications/index.js +1 -1
- package/dist/{pets-mnbN0kZG.d.ts → pets-DzXi_9hY.d.ts} +1 -1
- package/dist/{pets-BrdkpNJH.d.cts → pets-m61lisZt.d.cts} +1 -1
- package/dist/{petsRepository-RGI_xPK1.d.ts → petsRepository-B1I6Lq_m.d.ts} +1 -1
- package/dist/{petsRepository-CQgzEFyz.d.cts → petsRepository-CQeuDdDC.d.cts} +1 -1
- package/dist/photo/index.cjs +1 -1
- package/dist/photo/index.js +1 -1
- package/dist/{ports-Cu_Wc5Aw.d.ts → ports-CrGAcey9.d.ts} +6 -4
- package/dist/{ports-DibY-h60.d.cts → ports-DUqO_XX0.d.cts} +6 -4
- package/dist/records/depth/index.cjs +3 -3
- package/dist/records/depth/index.d.cts +7 -7
- package/dist/records/depth/index.d.ts +7 -7
- package/dist/records/depth/index.js +3 -3
- package/dist/records/index.cjs +7 -7
- package/dist/records/index.d.cts +9 -9
- package/dist/records/index.d.ts +9 -9
- package/dist/records/index.js +7 -7
- package/dist/{requestFunnel-BkSFsLKh.d.ts → requestFunnel-B86gQFka.d.ts} +2 -2
- package/dist/{requestFunnel-nmhlEdbM.d.cts → requestFunnel-hXkP5T7K.d.cts} +2 -2
- package/dist/{runtimeTypes-CWG1Cm4N.d.cts → runtimeTypes-Bt_tIj3h.d.cts} +29 -5
- package/dist/{runtimeTypes-CU2xVmiQ.d.ts → runtimeTypes-DXKxY2yq.d.ts} +29 -5
- package/dist/server/events/index.cjs +2 -2
- package/dist/server/events/index.d.cts +25 -6
- package/dist/server/events/index.d.ts +25 -6
- package/dist/server/events/index.js +2 -2
- package/dist/server/index.cjs +4 -4
- package/dist/server/index.d.cts +5 -4
- package/dist/server/index.d.ts +5 -4
- package/dist/server/index.js +4 -4
- package/dist/televet/booking/index.cjs +18 -15
- package/dist/televet/booking/index.d.cts +6 -6
- package/dist/televet/booking/index.d.ts +6 -6
- package/dist/televet/booking/index.js +19 -16
- package/dist/televet/index.cjs +1 -1
- package/dist/televet/index.js +1 -1
- package/dist/testing/index.d.cts +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/rn/index.cjs +1 -1
- package/dist/testing/rn/index.d.cts +7 -7
- package/dist/testing/rn/index.d.ts +7 -7
- package/dist/testing/rn/index.js +1 -1
- package/dist/testing/web/index.cjs +1 -1
- package/dist/testing/web/index.d.cts +7 -7
- package/dist/testing/web/index.d.ts +7 -7
- package/dist/testing/web/index.js +1 -1
- package/dist/{timelineRows-PWRoTntZ.d.ts → timelineRows-C2ObTmfN.d.ts} +1 -1
- package/dist/{timelineRows-CYF_I5Aq.d.cts → timelineRows-CrA-ePrQ.d.cts} +1 -1
- package/dist/{useRecordsDepth-Cg4cc4bQ.d.cts → useRecordsDepth-Dcr9y6i-.d.cts} +1 -1
- package/dist/{useRecordsDepth-eS9BJv_a.d.ts → useRecordsDepth-NQNJaGyk.d.ts} +1 -1
- package/dist/video/index.cjs +1 -1
- package/dist/video/index.js +1 -1
- package/dist/{view-n_oSGiiT.d.ts → view-DWJa2L0U.d.ts} +2 -2
- package/dist/{view-D4UOm-yo.d.cts → view-Dk7xpBJ4.d.cts} +2 -2
- package/dist/web/consent/index.cjs +1 -1
- package/dist/web/consent/index.d.cts +5 -5
- package/dist/web/consent/index.d.ts +5 -5
- package/dist/web/consent/index.js +1 -1
- package/dist/web/index.cjs +13 -12
- package/dist/web/index.d.cts +17 -16
- package/dist/web/index.d.ts +17 -16
- package/dist/web/index.js +13 -12
- package/dist/web/notifications/index.cjs +1 -1
- package/dist/web/notifications/index.d.cts +3 -3
- package/dist/web/notifications/index.d.ts +3 -3
- package/dist/web/notifications/index.js +1 -1
- package/dist/web/records/depth/index.cjs +3 -3
- package/dist/web/records/depth/index.d.cts +7 -7
- package/dist/web/records/depth/index.d.ts +7 -7
- package/dist/web/records/depth/index.js +3 -3
- package/dist/web/records/index.cjs +7 -7
- package/dist/web/records/index.d.cts +9 -9
- package/dist/web/records/index.d.ts +9 -9
- package/dist/web/records/index.js +7 -7
- package/dist/web/televet/booking/index.cjs +4 -4
- package/dist/web/televet/booking/index.d.cts +6 -6
- package/dist/web/televet/booking/index.d.ts +6 -6
- package/dist/web/televet/booking/index.js +4 -4
- package/dist/web/televet/index.cjs +1 -1
- package/dist/web/televet/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { E as EntitlementDecision, C as CapabilityName } from './resolve-D4Ywz5OS.js';
|
|
2
|
-
import { P as PetProfileInput, R as RegisteredPet, a as PetProfilePatch } from './petsRepository-
|
|
2
|
+
import { P as PetProfileInput, R as RegisteredPet, a as PetProfilePatch } from './petsRepository-B1I6Lq_m.js';
|
|
3
3
|
import { E as EverfurResult } from './EverfurResult-ClPTS0P2.js';
|
|
4
4
|
import { E as EverfurThemeInput, C as ClientBranding } from './branding-DJf4h12Q.js';
|
|
5
|
-
import { A as AuthContext, T as TokenProvider } from './identity-
|
|
5
|
+
import { A as AuthContext, T as TokenProvider } from './identity-4lohfP2L.js';
|
|
6
6
|
import { U as UserRef, P as PetRef, C as ConversationId } from './ids-B2GAAifq.js';
|
|
7
|
-
import { T as TransportPort } from './config-
|
|
7
|
+
import { T as TransportPort } from './config-CuOczZUI.js';
|
|
8
8
|
import { I as ImageCachePort, K as KvPort } from './cacheEpoch-DknKn3S0.js';
|
|
9
9
|
import { E as ErrorPolicyPort } from './ErrorPolicyPort-C3nNSS_j.js';
|
|
10
|
-
import { U as UploadPort, n as ChatController } from './ports-
|
|
10
|
+
import { U as UploadPort, n as ChatController } from './ports-CrGAcey9.js';
|
|
11
11
|
import { C as CameraPort } from './CameraPort-Cv31Pz7g.js';
|
|
12
12
|
import { T as TelemetryPort } from './TelemetryPort-BDNr00hu.js';
|
|
13
13
|
import { U as UploadTransport } from './ports-BN6RHF9W.js';
|
|
@@ -52,6 +52,23 @@ interface LogSink {
|
|
|
52
52
|
emit(record: Readonly<LogRecord>): void;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/** A lifecycle event, discriminated on `type`. New members may be added; switch with a `default` branch. */
|
|
56
|
+
type EverfurClientEvent = {
|
|
57
|
+
readonly type: 'ready';
|
|
58
|
+
} | {
|
|
59
|
+
readonly type: 'error';
|
|
60
|
+
readonly code: string;
|
|
61
|
+
readonly requestId: string | null;
|
|
62
|
+
} | {
|
|
63
|
+
readonly type: 'session_expired';
|
|
64
|
+
readonly userRef: string | null;
|
|
65
|
+
} | {
|
|
66
|
+
readonly type: 'conversation_started';
|
|
67
|
+
readonly conversationId: string;
|
|
68
|
+
};
|
|
69
|
+
/** The partner's handler. It may throw; the SDK reports and swallows it. */
|
|
70
|
+
type EverfurEventHandler = (event: EverfurClientEvent) => void;
|
|
71
|
+
|
|
55
72
|
/**
|
|
56
73
|
* The public init config the host passes at EverfurProvider mount: the lean client subset
|
|
57
74
|
* (publishableKey / apiBaseUrl / contractVersion / transport / debug) PLUS the host-seam ports. The client
|
|
@@ -96,6 +113,13 @@ interface EverfurRuntimeConfig {
|
|
|
96
113
|
readonly imageCache?: ImageCachePort;
|
|
97
114
|
/** Structured, redacted LogPort events when true. */
|
|
98
115
|
readonly debug?: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Lifecycle events (`ready`, `error`, `session_expired`, `conversation_started`; see `EverfurClientEvent`).
|
|
118
|
+
* Delivered asynchronously, never during a render; a throwing handler is reported and ignored. Best effort at
|
|
119
|
+
* teardown: an event still queued when the runtime is disposed is dropped, and a refusal during `logout()` is
|
|
120
|
+
* not reported.
|
|
121
|
+
*/
|
|
122
|
+
readonly onEvent?: EverfurEventHandler;
|
|
99
123
|
}
|
|
100
124
|
/** Identity handed to the runtime: the partner's opaque user id + a lazy token minter (SPEC-00 §4.3). */
|
|
101
125
|
interface RuntimeUser {
|
|
@@ -339,4 +363,4 @@ interface EverfurRuntime {
|
|
|
339
363
|
dispose(): void;
|
|
340
364
|
}
|
|
341
365
|
|
|
342
|
-
export { type BeforeLogoutContext as B, type CreateEverfurRuntimeInput as C, type
|
|
366
|
+
export { type BeforeLogoutContext as B, type CreateEverfurRuntimeInput as C, type EverfurClientEvent as E, type LogLevel as L, NULL_SECURE_STORE as N, type PrepareOptions as P, type RuntimeTheme as R, type SecureStorePort as S, type EverfurEventHandler as a, type LogRecord as b, type LogSink as c, type PrepareResult as d, type PrepareStatus as e, type EntitlementSnapshot as f, type EverfurRuntime as g, type BeforeLogoutHook as h, type CapabilityKind as i, type CapabilityRegistry as j, type CapabilityServices as k, type ChatControllerRegistry as l, type ChatScope as m, type EntitlementStore as n, type EverfurRuntimeConfig as o, type RuntimeUser as p };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";var crypto=require("crypto");function ok(value,warning){/* @__PURE__ */
|
|
2
2
|
return Object.freeze({ok:true,value:value})}function err(error){/* @__PURE__ */
|
|
3
|
-
return Object.freeze({ok:false,error:error})}var EverfurConfigError=class _EverfurConfigError extends Error{constructor(kind,message){super(message),this.name="EverfurConfigError",this.kind=kind,Object.setPrototypeOf(this,_EverfurConfigError.prototype)}};var EVERFUR_SIGNATURE_HEADER="Everfur-Signature",DEFAULT_WEBHOOK_TOLERANCE_SECONDS=300,SIGNATURE_SCHEME="v1",MAX_HEADER_LENGTH=4096,HEX_SHA256_LENGTH=64,DIGITS=/^[0-9]+$/,EverfurWebhookVerificationError=class _EverfurWebhookVerificationError extends Error{constructor(code){super(`Everfur webhook verification failed: ${code}`),this.name="EverfurWebhookVerificationError",this.code=code,Object.setPrototypeOf(this,_EverfurWebhookVerificationError.prototype)}};function constructEvent(payload,signatureHeader,secrets,options={}){let body=rawBodyBytes(payload),keys=requireSecrets(secrets),tolerance=options.toleranceSeconds??DEFAULT_WEBHOOK_TOLERANCE_SECONDS;if(!Number.isInteger(tolerance)||tolerance<0)throw new EverfurConfigError("invalid-argument","toleranceSeconds must be a non-negative integer");let parsed=parseSignatureHeader(signatureHeader),now=options.nowSeconds??Math.floor(Date.now()/1e3);if(Math.abs(now-parsed.timestamp)>tolerance)throw new EverfurWebhookVerificationError("timestamp_outside_tolerance");let matched=false;for(let key of keys){let expected=Buffer.from(computeSignature(key,parsed.timestamp,body),"ascii");for(let candidate of parsed.signatures){if(candidate.length!==HEX_SHA256_LENGTH)continue;let actual=Buffer.from(candidate,"utf8");actual.length===expected.length&&crypto.timingSafeEqual(expected,actual)&&(matched=true)}}if(!matched)throw new EverfurWebhookVerificationError("no_matching_signature");return parseEnvelope(body)}function generateTestSignatureHeader(params){let body=rawBodyBytes(params.payload),keys=requireSecrets(params.secrets),timestamp=params.timestamp??Math.floor(Date.now()/1e3);if(!Number.isSafeInteger(timestamp)||timestamp<0)throw new EverfurConfigError("invalid-argument","timestamp must be a non-negative integer (unix seconds)");return[`t=${timestamp}`,...keys.map(key=>`${SIGNATURE_SCHEME}=${computeSignature(key,timestamp,body)}`)].join(",")}function computeSignature(secret,timestamp,body){return crypto.createHmac("sha256",Buffer.from(secret,"utf8")).update(`${timestamp}.`,"ascii").update(body).digest("hex")}function rawBodyBytes(payload){if(typeof payload=="string")return Buffer.from(payload,"utf8");if(payload instanceof Uint8Array)return payload;throw new EverfurConfigError("invalid-argument","constructEvent needs the raw request body (a string or a Buffer), not parsed JSON: re-serialised JSON does not reproduce the signed bytes.")}function requireSecrets(secrets){let list=typeof secrets=="string"?[secrets]:Array.isArray(secrets)?secrets:[];if(list.length===0||list.some(s=>typeof s!="string"||s.length===0))throw new EverfurConfigError("invalid-argument","at least one non-empty webhook signing secret is required");return list}function parseSignatureHeader(header){if(typeof header!="string"||header.length===0||header.length>MAX_HEADER_LENGTH)throw new EverfurWebhookVerificationError("malformed_header");let timestamp=null,signatures=[];for(let item of header.split(",")){let trimmed=item.trim(),at=trimmed.indexOf("=");if(at<0)throw new EverfurWebhookVerificationError("malformed_header");let key=trimmed.slice(0,at),value=trimmed.slice(at+1);if(key==="t"){if(timestamp!==null||!DIGITS.test(value))throw new EverfurWebhookVerificationError("malformed_header");let parsed=Number(value);if(!Number.isSafeInteger(parsed))throw new EverfurWebhookVerificationError("malformed_header");timestamp=parsed}else key===SIGNATURE_SCHEME&&signatures.push(value)}if(timestamp===null||signatures.length===0)throw new EverfurWebhookVerificationError("malformed_header");return{timestamp:timestamp,signatures:signatures}}function parseEnvelope(body){let json;try{json=JSON.parse(Buffer.from(body.buffer,body.byteOffset,body.byteLength).toString("utf8"))}catch{throw new EverfurWebhookVerificationError("malformed_payload")}if(!isRecord(json))throw new EverfurWebhookVerificationError("malformed_payload");let{id:id,object:object,type:type,api_version:apiVersion,created:created,livemode:livemode,data:data}=json;if(typeof id!="string"||id.length===0||object!=="event"||typeof type!="string"||type.length===0||typeof apiVersion!="string"||typeof created!="number"||typeof livemode!="boolean"||!isRecord(data)||!isRecord(data.object))throw new EverfurWebhookVerificationError("malformed_payload");return json}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var SDK_VERSION="0.
|
|
3
|
+
return Object.freeze({ok:false,error:error})}var EverfurConfigError=class _EverfurConfigError extends Error{constructor(kind,message){super(message),this.name="EverfurConfigError",this.kind=kind,Object.setPrototypeOf(this,_EverfurConfigError.prototype)}};var EVERFUR_SIGNATURE_HEADER="Everfur-Signature",DEFAULT_WEBHOOK_TOLERANCE_SECONDS=300,SIGNATURE_SCHEME="v1",MAX_HEADER_LENGTH=4096,HEX_SHA256_LENGTH=64,DIGITS=/^[0-9]+$/,EverfurWebhookVerificationError=class _EverfurWebhookVerificationError extends Error{constructor(code){super(`Everfur webhook verification failed: ${code}`),this.name="EverfurWebhookVerificationError",this.code=code,Object.setPrototypeOf(this,_EverfurWebhookVerificationError.prototype)}};function constructEvent(payload,signatureHeader,secrets,options={}){let body=rawBodyBytes(payload),keys=requireSecrets(secrets),tolerance=options.toleranceSeconds??DEFAULT_WEBHOOK_TOLERANCE_SECONDS;if(!Number.isInteger(tolerance)||tolerance<0)throw new EverfurConfigError("invalid-argument","toleranceSeconds must be a non-negative integer");let parsed=parseSignatureHeader(signatureHeader),now=options.nowSeconds??Math.floor(Date.now()/1e3);if(Math.abs(now-parsed.timestamp)>tolerance)throw new EverfurWebhookVerificationError("timestamp_outside_tolerance");let matched=false;for(let key of keys){let expected=Buffer.from(computeSignature(key,parsed.timestamp,body),"ascii");for(let candidate of parsed.signatures){if(candidate.length!==HEX_SHA256_LENGTH)continue;let actual=Buffer.from(candidate,"utf8");actual.length===expected.length&&crypto.timingSafeEqual(expected,actual)&&(matched=true)}}if(!matched)throw new EverfurWebhookVerificationError("no_matching_signature");return parseEnvelope(body)}function generateTestSignatureHeader(params){let body=rawBodyBytes(params.payload),keys=requireSecrets(params.secrets),timestamp=params.timestamp??Math.floor(Date.now()/1e3);if(!Number.isSafeInteger(timestamp)||timestamp<0)throw new EverfurConfigError("invalid-argument","timestamp must be a non-negative integer (unix seconds)");return[`t=${timestamp}`,...keys.map(key=>`${SIGNATURE_SCHEME}=${computeSignature(key,timestamp,body)}`)].join(",")}function computeSignature(secret,timestamp,body){return crypto.createHmac("sha256",Buffer.from(secret,"utf8")).update(`${timestamp}.`,"ascii").update(body).digest("hex")}function rawBodyBytes(payload){if(typeof payload=="string")return Buffer.from(payload,"utf8");if(payload instanceof Uint8Array)return payload;throw new EverfurConfigError("invalid-argument","constructEvent needs the raw request body (a string or a Buffer), not parsed JSON: re-serialised JSON does not reproduce the signed bytes.")}function requireSecrets(secrets){let list=typeof secrets=="string"?[secrets]:Array.isArray(secrets)?secrets:[];if(list.length===0||list.some(s=>typeof s!="string"||s.length===0))throw new EverfurConfigError("invalid-argument","at least one non-empty webhook signing secret is required");return list}function parseSignatureHeader(header){if(typeof header!="string"||header.length===0||header.length>MAX_HEADER_LENGTH)throw new EverfurWebhookVerificationError("malformed_header");let timestamp=null,signatures=[];for(let item of header.split(",")){let trimmed=item.trim(),at=trimmed.indexOf("=");if(at<0)throw new EverfurWebhookVerificationError("malformed_header");let key=trimmed.slice(0,at),value=trimmed.slice(at+1);if(key==="t"){if(timestamp!==null||!DIGITS.test(value))throw new EverfurWebhookVerificationError("malformed_header");let parsed=Number(value);if(!Number.isSafeInteger(parsed))throw new EverfurWebhookVerificationError("malformed_header");timestamp=parsed}else key===SIGNATURE_SCHEME&&signatures.push(value)}if(timestamp===null||signatures.length===0)throw new EverfurWebhookVerificationError("malformed_header");return{timestamp:timestamp,signatures:signatures}}function parseEnvelope(body){let json;try{json=JSON.parse(Buffer.from(body.buffer,body.byteOffset,body.byteLength).toString("utf8"))}catch{throw new EverfurWebhookVerificationError("malformed_payload")}if(!isRecord(json))throw new EverfurWebhookVerificationError("malformed_payload");let{id:id,object:object,type:type,api_version:apiVersion,created:created,livemode:livemode,data:data}=json;if(typeof id!="string"||id.length===0||object!=="event"||typeof type!="string"||type.length===0||typeof apiVersion!="string"||typeof created!="number"||typeof livemode!="boolean"||!isRecord(data)||!isRecord(data.object))throw new EverfurWebhookVerificationError("malformed_payload");return json}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var SDK_VERSION="0.10.0",SDK_PLATFORM="react-native",DEFAULT_CONTRACT_VERSION="2026-09-19",ENV_API_BASE_URL="EVERFUR_API_BASE_URL";function configFailure(reason,message){/* @__PURE__ */
|
|
4
4
|
return Object.freeze({ok:false,failure:/* @__PURE__ */Object.freeze({reason:reason,message:message})})}function tryResolveApiBaseUrl(apiBaseUrl){let explicit=apiBaseUrl?.trim(),candidate=explicit&&explicit.length>0?explicit:readEnv(ENV_API_BASE_URL);return candidate?normalizeBaseUrl(candidate):configFailure("missing-api-base-url",`apiBaseUrl is required: pass config.apiBaseUrl or set ${ENV_API_BASE_URL}. The SDK never ships a hardcoded host.`)}function resolveApiBaseUrl(apiBaseUrl){let outcome=tryResolveApiBaseUrl(apiBaseUrl);if(!outcome.ok)throw new EverfurConfigError("invalid-argument",outcome.failure.message);return outcome.value}function buildBaseHeaders(cfg){return{"X-Everfur-SDK-Version":cfg.sdkVersion,"X-Everfur-SDK-Platform":cfg.platform,"X-Everfur-Contract":cfg.contractVersion}}var ABSOLUTE_URL=/^([A-Za-z][A-Za-z0-9+.-]*):\/\/([^/?#]*)/;function hostOf(authority){return authority.slice(authority.lastIndexOf("@")+1).replace(/:\d+$/,"").toLowerCase()}function isPrintableHost(host){return host.length===0||host.includes("@")?false:host.startsWith("[")&&host.endsWith("]")?true:!host.includes(":")}function canEchoOrigin(rawTrimmed,host){let schemeEnd=rawTrimmed.indexOf("://");return schemeEnd<0||rawTrimmed.slice(schemeEnd+3).includes("@")?false:isPrintableHost(host)}function safeOrigin(scheme,host){return`${scheme}://${host}`}function normalizeBaseUrl(raw){let trimmed=raw.trim(),match=ABSOLUTE_URL.exec(trimmed);if(match===null||match[2]===void 0||match[2].length===0)return configFailure("malformed-api-base-url","apiBaseUrl is not a valid absolute URL");let scheme=(match[1]??"").toLowerCase(),host=hostOf(match[2]);if(host.length===0)return configFailure("malformed-api-base-url","apiBaseUrl is not a valid absolute URL");let shown=canEchoOrigin(trimmed,host)?`: ${safeOrigin(scheme,host)}`:"";if(scheme!=="https"){if(!(scheme==="http"&&isLoopbackHost(host)))return scheme==="http"?configFailure("insecure-api-base-url",`apiBaseUrl must use https (cleartext http is only allowed for localhost)${shown}`):configFailure("unsupported-api-base-url-scheme",`apiBaseUrl must be http(s)${shown}`)}let value=trimmed.endsWith("/")?trimmed.slice(0,-1):trimmed;/* @__PURE__ */
|
|
5
5
|
return Object.freeze({ok:true,value:value})}function isLoopbackHost(hostname){let host=hostname.toLowerCase();return host==="localhost"||host==="127.0.0.1"||host==="[::1]"||host==="::1"}function readEnv(name){let value=globalThis.process?.env?.[name];return typeof value=="string"&&value.trim().length>0?value.trim():void 0}var CONTRACT_RETRYABILITY=/* @__PURE__ */Object.freeze([
|
|
6
6
|
/* @__PURE__ */Object.freeze({wireCode:"AccessDeniedException",envelope:"http_envelope",httpStatus:403,retryable:false}),
|
|
@@ -89,4 +89,4 @@ return Object.freeze({ok:true,value:value})}function isLoopbackHost(hostname){le
|
|
|
89
89
|
/* @__PURE__ */Object.freeze({wireCode:"verify_user_ref_invalid",envelope:"http_envelope",httpStatus:422,retryable:false}),
|
|
90
90
|
/* @__PURE__ */Object.freeze({wireCode:"webhook_endpoint_update_empty",envelope:"http_envelope",httpStatus:400,retryable:false}),
|
|
91
91
|
/* @__PURE__ */Object.freeze({wireCode:"webhook_endpoint_update_invalid",envelope:"http_envelope",httpStatus:400,retryable:false}),
|
|
92
|
-
/* @__PURE__ */Object.freeze({wireCode:"webhook_url_rejected",envelope:"http_envelope",httpStatus:400,retryable:false})]);/* @__PURE__ */Object.freeze(CONTRACT_RETRYABILITY.map(row=>row.wireCode));var NORMALIZED_FOLD=/* @__PURE__ */Object.freeze({ValidationException:"validationFailed",AuthorizationException:"authRejected",PaymentRequiredException:"paymentRequired",AccessDeniedException:"accessDenied",ResourceNotFoundException:"resourceNotFound",ConflictException:"conflict",ThrottlingException:"rateLimited",InternalFailureException:"internalError",NotImplementedException:"notImplemented",ServiceUnavailableException:"serviceUnavailable",MethodNotAllowedException:"validationFailed",authExpired:"authExpired",unavailable:"serviceUnavailable",session_required:"sessionRequired",accessDenied:"accessDenied",invalidRequest:"sdkUpdateRequired",authRejected:"authRejected",rateLimited:"rateLimited",insufficientCapability:"accessDenied",event_cursor_invalid:"validationFailed",event_filter_invalid:"validationFailed",event_payload_invalid:"validationFailed",event_type_unknown:"validationFailed",idempotency_key_invalid:"validationFailed",idempotency_key_required:"validationFailed",idempotency_key_reused:"idempotencyConflict",payload_too_large:"validationFailed",webhook_url_rejected:"validationFailed",webhook_endpoint_update_empty:"validationFailed",webhook_endpoint_update_invalid:"validationFailed",event_type_not_available:"conflict",record_subject_not_found:"resourceNotFound",records_consent_required:"conflict",record_species_unsupported:"validationFailed",record_upload_invalid:"validationFailed",FILE_TOO_LARGE:"validationFailed",INVALID_CONTENT_TYPE:"validationFailed",attachment_unreadable:"validationFailed",provider_unsupported:"validationFailed",token_invalid:"validationFailed",device_cipher_unavailable:"serviceUnavailable",email_invalid:"validationFailed",consent_required:"validationFailed",consent_invalid:"validationFailed",consent_scope_wrong_route:"validationFailed",IDEMPOTENCY_KEY_IN_FLIGHT:"idempotencyInFlight",IDEMPOTENCY_KEY_REUSED_DIFFERENT_REQUEST:"idempotencyConflict",DAILY_QUOTA_EXCEEDED:"quotaExceeded",TIER_UPGRADE_REQUIRED:"paymentRequired",not_found:"conversationNotFound",timeout:"streamTimeout",internal_error:"internalError",invalid_request:"validationFailed",invalid_client:"authRejected",invalid_grant:"authRejected",unsupported_grant_type:"validationFailed",invalid_scope:"validationFailed",invalid_target:"validationFailed",invalid_redirect_uri:"validationFailed",invalid_client_metadata:"validationFailed",unsupported_response_type:"validationFailed",access_denied:"accessDenied",slow_down:"rateLimited",mcp_request_not_found:"resourceNotFound",mcp_request_gone:"resourceNotFound",mcp_connection_not_found:"resourceNotFound",mcp_request_conflict:"conflict",sandbox_only:"accessDenied",tenant_has_no_capabilities:"conflict",verify_mint_refused:"accessDenied",verify_mint_rate_limited:"rateLimited",verify_mint_unavailable:"serviceUnavailable",verify_user_ref_invalid:"validationFailed",insufficient_scope:"accessDenied",tenant_filter_invalid:"validationFailed",tenant_resource_not_found:"resourceNotFound",tenant_surface_not_enabled:"conflict",pet_health_species_unsupported:"validationFailed",pet_health_list_removals_unconfirmed:"validationFailed",petRefInUse:"conflict",share_limit_reached:"conflict",pet_not_registered:"resourceNotFound",species_unsupported:"validationFailed",partner_visit_owner_only:"accessDenied",partner_visit_link_conflict:"conflict",partner_visit_pet_already_mapped:"conflict"}),CONTRACT_ERROR_ROWS=/* @__PURE__ */Object.freeze(CONTRACT_RETRYABILITY.map(generated=>/* @__PURE__ */Object.freeze({wireCode:generated.wireCode,envelope:generated.envelope,retryable:generated.retryable,normalized:NORMALIZED_FOLD[generated.wireCode]}))),BY_KEY=new Map(CONTRACT_ERROR_ROWS.map(r=>[r.envelope+r.wireCode.toUpperCase(),r])),ENVELOPE_LOOKUP_ORDER=/* @__PURE__ */Object.freeze(["http_envelope",...[...new Set(CONTRACT_ERROR_ROWS.map(r=>r.envelope))].filter(e=>e!=="http_envelope").sort()]);function contractErrorFor(wireCode,envelope){if(typeof wireCode!="string")return;let key=wireCode.trim().toUpperCase();if(key.length!==0)for(let candidate of[envelope??"http_envelope",...ENVELOPE_LOOKUP_ORDER]){let row=BY_KEY.get(candidate+key);if(row)return row}}var CATEGORY_OF=/* @__PURE__ */Object.freeze({authExpired:"authentication",authRejected:"authentication",sessionRequired:"authentication",identitySignatureRequired:"authentication",accessDenied:"authorization",paymentRequired:"entitlement",quotaExceeded:"rateLimit",rateLimited:"rateLimit",validationFailed:"invalidRequest",sdkUpdateRequired:"invalidRequest",runtimeDisposed:"invalidRequest",conversationNotFound:"notFound",petNotFound:"notFound",resourceNotFound:"notFound",conflict:"conflict",idempotencyConflict:"conflict",idempotencyInFlight:"conflict",streamTimeout:"connection",streamIncomplete:"connection",upstreamLlmTimeout:"connection",serviceUnavailable:"connection",internalError:"server",notImplemented:"server",mediaUploadFailed:"media",moderationBlocked:"policy",unknown:"unknown"});function categoryFor(code){return CATEGORY_OF[code]}function fromWire(wire){let contractRow=contractErrorFor(wire);if(contractRow)return contractRow.normalized;let upper=(wire??"").trim().toUpperCase(),canonical=upper.replace(/[^A-Z0-9]/g,"");if(canonical==="AUTHREJECTED")return"authRejected";if(upper.startsWith("AUTH"))return"authExpired";switch(canonical){case"DAILYQUOTAEXCEEDED":case"QUOTAEXCEEDED":return"quotaExceeded";case"RATELIMITED":case"TOOMANYREQUESTS":case"TELEVETRATELIMITED":return"rateLimited";case"IDEMPOTENCYKEYCONFLICT":case"IDEMPOTENCYCONFLICT":return"idempotencyConflict";case"ACCESSDENIED":case"FORBIDDEN":return"accessDenied";case"IDENTITYSIGNATUREREQUIRED":return"identitySignatureRequired";case"RUNTIMEDISPOSED":return"runtimeDisposed";case"NOTFOUND":case"CONVERSATIONNOTFOUND":return"conversationNotFound";case"PETNOTFOUND":return"petNotFound";case"TIMEOUT":case"STREAMTIMEOUT":return"streamTimeout";case"MEDIAUPLOADFAILED":case"UNRECOGNIZEDVIDEOFORMAT":case"FILETOOSMALL":return"mediaUploadFailed";case"MODERATIONBLOCKED":return"moderationBlocked";case"UPSTREAMLLMTIMEOUT":return"upstreamLlmTimeout";case"INTERNALERROR":case"INTERNALSERVERERROR":return"internalError";case"STREAMINCOMPLETE":case"CHATSTREAMINCOMPLETE":return"streamIncomplete";case"INVALIDANALYSISTYPE":case"INVALIDUPLOADPURPOSE":return"unknown";default:return"unknown"}}function fromHttpStatus(status){return status===401?"authExpired":status===403?"accessDenied":status===404?"conversationNotFound":status===409?"idempotencyConflict":status===421?"unknown":status===429?"rateLimited":status===400||status===422?"unknown":status>=500?"internalError":"unknown"}var AUTO_RETRYABLE_CODES=/* @__PURE__ */new Set(["streamTimeout","rateLimited","internalError","upstreamLlmTimeout","streamIncomplete"]);function isAutoRetryable(code){return AUTO_RETRYABLE_CODES.has(code)}var RETRYABLE_CONTRACT_CODES=/* @__PURE__ */new Set(["serviceUnavailable","conflict","idempotencyInFlight"]);function isRetryableCode(code){return isAutoRetryable(code)||RETRYABLE_CONTRACT_CODES.has(code)}var ACCESS_DENIED_COPY="This feature isn't available on your account right now.",VALIDATION_FAILED_COPY="Something in that request was not right. Check the details and try again.",USER_FACING_COPY=/* @__PURE__ */Object.freeze({authExpired:"Please sign in again to continue.",authRejected:"Please sign in again to continue.",sessionRequired:"This app needs to be updated to keep using Everfur.",accessDenied:ACCESS_DENIED_COPY,paymentRequired:"This is part of a paid plan.",quotaExceeded:"You have used today's messages. This resets tomorrow.",rateLimited:"You are sending messages quickly. Try again in a few seconds.",validationFailed:VALIDATION_FAILED_COPY,sdkUpdateRequired:"This app needs to be updated to keep using Everfur.",conflict:"That is already running. Wait for it to finish, then try again.",idempotencyConflict:"That message was already delivered.",idempotencyInFlight:"That is still processing. Give it a moment.",conversationNotFound:"This conversation is no longer available.",petNotFound:"We could not find that pet. Please pick a pet and try again.",resourceNotFound:"We could not find that.",streamTimeout:"The response timed out. Tap retry to try again.",mediaUploadFailed:"We could not upload that photo. Please attach it again.",moderationBlocked:"This request cannot be answered here.",upstreamLlmTimeout:"The response timed out. Tap retry to try again.",internalError:"We hit a snag on our end. Please try again.",notImplemented:"That is not available yet.",serviceUnavailable:"That service is briefly unavailable. Try again shortly.",streamIncomplete:"The connection dropped mid-answer. Tap retry to continue.",identitySignatureRequired:ACCESS_DENIED_COPY,runtimeDisposed:VALIDATION_FAILED_COPY,unknown:"Something went wrong. Please try again."});function userFacingError(code){return USER_FACING_COPY[code]}function defineHidden(target,key,value){Object.defineProperty(target,key,{value:value,enumerable:false,writable:false,configurable:false})}var REASON_CODE_SHAPE=/^[a-z][a-z0-9_]{0,63}$/;function makeEverfurError(code,opts){let row=contractErrorFor(opts?.wireCode,opts?.wireEnvelope),error={code:code,category:categoryFor(code),retryable:opts?.retryable??isRetryableCode(code),displayMessage:userFacingError(code)};opts?.httpStatus!==void 0&&(error.httpStatus=opts.httpStatus),opts?.requestId&&(error.requestId=opts.requestId),typeof opts?.reasonCode=="string"&&REASON_CODE_SHAPE.test(opts.reasonCode)&&(error.reasonCode=opts.reasonCode);let wait=opts?.retryAfterSeconds;if(typeof wait=="number"&&Number.isFinite(wait)&&wait>=0&&(error.retryAfterSeconds=Math.round(wait)),row);return opts?.wireMessage&&defineHidden(error,"wireMessage",opts.wireMessage),opts?.raw!==void 0&&opts.raw!==null&&defineHidden(error,"raw",opts.raw),/* @__PURE__ */Object.freeze(error)}var REQUEST_ID_HEADER="x-request-id";function errorFromResponse(status,body,requestId){let wireCode=extractWireCode(body),code=wireCode?fromWire(wireCode):fromHttpStatus(status),wireMessage=extractWireMessage(body);return makeEverfurError(code,{httpStatus:status,...extractRetryable(body)?{retryable:true}:{},...requestId?{requestId:requestId}:{},...wireCode?{wireCode:wireCode}:{},...extractReasonCode(body)?{reasonCode:extractReasonCode(body)}:{},...extractRetryAfterSeconds(body)!==null?{retryAfterSeconds:extractRetryAfterSeconds(body)}:{},...wireMessage?{wireMessage:wireMessage}:{},...body!=null?{raw:body}:{}})}function extractRetryAfterSeconds(body){let b=body,value=b?.retry_after_seconds??b?.error?.retry_after_seconds;return typeof value=="number"&&Number.isFinite(value)&&value>=0?value:null}function networkError(cause){return makeEverfurError("internalError",{retryable:true,wireMessage:describeCause(cause)})}function requestIdOf(res){let value=res.headers.get(REQUEST_ID_HEADER);return typeof value=="string"&&value.length>0?value:null}function getGlobalFetch(){let candidate=globalThis.fetch;if(typeof candidate!="function")throw new EverfurConfigError("missing-peer-dependency","global fetch is unavailable; provide config.transport or an injected fetch implementation");return candidate}function extractReasonCode(body){let b=body,reason=b?.error?.reason_code??b?.reason_code;return typeof reason=="string"&&reason.length>0?reason:null}function extractWireCode(body){let b=body,code=b?.error?.code??b?.code;return typeof code=="string"&&code.length>0?code:null}function extractWireMessage(body){let b=body,message=b?.error?.message??b?.message;return typeof message=="string"&&message.length>0?message:null}function extractRetryable(body){let b=body;return b?.error?.retryable===true||b?.retryable===true}function describeCause(cause){return cause instanceof Error?cause.message:typeof cause=="string"?cause:"network request failed"}var EVERFUR_WEBHOOK_EVENT_TYPES=/* @__PURE__ */Object.freeze(["member.linked","member.unlinked","visit.booked","visit.cancelled","visit.completed","visit.no_show","record_request.updated","record.ready","webhook_endpoint.test","chat.follow_up_due","chat.urgency.flagged","pet.vaccination.due","visit.rescheduled","visit.reminder","visit.followup_sent","chat.reminder_due","record.activation","visit.message_received","visit.ended"]),EVERFUR_WEBHOOK_ONLY_EVENT_TYPES=/* @__PURE__ */Object.freeze(["member.linked","member.unlinked","chat.urgency.flagged","webhook_endpoint.test"]);function isEverfurWebhookEventType(type){return typeof type=="string"&&EVERFUR_WEBHOOK_EVENT_TYPES.includes(type)}function isEverfurWebhookEvent(event){return isEverfurWebhookEventType(event.type)}var PARTNER_INBOUND_EVENT_TYPES=/* @__PURE__ */Object.freeze(["pet.profile.updated","pet.incident.reported","pet.behavior_note.added","pet.service_score.recorded","pet.deleted","member.status_changed","member.deleted"]);var USER_REF_MAX=128;function assertValidUserRef(raw){let length=typeof raw=="string"?[...raw].length:0;if(typeof raw!="string"||length<1||length>USER_REF_MAX)throw new EverfurConfigError("invalid-argument",`user_ref must be 1..${USER_REF_MAX} characters`);if(raw.trim().length===0)throw new EverfurConfigError("invalid-argument","user_ref must not be blank: the server strips surrounding whitespace before validating, so a whitespace-only value arrives empty and is rejected as required.");if(raw!==raw.trim())throw new EverfurConfigError("invalid-argument","user_ref must not have leading or trailing whitespace: the server strips it, so padded and unpadded forms of the same id resolve to ONE user. Pass the exact id you want to key on.");if(raw.includes("@"))throw new EverfurConfigError("invalid-argument","user_ref must not contain '@'");if(!isPrintable(raw))throw new EverfurConfigError("invalid-argument","user_ref must be printable (no control characters)");return raw}function isPrintable(value){return!NON_PRINTABLE.test(value)}var NON_PRINTABLE=/[\p{Cc}\p{Cf}\p{Cs}\p{Co}\p{Cn}\p{Zl}\p{Zp}]|(?!\u0020)[\p{Zs}]/u;function hasLoneSurrogate(value){for(let i=0;i<value.length;i+=1){let code=value.charCodeAt(i);if(code>=55296&&code<=56319){let low=value.charCodeAt(i+1);if(!(low>=56320&&low<=57343))return true;i+=1}else if(code>=56320&&code<=57343)return true}return false}function serverLength(value){return[...value].length}var SPECIES_ALIASES=/* @__PURE__ */Object.freeze({dog:"dog",canine:"dog",k9:"dog",puppy:"dog",cat:"cat",feline:"cat",kitten:"cat"});function canonicalPetSpecies(raw){if(typeof raw!="string")return null;let key=raw.trim().toLowerCase();return Object.prototype.hasOwnProperty.call(SPECIES_ALIASES,key)?SPECIES_ALIASES[key]:null}var LIST_MAX=50,REF_MAX=128,NAME_MAX=120,SHORT_MAX=120,NOTES_MAX=2e3,FOOD_MAX=120,MICROCHIP_MAX=80,SEXES=/* @__PURE__ */new Set(["male","female","unknown"]),PRECISIONS=/* @__PURE__ */new Set(["day","month","year"]),ACTIVITY=/* @__PURE__ */new Set(["low","medium","high","athletic"]),INDOOR_OUTDOOR=/* @__PURE__ */new Set(["indoor","outdoor","both"]),SEVERITIES=/* @__PURE__ */new Set(["mild","moderate","severe"]),ISO_DATE=/^(\d{4})-(\d{2})-(\d{2})$/,SCALAR_WIRE=[["sex","sex"],["spayedNeutered","spayed_neutered"],["birthDate","birth_date"],["birthDatePrecision","birth_date_precision"],["activityLevel","activity_level"],["indoorOutdoor","indoor_outdoor"],["foodBrand","food_brand"],["foodType","food_type"],["microchipId","microchip_id"]],LIST_WIRE=[["allergies","allergies"],["medications","medications"],["supplements","supplements"],["conditions","conditions"]];/* @__PURE__ */Object.freeze([...SCALAR_WIRE,...LIST_WIRE].map(([key])=>key));function isRealDate(value){let match=ISO_DATE.exec(value);if(match===null)return false;let[year,month,day]=[Number(match[1]),Number(match[2]),Number(match[3])],date2=new Date(Date.UTC(year,month-1,day));return date2.getUTCFullYear()===year&&date2.getUTCMonth()===month-1&&date2.getUTCDate()===day}var oneOf=allowed=>(field,value)=>typeof value=="string"&&allowed.has(value)?null:`${field} must be one of ${[...allowed].join(", ")}`,boolean=(field,value)=>typeof value=="boolean"?null:`${field} must be true or false`,date=(field,value)=>typeof value=="string"&&isRealDate(value)?null:`${field} must be a real date written YYYY-MM-DD`,text=(max,opts={})=>(field,value)=>{if(typeof value!="string")return`${field} must be a string`;if(hasLoneSurrogate(value))return`${field} contains an unpaired surrogate and cannot be encoded`;let measured=opts.trimmed?value.trim():value;if(opts.required&&measured.length===0)return`${field} is required and must not be blank`;let length=serverLength(measured);return length<=max?null:`${field} is ${length} characters; the server accepts at most ${max}`},SCALAR_CHECKS={sex:oneOf(SEXES),spayedNeutered:boolean,birthDate:date,birthDatePrecision:oneOf(PRECISIONS),activityLevel:oneOf(ACTIVITY),indoorOutdoor:oneOf(INDOOR_OUTDOOR),foodBrand:text(FOOD_MAX),foodType:text(FOOD_MAX),microchipId:text(MICROCHIP_MAX)},REF_FIELD=["ref","ref",false,text(REF_MAX,{required:true,trimmed:true})],NOTES_FIELD=["notes","notes",false,text(NOTES_MAX,{trimmed:true})],MEDICATION_FIELDS=[REF_FIELD,["name","name",true,text(NAME_MAX,{required:true,trimmed:true})],["dose","dose",false,text(SHORT_MAX,{trimmed:true})],["frequency","frequency",false,text(SHORT_MAX,{trimmed:true})],["startDate","start_date",false,date],["endDate","end_date",false,date],NOTES_FIELD],ITEM_FIELDS={allergies:[REF_FIELD,["allergen","allergen",true,text(NAME_MAX,{required:true,trimmed:true})],["severity","severity",false,oneOf(SEVERITIES)],NOTES_FIELD],medications:MEDICATION_FIELDS,supplements:MEDICATION_FIELDS,conditions:[REF_FIELD,["conditionName","condition_name",true,text(NAME_MAX,{required:true,trimmed:true})],["diagnosedDate","diagnosed_date",false,date],NOTES_FIELD]};function itemToWire(list,index,raw){let at=`${list}[${index}]`;if(typeof raw!="object"||raw===null||Array.isArray(raw))return{error:`${at} must be an object`};let source=raw,item={};for(let[key,wire,isRequired,check]of ITEM_FIELDS[list]){let value=source[key];if(value==null){if(isRequired)return{error:`${at}.${key} is required`};value===null&&(item[wire]=null);continue}let bad=check(`${at}.${key}`,value);if(bad!==null)return{error:bad};item[wire]=value}let start=item.start_date,end=item.end_date;return typeof start=="string"&&typeof end=="string"&&end<start?{error:`${at}.endDate must not be before startDate`}:{item:item}}function listToWire(list,raw){if(!Array.isArray(raw))return{error:`${list} must be an array (send [] to clear it)`};if(raw.length>LIST_MAX)return{error:`${list} has ${raw.length} items; the server accepts at most ${LIST_MAX}`};let items=[],refs=/* @__PURE__ */new Set;for(let index=0;index<raw.length;index+=1){let mapped=itemToWire(list,index,raw[index]);if("error"in mapped)return mapped;let ref=mapped.item.ref;if(typeof ref=="string"){let key=ref.trim();if(refs.has(key))return{error:`${list}: ref ${JSON.stringify(key)} is used twice; a ref names one item`};refs.add(key)}items.push(mapped.item)}return{items:items}}function petHealthToWire(input,species){let source=input,body={};for(let[key,wire]of SCALAR_WIRE){let value=source[key];if(value!==void 0){if(value!==null){let bad=SCALAR_CHECKS[key](key,value);if(bad!==null)return{error:bad}}body[wire]=value}}let dateSent=source.birthDate!==void 0,precisionSent=source.birthDatePrecision!==void 0;if(dateSent!==precisionSent||dateSent&&source.birthDate===null!=(source.birthDatePrecision===null))return{error:"birthDate and birthDatePrecision must be sent together, both set or both null"};for(let[key,wire]of LIST_WIRE){let value=source[key];if(value===void 0)continue;let mapped=listToWire(key,value);if("error"in mapped)return mapped;body[wire]=mapped.items}return Object.keys(body).length>0&&species!==void 0&&canonicalPetSpecies(species)===null?{error:"health fields need a pet Everfur reads as a dog or a cat (dog, canine, k9, puppy, cat, feline, kitten)"}:{body:body}}var SECRET_KEY_PREFIXES=["sk_partner_","rk_partner_"];function assertServerSecretKey(value,action){if(typeof value!="string"||value.length===0)throw new EverfurConfigError("invalid-argument","partnerSecretKey is required");if(value.startsWith("pk_"))throw new EverfurConfigError("invalid-argument",`partnerSecretKey is a publishable key (pk_...): ${action} needs your secret key, server side only`);if(!SECRET_KEY_PREFIXES.some(prefix=>value.startsWith(prefix)))throw new EverfurConfigError("invalid-argument","partnerSecretKey must be an sk_partner_ secret key or an rk_partner_ restricted key")}var PROFILE_FIELDS=[["name","name"],["species","species"],["breed","breed"],["ageYears","age_years"],["weightKg","weight_kg"],["partnerLabelInstructions","partner_label_instructions"]];function partnerPetProfileBody(profile){if(typeof profile!="object"||profile===null||Array.isArray(profile))throw new EverfurConfigError("invalid-argument","the pet profile must be an object");let body={};for(let[key,wire]of PROFILE_FIELDS)profile[key]!==void 0&&(body[wire]=profile[key]);let health=petHealthToWire(profile,profile.species);if("error"in health)throw new EverfurConfigError("invalid-argument",health.error);return Object.assign(body,health.body)}var IDEMPOTENCY_KEY_SHAPE=/^[\x21-\x7e]{1,255}$/,MAX_BODY_BYTES=32*1024,DATE_TIME_WITH_OFFSET=/^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:[Zz]|[+-]\d{2}:?\d{2})$/,SEND_TIMEOUT_MS=3e4,INBOUND_RULES=/* @__PURE__ */Object.freeze({"pet.profile.updated":{subject:"pet",schemaVersions:[1,2]},"pet.incident.reported":{subject:"pet",schemaVersions:[1]},"pet.behavior_note.added":{subject:"pet",schemaVersions:[1]},"pet.service_score.recorded":{subject:"pet",schemaVersions:[1]},"pet.deleted":{subject:"pet",schemaVersions:[1]},"member.status_changed":{subject:"member",schemaVersions:[1]},"member.deleted":{subject:"member",schemaVersions:[1]}});async function sendPartnerEvent(client,event,idempotencyKey){let key=idempotencyKey??crypto.randomUUID();if(typeof key!="string"||!IDEMPOTENCY_KEY_SHAPE.test(key))throw new EverfurConfigError("invalid-argument","idempotencyKey must be 1 to 255 visible ASCII characters (no spaces, no control or non-ASCII characters)");assertServerSecretKey(client.partnerSecretKey,"sending events");let payload=serialize(buildBody(event)),fetchImpl=client.fetchImpl??getGlobalFetch(),url=`${resolveApiBaseUrl(client.apiBaseUrl)}/partners/events`,headers={...buildBaseHeaders({sdkVersion:SDK_VERSION,platform:SDK_PLATFORM,contractVersion:client.contractVersion??DEFAULT_CONTRACT_VERSION}),accept:"application/json","content-type":"application/json","idempotency-key":key,"x-everfur-partner-secret-key":client.partnerSecretKey},controller=new AbortController,timer=setTimeout(()=>controller.abort(),SEND_TIMEOUT_MS),res;try{res=await fetchImpl(url,{method:"POST",headers:headers,body:payload,signal:controller.signal})}catch(cause){return err(networkError(cause))}finally{clearTimeout(timer)}let json=null;try{json=await res.json()}catch{json=null}let requestId=requestIdOf(res);if(!res.ok)return err(errorFromResponse(res.status,json,requestId));let receipt=parseReceipt(json,key);return receipt?ok(receipt):err(errorFromResponse(502,{error:{code:"INTERNAL_ERROR"}},requestId))}function isInboundType(value){return typeof value=="string"&&PARTNER_INBOUND_EVENT_TYPES.includes(value)}function buildBody(event){if(typeof event!="object"||event===null)throw new EverfurConfigError("invalid-argument","event is required");if(!isInboundType(event.type))throw new EverfurConfigError("invalid-argument",`event.type must be one of ${PARTNER_INBOUND_EVENT_TYPES.join(", ")}`);let rule=INBOUND_RULES[event.type],schemaVersion=event.schemaVersion??1;if(typeof schemaVersion!="number"||!rule.schemaVersions.includes(schemaVersion))throw new EverfurConfigError("invalid-argument",`event.schemaVersion must be one of ${rule.schemaVersions.join(", ")} for ${event.type}`);let userRef=assertValidUserRef(event.userRef);if(rule.subject==="pet"&&event.petRef===void 0)throw new EverfurConfigError("invalid-argument",`event.petRef is required for ${event.type}`);if(rule.subject==="member"&&event.petRef!==void 0)throw new EverfurConfigError("invalid-argument",`event.petRef is not accepted on ${event.type}`);let petRef=event.petRef===void 0?void 0:assertValidPetRef(event.petRef);if(typeof event.data!="object"||event.data===null||Array.isArray(event.data))throw new EverfurConfigError("invalid-argument","event.data must be an object");let data=event.type==="pet.profile.updated"&&schemaVersion===2?partnerPetProfileBody(event.data):event.data,body={type:event.type,schema_version:schemaVersion,user_ref:userRef,occurred_at:occurredAtIso(event.occurredAt),data:data};return petRef!==void 0&&(body.pet_ref=petRef),body}function assertValidPetRef(raw){try{return assertValidUserRef(raw)}catch(cause){throw cause instanceof EverfurConfigError?new EverfurConfigError("invalid-argument",`event.petRef follows the user_ref rule: ${cause.message}`):cause}}function occurredAtIso(value){if(typeof value=="string"&&!DATE_TIME_WITH_OFFSET.test(value))throw new EverfurConfigError("invalid-argument","event.occurredAt must be a Date or an ISO 8601 date-time with an explicit offset (Z or +05:30)");let date2=value instanceof Date?value:typeof value=="string"?new Date(value):new Date(Number.NaN);if(Number.isNaN(date2.getTime()))throw new EverfurConfigError("invalid-argument","event.occurredAt must be a Date or an ISO 8601 date-time with an explicit offset (Z or +05:30)");return date2.toISOString()}function serialize(body){let payload;try{payload=JSON.stringify(body)}catch{throw new EverfurConfigError("invalid-argument","event.data must be JSON-serialisable")}let bytes=(new TextEncoder).encode(payload).byteLength;if(bytes>MAX_BODY_BYTES)throw new EverfurConfigError("invalid-argument",`the event is ${bytes} bytes once serialised; Everfur accepts at most ${MAX_BODY_BYTES} (32 KB)`);return payload}function parseReceipt(json,idempotencyKey){if(typeof json!="object"||json===null)return null;let obj=json,id=obj.id,type=obj.type,schemaVersion=obj.schema_version,userRef=obj.user_ref,petRef=obj.pet_ref??null,occurredAt=obj.occurred_at,receivedAt=obj.received_at,status=obj.status,livemode=obj.livemode;return typeof id!="string"||id.length===0||!isInboundType(type)||typeof schemaVersion!="number"||typeof userRef!="string"||petRef!==null&&typeof petRef!="string"||typeof occurredAt!="string"||typeof receivedAt!="string"||typeof status!="string"||typeof livemode!="boolean"?null:/* @__PURE__ */Object.freeze({id:id,type:type,schemaVersion:schemaVersion,userRef:userRef,petRef:petRef,occurredAt:occurredAt,receivedAt:receivedAt,status:status,livemode:livemode,idempotencyKey:idempotencyKey})}exports.DEFAULT_WEBHOOK_TOLERANCE_SECONDS=DEFAULT_WEBHOOK_TOLERANCE_SECONDS;exports.EVERFUR_SIGNATURE_HEADER=EVERFUR_SIGNATURE_HEADER;exports.EVERFUR_WEBHOOK_EVENT_TYPES=EVERFUR_WEBHOOK_EVENT_TYPES;exports.EVERFUR_WEBHOOK_ONLY_EVENT_TYPES=EVERFUR_WEBHOOK_ONLY_EVENT_TYPES;exports.EverfurWebhookVerificationError=EverfurWebhookVerificationError;exports.PARTNER_INBOUND_EVENT_TYPES=PARTNER_INBOUND_EVENT_TYPES;exports.constructEvent=constructEvent;exports.generateTestSignatureHeader=generateTestSignatureHeader;exports.isEverfurWebhookEvent=isEverfurWebhookEvent;exports.isEverfurWebhookEventType=isEverfurWebhookEventType;exports.sendPartnerEvent=sendPartnerEvent;
|
|
92
|
+
/* @__PURE__ */Object.freeze({wireCode:"webhook_url_rejected",envelope:"http_envelope",httpStatus:400,retryable:false})]);/* @__PURE__ */Object.freeze(CONTRACT_RETRYABILITY.map(row=>row.wireCode));var NORMALIZED_FOLD=/* @__PURE__ */Object.freeze({ValidationException:"validationFailed",AuthorizationException:"authRejected",PaymentRequiredException:"paymentRequired",AccessDeniedException:"accessDenied",ResourceNotFoundException:"resourceNotFound",ConflictException:"conflict",ThrottlingException:"rateLimited",InternalFailureException:"internalError",NotImplementedException:"notImplemented",ServiceUnavailableException:"serviceUnavailable",MethodNotAllowedException:"validationFailed",authExpired:"authExpired",unavailable:"serviceUnavailable",session_required:"sessionRequired",accessDenied:"accessDenied",invalidRequest:"sdkUpdateRequired",authRejected:"authRejected",rateLimited:"rateLimited",insufficientCapability:"accessDenied",event_cursor_invalid:"validationFailed",event_filter_invalid:"validationFailed",event_payload_invalid:"validationFailed",event_type_unknown:"validationFailed",idempotency_key_invalid:"validationFailed",idempotency_key_required:"validationFailed",idempotency_key_reused:"idempotencyConflict",payload_too_large:"validationFailed",webhook_url_rejected:"validationFailed",webhook_endpoint_update_empty:"validationFailed",webhook_endpoint_update_invalid:"validationFailed",event_type_not_available:"conflict",record_subject_not_found:"resourceNotFound",records_consent_required:"conflict",record_species_unsupported:"validationFailed",record_upload_invalid:"validationFailed",FILE_TOO_LARGE:"validationFailed",INVALID_CONTENT_TYPE:"validationFailed",attachment_unreadable:"validationFailed",provider_unsupported:"validationFailed",token_invalid:"validationFailed",device_cipher_unavailable:"serviceUnavailable",email_invalid:"validationFailed",consent_required:"validationFailed",consent_invalid:"validationFailed",consent_scope_wrong_route:"validationFailed",IDEMPOTENCY_KEY_IN_FLIGHT:"idempotencyInFlight",IDEMPOTENCY_KEY_REUSED_DIFFERENT_REQUEST:"idempotencyConflict",DAILY_QUOTA_EXCEEDED:"quotaExceeded",TIER_UPGRADE_REQUIRED:"paymentRequired",not_found:"conversationNotFound",timeout:"streamTimeout",internal_error:"internalError",invalid_request:"validationFailed",invalid_client:"authRejected",invalid_grant:"authRejected",unsupported_grant_type:"validationFailed",invalid_scope:"validationFailed",invalid_target:"validationFailed",invalid_redirect_uri:"validationFailed",invalid_client_metadata:"validationFailed",unsupported_response_type:"validationFailed",access_denied:"accessDenied",slow_down:"rateLimited",mcp_request_not_found:"resourceNotFound",mcp_request_gone:"resourceNotFound",mcp_connection_not_found:"resourceNotFound",mcp_request_conflict:"conflict",sandbox_only:"accessDenied",tenant_has_no_capabilities:"conflict",verify_mint_refused:"accessDenied",verify_mint_rate_limited:"rateLimited",verify_mint_unavailable:"serviceUnavailable",verify_user_ref_invalid:"validationFailed",insufficient_scope:"accessDenied",tenant_filter_invalid:"validationFailed",tenant_resource_not_found:"resourceNotFound",tenant_surface_not_enabled:"conflict",pet_health_species_unsupported:"validationFailed",pet_health_list_removals_unconfirmed:"validationFailed",petRefInUse:"conflict",share_limit_reached:"conflict",pet_not_registered:"resourceNotFound",species_unsupported:"validationFailed",partner_visit_owner_only:"accessDenied",partner_visit_link_conflict:"conflict",partner_visit_pet_already_mapped:"conflict"}),CONTRACT_ERROR_ROWS=/* @__PURE__ */Object.freeze(CONTRACT_RETRYABILITY.map(generated=>/* @__PURE__ */Object.freeze({wireCode:generated.wireCode,envelope:generated.envelope,retryable:generated.retryable,normalized:NORMALIZED_FOLD[generated.wireCode]}))),BY_KEY=new Map(CONTRACT_ERROR_ROWS.map(r=>[r.envelope+r.wireCode.toUpperCase(),r])),ENVELOPE_LOOKUP_ORDER=/* @__PURE__ */Object.freeze(["http_envelope",...[...new Set(CONTRACT_ERROR_ROWS.map(r=>r.envelope))].filter(e=>e!=="http_envelope").sort()]);function contractErrorFor(wireCode,envelope){if(typeof wireCode!="string")return;let key=wireCode.trim().toUpperCase();if(key.length!==0)for(let candidate of[envelope??"http_envelope",...ENVELOPE_LOOKUP_ORDER]){let row=BY_KEY.get(candidate+key);if(row)return row}}var CATEGORY_OF=/* @__PURE__ */Object.freeze({authExpired:"authentication",authRejected:"authentication",sessionRequired:"authentication",identitySignatureRequired:"authentication",accessDenied:"authorization",paymentRequired:"entitlement",quotaExceeded:"rateLimit",rateLimited:"rateLimit",validationFailed:"invalidRequest",sdkUpdateRequired:"invalidRequest",runtimeDisposed:"invalidRequest",conversationNotFound:"notFound",petNotFound:"notFound",resourceNotFound:"notFound",conflict:"conflict",idempotencyConflict:"conflict",idempotencyInFlight:"conflict",streamTimeout:"connection",streamIncomplete:"connection",upstreamLlmTimeout:"connection",serviceUnavailable:"connection",internalError:"server",notImplemented:"server",mediaUploadFailed:"media",moderationBlocked:"policy",unknown:"unknown"});function categoryFor(code){return CATEGORY_OF[code]}function fromWire(wire){let contractRow=contractErrorFor(wire);if(contractRow)return contractRow.normalized;let upper=(wire??"").trim().toUpperCase(),canonical=upper.replace(/[^A-Z0-9]/g,"");if(canonical==="AUTHREJECTED")return"authRejected";if(upper.startsWith("AUTH"))return"authExpired";switch(canonical){case"DAILYQUOTAEXCEEDED":case"QUOTAEXCEEDED":return"quotaExceeded";case"RATELIMITED":case"TOOMANYREQUESTS":case"TELEVETRATELIMITED":return"rateLimited";case"IDEMPOTENCYKEYCONFLICT":case"IDEMPOTENCYCONFLICT":return"idempotencyConflict";case"ACCESSDENIED":case"FORBIDDEN":return"accessDenied";case"IDENTITYSIGNATUREREQUIRED":return"identitySignatureRequired";case"RUNTIMEDISPOSED":return"runtimeDisposed";case"NOTFOUND":case"CONVERSATIONNOTFOUND":return"conversationNotFound";case"PETNOTFOUND":return"petNotFound";case"TIMEOUT":case"STREAMTIMEOUT":return"streamTimeout";case"MEDIAUPLOADFAILED":case"UNRECOGNIZEDVIDEOFORMAT":case"FILETOOSMALL":return"mediaUploadFailed";case"MODERATIONBLOCKED":return"moderationBlocked";case"UPSTREAMLLMTIMEOUT":return"upstreamLlmTimeout";case"INTERNALERROR":case"INTERNALSERVERERROR":return"internalError";case"STREAMINCOMPLETE":case"CHATSTREAMINCOMPLETE":return"streamIncomplete";case"INVALIDANALYSISTYPE":case"INVALIDUPLOADPURPOSE":return"unknown";default:return"unknown"}}function fromHttpStatus(status){return status===401?"authExpired":status===403?"accessDenied":status===404?"conversationNotFound":status===409?"idempotencyConflict":status===421?"unknown":status===429?"rateLimited":status===400||status===422?"unknown":status>=500?"internalError":"unknown"}var AUTO_RETRYABLE_CODES=/* @__PURE__ */new Set(["streamTimeout","rateLimited","internalError","upstreamLlmTimeout","streamIncomplete"]);function isAutoRetryable(code){return AUTO_RETRYABLE_CODES.has(code)}var RETRYABLE_CONTRACT_CODES=/* @__PURE__ */new Set(["serviceUnavailable","conflict","idempotencyInFlight"]);function isRetryableCode(code){return isAutoRetryable(code)||RETRYABLE_CONTRACT_CODES.has(code)}var ACCESS_DENIED_COPY="This feature isn't available on your account right now.",VALIDATION_FAILED_COPY="Something in that request was not right. Check the details and try again.",USER_FACING_COPY=/* @__PURE__ */Object.freeze({authExpired:"Please sign in again to continue.",authRejected:"Please sign in again to continue.",sessionRequired:"This app needs to be updated to keep using Everfur.",accessDenied:ACCESS_DENIED_COPY,paymentRequired:"This is part of a paid plan.",quotaExceeded:"You have used today's messages. This resets tomorrow.",rateLimited:"You are sending messages quickly. Try again in a few seconds.",validationFailed:VALIDATION_FAILED_COPY,sdkUpdateRequired:"This app needs to be updated to keep using Everfur.",conflict:"That is already running. Wait for it to finish, then try again.",idempotencyConflict:"That message was already delivered.",idempotencyInFlight:"That is still processing. Give it a moment.",conversationNotFound:"This conversation is no longer available.",petNotFound:"We could not find that pet. Please pick a pet and try again.",resourceNotFound:"We could not find that.",streamTimeout:"The response timed out. Tap retry to try again.",mediaUploadFailed:"We could not upload that photo. Please attach it again.",moderationBlocked:"This request cannot be answered here.",upstreamLlmTimeout:"The response timed out. Tap retry to try again.",internalError:"We hit a snag on our end. Please try again.",notImplemented:"That is not available yet.",serviceUnavailable:"That service is briefly unavailable. Try again shortly.",streamIncomplete:"The connection dropped mid-answer. Tap retry to continue.",identitySignatureRequired:ACCESS_DENIED_COPY,runtimeDisposed:VALIDATION_FAILED_COPY,unknown:"Something went wrong. Please try again."});function userFacingError(code){return USER_FACING_COPY[code]}function defineHidden(target,key,value){Object.defineProperty(target,key,{value:value,enumerable:false,writable:false,configurable:false})}var REASON_CODE_SHAPE=/^[a-z][a-z0-9_]{0,63}$/;function makeEverfurError(code,opts){let row=contractErrorFor(opts?.wireCode,opts?.wireEnvelope),error={code:code,category:categoryFor(code),retryable:opts?.retryable??isRetryableCode(code),displayMessage:userFacingError(code)};opts?.httpStatus!==void 0&&(error.httpStatus=opts.httpStatus),opts?.requestId&&(error.requestId=opts.requestId),typeof opts?.reasonCode=="string"&&REASON_CODE_SHAPE.test(opts.reasonCode)&&(error.reasonCode=opts.reasonCode);let wait=opts?.retryAfterSeconds;if(typeof wait=="number"&&Number.isFinite(wait)&&wait>=0&&(error.retryAfterSeconds=Math.round(wait)),row);return opts?.wireMessage&&defineHidden(error,"wireMessage",opts.wireMessage),opts?.raw!==void 0&&opts.raw!==null&&defineHidden(error,"raw",opts.raw),/* @__PURE__ */Object.freeze(error)}var REQUEST_ID_HEADER="x-request-id";function errorFromResponse(status,body,requestId){let wireCode=extractWireCode(body),code=wireCode?fromWire(wireCode):fromHttpStatus(status),wireMessage=extractWireMessage(body);return makeEverfurError(code,{httpStatus:status,...extractRetryable(body)?{retryable:true}:{},...requestId?{requestId:requestId}:{},...wireCode?{wireCode:wireCode}:{},...extractReasonCode(body)?{reasonCode:extractReasonCode(body)}:{},...extractRetryAfterSeconds(body)!==null?{retryAfterSeconds:extractRetryAfterSeconds(body)}:{},...wireMessage?{wireMessage:wireMessage}:{},...body!=null?{raw:body}:{}})}function extractRetryAfterSeconds(body){let b=body,value=b?.retry_after_seconds??b?.error?.retry_after_seconds;return typeof value=="number"&&Number.isFinite(value)&&value>=0?value:null}function networkError(cause){return makeEverfurError("internalError",{retryable:true,wireMessage:describeCause(cause)})}function requestIdOf(res){let value=res.headers.get(REQUEST_ID_HEADER);return typeof value=="string"&&value.length>0?value:null}function getGlobalFetch(){let candidate=globalThis.fetch;if(typeof candidate!="function")throw new EverfurConfigError("missing-peer-dependency","global fetch is unavailable; provide config.transport or an injected fetch implementation");return candidate}function extractReasonCode(body){let b=body,reason=b?.error?.reason_code??b?.reason_code;return typeof reason=="string"&&reason.length>0?reason:null}function extractWireCode(body){let b=body,code=b?.error?.code??b?.code;return typeof code=="string"&&code.length>0?code:null}function extractWireMessage(body){let b=body,message=b?.error?.message??b?.message;return typeof message=="string"&&message.length>0?message:null}function extractRetryable(body){let b=body;return b?.error?.retryable===true||b?.retryable===true}function describeCause(cause){return cause instanceof Error?cause.message:typeof cause=="string"?cause:"network request failed"}var EVERFUR_WEBHOOK_EVENT_TYPES=/* @__PURE__ */Object.freeze(["member.linked","member.unlinked","visit.booked","visit.cancelled","visit.completed","visit.no_show","record_request.updated","record.ready","webhook_endpoint.test","chat.follow_up_due","chat.urgency.flagged","pet.vaccination.due","visit.rescheduled","visit.reminder","visit.followup_sent","chat.reminder_due","record.activation","visit.message_received","visit.ended","contact.exported"]),EVERFUR_WEBHOOK_ONLY_EVENT_TYPES=/* @__PURE__ */Object.freeze(["member.linked","member.unlinked","chat.urgency.flagged","webhook_endpoint.test","contact.exported"]);function isEverfurWebhookEventType(type){return typeof type=="string"&&EVERFUR_WEBHOOK_EVENT_TYPES.includes(type)}function isEverfurWebhookEvent(event){return isEverfurWebhookEventType(event.type)}var PARTNER_INBOUND_EVENT_TYPES=/* @__PURE__ */Object.freeze(["pet.profile.updated","pet.incident.reported","pet.behavior_note.added","pet.service_score.recorded","pet.deleted","member.status_changed","member.deleted"]);var SECRET_KEY_PREFIXES=["sk_partner_","rk_partner_"];function assertServerSecretKey(value,action){if(typeof value!="string"||value.length===0)throw new EverfurConfigError("invalid-argument","partnerSecretKey is required");if(value.startsWith("pk_"))throw new EverfurConfigError("invalid-argument",`partnerSecretKey is a publishable key (pk_...): ${action} needs your secret key, server side only`);if(!SECRET_KEY_PREFIXES.some(prefix=>value.startsWith(prefix)))throw new EverfurConfigError("invalid-argument","partnerSecretKey must be an sk_partner_ secret key or an rk_partner_ restricted key")}var USER_REF_MAX=128;function assertValidUserRef(raw){let length=typeof raw=="string"?[...raw].length:0;if(typeof raw!="string"||length<1||length>USER_REF_MAX)throw new EverfurConfigError("invalid-argument",`user_ref must be 1..${USER_REF_MAX} characters`);if(raw.trim().length===0)throw new EverfurConfigError("invalid-argument","user_ref must not be blank: the server strips surrounding whitespace before validating, so a whitespace-only value arrives empty and is rejected as required.");if(raw!==raw.trim())throw new EverfurConfigError("invalid-argument","user_ref must not have leading or trailing whitespace: the server strips it, so padded and unpadded forms of the same id resolve to ONE user. Pass the exact id you want to key on.");if(raw.includes("@"))throw new EverfurConfigError("invalid-argument","user_ref must not contain '@'");if(!isPrintable(raw))throw new EverfurConfigError("invalid-argument","user_ref must be printable (no control characters)");return raw}function isPrintable(value){return!NON_PRINTABLE.test(value)}var NON_PRINTABLE=/[\p{Cc}\p{Cf}\p{Cs}\p{Co}\p{Cn}\p{Zl}\p{Zp}]|(?!\u0020)[\p{Zs}]/u;function hasLoneSurrogate(value){for(let i=0;i<value.length;i+=1){let code=value.charCodeAt(i);if(code>=55296&&code<=56319){let low=value.charCodeAt(i+1);if(!(low>=56320&&low<=57343))return true;i+=1}else if(code>=56320&&code<=57343)return true}return false}function serverLength(value){return[...value].length}var SPECIES_ALIASES=/* @__PURE__ */Object.freeze({dog:"dog",canine:"dog",k9:"dog",puppy:"dog",cat:"cat",feline:"cat",kitten:"cat"});function canonicalPetSpecies(raw){if(typeof raw!="string")return null;let key=raw.trim().toLowerCase();return Object.prototype.hasOwnProperty.call(SPECIES_ALIASES,key)?SPECIES_ALIASES[key]:null}var LIST_MAX=50,REF_MAX=128,NAME_MAX=120,SHORT_MAX=120,NOTES_MAX=2e3,FOOD_MAX=120,MICROCHIP_MAX=80,SEXES=/* @__PURE__ */new Set(["male","female","unknown"]),PRECISIONS=/* @__PURE__ */new Set(["day","month","year"]),ACTIVITY=/* @__PURE__ */new Set(["low","medium","high","athletic"]),INDOOR_OUTDOOR=/* @__PURE__ */new Set(["indoor","outdoor","both"]),SEVERITIES=/* @__PURE__ */new Set(["mild","moderate","severe"]),ISO_DATE=/^(\d{4})-(\d{2})-(\d{2})$/,SCALAR_WIRE=[["sex","sex"],["spayedNeutered","spayed_neutered"],["birthDate","birth_date"],["birthDatePrecision","birth_date_precision"],["activityLevel","activity_level"],["indoorOutdoor","indoor_outdoor"],["foodBrand","food_brand"],["foodType","food_type"],["microchipId","microchip_id"]],LIST_WIRE=[["allergies","allergies"],["medications","medications"],["supplements","supplements"],["conditions","conditions"]];/* @__PURE__ */Object.freeze([...SCALAR_WIRE,...LIST_WIRE].map(([key])=>key));function isRealDate(value){let match=ISO_DATE.exec(value);if(match===null)return false;let[year,month,day]=[Number(match[1]),Number(match[2]),Number(match[3])],date2=new Date(Date.UTC(year,month-1,day));return date2.getUTCFullYear()===year&&date2.getUTCMonth()===month-1&&date2.getUTCDate()===day}var oneOf=allowed=>(field,value)=>typeof value=="string"&&allowed.has(value)?null:`${field} must be one of ${[...allowed].join(", ")}`,boolean=(field,value)=>typeof value=="boolean"?null:`${field} must be true or false`,date=(field,value)=>typeof value=="string"&&isRealDate(value)?null:`${field} must be a real date written YYYY-MM-DD`,text=(max,opts={})=>(field,value)=>{if(typeof value!="string")return`${field} must be a string`;if(hasLoneSurrogate(value))return`${field} contains an unpaired surrogate and cannot be encoded`;let measured=opts.trimmed?value.trim():value;if(opts.required&&measured.length===0)return`${field} is required and must not be blank`;let length=serverLength(measured);return length<=max?null:`${field} is ${length} characters; the server accepts at most ${max}`},SCALAR_CHECKS={sex:oneOf(SEXES),spayedNeutered:boolean,birthDate:date,birthDatePrecision:oneOf(PRECISIONS),activityLevel:oneOf(ACTIVITY),indoorOutdoor:oneOf(INDOOR_OUTDOOR),foodBrand:text(FOOD_MAX),foodType:text(FOOD_MAX),microchipId:text(MICROCHIP_MAX)},REF_FIELD=["ref","ref",false,text(REF_MAX,{required:true,trimmed:true})],NOTES_FIELD=["notes","notes",false,text(NOTES_MAX,{trimmed:true})],MEDICATION_FIELDS=[REF_FIELD,["name","name",true,text(NAME_MAX,{required:true,trimmed:true})],["dose","dose",false,text(SHORT_MAX,{trimmed:true})],["frequency","frequency",false,text(SHORT_MAX,{trimmed:true})],["startDate","start_date",false,date],["endDate","end_date",false,date],NOTES_FIELD],ITEM_FIELDS={allergies:[REF_FIELD,["allergen","allergen",true,text(NAME_MAX,{required:true,trimmed:true})],["severity","severity",false,oneOf(SEVERITIES)],NOTES_FIELD],medications:MEDICATION_FIELDS,supplements:MEDICATION_FIELDS,conditions:[REF_FIELD,["conditionName","condition_name",true,text(NAME_MAX,{required:true,trimmed:true})],["diagnosedDate","diagnosed_date",false,date],NOTES_FIELD]};function itemToWire(list,index,raw){let at=`${list}[${index}]`;if(typeof raw!="object"||raw===null||Array.isArray(raw))return{error:`${at} must be an object`};let source=raw,item={};for(let[key,wire,isRequired,check]of ITEM_FIELDS[list]){let value=source[key];if(value==null){if(isRequired)return{error:`${at}.${key} is required`};value===null&&(item[wire]=null);continue}let bad=check(`${at}.${key}`,value);if(bad!==null)return{error:bad};item[wire]=value}let start=item.start_date,end=item.end_date;return typeof start=="string"&&typeof end=="string"&&end<start?{error:`${at}.endDate must not be before startDate`}:{item:item}}function listToWire(list,raw){if(!Array.isArray(raw))return{error:`${list} must be an array (send [] to clear it)`};if(raw.length>LIST_MAX)return{error:`${list} has ${raw.length} items; the server accepts at most ${LIST_MAX}`};let items=[],refs=/* @__PURE__ */new Set;for(let index=0;index<raw.length;index+=1){let mapped=itemToWire(list,index,raw[index]);if("error"in mapped)return mapped;let ref=mapped.item.ref;if(typeof ref=="string"){let key=ref.trim();if(refs.has(key))return{error:`${list}: ref ${JSON.stringify(key)} is used twice; a ref names one item`};refs.add(key)}items.push(mapped.item)}return{items:items}}function petHealthToWire(input,species){let source=input,body={};for(let[key,wire]of SCALAR_WIRE){let value=source[key];if(value!==void 0){if(value!==null){let bad=SCALAR_CHECKS[key](key,value);if(bad!==null)return{error:bad}}body[wire]=value}}let dateSent=source.birthDate!==void 0,precisionSent=source.birthDatePrecision!==void 0;if(dateSent!==precisionSent||dateSent&&source.birthDate===null!=(source.birthDatePrecision===null))return{error:"birthDate and birthDatePrecision must be sent together, both set or both null"};for(let[key,wire]of LIST_WIRE){let value=source[key];if(value===void 0)continue;let mapped=listToWire(key,value);if("error"in mapped)return mapped;body[wire]=mapped.items}return Object.keys(body).length>0&&species!==void 0&&canonicalPetSpecies(species)===null?{error:"health fields need a pet Everfur reads as a dog or a cat (dog, canine, k9, puppy, cat, feline, kitten)"}:{body:body}}var PROFILE_FIELDS=[["name","name"],["species","species"],["breed","breed"],["ageYears","age_years"],["weightKg","weight_kg"],["partnerLabelInstructions","partner_label_instructions"]];function partnerPetProfileBody(profile){if(typeof profile!="object"||profile===null||Array.isArray(profile))throw new EverfurConfigError("invalid-argument","the pet profile must be an object");let body={};for(let[key,wire]of PROFILE_FIELDS)profile[key]!==void 0&&(body[wire]=profile[key]);let health=petHealthToWire(profile,profile.species);if("error"in health)throw new EverfurConfigError("invalid-argument",health.error);return Object.assign(body,health.body)}var IDEMPOTENCY_KEY_SHAPE=/^[\x21-\x7e]{1,255}$/,MAX_BODY_BYTES=32*1024,DATE_TIME_WITH_OFFSET=/^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:[Zz]|[+-]\d{2}:?\d{2})$/,SEND_TIMEOUT_MS=3e4,INBOUND_RULES=/* @__PURE__ */Object.freeze({"pet.profile.updated":{subject:"pet",schemaVersions:[1,2]},"pet.incident.reported":{subject:"pet",schemaVersions:[1]},"pet.behavior_note.added":{subject:"pet",schemaVersions:[1]},"pet.service_score.recorded":{subject:"pet",schemaVersions:[1]},"pet.deleted":{subject:"pet",schemaVersions:[1]},"member.status_changed":{subject:"member",schemaVersions:[1]},"member.deleted":{subject:"member",schemaVersions:[1]}});async function sendPartnerEvent(client,event,idempotencyKey){let key=idempotencyKey??crypto.randomUUID();if(typeof key!="string"||!IDEMPOTENCY_KEY_SHAPE.test(key))throw new EverfurConfigError("invalid-argument","idempotencyKey must be 1 to 255 visible ASCII characters (no spaces, no control or non-ASCII characters)");assertServerSecretKey(client.partnerSecretKey,"sending events");let payload=serialize(buildBody(event)),fetchImpl=client.fetchImpl??getGlobalFetch(),url=`${resolveApiBaseUrl(client.apiBaseUrl)}/partners/events`,headers={...buildBaseHeaders({sdkVersion:SDK_VERSION,platform:SDK_PLATFORM,contractVersion:client.contractVersion??DEFAULT_CONTRACT_VERSION}),accept:"application/json","content-type":"application/json","idempotency-key":key,"x-everfur-partner-secret-key":client.partnerSecretKey},controller=new AbortController,timer=setTimeout(()=>controller.abort(),SEND_TIMEOUT_MS),res;try{res=await fetchImpl(url,{method:"POST",headers:headers,body:payload,signal:controller.signal})}catch(cause){return err(networkError(cause))}finally{clearTimeout(timer)}let json=null;try{json=await res.json()}catch{json=null}let requestId=requestIdOf(res);if(!res.ok)return err(errorFromResponse(res.status,json,requestId));let receipt=parseReceipt(json,key);return receipt?ok(receipt):err(errorFromResponse(502,{error:{code:"INTERNAL_ERROR"}},requestId))}function isInboundType(value){return typeof value=="string"&&PARTNER_INBOUND_EVENT_TYPES.includes(value)}function buildBody(event){if(typeof event!="object"||event===null)throw new EverfurConfigError("invalid-argument","event is required");if(!isInboundType(event.type))throw new EverfurConfigError("invalid-argument",`event.type must be one of ${PARTNER_INBOUND_EVENT_TYPES.join(", ")}`);let rule=INBOUND_RULES[event.type],schemaVersion=event.schemaVersion??1;if(typeof schemaVersion!="number"||!rule.schemaVersions.includes(schemaVersion))throw new EverfurConfigError("invalid-argument",`event.schemaVersion must be one of ${rule.schemaVersions.join(", ")} for ${event.type}`);let userRef=assertValidUserRef(event.userRef);if(rule.subject==="pet"&&event.petRef===void 0)throw new EverfurConfigError("invalid-argument",`event.petRef is required for ${event.type}`);if(rule.subject==="member"&&event.petRef!==void 0)throw new EverfurConfigError("invalid-argument",`event.petRef is not accepted on ${event.type}`);let petRef=event.petRef===void 0?void 0:assertValidPetRef(event.petRef);if(typeof event.data!="object"||event.data===null||Array.isArray(event.data))throw new EverfurConfigError("invalid-argument","event.data must be an object");let data=event.type==="pet.profile.updated"&&schemaVersion===2?partnerPetProfileBody(event.data):event.data,body={type:event.type,schema_version:schemaVersion,user_ref:userRef,occurred_at:occurredAtIso(event.occurredAt),data:data};return petRef!==void 0&&(body.pet_ref=petRef),body}function assertValidPetRef(raw){try{return assertValidUserRef(raw)}catch(cause){throw cause instanceof EverfurConfigError?new EverfurConfigError("invalid-argument",`event.petRef follows the user_ref rule: ${cause.message}`):cause}}function occurredAtIso(value){if(typeof value=="string"&&!DATE_TIME_WITH_OFFSET.test(value))throw new EverfurConfigError("invalid-argument","event.occurredAt must be a Date or an ISO 8601 date-time with an explicit offset (Z or +05:30)");let date2=value instanceof Date?value:typeof value=="string"?new Date(value):new Date(Number.NaN);if(Number.isNaN(date2.getTime()))throw new EverfurConfigError("invalid-argument","event.occurredAt must be a Date or an ISO 8601 date-time with an explicit offset (Z or +05:30)");return date2.toISOString()}function serialize(body){let payload;try{payload=JSON.stringify(body)}catch{throw new EverfurConfigError("invalid-argument","event.data must be JSON-serialisable")}let bytes=(new TextEncoder).encode(payload).byteLength;if(bytes>MAX_BODY_BYTES)throw new EverfurConfigError("invalid-argument",`the event is ${bytes} bytes once serialised; Everfur accepts at most ${MAX_BODY_BYTES} (32 KB)`);return payload}function parseReceipt(json,idempotencyKey){if(typeof json!="object"||json===null)return null;let obj=json,id=obj.id,type=obj.type,schemaVersion=obj.schema_version,userRef=obj.user_ref,petRef=obj.pet_ref??null,occurredAt=obj.occurred_at,receivedAt=obj.received_at,status=obj.status,livemode=obj.livemode;return typeof id!="string"||id.length===0||!isInboundType(type)||typeof schemaVersion!="number"||typeof userRef!="string"||petRef!==null&&typeof petRef!="string"||typeof occurredAt!="string"||typeof receivedAt!="string"||typeof status!="string"||typeof livemode!="boolean"?null:/* @__PURE__ */Object.freeze({id:id,type:type,schemaVersion:schemaVersion,userRef:userRef,petRef:petRef,occurredAt:occurredAt,receivedAt:receivedAt,status:status,livemode:livemode,idempotencyKey:idempotencyKey})}exports.DEFAULT_WEBHOOK_TOLERANCE_SECONDS=DEFAULT_WEBHOOK_TOLERANCE_SECONDS;exports.EVERFUR_SIGNATURE_HEADER=EVERFUR_SIGNATURE_HEADER;exports.EVERFUR_WEBHOOK_EVENT_TYPES=EVERFUR_WEBHOOK_EVENT_TYPES;exports.EVERFUR_WEBHOOK_ONLY_EVENT_TYPES=EVERFUR_WEBHOOK_ONLY_EVENT_TYPES;exports.EverfurWebhookVerificationError=EverfurWebhookVerificationError;exports.PARTNER_INBOUND_EVENT_TYPES=PARTNER_INBOUND_EVENT_TYPES;exports.constructEvent=constructEvent;exports.generateTestSignatureHeader=generateTestSignatureHeader;exports.isEverfurWebhookEvent=isEverfurWebhookEvent;exports.isEverfurWebhookEventType=isEverfurWebhookEventType;exports.sendPartnerEvent=sendPartnerEvent;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { b as PartnerPetProfile } from '../../pets-
|
|
1
|
+
import { b as PartnerPetProfile } from '../../pets-m61lisZt.cjs';
|
|
2
2
|
import { E as EverfurResult } from '../../EverfurResult-COlXj1wq.cjs';
|
|
3
|
-
import { j as FetchLike } from '../../config-
|
|
3
|
+
import { j as FetchLike } from '../../config-lilR0260.cjs';
|
|
4
4
|
export { b as PetActivityLevel, c as PetAllergy, d as PetAllergySeverity, e as PetBirthDatePrecision, f as PetCondition, P as PetHealthProfileInput, g as PetIndoorOutdoor, h as PetMedication, i as PetSex } from '../../profile-CSs1wlXT.cjs';
|
|
5
5
|
import '../../EverfurError-DeBqRpQV.cjs';
|
|
6
6
|
|
|
7
7
|
/** Every outbound event type in the catalog. Order matches EFBackend `OUTBOUND_EVENT_TYPES`. */
|
|
8
|
-
declare const EVERFUR_WEBHOOK_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "visit.booked", "visit.cancelled", "visit.completed", "visit.no_show", "record_request.updated", "record.ready", "webhook_endpoint.test", "chat.follow_up_due", "chat.urgency.flagged", "pet.vaccination.due", "visit.rescheduled", "visit.reminder", "visit.followup_sent", "chat.reminder_due", "record.activation", "visit.message_received", "visit.ended"];
|
|
8
|
+
declare const EVERFUR_WEBHOOK_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "visit.booked", "visit.cancelled", "visit.completed", "visit.no_show", "record_request.updated", "record.ready", "webhook_endpoint.test", "chat.follow_up_due", "chat.urgency.flagged", "pet.vaccination.due", "visit.rescheduled", "visit.reminder", "visit.followup_sent", "chat.reminder_due", "record.activation", "visit.message_received", "visit.ended", "contact.exported"];
|
|
9
9
|
/** One outbound event type name. */
|
|
10
10
|
type EverfurWebhookEventType = (typeof EVERFUR_WEBHOOK_EVENT_TYPES)[number];
|
|
11
11
|
/**
|
|
@@ -15,14 +15,15 @@ type EverfurWebhookEventType = (typeof EVERFUR_WEBHOOK_EVENT_TYPES)[number];
|
|
|
15
15
|
*
|
|
16
16
|
* - `member.linked` / `member.unlinked` are your bookkeeping, not news for the member;
|
|
17
17
|
* - `chat.urgency.flagged` is an in-app affordance, not a push;
|
|
18
|
-
* - `webhook_endpoint.test` is the console's own test button
|
|
18
|
+
* - `webhook_endpoint.test` is the console's own test button;
|
|
19
|
+
* - `contact.exported` is export data for your server, never a member message.
|
|
19
20
|
*
|
|
20
21
|
* Every OTHER catalog type does build a push target, so it can announce itself on a device and
|
|
21
22
|
* `parseEverfurNotification` can read it (three of them, `visit.completed`, `visit.rescheduled` and
|
|
22
23
|
* `visit.ended`, have a target but no consumer copy, so in practice no push is sent for them either).
|
|
23
24
|
* Read this list when you decide which events your own backend must act on rather than leave to the device.
|
|
24
25
|
*/
|
|
25
|
-
declare const EVERFUR_WEBHOOK_ONLY_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "chat.urgency.flagged", "webhook_endpoint.test"];
|
|
26
|
+
declare const EVERFUR_WEBHOOK_ONLY_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "chat.urgency.flagged", "webhook_endpoint.test", "contact.exported"];
|
|
26
27
|
/** One type that never reaches a device. */
|
|
27
28
|
type EverfurWebhookOnlyEventType = (typeof EVERFUR_WEBHOOK_ONLY_EVENT_TYPES)[number];
|
|
28
29
|
/** Fields any payload may carry beyond the ones typed here (forward compatible). */
|
|
@@ -238,6 +239,23 @@ interface WebhookEndpointTestPayload extends OpenEventPayload {
|
|
|
238
239
|
readonly object: 'webhook_endpoint';
|
|
239
240
|
readonly endpoint_id: string;
|
|
240
241
|
}
|
|
242
|
+
/** How a `contact.exported` identifier was derived. Keyed to your tenant either way; never an address. */
|
|
243
|
+
type EverfurContactIdentifierType = 'partner_hmac' | 'sha256_email';
|
|
244
|
+
/** One pet of an exported contact: species and breed only. */
|
|
245
|
+
interface ContactExportedPet {
|
|
246
|
+
readonly species: string | null;
|
|
247
|
+
readonly breed: string | null;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* `contact.exported`: one consented contact in a partner export run (EFBackend `partner_export`
|
|
251
|
+
* `ExportRecord.as_dict`). Sent only to an endpoint that subscribes to this type by name.
|
|
252
|
+
*/
|
|
253
|
+
interface ContactExportedPayload extends OpenEventPayload {
|
|
254
|
+
readonly object: 'contact';
|
|
255
|
+
readonly identifier: string;
|
|
256
|
+
readonly identifier_type: EverfurContactIdentifierType;
|
|
257
|
+
readonly pets: readonly ContactExportedPet[];
|
|
258
|
+
}
|
|
241
259
|
/** Payload type for each outbound event type. */
|
|
242
260
|
interface EverfurWebhookPayloadMap {
|
|
243
261
|
readonly 'member.linked': MemberLinkPayload;
|
|
@@ -259,6 +277,7 @@ interface EverfurWebhookPayloadMap {
|
|
|
259
277
|
readonly 'record.activation': RecordActivationPayload;
|
|
260
278
|
readonly 'visit.message_received': VisitMessageReceivedPayload;
|
|
261
279
|
readonly 'visit.ended': VisitEndedPayload;
|
|
280
|
+
readonly 'contact.exported': ContactExportedPayload;
|
|
262
281
|
}
|
|
263
282
|
/** The signed envelope of one outbound event of type `T`. */
|
|
264
283
|
interface EverfurWebhookEventOf<T extends EverfurWebhookEventType> {
|
|
@@ -548,4 +567,4 @@ interface PartnerEventReceipt {
|
|
|
548
567
|
*/
|
|
549
568
|
declare function sendPartnerEvent(client: PartnerEventsClient, event: PartnerInboundEvent, idempotencyKey?: string): Promise<EverfurResult<PartnerEventReceipt>>;
|
|
550
569
|
|
|
551
|
-
export { type ChatFollowUpDuePayload, type ChatReminderDuePayload, type ChatUrgencyFlaggedPayload, type ConstructEventOptions, DEFAULT_WEBHOOK_TOLERANCE_SECONDS, EVERFUR_SIGNATURE_HEADER, EVERFUR_WEBHOOK_EVENT_TYPES, EVERFUR_WEBHOOK_ONLY_EVENT_TYPES, type EverfurChatReminderKind, type EverfurRecordClass, type EverfurVaccinationDueStage, type EverfurVaccine, type EverfurVisitReminderStage, type EverfurVisitStatus, type EverfurWebhookEvent, type EverfurWebhookEventOf, type EverfurWebhookEventType, type EverfurWebhookOnlyEventType, type EverfurWebhookPayloadMap, EverfurWebhookVerificationError, type MemberDeletedData, type MemberLinkPayload, type MemberStatusChangedData, type OpenEventPayload, PARTNER_INBOUND_EVENT_TYPES, type PartnerEventReceipt, type PartnerEventsClient, type PartnerInboundEvent, type PartnerInboundEventDataMap, type PartnerInboundEventOf, type PartnerInboundEventType, PartnerPetProfile, type PetBehaviorNoteAddedData, type PetDeletedData, type PetIncidentReportedData, type PetProfileUpdatedData, type PetProfileUpdatedV2Event, type PetServiceScoreRecordedData, type PetVaccinationDuePayload, type RecordActivationPayload, type RecordReadyPayload, type RecordRequestSimpleStatus, type RecordRequestUpdatedPayload, type TestSignatureHeaderParams, type UnrecognizedEverfurWebhookEvent, type VisitEndedPayload, type VisitFollowupSentPayload, type VisitMessageReceivedPayload, type VisitPayload, type VisitReminderPayload, type VisitRescheduledPayload, type WebhookEndpointTestPayload, type WebhookPayload, type WebhookVerificationFailure, constructEvent, generateTestSignatureHeader, isEverfurWebhookEvent, isEverfurWebhookEventType, sendPartnerEvent };
|
|
570
|
+
export { type ChatFollowUpDuePayload, type ChatReminderDuePayload, type ChatUrgencyFlaggedPayload, type ConstructEventOptions, type ContactExportedPayload, type ContactExportedPet, DEFAULT_WEBHOOK_TOLERANCE_SECONDS, EVERFUR_SIGNATURE_HEADER, EVERFUR_WEBHOOK_EVENT_TYPES, EVERFUR_WEBHOOK_ONLY_EVENT_TYPES, type EverfurChatReminderKind, type EverfurContactIdentifierType, type EverfurRecordClass, type EverfurVaccinationDueStage, type EverfurVaccine, type EverfurVisitReminderStage, type EverfurVisitStatus, type EverfurWebhookEvent, type EverfurWebhookEventOf, type EverfurWebhookEventType, type EverfurWebhookOnlyEventType, type EverfurWebhookPayloadMap, EverfurWebhookVerificationError, type MemberDeletedData, type MemberLinkPayload, type MemberStatusChangedData, type OpenEventPayload, PARTNER_INBOUND_EVENT_TYPES, type PartnerEventReceipt, type PartnerEventsClient, type PartnerInboundEvent, type PartnerInboundEventDataMap, type PartnerInboundEventOf, type PartnerInboundEventType, PartnerPetProfile, type PetBehaviorNoteAddedData, type PetDeletedData, type PetIncidentReportedData, type PetProfileUpdatedData, type PetProfileUpdatedV2Event, type PetServiceScoreRecordedData, type PetVaccinationDuePayload, type RecordActivationPayload, type RecordReadyPayload, type RecordRequestSimpleStatus, type RecordRequestUpdatedPayload, type TestSignatureHeaderParams, type UnrecognizedEverfurWebhookEvent, type VisitEndedPayload, type VisitFollowupSentPayload, type VisitMessageReceivedPayload, type VisitPayload, type VisitReminderPayload, type VisitRescheduledPayload, type WebhookEndpointTestPayload, type WebhookPayload, type WebhookVerificationFailure, constructEvent, generateTestSignatureHeader, isEverfurWebhookEvent, isEverfurWebhookEventType, sendPartnerEvent };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { b as PartnerPetProfile } from '../../pets-
|
|
1
|
+
import { b as PartnerPetProfile } from '../../pets-DzXi_9hY.js';
|
|
2
2
|
import { E as EverfurResult } from '../../EverfurResult-ClPTS0P2.js';
|
|
3
|
-
import { j as FetchLike } from '../../config-
|
|
3
|
+
import { j as FetchLike } from '../../config-CuOczZUI.js';
|
|
4
4
|
export { b as PetActivityLevel, c as PetAllergy, d as PetAllergySeverity, e as PetBirthDatePrecision, f as PetCondition, P as PetHealthProfileInput, g as PetIndoorOutdoor, h as PetMedication, i as PetSex } from '../../profile-CSs1wlXT.js';
|
|
5
5
|
import '../../EverfurError-DeBqRpQV.js';
|
|
6
6
|
|
|
7
7
|
/** Every outbound event type in the catalog. Order matches EFBackend `OUTBOUND_EVENT_TYPES`. */
|
|
8
|
-
declare const EVERFUR_WEBHOOK_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "visit.booked", "visit.cancelled", "visit.completed", "visit.no_show", "record_request.updated", "record.ready", "webhook_endpoint.test", "chat.follow_up_due", "chat.urgency.flagged", "pet.vaccination.due", "visit.rescheduled", "visit.reminder", "visit.followup_sent", "chat.reminder_due", "record.activation", "visit.message_received", "visit.ended"];
|
|
8
|
+
declare const EVERFUR_WEBHOOK_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "visit.booked", "visit.cancelled", "visit.completed", "visit.no_show", "record_request.updated", "record.ready", "webhook_endpoint.test", "chat.follow_up_due", "chat.urgency.flagged", "pet.vaccination.due", "visit.rescheduled", "visit.reminder", "visit.followup_sent", "chat.reminder_due", "record.activation", "visit.message_received", "visit.ended", "contact.exported"];
|
|
9
9
|
/** One outbound event type name. */
|
|
10
10
|
type EverfurWebhookEventType = (typeof EVERFUR_WEBHOOK_EVENT_TYPES)[number];
|
|
11
11
|
/**
|
|
@@ -15,14 +15,15 @@ type EverfurWebhookEventType = (typeof EVERFUR_WEBHOOK_EVENT_TYPES)[number];
|
|
|
15
15
|
*
|
|
16
16
|
* - `member.linked` / `member.unlinked` are your bookkeeping, not news for the member;
|
|
17
17
|
* - `chat.urgency.flagged` is an in-app affordance, not a push;
|
|
18
|
-
* - `webhook_endpoint.test` is the console's own test button
|
|
18
|
+
* - `webhook_endpoint.test` is the console's own test button;
|
|
19
|
+
* - `contact.exported` is export data for your server, never a member message.
|
|
19
20
|
*
|
|
20
21
|
* Every OTHER catalog type does build a push target, so it can announce itself on a device and
|
|
21
22
|
* `parseEverfurNotification` can read it (three of them, `visit.completed`, `visit.rescheduled` and
|
|
22
23
|
* `visit.ended`, have a target but no consumer copy, so in practice no push is sent for them either).
|
|
23
24
|
* Read this list when you decide which events your own backend must act on rather than leave to the device.
|
|
24
25
|
*/
|
|
25
|
-
declare const EVERFUR_WEBHOOK_ONLY_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "chat.urgency.flagged", "webhook_endpoint.test"];
|
|
26
|
+
declare const EVERFUR_WEBHOOK_ONLY_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "chat.urgency.flagged", "webhook_endpoint.test", "contact.exported"];
|
|
26
27
|
/** One type that never reaches a device. */
|
|
27
28
|
type EverfurWebhookOnlyEventType = (typeof EVERFUR_WEBHOOK_ONLY_EVENT_TYPES)[number];
|
|
28
29
|
/** Fields any payload may carry beyond the ones typed here (forward compatible). */
|
|
@@ -238,6 +239,23 @@ interface WebhookEndpointTestPayload extends OpenEventPayload {
|
|
|
238
239
|
readonly object: 'webhook_endpoint';
|
|
239
240
|
readonly endpoint_id: string;
|
|
240
241
|
}
|
|
242
|
+
/** How a `contact.exported` identifier was derived. Keyed to your tenant either way; never an address. */
|
|
243
|
+
type EverfurContactIdentifierType = 'partner_hmac' | 'sha256_email';
|
|
244
|
+
/** One pet of an exported contact: species and breed only. */
|
|
245
|
+
interface ContactExportedPet {
|
|
246
|
+
readonly species: string | null;
|
|
247
|
+
readonly breed: string | null;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* `contact.exported`: one consented contact in a partner export run (EFBackend `partner_export`
|
|
251
|
+
* `ExportRecord.as_dict`). Sent only to an endpoint that subscribes to this type by name.
|
|
252
|
+
*/
|
|
253
|
+
interface ContactExportedPayload extends OpenEventPayload {
|
|
254
|
+
readonly object: 'contact';
|
|
255
|
+
readonly identifier: string;
|
|
256
|
+
readonly identifier_type: EverfurContactIdentifierType;
|
|
257
|
+
readonly pets: readonly ContactExportedPet[];
|
|
258
|
+
}
|
|
241
259
|
/** Payload type for each outbound event type. */
|
|
242
260
|
interface EverfurWebhookPayloadMap {
|
|
243
261
|
readonly 'member.linked': MemberLinkPayload;
|
|
@@ -259,6 +277,7 @@ interface EverfurWebhookPayloadMap {
|
|
|
259
277
|
readonly 'record.activation': RecordActivationPayload;
|
|
260
278
|
readonly 'visit.message_received': VisitMessageReceivedPayload;
|
|
261
279
|
readonly 'visit.ended': VisitEndedPayload;
|
|
280
|
+
readonly 'contact.exported': ContactExportedPayload;
|
|
262
281
|
}
|
|
263
282
|
/** The signed envelope of one outbound event of type `T`. */
|
|
264
283
|
interface EverfurWebhookEventOf<T extends EverfurWebhookEventType> {
|
|
@@ -548,4 +567,4 @@ interface PartnerEventReceipt {
|
|
|
548
567
|
*/
|
|
549
568
|
declare function sendPartnerEvent(client: PartnerEventsClient, event: PartnerInboundEvent, idempotencyKey?: string): Promise<EverfurResult<PartnerEventReceipt>>;
|
|
550
569
|
|
|
551
|
-
export { type ChatFollowUpDuePayload, type ChatReminderDuePayload, type ChatUrgencyFlaggedPayload, type ConstructEventOptions, DEFAULT_WEBHOOK_TOLERANCE_SECONDS, EVERFUR_SIGNATURE_HEADER, EVERFUR_WEBHOOK_EVENT_TYPES, EVERFUR_WEBHOOK_ONLY_EVENT_TYPES, type EverfurChatReminderKind, type EverfurRecordClass, type EverfurVaccinationDueStage, type EverfurVaccine, type EverfurVisitReminderStage, type EverfurVisitStatus, type EverfurWebhookEvent, type EverfurWebhookEventOf, type EverfurWebhookEventType, type EverfurWebhookOnlyEventType, type EverfurWebhookPayloadMap, EverfurWebhookVerificationError, type MemberDeletedData, type MemberLinkPayload, type MemberStatusChangedData, type OpenEventPayload, PARTNER_INBOUND_EVENT_TYPES, type PartnerEventReceipt, type PartnerEventsClient, type PartnerInboundEvent, type PartnerInboundEventDataMap, type PartnerInboundEventOf, type PartnerInboundEventType, PartnerPetProfile, type PetBehaviorNoteAddedData, type PetDeletedData, type PetIncidentReportedData, type PetProfileUpdatedData, type PetProfileUpdatedV2Event, type PetServiceScoreRecordedData, type PetVaccinationDuePayload, type RecordActivationPayload, type RecordReadyPayload, type RecordRequestSimpleStatus, type RecordRequestUpdatedPayload, type TestSignatureHeaderParams, type UnrecognizedEverfurWebhookEvent, type VisitEndedPayload, type VisitFollowupSentPayload, type VisitMessageReceivedPayload, type VisitPayload, type VisitReminderPayload, type VisitRescheduledPayload, type WebhookEndpointTestPayload, type WebhookPayload, type WebhookVerificationFailure, constructEvent, generateTestSignatureHeader, isEverfurWebhookEvent, isEverfurWebhookEventType, sendPartnerEvent };
|
|
570
|
+
export { type ChatFollowUpDuePayload, type ChatReminderDuePayload, type ChatUrgencyFlaggedPayload, type ConstructEventOptions, type ContactExportedPayload, type ContactExportedPet, DEFAULT_WEBHOOK_TOLERANCE_SECONDS, EVERFUR_SIGNATURE_HEADER, EVERFUR_WEBHOOK_EVENT_TYPES, EVERFUR_WEBHOOK_ONLY_EVENT_TYPES, type EverfurChatReminderKind, type EverfurContactIdentifierType, type EverfurRecordClass, type EverfurVaccinationDueStage, type EverfurVaccine, type EverfurVisitReminderStage, type EverfurVisitStatus, type EverfurWebhookEvent, type EverfurWebhookEventOf, type EverfurWebhookEventType, type EverfurWebhookOnlyEventType, type EverfurWebhookPayloadMap, EverfurWebhookVerificationError, type MemberDeletedData, type MemberLinkPayload, type MemberStatusChangedData, type OpenEventPayload, PARTNER_INBOUND_EVENT_TYPES, type PartnerEventReceipt, type PartnerEventsClient, type PartnerInboundEvent, type PartnerInboundEventDataMap, type PartnerInboundEventOf, type PartnerInboundEventType, PartnerPetProfile, type PetBehaviorNoteAddedData, type PetDeletedData, type PetIncidentReportedData, type PetProfileUpdatedData, type PetProfileUpdatedV2Event, type PetServiceScoreRecordedData, type PetVaccinationDuePayload, type RecordActivationPayload, type RecordReadyPayload, type RecordRequestSimpleStatus, type RecordRequestUpdatedPayload, type TestSignatureHeaderParams, type UnrecognizedEverfurWebhookEvent, type VisitEndedPayload, type VisitFollowupSentPayload, type VisitMessageReceivedPayload, type VisitPayload, type VisitReminderPayload, type VisitRescheduledPayload, type WebhookEndpointTestPayload, type WebhookPayload, type WebhookVerificationFailure, constructEvent, generateTestSignatureHeader, isEverfurWebhookEvent, isEverfurWebhookEventType, sendPartnerEvent };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import{timingSafeEqual,createHmac,randomUUID}from"crypto";function ok(value,warning){/* @__PURE__ */
|
|
2
2
|
return Object.freeze({ok:true,value:value})}function err(error){/* @__PURE__ */
|
|
3
|
-
return Object.freeze({ok:false,error:error})}var EverfurConfigError=class _EverfurConfigError extends Error{constructor(kind,message){super(message),this.name="EverfurConfigError",this.kind=kind,Object.setPrototypeOf(this,_EverfurConfigError.prototype)}};var EVERFUR_SIGNATURE_HEADER="Everfur-Signature",DEFAULT_WEBHOOK_TOLERANCE_SECONDS=300,SIGNATURE_SCHEME="v1",MAX_HEADER_LENGTH=4096,HEX_SHA256_LENGTH=64,DIGITS=/^[0-9]+$/,EverfurWebhookVerificationError=class _EverfurWebhookVerificationError extends Error{constructor(code){super(`Everfur webhook verification failed: ${code}`),this.name="EverfurWebhookVerificationError",this.code=code,Object.setPrototypeOf(this,_EverfurWebhookVerificationError.prototype)}};function constructEvent(payload,signatureHeader,secrets,options={}){let body=rawBodyBytes(payload),keys=requireSecrets(secrets),tolerance=options.toleranceSeconds??DEFAULT_WEBHOOK_TOLERANCE_SECONDS;if(!Number.isInteger(tolerance)||tolerance<0)throw new EverfurConfigError("invalid-argument","toleranceSeconds must be a non-negative integer");let parsed=parseSignatureHeader(signatureHeader),now=options.nowSeconds??Math.floor(Date.now()/1e3);if(Math.abs(now-parsed.timestamp)>tolerance)throw new EverfurWebhookVerificationError("timestamp_outside_tolerance");let matched=false;for(let key of keys){let expected=Buffer.from(computeSignature(key,parsed.timestamp,body),"ascii");for(let candidate of parsed.signatures){if(candidate.length!==HEX_SHA256_LENGTH)continue;let actual=Buffer.from(candidate,"utf8");actual.length===expected.length&&timingSafeEqual(expected,actual)&&(matched=true)}}if(!matched)throw new EverfurWebhookVerificationError("no_matching_signature");return parseEnvelope(body)}function generateTestSignatureHeader(params){let body=rawBodyBytes(params.payload),keys=requireSecrets(params.secrets),timestamp=params.timestamp??Math.floor(Date.now()/1e3);if(!Number.isSafeInteger(timestamp)||timestamp<0)throw new EverfurConfigError("invalid-argument","timestamp must be a non-negative integer (unix seconds)");return[`t=${timestamp}`,...keys.map(key=>`${SIGNATURE_SCHEME}=${computeSignature(key,timestamp,body)}`)].join(",")}function computeSignature(secret,timestamp,body){return createHmac("sha256",Buffer.from(secret,"utf8")).update(`${timestamp}.`,"ascii").update(body).digest("hex")}function rawBodyBytes(payload){if(typeof payload=="string")return Buffer.from(payload,"utf8");if(payload instanceof Uint8Array)return payload;throw new EverfurConfigError("invalid-argument","constructEvent needs the raw request body (a string or a Buffer), not parsed JSON: re-serialised JSON does not reproduce the signed bytes.")}function requireSecrets(secrets){let list=typeof secrets=="string"?[secrets]:Array.isArray(secrets)?secrets:[];if(list.length===0||list.some(s=>typeof s!="string"||s.length===0))throw new EverfurConfigError("invalid-argument","at least one non-empty webhook signing secret is required");return list}function parseSignatureHeader(header){if(typeof header!="string"||header.length===0||header.length>MAX_HEADER_LENGTH)throw new EverfurWebhookVerificationError("malformed_header");let timestamp=null,signatures=[];for(let item of header.split(",")){let trimmed=item.trim(),at=trimmed.indexOf("=");if(at<0)throw new EverfurWebhookVerificationError("malformed_header");let key=trimmed.slice(0,at),value=trimmed.slice(at+1);if(key==="t"){if(timestamp!==null||!DIGITS.test(value))throw new EverfurWebhookVerificationError("malformed_header");let parsed=Number(value);if(!Number.isSafeInteger(parsed))throw new EverfurWebhookVerificationError("malformed_header");timestamp=parsed}else key===SIGNATURE_SCHEME&&signatures.push(value)}if(timestamp===null||signatures.length===0)throw new EverfurWebhookVerificationError("malformed_header");return{timestamp:timestamp,signatures:signatures}}function parseEnvelope(body){let json;try{json=JSON.parse(Buffer.from(body.buffer,body.byteOffset,body.byteLength).toString("utf8"))}catch{throw new EverfurWebhookVerificationError("malformed_payload")}if(!isRecord(json))throw new EverfurWebhookVerificationError("malformed_payload");let{id:id,object:object,type:type,api_version:apiVersion,created:created,livemode:livemode,data:data}=json;if(typeof id!="string"||id.length===0||object!=="event"||typeof type!="string"||type.length===0||typeof apiVersion!="string"||typeof created!="number"||typeof livemode!="boolean"||!isRecord(data)||!isRecord(data.object))throw new EverfurWebhookVerificationError("malformed_payload");return json}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var SDK_VERSION="0.
|
|
3
|
+
return Object.freeze({ok:false,error:error})}var EverfurConfigError=class _EverfurConfigError extends Error{constructor(kind,message){super(message),this.name="EverfurConfigError",this.kind=kind,Object.setPrototypeOf(this,_EverfurConfigError.prototype)}};var EVERFUR_SIGNATURE_HEADER="Everfur-Signature",DEFAULT_WEBHOOK_TOLERANCE_SECONDS=300,SIGNATURE_SCHEME="v1",MAX_HEADER_LENGTH=4096,HEX_SHA256_LENGTH=64,DIGITS=/^[0-9]+$/,EverfurWebhookVerificationError=class _EverfurWebhookVerificationError extends Error{constructor(code){super(`Everfur webhook verification failed: ${code}`),this.name="EverfurWebhookVerificationError",this.code=code,Object.setPrototypeOf(this,_EverfurWebhookVerificationError.prototype)}};function constructEvent(payload,signatureHeader,secrets,options={}){let body=rawBodyBytes(payload),keys=requireSecrets(secrets),tolerance=options.toleranceSeconds??DEFAULT_WEBHOOK_TOLERANCE_SECONDS;if(!Number.isInteger(tolerance)||tolerance<0)throw new EverfurConfigError("invalid-argument","toleranceSeconds must be a non-negative integer");let parsed=parseSignatureHeader(signatureHeader),now=options.nowSeconds??Math.floor(Date.now()/1e3);if(Math.abs(now-parsed.timestamp)>tolerance)throw new EverfurWebhookVerificationError("timestamp_outside_tolerance");let matched=false;for(let key of keys){let expected=Buffer.from(computeSignature(key,parsed.timestamp,body),"ascii");for(let candidate of parsed.signatures){if(candidate.length!==HEX_SHA256_LENGTH)continue;let actual=Buffer.from(candidate,"utf8");actual.length===expected.length&&timingSafeEqual(expected,actual)&&(matched=true)}}if(!matched)throw new EverfurWebhookVerificationError("no_matching_signature");return parseEnvelope(body)}function generateTestSignatureHeader(params){let body=rawBodyBytes(params.payload),keys=requireSecrets(params.secrets),timestamp=params.timestamp??Math.floor(Date.now()/1e3);if(!Number.isSafeInteger(timestamp)||timestamp<0)throw new EverfurConfigError("invalid-argument","timestamp must be a non-negative integer (unix seconds)");return[`t=${timestamp}`,...keys.map(key=>`${SIGNATURE_SCHEME}=${computeSignature(key,timestamp,body)}`)].join(",")}function computeSignature(secret,timestamp,body){return createHmac("sha256",Buffer.from(secret,"utf8")).update(`${timestamp}.`,"ascii").update(body).digest("hex")}function rawBodyBytes(payload){if(typeof payload=="string")return Buffer.from(payload,"utf8");if(payload instanceof Uint8Array)return payload;throw new EverfurConfigError("invalid-argument","constructEvent needs the raw request body (a string or a Buffer), not parsed JSON: re-serialised JSON does not reproduce the signed bytes.")}function requireSecrets(secrets){let list=typeof secrets=="string"?[secrets]:Array.isArray(secrets)?secrets:[];if(list.length===0||list.some(s=>typeof s!="string"||s.length===0))throw new EverfurConfigError("invalid-argument","at least one non-empty webhook signing secret is required");return list}function parseSignatureHeader(header){if(typeof header!="string"||header.length===0||header.length>MAX_HEADER_LENGTH)throw new EverfurWebhookVerificationError("malformed_header");let timestamp=null,signatures=[];for(let item of header.split(",")){let trimmed=item.trim(),at=trimmed.indexOf("=");if(at<0)throw new EverfurWebhookVerificationError("malformed_header");let key=trimmed.slice(0,at),value=trimmed.slice(at+1);if(key==="t"){if(timestamp!==null||!DIGITS.test(value))throw new EverfurWebhookVerificationError("malformed_header");let parsed=Number(value);if(!Number.isSafeInteger(parsed))throw new EverfurWebhookVerificationError("malformed_header");timestamp=parsed}else key===SIGNATURE_SCHEME&&signatures.push(value)}if(timestamp===null||signatures.length===0)throw new EverfurWebhookVerificationError("malformed_header");return{timestamp:timestamp,signatures:signatures}}function parseEnvelope(body){let json;try{json=JSON.parse(Buffer.from(body.buffer,body.byteOffset,body.byteLength).toString("utf8"))}catch{throw new EverfurWebhookVerificationError("malformed_payload")}if(!isRecord(json))throw new EverfurWebhookVerificationError("malformed_payload");let{id:id,object:object,type:type,api_version:apiVersion,created:created,livemode:livemode,data:data}=json;if(typeof id!="string"||id.length===0||object!=="event"||typeof type!="string"||type.length===0||typeof apiVersion!="string"||typeof created!="number"||typeof livemode!="boolean"||!isRecord(data)||!isRecord(data.object))throw new EverfurWebhookVerificationError("malformed_payload");return json}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var SDK_VERSION="0.10.0",SDK_PLATFORM="react-native",DEFAULT_CONTRACT_VERSION="2026-09-19",ENV_API_BASE_URL="EVERFUR_API_BASE_URL";function configFailure(reason,message){/* @__PURE__ */
|
|
4
4
|
return Object.freeze({ok:false,failure:/* @__PURE__ */Object.freeze({reason:reason,message:message})})}function tryResolveApiBaseUrl(apiBaseUrl){let explicit=apiBaseUrl?.trim(),candidate=explicit&&explicit.length>0?explicit:readEnv(ENV_API_BASE_URL);return candidate?normalizeBaseUrl(candidate):configFailure("missing-api-base-url",`apiBaseUrl is required: pass config.apiBaseUrl or set ${ENV_API_BASE_URL}. The SDK never ships a hardcoded host.`)}function resolveApiBaseUrl(apiBaseUrl){let outcome=tryResolveApiBaseUrl(apiBaseUrl);if(!outcome.ok)throw new EverfurConfigError("invalid-argument",outcome.failure.message);return outcome.value}function buildBaseHeaders(cfg){return{"X-Everfur-SDK-Version":cfg.sdkVersion,"X-Everfur-SDK-Platform":cfg.platform,"X-Everfur-Contract":cfg.contractVersion}}var ABSOLUTE_URL=/^([A-Za-z][A-Za-z0-9+.-]*):\/\/([^/?#]*)/;function hostOf(authority){return authority.slice(authority.lastIndexOf("@")+1).replace(/:\d+$/,"").toLowerCase()}function isPrintableHost(host){return host.length===0||host.includes("@")?false:host.startsWith("[")&&host.endsWith("]")?true:!host.includes(":")}function canEchoOrigin(rawTrimmed,host){let schemeEnd=rawTrimmed.indexOf("://");return schemeEnd<0||rawTrimmed.slice(schemeEnd+3).includes("@")?false:isPrintableHost(host)}function safeOrigin(scheme,host){return`${scheme}://${host}`}function normalizeBaseUrl(raw){let trimmed=raw.trim(),match=ABSOLUTE_URL.exec(trimmed);if(match===null||match[2]===void 0||match[2].length===0)return configFailure("malformed-api-base-url","apiBaseUrl is not a valid absolute URL");let scheme=(match[1]??"").toLowerCase(),host=hostOf(match[2]);if(host.length===0)return configFailure("malformed-api-base-url","apiBaseUrl is not a valid absolute URL");let shown=canEchoOrigin(trimmed,host)?`: ${safeOrigin(scheme,host)}`:"";if(scheme!=="https"){if(!(scheme==="http"&&isLoopbackHost(host)))return scheme==="http"?configFailure("insecure-api-base-url",`apiBaseUrl must use https (cleartext http is only allowed for localhost)${shown}`):configFailure("unsupported-api-base-url-scheme",`apiBaseUrl must be http(s)${shown}`)}let value=trimmed.endsWith("/")?trimmed.slice(0,-1):trimmed;/* @__PURE__ */
|
|
5
5
|
return Object.freeze({ok:true,value:value})}function isLoopbackHost(hostname){let host=hostname.toLowerCase();return host==="localhost"||host==="127.0.0.1"||host==="[::1]"||host==="::1"}function readEnv(name){let value=globalThis.process?.env?.[name];return typeof value=="string"&&value.trim().length>0?value.trim():void 0}var CONTRACT_RETRYABILITY=/* @__PURE__ */Object.freeze([
|
|
6
6
|
/* @__PURE__ */Object.freeze({wireCode:"AccessDeniedException",envelope:"http_envelope",httpStatus:403,retryable:false}),
|
|
@@ -89,4 +89,4 @@ return Object.freeze({ok:true,value:value})}function isLoopbackHost(hostname){le
|
|
|
89
89
|
/* @__PURE__ */Object.freeze({wireCode:"verify_user_ref_invalid",envelope:"http_envelope",httpStatus:422,retryable:false}),
|
|
90
90
|
/* @__PURE__ */Object.freeze({wireCode:"webhook_endpoint_update_empty",envelope:"http_envelope",httpStatus:400,retryable:false}),
|
|
91
91
|
/* @__PURE__ */Object.freeze({wireCode:"webhook_endpoint_update_invalid",envelope:"http_envelope",httpStatus:400,retryable:false}),
|
|
92
|
-
/* @__PURE__ */Object.freeze({wireCode:"webhook_url_rejected",envelope:"http_envelope",httpStatus:400,retryable:false})]);/* @__PURE__ */Object.freeze(CONTRACT_RETRYABILITY.map(row=>row.wireCode));var NORMALIZED_FOLD=/* @__PURE__ */Object.freeze({ValidationException:"validationFailed",AuthorizationException:"authRejected",PaymentRequiredException:"paymentRequired",AccessDeniedException:"accessDenied",ResourceNotFoundException:"resourceNotFound",ConflictException:"conflict",ThrottlingException:"rateLimited",InternalFailureException:"internalError",NotImplementedException:"notImplemented",ServiceUnavailableException:"serviceUnavailable",MethodNotAllowedException:"validationFailed",authExpired:"authExpired",unavailable:"serviceUnavailable",session_required:"sessionRequired",accessDenied:"accessDenied",invalidRequest:"sdkUpdateRequired",authRejected:"authRejected",rateLimited:"rateLimited",insufficientCapability:"accessDenied",event_cursor_invalid:"validationFailed",event_filter_invalid:"validationFailed",event_payload_invalid:"validationFailed",event_type_unknown:"validationFailed",idempotency_key_invalid:"validationFailed",idempotency_key_required:"validationFailed",idempotency_key_reused:"idempotencyConflict",payload_too_large:"validationFailed",webhook_url_rejected:"validationFailed",webhook_endpoint_update_empty:"validationFailed",webhook_endpoint_update_invalid:"validationFailed",event_type_not_available:"conflict",record_subject_not_found:"resourceNotFound",records_consent_required:"conflict",record_species_unsupported:"validationFailed",record_upload_invalid:"validationFailed",FILE_TOO_LARGE:"validationFailed",INVALID_CONTENT_TYPE:"validationFailed",attachment_unreadable:"validationFailed",provider_unsupported:"validationFailed",token_invalid:"validationFailed",device_cipher_unavailable:"serviceUnavailable",email_invalid:"validationFailed",consent_required:"validationFailed",consent_invalid:"validationFailed",consent_scope_wrong_route:"validationFailed",IDEMPOTENCY_KEY_IN_FLIGHT:"idempotencyInFlight",IDEMPOTENCY_KEY_REUSED_DIFFERENT_REQUEST:"idempotencyConflict",DAILY_QUOTA_EXCEEDED:"quotaExceeded",TIER_UPGRADE_REQUIRED:"paymentRequired",not_found:"conversationNotFound",timeout:"streamTimeout",internal_error:"internalError",invalid_request:"validationFailed",invalid_client:"authRejected",invalid_grant:"authRejected",unsupported_grant_type:"validationFailed",invalid_scope:"validationFailed",invalid_target:"validationFailed",invalid_redirect_uri:"validationFailed",invalid_client_metadata:"validationFailed",unsupported_response_type:"validationFailed",access_denied:"accessDenied",slow_down:"rateLimited",mcp_request_not_found:"resourceNotFound",mcp_request_gone:"resourceNotFound",mcp_connection_not_found:"resourceNotFound",mcp_request_conflict:"conflict",sandbox_only:"accessDenied",tenant_has_no_capabilities:"conflict",verify_mint_refused:"accessDenied",verify_mint_rate_limited:"rateLimited",verify_mint_unavailable:"serviceUnavailable",verify_user_ref_invalid:"validationFailed",insufficient_scope:"accessDenied",tenant_filter_invalid:"validationFailed",tenant_resource_not_found:"resourceNotFound",tenant_surface_not_enabled:"conflict",pet_health_species_unsupported:"validationFailed",pet_health_list_removals_unconfirmed:"validationFailed",petRefInUse:"conflict",share_limit_reached:"conflict",pet_not_registered:"resourceNotFound",species_unsupported:"validationFailed",partner_visit_owner_only:"accessDenied",partner_visit_link_conflict:"conflict",partner_visit_pet_already_mapped:"conflict"}),CONTRACT_ERROR_ROWS=/* @__PURE__ */Object.freeze(CONTRACT_RETRYABILITY.map(generated=>/* @__PURE__ */Object.freeze({wireCode:generated.wireCode,envelope:generated.envelope,retryable:generated.retryable,normalized:NORMALIZED_FOLD[generated.wireCode]}))),BY_KEY=new Map(CONTRACT_ERROR_ROWS.map(r=>[r.envelope+r.wireCode.toUpperCase(),r])),ENVELOPE_LOOKUP_ORDER=/* @__PURE__ */Object.freeze(["http_envelope",...[...new Set(CONTRACT_ERROR_ROWS.map(r=>r.envelope))].filter(e=>e!=="http_envelope").sort()]);function contractErrorFor(wireCode,envelope){if(typeof wireCode!="string")return;let key=wireCode.trim().toUpperCase();if(key.length!==0)for(let candidate of[envelope??"http_envelope",...ENVELOPE_LOOKUP_ORDER]){let row=BY_KEY.get(candidate+key);if(row)return row}}var CATEGORY_OF=/* @__PURE__ */Object.freeze({authExpired:"authentication",authRejected:"authentication",sessionRequired:"authentication",identitySignatureRequired:"authentication",accessDenied:"authorization",paymentRequired:"entitlement",quotaExceeded:"rateLimit",rateLimited:"rateLimit",validationFailed:"invalidRequest",sdkUpdateRequired:"invalidRequest",runtimeDisposed:"invalidRequest",conversationNotFound:"notFound",petNotFound:"notFound",resourceNotFound:"notFound",conflict:"conflict",idempotencyConflict:"conflict",idempotencyInFlight:"conflict",streamTimeout:"connection",streamIncomplete:"connection",upstreamLlmTimeout:"connection",serviceUnavailable:"connection",internalError:"server",notImplemented:"server",mediaUploadFailed:"media",moderationBlocked:"policy",unknown:"unknown"});function categoryFor(code){return CATEGORY_OF[code]}function fromWire(wire){let contractRow=contractErrorFor(wire);if(contractRow)return contractRow.normalized;let upper=(wire??"").trim().toUpperCase(),canonical=upper.replace(/[^A-Z0-9]/g,"");if(canonical==="AUTHREJECTED")return"authRejected";if(upper.startsWith("AUTH"))return"authExpired";switch(canonical){case"DAILYQUOTAEXCEEDED":case"QUOTAEXCEEDED":return"quotaExceeded";case"RATELIMITED":case"TOOMANYREQUESTS":case"TELEVETRATELIMITED":return"rateLimited";case"IDEMPOTENCYKEYCONFLICT":case"IDEMPOTENCYCONFLICT":return"idempotencyConflict";case"ACCESSDENIED":case"FORBIDDEN":return"accessDenied";case"IDENTITYSIGNATUREREQUIRED":return"identitySignatureRequired";case"RUNTIMEDISPOSED":return"runtimeDisposed";case"NOTFOUND":case"CONVERSATIONNOTFOUND":return"conversationNotFound";case"PETNOTFOUND":return"petNotFound";case"TIMEOUT":case"STREAMTIMEOUT":return"streamTimeout";case"MEDIAUPLOADFAILED":case"UNRECOGNIZEDVIDEOFORMAT":case"FILETOOSMALL":return"mediaUploadFailed";case"MODERATIONBLOCKED":return"moderationBlocked";case"UPSTREAMLLMTIMEOUT":return"upstreamLlmTimeout";case"INTERNALERROR":case"INTERNALSERVERERROR":return"internalError";case"STREAMINCOMPLETE":case"CHATSTREAMINCOMPLETE":return"streamIncomplete";case"INVALIDANALYSISTYPE":case"INVALIDUPLOADPURPOSE":return"unknown";default:return"unknown"}}function fromHttpStatus(status){return status===401?"authExpired":status===403?"accessDenied":status===404?"conversationNotFound":status===409?"idempotencyConflict":status===421?"unknown":status===429?"rateLimited":status===400||status===422?"unknown":status>=500?"internalError":"unknown"}var AUTO_RETRYABLE_CODES=/* @__PURE__ */new Set(["streamTimeout","rateLimited","internalError","upstreamLlmTimeout","streamIncomplete"]);function isAutoRetryable(code){return AUTO_RETRYABLE_CODES.has(code)}var RETRYABLE_CONTRACT_CODES=/* @__PURE__ */new Set(["serviceUnavailable","conflict","idempotencyInFlight"]);function isRetryableCode(code){return isAutoRetryable(code)||RETRYABLE_CONTRACT_CODES.has(code)}var ACCESS_DENIED_COPY="This feature isn't available on your account right now.",VALIDATION_FAILED_COPY="Something in that request was not right. Check the details and try again.",USER_FACING_COPY=/* @__PURE__ */Object.freeze({authExpired:"Please sign in again to continue.",authRejected:"Please sign in again to continue.",sessionRequired:"This app needs to be updated to keep using Everfur.",accessDenied:ACCESS_DENIED_COPY,paymentRequired:"This is part of a paid plan.",quotaExceeded:"You have used today's messages. This resets tomorrow.",rateLimited:"You are sending messages quickly. Try again in a few seconds.",validationFailed:VALIDATION_FAILED_COPY,sdkUpdateRequired:"This app needs to be updated to keep using Everfur.",conflict:"That is already running. Wait for it to finish, then try again.",idempotencyConflict:"That message was already delivered.",idempotencyInFlight:"That is still processing. Give it a moment.",conversationNotFound:"This conversation is no longer available.",petNotFound:"We could not find that pet. Please pick a pet and try again.",resourceNotFound:"We could not find that.",streamTimeout:"The response timed out. Tap retry to try again.",mediaUploadFailed:"We could not upload that photo. Please attach it again.",moderationBlocked:"This request cannot be answered here.",upstreamLlmTimeout:"The response timed out. Tap retry to try again.",internalError:"We hit a snag on our end. Please try again.",notImplemented:"That is not available yet.",serviceUnavailable:"That service is briefly unavailable. Try again shortly.",streamIncomplete:"The connection dropped mid-answer. Tap retry to continue.",identitySignatureRequired:ACCESS_DENIED_COPY,runtimeDisposed:VALIDATION_FAILED_COPY,unknown:"Something went wrong. Please try again."});function userFacingError(code){return USER_FACING_COPY[code]}function defineHidden(target,key,value){Object.defineProperty(target,key,{value:value,enumerable:false,writable:false,configurable:false})}var REASON_CODE_SHAPE=/^[a-z][a-z0-9_]{0,63}$/;function makeEverfurError(code,opts){let row=contractErrorFor(opts?.wireCode,opts?.wireEnvelope),error={code:code,category:categoryFor(code),retryable:opts?.retryable??isRetryableCode(code),displayMessage:userFacingError(code)};opts?.httpStatus!==void 0&&(error.httpStatus=opts.httpStatus),opts?.requestId&&(error.requestId=opts.requestId),typeof opts?.reasonCode=="string"&&REASON_CODE_SHAPE.test(opts.reasonCode)&&(error.reasonCode=opts.reasonCode);let wait=opts?.retryAfterSeconds;if(typeof wait=="number"&&Number.isFinite(wait)&&wait>=0&&(error.retryAfterSeconds=Math.round(wait)),row);return opts?.wireMessage&&defineHidden(error,"wireMessage",opts.wireMessage),opts?.raw!==void 0&&opts.raw!==null&&defineHidden(error,"raw",opts.raw),/* @__PURE__ */Object.freeze(error)}var REQUEST_ID_HEADER="x-request-id";function errorFromResponse(status,body,requestId){let wireCode=extractWireCode(body),code=wireCode?fromWire(wireCode):fromHttpStatus(status),wireMessage=extractWireMessage(body);return makeEverfurError(code,{httpStatus:status,...extractRetryable(body)?{retryable:true}:{},...requestId?{requestId:requestId}:{},...wireCode?{wireCode:wireCode}:{},...extractReasonCode(body)?{reasonCode:extractReasonCode(body)}:{},...extractRetryAfterSeconds(body)!==null?{retryAfterSeconds:extractRetryAfterSeconds(body)}:{},...wireMessage?{wireMessage:wireMessage}:{},...body!=null?{raw:body}:{}})}function extractRetryAfterSeconds(body){let b=body,value=b?.retry_after_seconds??b?.error?.retry_after_seconds;return typeof value=="number"&&Number.isFinite(value)&&value>=0?value:null}function networkError(cause){return makeEverfurError("internalError",{retryable:true,wireMessage:describeCause(cause)})}function requestIdOf(res){let value=res.headers.get(REQUEST_ID_HEADER);return typeof value=="string"&&value.length>0?value:null}function getGlobalFetch(){let candidate=globalThis.fetch;if(typeof candidate!="function")throw new EverfurConfigError("missing-peer-dependency","global fetch is unavailable; provide config.transport or an injected fetch implementation");return candidate}function extractReasonCode(body){let b=body,reason=b?.error?.reason_code??b?.reason_code;return typeof reason=="string"&&reason.length>0?reason:null}function extractWireCode(body){let b=body,code=b?.error?.code??b?.code;return typeof code=="string"&&code.length>0?code:null}function extractWireMessage(body){let b=body,message=b?.error?.message??b?.message;return typeof message=="string"&&message.length>0?message:null}function extractRetryable(body){let b=body;return b?.error?.retryable===true||b?.retryable===true}function describeCause(cause){return cause instanceof Error?cause.message:typeof cause=="string"?cause:"network request failed"}var EVERFUR_WEBHOOK_EVENT_TYPES=/* @__PURE__ */Object.freeze(["member.linked","member.unlinked","visit.booked","visit.cancelled","visit.completed","visit.no_show","record_request.updated","record.ready","webhook_endpoint.test","chat.follow_up_due","chat.urgency.flagged","pet.vaccination.due","visit.rescheduled","visit.reminder","visit.followup_sent","chat.reminder_due","record.activation","visit.message_received","visit.ended"]),EVERFUR_WEBHOOK_ONLY_EVENT_TYPES=/* @__PURE__ */Object.freeze(["member.linked","member.unlinked","chat.urgency.flagged","webhook_endpoint.test"]);function isEverfurWebhookEventType(type){return typeof type=="string"&&EVERFUR_WEBHOOK_EVENT_TYPES.includes(type)}function isEverfurWebhookEvent(event){return isEverfurWebhookEventType(event.type)}var PARTNER_INBOUND_EVENT_TYPES=/* @__PURE__ */Object.freeze(["pet.profile.updated","pet.incident.reported","pet.behavior_note.added","pet.service_score.recorded","pet.deleted","member.status_changed","member.deleted"]);var USER_REF_MAX=128;function assertValidUserRef(raw){let length=typeof raw=="string"?[...raw].length:0;if(typeof raw!="string"||length<1||length>USER_REF_MAX)throw new EverfurConfigError("invalid-argument",`user_ref must be 1..${USER_REF_MAX} characters`);if(raw.trim().length===0)throw new EverfurConfigError("invalid-argument","user_ref must not be blank: the server strips surrounding whitespace before validating, so a whitespace-only value arrives empty and is rejected as required.");if(raw!==raw.trim())throw new EverfurConfigError("invalid-argument","user_ref must not have leading or trailing whitespace: the server strips it, so padded and unpadded forms of the same id resolve to ONE user. Pass the exact id you want to key on.");if(raw.includes("@"))throw new EverfurConfigError("invalid-argument","user_ref must not contain '@'");if(!isPrintable(raw))throw new EverfurConfigError("invalid-argument","user_ref must be printable (no control characters)");return raw}function isPrintable(value){return!NON_PRINTABLE.test(value)}var NON_PRINTABLE=/[\p{Cc}\p{Cf}\p{Cs}\p{Co}\p{Cn}\p{Zl}\p{Zp}]|(?!\u0020)[\p{Zs}]/u;function hasLoneSurrogate(value){for(let i=0;i<value.length;i+=1){let code=value.charCodeAt(i);if(code>=55296&&code<=56319){let low=value.charCodeAt(i+1);if(!(low>=56320&&low<=57343))return true;i+=1}else if(code>=56320&&code<=57343)return true}return false}function serverLength(value){return[...value].length}var SPECIES_ALIASES=/* @__PURE__ */Object.freeze({dog:"dog",canine:"dog",k9:"dog",puppy:"dog",cat:"cat",feline:"cat",kitten:"cat"});function canonicalPetSpecies(raw){if(typeof raw!="string")return null;let key=raw.trim().toLowerCase();return Object.prototype.hasOwnProperty.call(SPECIES_ALIASES,key)?SPECIES_ALIASES[key]:null}var LIST_MAX=50,REF_MAX=128,NAME_MAX=120,SHORT_MAX=120,NOTES_MAX=2e3,FOOD_MAX=120,MICROCHIP_MAX=80,SEXES=/* @__PURE__ */new Set(["male","female","unknown"]),PRECISIONS=/* @__PURE__ */new Set(["day","month","year"]),ACTIVITY=/* @__PURE__ */new Set(["low","medium","high","athletic"]),INDOOR_OUTDOOR=/* @__PURE__ */new Set(["indoor","outdoor","both"]),SEVERITIES=/* @__PURE__ */new Set(["mild","moderate","severe"]),ISO_DATE=/^(\d{4})-(\d{2})-(\d{2})$/,SCALAR_WIRE=[["sex","sex"],["spayedNeutered","spayed_neutered"],["birthDate","birth_date"],["birthDatePrecision","birth_date_precision"],["activityLevel","activity_level"],["indoorOutdoor","indoor_outdoor"],["foodBrand","food_brand"],["foodType","food_type"],["microchipId","microchip_id"]],LIST_WIRE=[["allergies","allergies"],["medications","medications"],["supplements","supplements"],["conditions","conditions"]];/* @__PURE__ */Object.freeze([...SCALAR_WIRE,...LIST_WIRE].map(([key])=>key));function isRealDate(value){let match=ISO_DATE.exec(value);if(match===null)return false;let[year,month,day]=[Number(match[1]),Number(match[2]),Number(match[3])],date2=new Date(Date.UTC(year,month-1,day));return date2.getUTCFullYear()===year&&date2.getUTCMonth()===month-1&&date2.getUTCDate()===day}var oneOf=allowed=>(field,value)=>typeof value=="string"&&allowed.has(value)?null:`${field} must be one of ${[...allowed].join(", ")}`,boolean=(field,value)=>typeof value=="boolean"?null:`${field} must be true or false`,date=(field,value)=>typeof value=="string"&&isRealDate(value)?null:`${field} must be a real date written YYYY-MM-DD`,text=(max,opts={})=>(field,value)=>{if(typeof value!="string")return`${field} must be a string`;if(hasLoneSurrogate(value))return`${field} contains an unpaired surrogate and cannot be encoded`;let measured=opts.trimmed?value.trim():value;if(opts.required&&measured.length===0)return`${field} is required and must not be blank`;let length=serverLength(measured);return length<=max?null:`${field} is ${length} characters; the server accepts at most ${max}`},SCALAR_CHECKS={sex:oneOf(SEXES),spayedNeutered:boolean,birthDate:date,birthDatePrecision:oneOf(PRECISIONS),activityLevel:oneOf(ACTIVITY),indoorOutdoor:oneOf(INDOOR_OUTDOOR),foodBrand:text(FOOD_MAX),foodType:text(FOOD_MAX),microchipId:text(MICROCHIP_MAX)},REF_FIELD=["ref","ref",false,text(REF_MAX,{required:true,trimmed:true})],NOTES_FIELD=["notes","notes",false,text(NOTES_MAX,{trimmed:true})],MEDICATION_FIELDS=[REF_FIELD,["name","name",true,text(NAME_MAX,{required:true,trimmed:true})],["dose","dose",false,text(SHORT_MAX,{trimmed:true})],["frequency","frequency",false,text(SHORT_MAX,{trimmed:true})],["startDate","start_date",false,date],["endDate","end_date",false,date],NOTES_FIELD],ITEM_FIELDS={allergies:[REF_FIELD,["allergen","allergen",true,text(NAME_MAX,{required:true,trimmed:true})],["severity","severity",false,oneOf(SEVERITIES)],NOTES_FIELD],medications:MEDICATION_FIELDS,supplements:MEDICATION_FIELDS,conditions:[REF_FIELD,["conditionName","condition_name",true,text(NAME_MAX,{required:true,trimmed:true})],["diagnosedDate","diagnosed_date",false,date],NOTES_FIELD]};function itemToWire(list,index,raw){let at=`${list}[${index}]`;if(typeof raw!="object"||raw===null||Array.isArray(raw))return{error:`${at} must be an object`};let source=raw,item={};for(let[key,wire,isRequired,check]of ITEM_FIELDS[list]){let value=source[key];if(value==null){if(isRequired)return{error:`${at}.${key} is required`};value===null&&(item[wire]=null);continue}let bad=check(`${at}.${key}`,value);if(bad!==null)return{error:bad};item[wire]=value}let start=item.start_date,end=item.end_date;return typeof start=="string"&&typeof end=="string"&&end<start?{error:`${at}.endDate must not be before startDate`}:{item:item}}function listToWire(list,raw){if(!Array.isArray(raw))return{error:`${list} must be an array (send [] to clear it)`};if(raw.length>LIST_MAX)return{error:`${list} has ${raw.length} items; the server accepts at most ${LIST_MAX}`};let items=[],refs=/* @__PURE__ */new Set;for(let index=0;index<raw.length;index+=1){let mapped=itemToWire(list,index,raw[index]);if("error"in mapped)return mapped;let ref=mapped.item.ref;if(typeof ref=="string"){let key=ref.trim();if(refs.has(key))return{error:`${list}: ref ${JSON.stringify(key)} is used twice; a ref names one item`};refs.add(key)}items.push(mapped.item)}return{items:items}}function petHealthToWire(input,species){let source=input,body={};for(let[key,wire]of SCALAR_WIRE){let value=source[key];if(value!==void 0){if(value!==null){let bad=SCALAR_CHECKS[key](key,value);if(bad!==null)return{error:bad}}body[wire]=value}}let dateSent=source.birthDate!==void 0,precisionSent=source.birthDatePrecision!==void 0;if(dateSent!==precisionSent||dateSent&&source.birthDate===null!=(source.birthDatePrecision===null))return{error:"birthDate and birthDatePrecision must be sent together, both set or both null"};for(let[key,wire]of LIST_WIRE){let value=source[key];if(value===void 0)continue;let mapped=listToWire(key,value);if("error"in mapped)return mapped;body[wire]=mapped.items}return Object.keys(body).length>0&&species!==void 0&&canonicalPetSpecies(species)===null?{error:"health fields need a pet Everfur reads as a dog or a cat (dog, canine, k9, puppy, cat, feline, kitten)"}:{body:body}}var SECRET_KEY_PREFIXES=["sk_partner_","rk_partner_"];function assertServerSecretKey(value,action){if(typeof value!="string"||value.length===0)throw new EverfurConfigError("invalid-argument","partnerSecretKey is required");if(value.startsWith("pk_"))throw new EverfurConfigError("invalid-argument",`partnerSecretKey is a publishable key (pk_...): ${action} needs your secret key, server side only`);if(!SECRET_KEY_PREFIXES.some(prefix=>value.startsWith(prefix)))throw new EverfurConfigError("invalid-argument","partnerSecretKey must be an sk_partner_ secret key or an rk_partner_ restricted key")}var PROFILE_FIELDS=[["name","name"],["species","species"],["breed","breed"],["ageYears","age_years"],["weightKg","weight_kg"],["partnerLabelInstructions","partner_label_instructions"]];function partnerPetProfileBody(profile){if(typeof profile!="object"||profile===null||Array.isArray(profile))throw new EverfurConfigError("invalid-argument","the pet profile must be an object");let body={};for(let[key,wire]of PROFILE_FIELDS)profile[key]!==void 0&&(body[wire]=profile[key]);let health=petHealthToWire(profile,profile.species);if("error"in health)throw new EverfurConfigError("invalid-argument",health.error);return Object.assign(body,health.body)}var IDEMPOTENCY_KEY_SHAPE=/^[\x21-\x7e]{1,255}$/,MAX_BODY_BYTES=32*1024,DATE_TIME_WITH_OFFSET=/^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:[Zz]|[+-]\d{2}:?\d{2})$/,SEND_TIMEOUT_MS=3e4,INBOUND_RULES=/* @__PURE__ */Object.freeze({"pet.profile.updated":{subject:"pet",schemaVersions:[1,2]},"pet.incident.reported":{subject:"pet",schemaVersions:[1]},"pet.behavior_note.added":{subject:"pet",schemaVersions:[1]},"pet.service_score.recorded":{subject:"pet",schemaVersions:[1]},"pet.deleted":{subject:"pet",schemaVersions:[1]},"member.status_changed":{subject:"member",schemaVersions:[1]},"member.deleted":{subject:"member",schemaVersions:[1]}});async function sendPartnerEvent(client,event,idempotencyKey){let key=idempotencyKey??randomUUID();if(typeof key!="string"||!IDEMPOTENCY_KEY_SHAPE.test(key))throw new EverfurConfigError("invalid-argument","idempotencyKey must be 1 to 255 visible ASCII characters (no spaces, no control or non-ASCII characters)");assertServerSecretKey(client.partnerSecretKey,"sending events");let payload=serialize(buildBody(event)),fetchImpl=client.fetchImpl??getGlobalFetch(),url=`${resolveApiBaseUrl(client.apiBaseUrl)}/partners/events`,headers={...buildBaseHeaders({sdkVersion:SDK_VERSION,platform:SDK_PLATFORM,contractVersion:client.contractVersion??DEFAULT_CONTRACT_VERSION}),accept:"application/json","content-type":"application/json","idempotency-key":key,"x-everfur-partner-secret-key":client.partnerSecretKey},controller=new AbortController,timer=setTimeout(()=>controller.abort(),SEND_TIMEOUT_MS),res;try{res=await fetchImpl(url,{method:"POST",headers:headers,body:payload,signal:controller.signal})}catch(cause){return err(networkError(cause))}finally{clearTimeout(timer)}let json=null;try{json=await res.json()}catch{json=null}let requestId=requestIdOf(res);if(!res.ok)return err(errorFromResponse(res.status,json,requestId));let receipt=parseReceipt(json,key);return receipt?ok(receipt):err(errorFromResponse(502,{error:{code:"INTERNAL_ERROR"}},requestId))}function isInboundType(value){return typeof value=="string"&&PARTNER_INBOUND_EVENT_TYPES.includes(value)}function buildBody(event){if(typeof event!="object"||event===null)throw new EverfurConfigError("invalid-argument","event is required");if(!isInboundType(event.type))throw new EverfurConfigError("invalid-argument",`event.type must be one of ${PARTNER_INBOUND_EVENT_TYPES.join(", ")}`);let rule=INBOUND_RULES[event.type],schemaVersion=event.schemaVersion??1;if(typeof schemaVersion!="number"||!rule.schemaVersions.includes(schemaVersion))throw new EverfurConfigError("invalid-argument",`event.schemaVersion must be one of ${rule.schemaVersions.join(", ")} for ${event.type}`);let userRef=assertValidUserRef(event.userRef);if(rule.subject==="pet"&&event.petRef===void 0)throw new EverfurConfigError("invalid-argument",`event.petRef is required for ${event.type}`);if(rule.subject==="member"&&event.petRef!==void 0)throw new EverfurConfigError("invalid-argument",`event.petRef is not accepted on ${event.type}`);let petRef=event.petRef===void 0?void 0:assertValidPetRef(event.petRef);if(typeof event.data!="object"||event.data===null||Array.isArray(event.data))throw new EverfurConfigError("invalid-argument","event.data must be an object");let data=event.type==="pet.profile.updated"&&schemaVersion===2?partnerPetProfileBody(event.data):event.data,body={type:event.type,schema_version:schemaVersion,user_ref:userRef,occurred_at:occurredAtIso(event.occurredAt),data:data};return petRef!==void 0&&(body.pet_ref=petRef),body}function assertValidPetRef(raw){try{return assertValidUserRef(raw)}catch(cause){throw cause instanceof EverfurConfigError?new EverfurConfigError("invalid-argument",`event.petRef follows the user_ref rule: ${cause.message}`):cause}}function occurredAtIso(value){if(typeof value=="string"&&!DATE_TIME_WITH_OFFSET.test(value))throw new EverfurConfigError("invalid-argument","event.occurredAt must be a Date or an ISO 8601 date-time with an explicit offset (Z or +05:30)");let date2=value instanceof Date?value:typeof value=="string"?new Date(value):new Date(Number.NaN);if(Number.isNaN(date2.getTime()))throw new EverfurConfigError("invalid-argument","event.occurredAt must be a Date or an ISO 8601 date-time with an explicit offset (Z or +05:30)");return date2.toISOString()}function serialize(body){let payload;try{payload=JSON.stringify(body)}catch{throw new EverfurConfigError("invalid-argument","event.data must be JSON-serialisable")}let bytes=(new TextEncoder).encode(payload).byteLength;if(bytes>MAX_BODY_BYTES)throw new EverfurConfigError("invalid-argument",`the event is ${bytes} bytes once serialised; Everfur accepts at most ${MAX_BODY_BYTES} (32 KB)`);return payload}function parseReceipt(json,idempotencyKey){if(typeof json!="object"||json===null)return null;let obj=json,id=obj.id,type=obj.type,schemaVersion=obj.schema_version,userRef=obj.user_ref,petRef=obj.pet_ref??null,occurredAt=obj.occurred_at,receivedAt=obj.received_at,status=obj.status,livemode=obj.livemode;return typeof id!="string"||id.length===0||!isInboundType(type)||typeof schemaVersion!="number"||typeof userRef!="string"||petRef!==null&&typeof petRef!="string"||typeof occurredAt!="string"||typeof receivedAt!="string"||typeof status!="string"||typeof livemode!="boolean"?null:/* @__PURE__ */Object.freeze({id:id,type:type,schemaVersion:schemaVersion,userRef:userRef,petRef:petRef,occurredAt:occurredAt,receivedAt:receivedAt,status:status,livemode:livemode,idempotencyKey:idempotencyKey})}export{DEFAULT_WEBHOOK_TOLERANCE_SECONDS,EVERFUR_SIGNATURE_HEADER,EVERFUR_WEBHOOK_EVENT_TYPES,EVERFUR_WEBHOOK_ONLY_EVENT_TYPES,EverfurWebhookVerificationError,PARTNER_INBOUND_EVENT_TYPES,constructEvent,generateTestSignatureHeader,isEverfurWebhookEvent,isEverfurWebhookEventType,sendPartnerEvent};
|
|
92
|
+
/* @__PURE__ */Object.freeze({wireCode:"webhook_url_rejected",envelope:"http_envelope",httpStatus:400,retryable:false})]);/* @__PURE__ */Object.freeze(CONTRACT_RETRYABILITY.map(row=>row.wireCode));var NORMALIZED_FOLD=/* @__PURE__ */Object.freeze({ValidationException:"validationFailed",AuthorizationException:"authRejected",PaymentRequiredException:"paymentRequired",AccessDeniedException:"accessDenied",ResourceNotFoundException:"resourceNotFound",ConflictException:"conflict",ThrottlingException:"rateLimited",InternalFailureException:"internalError",NotImplementedException:"notImplemented",ServiceUnavailableException:"serviceUnavailable",MethodNotAllowedException:"validationFailed",authExpired:"authExpired",unavailable:"serviceUnavailable",session_required:"sessionRequired",accessDenied:"accessDenied",invalidRequest:"sdkUpdateRequired",authRejected:"authRejected",rateLimited:"rateLimited",insufficientCapability:"accessDenied",event_cursor_invalid:"validationFailed",event_filter_invalid:"validationFailed",event_payload_invalid:"validationFailed",event_type_unknown:"validationFailed",idempotency_key_invalid:"validationFailed",idempotency_key_required:"validationFailed",idempotency_key_reused:"idempotencyConflict",payload_too_large:"validationFailed",webhook_url_rejected:"validationFailed",webhook_endpoint_update_empty:"validationFailed",webhook_endpoint_update_invalid:"validationFailed",event_type_not_available:"conflict",record_subject_not_found:"resourceNotFound",records_consent_required:"conflict",record_species_unsupported:"validationFailed",record_upload_invalid:"validationFailed",FILE_TOO_LARGE:"validationFailed",INVALID_CONTENT_TYPE:"validationFailed",attachment_unreadable:"validationFailed",provider_unsupported:"validationFailed",token_invalid:"validationFailed",device_cipher_unavailable:"serviceUnavailable",email_invalid:"validationFailed",consent_required:"validationFailed",consent_invalid:"validationFailed",consent_scope_wrong_route:"validationFailed",IDEMPOTENCY_KEY_IN_FLIGHT:"idempotencyInFlight",IDEMPOTENCY_KEY_REUSED_DIFFERENT_REQUEST:"idempotencyConflict",DAILY_QUOTA_EXCEEDED:"quotaExceeded",TIER_UPGRADE_REQUIRED:"paymentRequired",not_found:"conversationNotFound",timeout:"streamTimeout",internal_error:"internalError",invalid_request:"validationFailed",invalid_client:"authRejected",invalid_grant:"authRejected",unsupported_grant_type:"validationFailed",invalid_scope:"validationFailed",invalid_target:"validationFailed",invalid_redirect_uri:"validationFailed",invalid_client_metadata:"validationFailed",unsupported_response_type:"validationFailed",access_denied:"accessDenied",slow_down:"rateLimited",mcp_request_not_found:"resourceNotFound",mcp_request_gone:"resourceNotFound",mcp_connection_not_found:"resourceNotFound",mcp_request_conflict:"conflict",sandbox_only:"accessDenied",tenant_has_no_capabilities:"conflict",verify_mint_refused:"accessDenied",verify_mint_rate_limited:"rateLimited",verify_mint_unavailable:"serviceUnavailable",verify_user_ref_invalid:"validationFailed",insufficient_scope:"accessDenied",tenant_filter_invalid:"validationFailed",tenant_resource_not_found:"resourceNotFound",tenant_surface_not_enabled:"conflict",pet_health_species_unsupported:"validationFailed",pet_health_list_removals_unconfirmed:"validationFailed",petRefInUse:"conflict",share_limit_reached:"conflict",pet_not_registered:"resourceNotFound",species_unsupported:"validationFailed",partner_visit_owner_only:"accessDenied",partner_visit_link_conflict:"conflict",partner_visit_pet_already_mapped:"conflict"}),CONTRACT_ERROR_ROWS=/* @__PURE__ */Object.freeze(CONTRACT_RETRYABILITY.map(generated=>/* @__PURE__ */Object.freeze({wireCode:generated.wireCode,envelope:generated.envelope,retryable:generated.retryable,normalized:NORMALIZED_FOLD[generated.wireCode]}))),BY_KEY=new Map(CONTRACT_ERROR_ROWS.map(r=>[r.envelope+r.wireCode.toUpperCase(),r])),ENVELOPE_LOOKUP_ORDER=/* @__PURE__ */Object.freeze(["http_envelope",...[...new Set(CONTRACT_ERROR_ROWS.map(r=>r.envelope))].filter(e=>e!=="http_envelope").sort()]);function contractErrorFor(wireCode,envelope){if(typeof wireCode!="string")return;let key=wireCode.trim().toUpperCase();if(key.length!==0)for(let candidate of[envelope??"http_envelope",...ENVELOPE_LOOKUP_ORDER]){let row=BY_KEY.get(candidate+key);if(row)return row}}var CATEGORY_OF=/* @__PURE__ */Object.freeze({authExpired:"authentication",authRejected:"authentication",sessionRequired:"authentication",identitySignatureRequired:"authentication",accessDenied:"authorization",paymentRequired:"entitlement",quotaExceeded:"rateLimit",rateLimited:"rateLimit",validationFailed:"invalidRequest",sdkUpdateRequired:"invalidRequest",runtimeDisposed:"invalidRequest",conversationNotFound:"notFound",petNotFound:"notFound",resourceNotFound:"notFound",conflict:"conflict",idempotencyConflict:"conflict",idempotencyInFlight:"conflict",streamTimeout:"connection",streamIncomplete:"connection",upstreamLlmTimeout:"connection",serviceUnavailable:"connection",internalError:"server",notImplemented:"server",mediaUploadFailed:"media",moderationBlocked:"policy",unknown:"unknown"});function categoryFor(code){return CATEGORY_OF[code]}function fromWire(wire){let contractRow=contractErrorFor(wire);if(contractRow)return contractRow.normalized;let upper=(wire??"").trim().toUpperCase(),canonical=upper.replace(/[^A-Z0-9]/g,"");if(canonical==="AUTHREJECTED")return"authRejected";if(upper.startsWith("AUTH"))return"authExpired";switch(canonical){case"DAILYQUOTAEXCEEDED":case"QUOTAEXCEEDED":return"quotaExceeded";case"RATELIMITED":case"TOOMANYREQUESTS":case"TELEVETRATELIMITED":return"rateLimited";case"IDEMPOTENCYKEYCONFLICT":case"IDEMPOTENCYCONFLICT":return"idempotencyConflict";case"ACCESSDENIED":case"FORBIDDEN":return"accessDenied";case"IDENTITYSIGNATUREREQUIRED":return"identitySignatureRequired";case"RUNTIMEDISPOSED":return"runtimeDisposed";case"NOTFOUND":case"CONVERSATIONNOTFOUND":return"conversationNotFound";case"PETNOTFOUND":return"petNotFound";case"TIMEOUT":case"STREAMTIMEOUT":return"streamTimeout";case"MEDIAUPLOADFAILED":case"UNRECOGNIZEDVIDEOFORMAT":case"FILETOOSMALL":return"mediaUploadFailed";case"MODERATIONBLOCKED":return"moderationBlocked";case"UPSTREAMLLMTIMEOUT":return"upstreamLlmTimeout";case"INTERNALERROR":case"INTERNALSERVERERROR":return"internalError";case"STREAMINCOMPLETE":case"CHATSTREAMINCOMPLETE":return"streamIncomplete";case"INVALIDANALYSISTYPE":case"INVALIDUPLOADPURPOSE":return"unknown";default:return"unknown"}}function fromHttpStatus(status){return status===401?"authExpired":status===403?"accessDenied":status===404?"conversationNotFound":status===409?"idempotencyConflict":status===421?"unknown":status===429?"rateLimited":status===400||status===422?"unknown":status>=500?"internalError":"unknown"}var AUTO_RETRYABLE_CODES=/* @__PURE__ */new Set(["streamTimeout","rateLimited","internalError","upstreamLlmTimeout","streamIncomplete"]);function isAutoRetryable(code){return AUTO_RETRYABLE_CODES.has(code)}var RETRYABLE_CONTRACT_CODES=/* @__PURE__ */new Set(["serviceUnavailable","conflict","idempotencyInFlight"]);function isRetryableCode(code){return isAutoRetryable(code)||RETRYABLE_CONTRACT_CODES.has(code)}var ACCESS_DENIED_COPY="This feature isn't available on your account right now.",VALIDATION_FAILED_COPY="Something in that request was not right. Check the details and try again.",USER_FACING_COPY=/* @__PURE__ */Object.freeze({authExpired:"Please sign in again to continue.",authRejected:"Please sign in again to continue.",sessionRequired:"This app needs to be updated to keep using Everfur.",accessDenied:ACCESS_DENIED_COPY,paymentRequired:"This is part of a paid plan.",quotaExceeded:"You have used today's messages. This resets tomorrow.",rateLimited:"You are sending messages quickly. Try again in a few seconds.",validationFailed:VALIDATION_FAILED_COPY,sdkUpdateRequired:"This app needs to be updated to keep using Everfur.",conflict:"That is already running. Wait for it to finish, then try again.",idempotencyConflict:"That message was already delivered.",idempotencyInFlight:"That is still processing. Give it a moment.",conversationNotFound:"This conversation is no longer available.",petNotFound:"We could not find that pet. Please pick a pet and try again.",resourceNotFound:"We could not find that.",streamTimeout:"The response timed out. Tap retry to try again.",mediaUploadFailed:"We could not upload that photo. Please attach it again.",moderationBlocked:"This request cannot be answered here.",upstreamLlmTimeout:"The response timed out. Tap retry to try again.",internalError:"We hit a snag on our end. Please try again.",notImplemented:"That is not available yet.",serviceUnavailable:"That service is briefly unavailable. Try again shortly.",streamIncomplete:"The connection dropped mid-answer. Tap retry to continue.",identitySignatureRequired:ACCESS_DENIED_COPY,runtimeDisposed:VALIDATION_FAILED_COPY,unknown:"Something went wrong. Please try again."});function userFacingError(code){return USER_FACING_COPY[code]}function defineHidden(target,key,value){Object.defineProperty(target,key,{value:value,enumerable:false,writable:false,configurable:false})}var REASON_CODE_SHAPE=/^[a-z][a-z0-9_]{0,63}$/;function makeEverfurError(code,opts){let row=contractErrorFor(opts?.wireCode,opts?.wireEnvelope),error={code:code,category:categoryFor(code),retryable:opts?.retryable??isRetryableCode(code),displayMessage:userFacingError(code)};opts?.httpStatus!==void 0&&(error.httpStatus=opts.httpStatus),opts?.requestId&&(error.requestId=opts.requestId),typeof opts?.reasonCode=="string"&&REASON_CODE_SHAPE.test(opts.reasonCode)&&(error.reasonCode=opts.reasonCode);let wait=opts?.retryAfterSeconds;if(typeof wait=="number"&&Number.isFinite(wait)&&wait>=0&&(error.retryAfterSeconds=Math.round(wait)),row);return opts?.wireMessage&&defineHidden(error,"wireMessage",opts.wireMessage),opts?.raw!==void 0&&opts.raw!==null&&defineHidden(error,"raw",opts.raw),/* @__PURE__ */Object.freeze(error)}var REQUEST_ID_HEADER="x-request-id";function errorFromResponse(status,body,requestId){let wireCode=extractWireCode(body),code=wireCode?fromWire(wireCode):fromHttpStatus(status),wireMessage=extractWireMessage(body);return makeEverfurError(code,{httpStatus:status,...extractRetryable(body)?{retryable:true}:{},...requestId?{requestId:requestId}:{},...wireCode?{wireCode:wireCode}:{},...extractReasonCode(body)?{reasonCode:extractReasonCode(body)}:{},...extractRetryAfterSeconds(body)!==null?{retryAfterSeconds:extractRetryAfterSeconds(body)}:{},...wireMessage?{wireMessage:wireMessage}:{},...body!=null?{raw:body}:{}})}function extractRetryAfterSeconds(body){let b=body,value=b?.retry_after_seconds??b?.error?.retry_after_seconds;return typeof value=="number"&&Number.isFinite(value)&&value>=0?value:null}function networkError(cause){return makeEverfurError("internalError",{retryable:true,wireMessage:describeCause(cause)})}function requestIdOf(res){let value=res.headers.get(REQUEST_ID_HEADER);return typeof value=="string"&&value.length>0?value:null}function getGlobalFetch(){let candidate=globalThis.fetch;if(typeof candidate!="function")throw new EverfurConfigError("missing-peer-dependency","global fetch is unavailable; provide config.transport or an injected fetch implementation");return candidate}function extractReasonCode(body){let b=body,reason=b?.error?.reason_code??b?.reason_code;return typeof reason=="string"&&reason.length>0?reason:null}function extractWireCode(body){let b=body,code=b?.error?.code??b?.code;return typeof code=="string"&&code.length>0?code:null}function extractWireMessage(body){let b=body,message=b?.error?.message??b?.message;return typeof message=="string"&&message.length>0?message:null}function extractRetryable(body){let b=body;return b?.error?.retryable===true||b?.retryable===true}function describeCause(cause){return cause instanceof Error?cause.message:typeof cause=="string"?cause:"network request failed"}var EVERFUR_WEBHOOK_EVENT_TYPES=/* @__PURE__ */Object.freeze(["member.linked","member.unlinked","visit.booked","visit.cancelled","visit.completed","visit.no_show","record_request.updated","record.ready","webhook_endpoint.test","chat.follow_up_due","chat.urgency.flagged","pet.vaccination.due","visit.rescheduled","visit.reminder","visit.followup_sent","chat.reminder_due","record.activation","visit.message_received","visit.ended","contact.exported"]),EVERFUR_WEBHOOK_ONLY_EVENT_TYPES=/* @__PURE__ */Object.freeze(["member.linked","member.unlinked","chat.urgency.flagged","webhook_endpoint.test","contact.exported"]);function isEverfurWebhookEventType(type){return typeof type=="string"&&EVERFUR_WEBHOOK_EVENT_TYPES.includes(type)}function isEverfurWebhookEvent(event){return isEverfurWebhookEventType(event.type)}var PARTNER_INBOUND_EVENT_TYPES=/* @__PURE__ */Object.freeze(["pet.profile.updated","pet.incident.reported","pet.behavior_note.added","pet.service_score.recorded","pet.deleted","member.status_changed","member.deleted"]);var SECRET_KEY_PREFIXES=["sk_partner_","rk_partner_"];function assertServerSecretKey(value,action){if(typeof value!="string"||value.length===0)throw new EverfurConfigError("invalid-argument","partnerSecretKey is required");if(value.startsWith("pk_"))throw new EverfurConfigError("invalid-argument",`partnerSecretKey is a publishable key (pk_...): ${action} needs your secret key, server side only`);if(!SECRET_KEY_PREFIXES.some(prefix=>value.startsWith(prefix)))throw new EverfurConfigError("invalid-argument","partnerSecretKey must be an sk_partner_ secret key or an rk_partner_ restricted key")}var USER_REF_MAX=128;function assertValidUserRef(raw){let length=typeof raw=="string"?[...raw].length:0;if(typeof raw!="string"||length<1||length>USER_REF_MAX)throw new EverfurConfigError("invalid-argument",`user_ref must be 1..${USER_REF_MAX} characters`);if(raw.trim().length===0)throw new EverfurConfigError("invalid-argument","user_ref must not be blank: the server strips surrounding whitespace before validating, so a whitespace-only value arrives empty and is rejected as required.");if(raw!==raw.trim())throw new EverfurConfigError("invalid-argument","user_ref must not have leading or trailing whitespace: the server strips it, so padded and unpadded forms of the same id resolve to ONE user. Pass the exact id you want to key on.");if(raw.includes("@"))throw new EverfurConfigError("invalid-argument","user_ref must not contain '@'");if(!isPrintable(raw))throw new EverfurConfigError("invalid-argument","user_ref must be printable (no control characters)");return raw}function isPrintable(value){return!NON_PRINTABLE.test(value)}var NON_PRINTABLE=/[\p{Cc}\p{Cf}\p{Cs}\p{Co}\p{Cn}\p{Zl}\p{Zp}]|(?!\u0020)[\p{Zs}]/u;function hasLoneSurrogate(value){for(let i=0;i<value.length;i+=1){let code=value.charCodeAt(i);if(code>=55296&&code<=56319){let low=value.charCodeAt(i+1);if(!(low>=56320&&low<=57343))return true;i+=1}else if(code>=56320&&code<=57343)return true}return false}function serverLength(value){return[...value].length}var SPECIES_ALIASES=/* @__PURE__ */Object.freeze({dog:"dog",canine:"dog",k9:"dog",puppy:"dog",cat:"cat",feline:"cat",kitten:"cat"});function canonicalPetSpecies(raw){if(typeof raw!="string")return null;let key=raw.trim().toLowerCase();return Object.prototype.hasOwnProperty.call(SPECIES_ALIASES,key)?SPECIES_ALIASES[key]:null}var LIST_MAX=50,REF_MAX=128,NAME_MAX=120,SHORT_MAX=120,NOTES_MAX=2e3,FOOD_MAX=120,MICROCHIP_MAX=80,SEXES=/* @__PURE__ */new Set(["male","female","unknown"]),PRECISIONS=/* @__PURE__ */new Set(["day","month","year"]),ACTIVITY=/* @__PURE__ */new Set(["low","medium","high","athletic"]),INDOOR_OUTDOOR=/* @__PURE__ */new Set(["indoor","outdoor","both"]),SEVERITIES=/* @__PURE__ */new Set(["mild","moderate","severe"]),ISO_DATE=/^(\d{4})-(\d{2})-(\d{2})$/,SCALAR_WIRE=[["sex","sex"],["spayedNeutered","spayed_neutered"],["birthDate","birth_date"],["birthDatePrecision","birth_date_precision"],["activityLevel","activity_level"],["indoorOutdoor","indoor_outdoor"],["foodBrand","food_brand"],["foodType","food_type"],["microchipId","microchip_id"]],LIST_WIRE=[["allergies","allergies"],["medications","medications"],["supplements","supplements"],["conditions","conditions"]];/* @__PURE__ */Object.freeze([...SCALAR_WIRE,...LIST_WIRE].map(([key])=>key));function isRealDate(value){let match=ISO_DATE.exec(value);if(match===null)return false;let[year,month,day]=[Number(match[1]),Number(match[2]),Number(match[3])],date2=new Date(Date.UTC(year,month-1,day));return date2.getUTCFullYear()===year&&date2.getUTCMonth()===month-1&&date2.getUTCDate()===day}var oneOf=allowed=>(field,value)=>typeof value=="string"&&allowed.has(value)?null:`${field} must be one of ${[...allowed].join(", ")}`,boolean=(field,value)=>typeof value=="boolean"?null:`${field} must be true or false`,date=(field,value)=>typeof value=="string"&&isRealDate(value)?null:`${field} must be a real date written YYYY-MM-DD`,text=(max,opts={})=>(field,value)=>{if(typeof value!="string")return`${field} must be a string`;if(hasLoneSurrogate(value))return`${field} contains an unpaired surrogate and cannot be encoded`;let measured=opts.trimmed?value.trim():value;if(opts.required&&measured.length===0)return`${field} is required and must not be blank`;let length=serverLength(measured);return length<=max?null:`${field} is ${length} characters; the server accepts at most ${max}`},SCALAR_CHECKS={sex:oneOf(SEXES),spayedNeutered:boolean,birthDate:date,birthDatePrecision:oneOf(PRECISIONS),activityLevel:oneOf(ACTIVITY),indoorOutdoor:oneOf(INDOOR_OUTDOOR),foodBrand:text(FOOD_MAX),foodType:text(FOOD_MAX),microchipId:text(MICROCHIP_MAX)},REF_FIELD=["ref","ref",false,text(REF_MAX,{required:true,trimmed:true})],NOTES_FIELD=["notes","notes",false,text(NOTES_MAX,{trimmed:true})],MEDICATION_FIELDS=[REF_FIELD,["name","name",true,text(NAME_MAX,{required:true,trimmed:true})],["dose","dose",false,text(SHORT_MAX,{trimmed:true})],["frequency","frequency",false,text(SHORT_MAX,{trimmed:true})],["startDate","start_date",false,date],["endDate","end_date",false,date],NOTES_FIELD],ITEM_FIELDS={allergies:[REF_FIELD,["allergen","allergen",true,text(NAME_MAX,{required:true,trimmed:true})],["severity","severity",false,oneOf(SEVERITIES)],NOTES_FIELD],medications:MEDICATION_FIELDS,supplements:MEDICATION_FIELDS,conditions:[REF_FIELD,["conditionName","condition_name",true,text(NAME_MAX,{required:true,trimmed:true})],["diagnosedDate","diagnosed_date",false,date],NOTES_FIELD]};function itemToWire(list,index,raw){let at=`${list}[${index}]`;if(typeof raw!="object"||raw===null||Array.isArray(raw))return{error:`${at} must be an object`};let source=raw,item={};for(let[key,wire,isRequired,check]of ITEM_FIELDS[list]){let value=source[key];if(value==null){if(isRequired)return{error:`${at}.${key} is required`};value===null&&(item[wire]=null);continue}let bad=check(`${at}.${key}`,value);if(bad!==null)return{error:bad};item[wire]=value}let start=item.start_date,end=item.end_date;return typeof start=="string"&&typeof end=="string"&&end<start?{error:`${at}.endDate must not be before startDate`}:{item:item}}function listToWire(list,raw){if(!Array.isArray(raw))return{error:`${list} must be an array (send [] to clear it)`};if(raw.length>LIST_MAX)return{error:`${list} has ${raw.length} items; the server accepts at most ${LIST_MAX}`};let items=[],refs=/* @__PURE__ */new Set;for(let index=0;index<raw.length;index+=1){let mapped=itemToWire(list,index,raw[index]);if("error"in mapped)return mapped;let ref=mapped.item.ref;if(typeof ref=="string"){let key=ref.trim();if(refs.has(key))return{error:`${list}: ref ${JSON.stringify(key)} is used twice; a ref names one item`};refs.add(key)}items.push(mapped.item)}return{items:items}}function petHealthToWire(input,species){let source=input,body={};for(let[key,wire]of SCALAR_WIRE){let value=source[key];if(value!==void 0){if(value!==null){let bad=SCALAR_CHECKS[key](key,value);if(bad!==null)return{error:bad}}body[wire]=value}}let dateSent=source.birthDate!==void 0,precisionSent=source.birthDatePrecision!==void 0;if(dateSent!==precisionSent||dateSent&&source.birthDate===null!=(source.birthDatePrecision===null))return{error:"birthDate and birthDatePrecision must be sent together, both set or both null"};for(let[key,wire]of LIST_WIRE){let value=source[key];if(value===void 0)continue;let mapped=listToWire(key,value);if("error"in mapped)return mapped;body[wire]=mapped.items}return Object.keys(body).length>0&&species!==void 0&&canonicalPetSpecies(species)===null?{error:"health fields need a pet Everfur reads as a dog or a cat (dog, canine, k9, puppy, cat, feline, kitten)"}:{body:body}}var PROFILE_FIELDS=[["name","name"],["species","species"],["breed","breed"],["ageYears","age_years"],["weightKg","weight_kg"],["partnerLabelInstructions","partner_label_instructions"]];function partnerPetProfileBody(profile){if(typeof profile!="object"||profile===null||Array.isArray(profile))throw new EverfurConfigError("invalid-argument","the pet profile must be an object");let body={};for(let[key,wire]of PROFILE_FIELDS)profile[key]!==void 0&&(body[wire]=profile[key]);let health=petHealthToWire(profile,profile.species);if("error"in health)throw new EverfurConfigError("invalid-argument",health.error);return Object.assign(body,health.body)}var IDEMPOTENCY_KEY_SHAPE=/^[\x21-\x7e]{1,255}$/,MAX_BODY_BYTES=32*1024,DATE_TIME_WITH_OFFSET=/^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:[Zz]|[+-]\d{2}:?\d{2})$/,SEND_TIMEOUT_MS=3e4,INBOUND_RULES=/* @__PURE__ */Object.freeze({"pet.profile.updated":{subject:"pet",schemaVersions:[1,2]},"pet.incident.reported":{subject:"pet",schemaVersions:[1]},"pet.behavior_note.added":{subject:"pet",schemaVersions:[1]},"pet.service_score.recorded":{subject:"pet",schemaVersions:[1]},"pet.deleted":{subject:"pet",schemaVersions:[1]},"member.status_changed":{subject:"member",schemaVersions:[1]},"member.deleted":{subject:"member",schemaVersions:[1]}});async function sendPartnerEvent(client,event,idempotencyKey){let key=idempotencyKey??randomUUID();if(typeof key!="string"||!IDEMPOTENCY_KEY_SHAPE.test(key))throw new EverfurConfigError("invalid-argument","idempotencyKey must be 1 to 255 visible ASCII characters (no spaces, no control or non-ASCII characters)");assertServerSecretKey(client.partnerSecretKey,"sending events");let payload=serialize(buildBody(event)),fetchImpl=client.fetchImpl??getGlobalFetch(),url=`${resolveApiBaseUrl(client.apiBaseUrl)}/partners/events`,headers={...buildBaseHeaders({sdkVersion:SDK_VERSION,platform:SDK_PLATFORM,contractVersion:client.contractVersion??DEFAULT_CONTRACT_VERSION}),accept:"application/json","content-type":"application/json","idempotency-key":key,"x-everfur-partner-secret-key":client.partnerSecretKey},controller=new AbortController,timer=setTimeout(()=>controller.abort(),SEND_TIMEOUT_MS),res;try{res=await fetchImpl(url,{method:"POST",headers:headers,body:payload,signal:controller.signal})}catch(cause){return err(networkError(cause))}finally{clearTimeout(timer)}let json=null;try{json=await res.json()}catch{json=null}let requestId=requestIdOf(res);if(!res.ok)return err(errorFromResponse(res.status,json,requestId));let receipt=parseReceipt(json,key);return receipt?ok(receipt):err(errorFromResponse(502,{error:{code:"INTERNAL_ERROR"}},requestId))}function isInboundType(value){return typeof value=="string"&&PARTNER_INBOUND_EVENT_TYPES.includes(value)}function buildBody(event){if(typeof event!="object"||event===null)throw new EverfurConfigError("invalid-argument","event is required");if(!isInboundType(event.type))throw new EverfurConfigError("invalid-argument",`event.type must be one of ${PARTNER_INBOUND_EVENT_TYPES.join(", ")}`);let rule=INBOUND_RULES[event.type],schemaVersion=event.schemaVersion??1;if(typeof schemaVersion!="number"||!rule.schemaVersions.includes(schemaVersion))throw new EverfurConfigError("invalid-argument",`event.schemaVersion must be one of ${rule.schemaVersions.join(", ")} for ${event.type}`);let userRef=assertValidUserRef(event.userRef);if(rule.subject==="pet"&&event.petRef===void 0)throw new EverfurConfigError("invalid-argument",`event.petRef is required for ${event.type}`);if(rule.subject==="member"&&event.petRef!==void 0)throw new EverfurConfigError("invalid-argument",`event.petRef is not accepted on ${event.type}`);let petRef=event.petRef===void 0?void 0:assertValidPetRef(event.petRef);if(typeof event.data!="object"||event.data===null||Array.isArray(event.data))throw new EverfurConfigError("invalid-argument","event.data must be an object");let data=event.type==="pet.profile.updated"&&schemaVersion===2?partnerPetProfileBody(event.data):event.data,body={type:event.type,schema_version:schemaVersion,user_ref:userRef,occurred_at:occurredAtIso(event.occurredAt),data:data};return petRef!==void 0&&(body.pet_ref=petRef),body}function assertValidPetRef(raw){try{return assertValidUserRef(raw)}catch(cause){throw cause instanceof EverfurConfigError?new EverfurConfigError("invalid-argument",`event.petRef follows the user_ref rule: ${cause.message}`):cause}}function occurredAtIso(value){if(typeof value=="string"&&!DATE_TIME_WITH_OFFSET.test(value))throw new EverfurConfigError("invalid-argument","event.occurredAt must be a Date or an ISO 8601 date-time with an explicit offset (Z or +05:30)");let date2=value instanceof Date?value:typeof value=="string"?new Date(value):new Date(Number.NaN);if(Number.isNaN(date2.getTime()))throw new EverfurConfigError("invalid-argument","event.occurredAt must be a Date or an ISO 8601 date-time with an explicit offset (Z or +05:30)");return date2.toISOString()}function serialize(body){let payload;try{payload=JSON.stringify(body)}catch{throw new EverfurConfigError("invalid-argument","event.data must be JSON-serialisable")}let bytes=(new TextEncoder).encode(payload).byteLength;if(bytes>MAX_BODY_BYTES)throw new EverfurConfigError("invalid-argument",`the event is ${bytes} bytes once serialised; Everfur accepts at most ${MAX_BODY_BYTES} (32 KB)`);return payload}function parseReceipt(json,idempotencyKey){if(typeof json!="object"||json===null)return null;let obj=json,id=obj.id,type=obj.type,schemaVersion=obj.schema_version,userRef=obj.user_ref,petRef=obj.pet_ref??null,occurredAt=obj.occurred_at,receivedAt=obj.received_at,status=obj.status,livemode=obj.livemode;return typeof id!="string"||id.length===0||!isInboundType(type)||typeof schemaVersion!="number"||typeof userRef!="string"||petRef!==null&&typeof petRef!="string"||typeof occurredAt!="string"||typeof receivedAt!="string"||typeof status!="string"||typeof livemode!="boolean"?null:/* @__PURE__ */Object.freeze({id:id,type:type,schemaVersion:schemaVersion,userRef:userRef,petRef:petRef,occurredAt:occurredAt,receivedAt:receivedAt,status:status,livemode:livemode,idempotencyKey:idempotencyKey})}export{DEFAULT_WEBHOOK_TOLERANCE_SECONDS,EVERFUR_SIGNATURE_HEADER,EVERFUR_WEBHOOK_EVENT_TYPES,EVERFUR_WEBHOOK_ONLY_EVENT_TYPES,EverfurWebhookVerificationError,PARTNER_INBOUND_EVENT_TYPES,constructEvent,generateTestSignatureHeader,isEverfurWebhookEvent,isEverfurWebhookEventType,sendPartnerEvent};
|