import {z} from 'zod' export type GetApiV1SubscribeEventsOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const eventId = z.string(); export const eventModelKey = z.literal("event"); export const deviceId = z.string(); export const ringEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("ring"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const sensorValue = z.number(); export const sensorStatus = z.enum(["neutral", "low", "safe", "high", "unknown"]); export const sensorExtremeValueEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorExtremeValues"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({sensorType: z.object({text: z.enum(["temperature", "light", "humidity", "aqi", "vape", "tvoc", "pm1p0", "pm2p5", "pm4p0", "pm10p0", "co2", "voc"])}), sensorValue: z.object({text: sensorValue}), status: z.object({text: sensorStatus})})}); export const sensorMountType = z.enum(["door", "window", "garage", "leak", "none"]); export const sensorWaterLeakEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorWaterLeak"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({sensorMountType: z.object({text: sensorMountType})})}); export const sensorTamperEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorTamper"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const sensorBatteryLowEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorBatteryLow"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({sensorBatteryPercentage: z.object({number: z.number()})})}); export const sensorAlarmEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorAlarm"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({alarmType: z.object({text: z.enum(["smoke", "CO", "glassBreak", "sensorButtonPress", "tamper", "short", "cut"])})})}); export const sensorVapeEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorVape"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const sensorOpenEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorOpened"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({sensorMountType: z.object({text: sensorMountType})})}); export const sensorClosedEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorClosed"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({sensorMountType: z.object({text: sensorMountType})})}); export const sensorSmokeTestEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorSmokeTest"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({source: z.enum(["remote", "local"]).optional()})}); export const sensorSmokeBatteryLowEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorSmokeBatteryLow"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const sensorSmokeNeedsCleaningEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorSmokeNeedsCleaning"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const sensorSmokeFaultEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorSmokeFault"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const sensorCoFaultEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorCoFault"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const sensorSmokeEndOfLifeEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorSmokeEndOfLife"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const sensorMotionEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorMotion"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const sensorButtonPressedEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("sensorButtonPressed"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({button: z.object({text: z.enum(["function", "alarmHubButton", "arm", "disarm", "night", "panic", "left", "right", "input1", "input2"])})})}); export const lightMotionEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("lightMotion"), start: z.number().gt(0), device: deviceId}); export const cameraMotionEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("motion"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const cameraSmartDetectAudioEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("smartAudioDetect"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, smartDetectTypes: z.array(z.enum(["alrmSmoke", "alrmCmonx", "alrmSiren", "alrmBabyCry", "alrmSpeak", "alrmBark", "alrmBurglar", "alrmCarHorn", "alrmGlassBreak"])).nullable()}); export const cameraSmartDetectZoneEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("smartDetectZone"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, smartDetectTypes: z.array(z.enum(["person", "vehicle", "package", "licensePlate", "face", "animal"])).nullable()}); export const cameraSmartDetectLineEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("smartDetectLine"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, smartDetectTypes: z.array(z.enum(["person", "vehicle", "package", "licensePlate", "face", "animal"])).nullable()}); export const cameraSmartDetectLoiterEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("smartDetectLoiterZone"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, smartDetectTypes: z.array(z.enum(["person", "vehicle", "package", "licensePlate", "face", "animal"])).nullable()}); export const relayInputChangedEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("relayInputChanged"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({inputState: z.object({text: z.enum(["circuitClosed", "circuitOpen"])}), inputChannel: z.object({text: z.string()})})}); export const alarmHubMotionEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubMotion"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({pin: z.object({text: z.string()}), status: z.object({text: z.string()}), deviceId: z.object({text: z.string()}), deviceName: z.object({text: z.string()})}).optional()}); export const alarmHubEntryOpenedEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubEntryOpened"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({pin: z.object({text: z.string()}), status: z.object({text: z.string()}), deviceId: z.object({text: z.string()}), deviceName: z.object({text: z.string()})}).optional()}); export const alarmHubEntryClosedEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubEntryClosed"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({pin: z.object({text: z.string()}), status: z.object({text: z.string()}), deviceId: z.object({text: z.string()}), deviceName: z.object({text: z.string()})}).optional()}); export const alarmHubSmokeEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubSmoke"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({pin: z.object({text: z.string()}), status: z.object({text: z.string()}), alarmType: z.object({text: z.enum(["smoke", "CO", "glassBreak", "sensorButtonPress", "tamper", "short", "cut"])}), deviceId: z.object({text: z.string()}), deviceName: z.object({text: z.string()})}).optional()}); export const alarmHubGlassBreakEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubGlassBreak"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({pin: z.object({text: z.string()}), status: z.object({text: z.string()}), alarmType: z.object({text: z.enum(["smoke", "CO", "glassBreak", "sensorButtonPress", "tamper", "short", "cut"])}), deviceId: z.object({text: z.string()}), deviceName: z.object({text: z.string()})}).optional()}); export const alarmHubButtonPressEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubButtonPress"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({pin: z.object({text: z.string()}), status: z.object({text: z.string()}), button: z.object({text: z.enum(["function", "alarmHubButton", "arm", "disarm", "night", "panic", "left", "right", "input1", "input2"])}), alarmType: z.object({text: z.enum(["smoke", "CO", "glassBreak", "sensorButtonPress", "tamper", "short", "cut"])}), deviceId: z.object({text: z.string()}), deviceName: z.object({text: z.string()})}).optional()}); export const alarmHubTamperEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubTamper"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: z.object({pin: z.object({text: z.string()}), status: z.object({text: z.string()}), alarmType: z.object({text: z.enum(["smoke", "CO", "glassBreak", "sensorButtonPress", "tamper", "short", "cut"])}), deviceId: z.object({text: z.string()}), deviceName: z.object({text: z.string()})}).optional()}); export const alarmHubRelaySwitchedEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubRelaySwitched"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const alarmHubBatteryLowEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubBatteryLow"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const alarmHubBatteryConnectedEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("alarmHubBatteryConnected"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId}); export const nfcMetadata = z.object({nfc: z.object({ulpId: z.string().nullable()})}); export const nfcCardScannedEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("nfcCardScanned"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: nfcMetadata}); export const fingerprintMetadata = z.object({fingerprint: z.object({ulpId: z.string().nullable()})}); export const fingerprintIdentifiedEvent = z.object({id: eventId, modelKey: eventModelKey, type: z.literal("fingerprintIdentified"), start: z.number().gt(0), end: z.number().nullable().optional(), device: deviceId, metadata: fingerprintMetadata}); export const event = z.discriminatedUnion("type", [ringEvent, sensorExtremeValueEvent, sensorWaterLeakEvent, sensorTamperEvent, sensorBatteryLowEvent, sensorAlarmEvent, sensorVapeEvent, sensorOpenEvent, sensorClosedEvent, sensorSmokeTestEvent, sensorSmokeBatteryLowEvent, sensorSmokeNeedsCleaningEvent, sensorSmokeFaultEvent, sensorCoFaultEvent, sensorSmokeEndOfLifeEvent, sensorMotionEvent, sensorButtonPressedEvent, lightMotionEvent, cameraMotionEvent, cameraSmartDetectAudioEvent, cameraSmartDetectZoneEvent, cameraSmartDetectLineEvent, cameraSmartDetectLoiterEvent, relayInputChangedEvent, alarmHubMotionEvent, alarmHubEntryOpenedEvent, alarmHubEntryClosedEvent, alarmHubSmokeEvent, alarmHubGlassBreakEvent, alarmHubButtonPressEvent, alarmHubTamperEvent, alarmHubRelaySwitchedEvent, alarmHubBatteryLowEvent, alarmHubBatteryConnectedEvent, nfcCardScannedEvent, fingerprintIdentifiedEvent]); export const eventAdd = z.object({type: z.literal("add"), item: event}); export const eventUpdate = z.object({type: z.literal("update"), item: event}); export const getApiV1SubscribeEventsResponse = z.discriminatedUnion("type", [eventAdd, eventUpdate]); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Get Protect event messages * * GET /v1/subscribe/events */ export const getApiV1SubscribeEvents = async (options?: GetApiV1SubscribeEventsOptions) => { const {baseUrl = "https://api.ui.com/v1/connector/consoles/942A6FF664C0000000000964970E0000000009E710560000000068A9873F:9999999999/proxy/protect/integration", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/v1/subscribe/events${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(getApiV1SubscribeEventsResponse, await res.json()) };