diff --git a/docs/api/_report.md b/docs/api/_report.md index 327adc94..750449c8 100644 --- a/docs/api/_report.md +++ b/docs/api/_report.md @@ -7,7 +7,6 @@ - `/access_codes` - `/access_codes/simulate` - `/access_codes/unmanaged` -- `/action_attempts` - `/bridges` - `/client_sessions` - `/connect_webviews` diff --git a/docs/api/action_attempts/README.md b/docs/api/action_attempts/README.md new file mode 100644 index 00000000..c711012e --- /dev/null +++ b/docs/api/action_attempts/README.md @@ -0,0 +1,293 @@ +# Action Attempts + +## `action_attempt` + +Represents an attempt to perform an action against a device. + +### `action_attempt_id` + +Format: `UUID` + +ID of the action attempt. + +--- + +### `status` + +Format: `Enum` + +Possible enum values: +- `success` +- `pending` +- `error` + +--- + +### `action_type` + +Format: `String` + +Type of the action attempt. + +Possible enum values: +- `LOCK_DOOR` +- `UNLOCK_DOOR` +- `SCAN_CREDENTIAL` +- `ENCODE_ACCESS_METHOD` +- `ENCODE_CREDENTIAL` +- `RESET_SANDBOX_WORKSPACE` +- `SET_FAN_MODE` +- `SET_HVAC_MODE` +- `ACTIVATE_CLIMATE_PRESET` +- `SIMULATE_KEYPAD_CODE_ENTRY` +- `SIMULATE_MANUAL_LOCK_VIA_KEYPAD` +- `PUSH_THERMOSTAT_PROGRAMS` +- `SYNC_ACCESS_CODES` +- `CREATE_ACCESS_CODE` +- `DELETE_ACCESS_CODE` +- `UPDATE_ACCESS_CODE` +- `CREATE_NOISE_THRESHOLD` +- `DELETE_NOISE_THRESHOLD` +- `UPDATE_NOISE_THRESHOLD` + +--- + +### `error` + +Format: `Object` + +Errors associated with the action attempt. Null for pending action attempts. + +--- + +### `result` + +Format: `Object` + +Result of the action attempt. Null for pending action attempts. + +--- + +## Endpoints + + +--- + +## Events + +### `action_attempt.lock_door.succeeded` + +A lock door [action attempt](../../core-concepts/action-attempts.md) succeeded. + +
+ +action_attempt_id Format: UUID + +ID of the [action attempt](../../core-concepts/action-attempts.md). +
+
+ +action_type Format: String + +Type of action. +
+
+ +created_at Format: Datetime + +Date and time at which the event was created. +
+
+ +event_id Format: UUID + +ID of the event. +
+
+ +event_type Format: Enum + +Value: `action_attempt.lock_door.succeeded` +
+
+ +occurred_at Format: Datetime + +Date and time at which the event occurred. +
+
+ +status Format: String + +Status of the action. +
+
+ +workspace_id Format: UUID + +ID of the [workspace](../../core-concepts/workspaces/README.md). +
+--- + +### `action_attempt.lock_door.failed` + +A lock door [action attempt](../../core-concepts/action-attempts.md) failed. + +
+ +action_attempt_id Format: UUID + +ID of the [action attempt](../../core-concepts/action-attempts.md). +
+
+ +action_type Format: String + +Type of action. +
+
+ +created_at Format: Datetime + +Date and time at which the event was created. +
+
+ +event_id Format: UUID + +ID of the event. +
+
+ +event_type Format: Enum + +Value: `action_attempt.lock_door.failed` +
+
+ +occurred_at Format: Datetime + +Date and time at which the event occurred. +
+
+ +status Format: String + +Status of the action. +
+
+ +workspace_id Format: UUID + +ID of the [workspace](../../core-concepts/workspaces/README.md). +
+--- + +### `action_attempt.unlock_door.succeeded` + +An unlock door [action attempt](../../core-concepts/action-attempts.md) succeeded. + +
+ +action_attempt_id Format: UUID + +ID of the [action attempt](../../core-concepts/action-attempts.md). +
+
+ +action_type Format: String + +Type of action. +
+
+ +created_at Format: Datetime + +Date and time at which the event was created. +
+
+ +event_id Format: UUID + +ID of the event. +
+
+ +event_type Format: Enum + +Value: `action_attempt.unlock_door.succeeded` +
+
+ +occurred_at Format: Datetime + +Date and time at which the event occurred. +
+
+ +status Format: String + +Status of the action. +
+
+ +workspace_id Format: UUID + +ID of the [workspace](../../core-concepts/workspaces/README.md). +
+--- + +### `action_attempt.unlock_door.failed` + +An unlock door [action attempt](../../core-concepts/action-attempts.md) failed. + +
+ +action_attempt_id Format: UUID + +ID of the [action attempt](../../core-concepts/action-attempts.md). +
+
+ +action_type Format: String + +Type of action. +
+
+ +created_at Format: Datetime + +Date and time at which the event was created. +
+
+ +event_id Format: UUID + +ID of the event. +
+
+ +event_type Format: Enum + +Value: `action_attempt.unlock_door.failed` +
+
+ +occurred_at Format: Datetime + +Date and time at which the event occurred. +
+
+ +status Format: String + +Status of the action. +
+
+ +workspace_id Format: UUID + +ID of the [workspace](../../core-concepts/workspaces/README.md). +
+--- + diff --git a/src/data/paths.yaml b/src/data/paths.yaml index 4b9238aa..99af5a94 100644 --- a/src/data/paths.yaml +++ b/src/data/paths.yaml @@ -80,3 +80,8 @@ title: Enrollment Automations resources: - enrollment_automation + +/action_attempts: + title: Action Attempts + resources: + - action_attempt diff --git a/src/lib/layout/action-attempt-resource.ts b/src/lib/layout/action-attempt-resource.ts new file mode 100644 index 00000000..dfcca3ff --- /dev/null +++ b/src/lib/layout/action-attempt-resource.ts @@ -0,0 +1,93 @@ +import type { Blueprint } from '@seamapi/blueprint' + +import { + type ApiError, + type ApiRouteEvent, + type ApiRouteProperty, + type ApiRouteResource, + type ApiWarning, + mapBlueprintPropertyToRouteProperty, + type ResourceSampleContext, +} from './api-route.js' + +export function processActionAttemptResource( + blueprint: Blueprint, + resources: Array< + ApiRouteResource & { + warnings: ApiWarning[] + errors: ApiError[] + resourceSamples: ResourceSampleContext[] + } + >, + eventsByRoutePath: Map, +): void { + const blueprintActionAttemptDef = blueprint.actionAttempts[0] + if (blueprintActionAttemptDef == null) { + throw new Error( + 'Cannot process action attempt resource: blueprint.actionAttempts is empty.', + ) + } + + const idPropKey = 'action_attempt_id' + const idPropDef = blueprintActionAttemptDef.properties.find( + (p) => p.name === idPropKey, + ) + if (idPropDef == null) { + throw new Error( + `Blueprint action attempt is missing "${idPropKey}" property.`, + ) + } + + const statusPropKey = 'status' + const statusPropDef = blueprintActionAttemptDef.properties.find( + (p) => p.name === statusPropKey, + ) + if (statusPropDef == null) { + throw new Error( + `Blueprint action attempt is missing "${statusPropKey}" property.`, + ) + } + + const actionTypes = blueprint.actionAttempts.map( + (attempt) => attempt.actionAttemptType, + ) + + const properties: ApiRouteProperty[] = [ + mapBlueprintPropertyToRouteProperty(idPropDef), + mapBlueprintPropertyToRouteProperty(statusPropDef), + { + name: 'action_type', + description: 'Type of the action attempt.', + format: 'String', + isDeprecated: false, + deprecationMessage: '', + enumValues: actionTypes, + }, + { + name: 'error', + description: + 'Errors associated with the action attempt. Null for pending action attempts.', + format: 'Object', + isDeprecated: false, + deprecationMessage: '', + }, + { + name: 'result', + description: + 'Result of the action attempt. Null for pending action attempts.', + format: 'Object', + isDeprecated: false, + deprecationMessage: '', + }, + ] + + resources.push({ + name: 'action_attempt', + description: 'Represents an attempt to perform an action against a device.', + properties, + errors: [], + warnings: [], + events: eventsByRoutePath.get('/action_attempts') ?? [], + resourceSamples: [], + }) +} diff --git a/src/lib/layout/api-route.ts b/src/lib/layout/api-route.ts index fd51d64c..f4b836dd 100644 --- a/src/lib/layout/api-route.ts +++ b/src/lib/layout/api-route.ts @@ -15,6 +15,8 @@ import type { ResourceSample } from 'node_modules/@seamapi/blueprint/lib/samples import type { PathMetadata } from 'lib/path-metadata.js' +import { processActionAttemptResource } from './action-attempt-resource.js' + export interface ApiRouteLayoutContext { title: string description: string @@ -30,19 +32,19 @@ export interface ApiRouteLayoutContext { events: ApiRouteEvent[] } -interface ApiRouteEvent { +export interface ApiRouteEvent { name: string description: string properties: ApiRouteProperty[] } -interface ResourceSampleContext { +export interface ResourceSampleContext { title: string resourceData: string resourceDataSyntax: SyntaxName } -type ApiRouteProperty = Pick< +export type ApiRouteProperty = Pick< Property, 'name' | 'description' | 'isDeprecated' | 'deprecationMessage' > & { @@ -68,11 +70,12 @@ export interface ApiRouteResource { events: ApiRouteEvent[] } -interface ApiWarning { +export interface ApiWarning { name: string description: string } -interface ApiError { + +export interface ApiError { name: string description: string } @@ -108,6 +111,11 @@ export function setApiRouteLayoutContext( file.resources = [] for (const resourceType of metadata.resources) { + if (resourceType === 'action_attempt') { + processActionAttemptResource(blueprint, file.resources, eventsByRoutePath) + continue + } + const resource = blueprint.resources[resourceType] if (resource == null) { @@ -150,8 +158,6 @@ const groupEventsByRoutePath = ( const eventsByRoutePath = new Map() for (const event of events) { - if (event.routePath == null) continue - const routeEvents = eventsByRoutePath.get(event.routePath) ?? [] routeEvents.push({ name: event.eventType, diff --git a/src/lib/reference.ts b/src/lib/reference.ts index adae39a5..4cae12d1 100644 --- a/src/lib/reference.ts +++ b/src/lib/reference.ts @@ -57,7 +57,8 @@ export const reference = ( !route.path.startsWith('/acs') && !route.path.startsWith('/thermostats') && !route.path.startsWith('/phones') && - !route.path.startsWith('/user_identities') + !route.path.startsWith('/user_identities') && + !route.path.startsWith('/action_attempts') ) { continue }