diff --git a/README.md b/README.md index f48c39be..2abf4542 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,31 @@ succeeds and returns the finished attempt, raising var actionAttempt = await seam.Locks.UnlockDoorAsync(new() { DeviceId = deviceId }); ``` +Each action attempt deserializes to a subclass for its `action_type` and +`status` pair, e.g. `ActionAttemptUnlockDoorSuccess`. The `Error` and `Result` +properties are declared only on the status subclass that populates them, so +pattern match on the subclass to read them: + +```csharp +var actionAttempt = await seam.Locks.UnlockDoorAsync( + new() { DeviceId = deviceId }, + waitForActionAttempt: false +); + +switch (actionAttempt) +{ + case ActionAttemptUnlockDoorSuccess success: + Console.WriteLine(success.Result.WasConfirmedByDevice); + break; + case ActionAttemptUnlockDoorError error: + Console.WriteLine(error.Error.Message); + break; + case ActionAttemptUnlockDoorPending: + Console.WriteLine("Still pending"); + break; +} +``` + Configure or disable waiting per client or per call with `ActionAttemptWait`: ```csharp diff --git a/codegen/layouts/partials/oneof-union.hbs b/codegen/layouts/partials/oneof-union.hbs index 07c0ba98..c0688ca3 100644 --- a/codegen/layouts/partials/oneof-union.hbs +++ b/codegen/layouts/partials/oneof-union.hbs @@ -1,13 +1,16 @@ +{{> documentation}} [JsonConverter(typeof(SeamUnionConverter))] [SeamUnion("{{discriminatorSnake}}")] {{#each knownSubTypes}} [SeamUnionVariant("{{value}}", typeof({{typeName}}))] {{/each}} [SeamUnionFallback(typeof({{unrecognizedTypeName}}))] -public abstract record {{className}} +public abstract record {{className}}{{#if baseClass}} : {{baseClass}}{{/if}} { +{{#unless inheritsDiscriminator}} /// The value of the {{discriminatorSnake}} discriminator. public abstract string {{discriminatorPascal}} { get; } +{{/unless}} {{#each baseProps}} {{> data-member this}} @@ -15,5 +18,9 @@ public abstract string {{discriminatorPascal}} { get; } } {{#each subclasses}} +{{#if (eq kind "union")}} +{{> oneof-union this}} +{{else}} {{> model-class this}} +{{/if}} {{/each}} diff --git a/codegen/lib/build-model.ts b/codegen/lib/build-model.ts index 48cc65d1..38a0410f 100644 --- a/codegen/lib/build-model.ts +++ b/codegen/lib/build-model.ts @@ -21,7 +21,9 @@ import type { ActionAttempt, + ActionAttemptStatus, Endpoint, + EnumProperty, EventResource, Parameter, Property, @@ -99,6 +101,7 @@ interface Variant { fields: Field[] description?: string deprecationMessage?: string + buildAsUnion?: (subName: string, omitNames: Set) => CsUnion } const normalizeEnumValues = ( @@ -306,7 +309,12 @@ interface BuildClassOptions { resourceType: 'response' | 'request' | 'model' // When set, the class is a discriminated-union subclass: the discriminator // property is emitted as a get-only override with a constant value. - discriminator?: { name: string; value: string; base: string } + discriminator?: { + name: string + value: string + base: string + declareProperty?: boolean + } // Field names declared concretely on the union base; omitted from subclasses. omitNames?: Set | undefined documentation?: string @@ -430,7 +438,7 @@ const buildClass = ( if (omitNames?.has(field.name) ?? false) continue properties.push(mapField(field)) } - if (discriminator != null) { + if (discriminator != null && (discriminator.declareProperty ?? true)) { properties.unshift({ pascalName: pascalCase(discriminator.name), snakeName: snakeCase(discriminator.name), @@ -459,9 +467,14 @@ interface BuildUnionOptions { resourceType: 'response' | 'request' | 'model' // Field names removed from every variant in favor of `extraBaseProps` // declared on the base with a shared type, e.g. the action attempt - // status/error contract the runtime resolver depends on. + // status contract the runtime resolver depends on. omitFieldNames?: string[] extraBaseProps?: CsProperty[] + baseClass?: string + inheritsDiscriminator?: boolean + leadingBaseProps?: CsProperty[] + documentation?: string + obsoleteMessage?: string } const buildUnion = ( @@ -470,7 +483,16 @@ const buildUnion = ( variants: Variant[], options: BuildUnionOptions, ): CsUnion => { - const { resourceType, omitFieldNames = [], extraBaseProps = [] } = options + const { + resourceType, + omitFieldNames = [], + extraBaseProps = [], + baseClass, + inheritsDiscriminator, + leadingBaseProps = [], + documentation, + obsoleteMessage, + } = options const omitted = new Set(omitFieldNames) // Lift properties shared by every variant onto the base so consumers can @@ -507,6 +529,7 @@ const buildUnion = ( ]) const baseProps: CsProperty[] = [ + ...leadingBaseProps, ...liftedFields.map((field): CsProperty => { const type = primType(field) as string return { @@ -528,17 +551,25 @@ const buildUnion = ( ...extraBaseProps, ] - const subclasses: CsClass[] = [] + const subclasses: Array = [] const known: Array<[string, string]> = [] for (const variant of variants) { const subName = pascalCase(className + pascalCase(variant.value)) + if (variant.buildAsUnion != null) { + subclasses.push( + variant.buildAsUnion(subName, new Set([...omitNames, discriminator])), + ) + known.push([subName, variant.value]) + continue + } const built = buildClass(subName, variant.fields, { resourceType, discriminator: { name: discriminator, value: variant.value, base: className, + ...(inheritsDiscriminator ? { declareProperty: false } : {}), }, omitNames, ...(variant.description != null @@ -559,6 +590,7 @@ const buildUnion = ( name: discriminator, value: 'unrecognized', base: className, + ...(inheritsDiscriminator ? { declareProperty: false } : {}), }, }) subclasses.push({ ...fallback.main, isUnrecognizedFallback: true }) @@ -568,12 +600,16 @@ const buildUnion = ( return { kind: 'union', className, + ...(baseClass != null ? { baseClass } : {}), discriminatorSnake: discriminator, discriminatorPascal: pascalCase(discriminator), + ...(inheritsDiscriminator ? { inheritsDiscriminator } : {}), knownSubTypes, unrecognizedTypeName, baseProps, subclasses, + ...(documentation != null ? { documentation } : {}), + ...(obsoleteMessage != null ? { obsoleteMessage } : {}), } } @@ -591,29 +627,109 @@ export const buildModelFile = ( return { name, file: { decls: [built.main, ...built.siblings] } } } +const actionAttemptRuntimeTypes: Record = { + error: 'ActionAttemptError', +} + +const normalizeActionAttemptField = (property: Property): Field => { + const runtimeType = actionAttemptRuntimeTypes[property.name] + const field = normalizeProperty(property) + if (runtimeType == null) return field + return { ...field, kind: { t: 'ref', cs: runtimeType } } +} + +const findActionAttemptStatusProperty = ( + actionAttempt: ActionAttempt, +): EnumProperty | undefined => + actionAttempt.properties.find( + (property): property is EnumProperty => + property.name === 'status' && property.format === 'enum', + ) + +const buildActionAttemptStatusUnion = ( + actionAttempt: ActionAttempt, + statusProperty: EnumProperty, + subName: string, + omitNames: Set, +): CsUnion => + buildUnion( + subName, + statusProperty.name, + statusProperty.values.map(({ name }) => { + const status = name as ActionAttemptStatus + return { + value: status, + fields: actionAttempt.properties.flatMap((property) => { + if (property === statusProperty || omitNames.has(property.name)) { + return [] + } + const statuses = property.actionAttemptStatuses + if (statuses != null && !statuses.includes(status)) return [] + return [normalizeActionAttemptField(property)] + }), + } + }), + { + resourceType: 'model', + baseClass: 'ActionAttempt', + inheritsDiscriminator: true, + leadingBaseProps: [ + { + pascalName: 'ActionType', + snakeName: 'action_type', + type: 'string', + isRequired: false, + isOverride: true, + getOnly: true, + initializer: `"${actionAttempt.actionAttemptType}"`, + }, + ], + documentation: actionAttempt.description, + ...(actionAttempt.isDeprecated + ? { + obsoleteMessage: actionAttempt.deprecationMessage || 'Deprecated.', + } + : {}), + }, + ) + export const buildActionAttemptFile = ( actionAttempts: ActionAttempt[], ): { name: string; file: CsModelFile } => { - // The status and error of every action attempt share one wire shape, so they - // are declared once on the base with the runtime-owned ActionAttemptStatus - // and ActionAttemptError types the action attempt resolver depends on. + // The status of every action attempt shares one wire shape, so it is + // declared once on the base with the runtime-owned ActionAttemptStatus type + // the action attempt resolver depends on. const union = buildUnion( 'ActionAttempt', 'action_type', - actionAttempts.map((actionAttempt) => ({ - value: actionAttempt.actionAttemptType, - fields: actionAttempt.properties.map(normalizeProperty), - description: actionAttempt.description, - ...(actionAttempt.isDeprecated - ? { - deprecationMessage: - actionAttempt.deprecationMessage || 'Deprecated.', - } - : {}), - })), + actionAttempts.map((actionAttempt) => { + const statusProperty = findActionAttemptStatusProperty(actionAttempt) + return { + value: actionAttempt.actionAttemptType, + fields: actionAttempt.properties.map(normalizeActionAttemptField), + description: actionAttempt.description, + ...(actionAttempt.isDeprecated + ? { + deprecationMessage: + actionAttempt.deprecationMessage || 'Deprecated.', + } + : {}), + ...(statusProperty == null + ? {} + : { + buildAsUnion: (subName: string, omitNames: Set) => + buildActionAttemptStatusUnion( + actionAttempt, + statusProperty, + subName, + omitNames, + ), + }), + } + }), { resourceType: 'model', - omitFieldNames: ['status', 'error'], + omitFieldNames: ['status'], extraBaseProps: [ { pascalName: 'Status', @@ -624,15 +740,6 @@ export const buildActionAttemptFile = ( getOnly: false, documentation: 'The status of the action attempt.', }, - { - pascalName: 'Error', - snakeName: 'error', - type: 'ActionAttemptError?', - isRequired: false, - isOverride: false, - getOnly: false, - documentation: 'The error of a failed action attempt, or null.', - }, ], }, ) diff --git a/codegen/lib/class-model.ts b/codegen/lib/class-model.ts index 4beaa522..ec4fe195 100644 --- a/codegen/lib/class-model.ts +++ b/codegen/lib/class-model.ts @@ -70,8 +70,10 @@ export interface CsClass { export interface CsUnion { kind: 'union' className: string + baseClass?: string discriminatorSnake: string discriminatorPascal: string + inheritsDiscriminator?: boolean // [SeamUnionVariant] attributes, in variant definition order. knownSubTypes: Array<{ typeName: string; value: string }> unrecognizedTypeName: string @@ -81,7 +83,9 @@ export interface CsUnion { baseProps: CsProperty[] // Concrete subclasses followed by the Unrecognized fallback, in definition // order. - subclasses: CsClass[] + subclasses: Array + documentation?: string + obsoleteMessage?: string } export type CsDecl = CsClass | CsUnion diff --git a/package-lock.json b/package-lock.json index b9818987..5eec64b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "2.0.0-beta.4", "license": "MIT", "devDependencies": { - "@seamapi/blueprint": "^1.8.0", + "@seamapi/blueprint": "^1.10.0", "@seamapi/fake-seam-connect": "2.0.5", "@seamapi/smith": "^1.1.0", "@seamapi/types": "1.1034.0", @@ -789,9 +789,9 @@ "license": "MIT" }, "node_modules/@seamapi/blueprint": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@seamapi/blueprint/-/blueprint-1.8.0.tgz", - "integrity": "sha512-NUghBmYaKreBeBxwPIB2O9hjIFZtEjVj73tAsuKdJR8t4BxlKK1I0XDQXxo3ZsH2QezNlbdo9/0MoX/33VXuhQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@seamapi/blueprint/-/blueprint-1.10.0.tgz", + "integrity": "sha512-XyP6zvbhv5naWEa9T9utNLi3FVVmvUB1Htih/IjUqS3Uz0FrIIBWy7Myk5+s4uylEt+wTdtSBaA1fGOF/6ILmA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 562e67ac..1ce5344d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ }, "packageManager": "npm@11.19.0", "devDependencies": { - "@seamapi/blueprint": "^1.8.0", + "@seamapi/blueprint": "^1.10.0", "@seamapi/fake-seam-connect": "2.0.5", "@seamapi/smith": "^1.1.0", "@seamapi/types": "1.1034.0", diff --git a/src/Seam/Exceptions/SeamActionAttemptException.cs b/src/Seam/Exceptions/SeamActionAttemptException.cs index 0c164e2b..9003be21 100644 --- a/src/Seam/Exceptions/SeamActionAttemptException.cs +++ b/src/Seam/Exceptions/SeamActionAttemptException.cs @@ -22,13 +22,17 @@ protected SeamActionAttemptException(string message, Models.ActionAttempt action public class SeamActionAttemptFailedException : SeamActionAttemptException { public SeamActionAttemptFailedException(Models.ActionAttempt actionAttempt) - : base(actionAttempt.Error?.Message ?? "Action attempt failed", actionAttempt) + : base(GetError(actionAttempt)?.Message ?? "Action attempt failed", actionAttempt) { - Code = actionAttempt.Error?.Type ?? "unknown_error"; + Code = GetError(actionAttempt)?.Type ?? "unknown_error"; } /// The action attempt error type. public string Code { get; } + + private static Models.ActionAttemptError? GetError(Models.ActionAttempt actionAttempt) => + actionAttempt.GetType().GetProperty("Error")?.GetValue(actionAttempt) + as Models.ActionAttemptError; } /// diff --git a/src/Seam/Models/ActionAttempt.cs b/src/Seam/Models/ActionAttempt.cs index 0a7bbca2..04dc951c 100644 --- a/src/Seam/Models/ActionAttempt.cs +++ b/src/Seam/Models/ActionAttempt.cs @@ -52,30 +52,33 @@ public abstract record ActionAttempt /// [JsonPropertyName("status")] public ActionAttemptStatus Status { get; init; } - - /// - /// The error of a failed action attempt, or null. - /// - [JsonPropertyName("error")] - public ActionAttemptError? Error { get; init; } } /// /// Locking a door is pending. /// - public sealed record ActionAttemptLockDoor : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptLockDoorSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptLockDoorPending))] + [SeamUnionVariant("error", typeof(ActionAttemptLockDoorError))] + [SeamUnionFallback(typeof(ActionAttemptLockDoorUnrecognized))] + public abstract record ActionAttemptLockDoor : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "LOCK_DOOR"; + } + public sealed record ActionAttemptLockDoorSuccess : ActionAttemptLockDoor + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptLockDoorResult Result { get; init; } = default!; + public ActionAttemptLockDoorSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptLockDoorResult + public sealed record ActionAttemptLockDoorSuccessResult { /// /// Indicates whether the device confirmed that the lock action occurred. @@ -84,22 +87,51 @@ public sealed record ActionAttemptLockDoorResult public bool? WasConfirmedByDevice { get; init; } } + public sealed record ActionAttemptLockDoorPending : ActionAttemptLockDoor { } + + public sealed record ActionAttemptLockDoorError : ActionAttemptLockDoor + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptLockDoorUnrecognized + : ActionAttemptLockDoor, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + /// /// Unlocking a door is pending. /// - public sealed record ActionAttemptUnlockDoor : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptUnlockDoorSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptUnlockDoorPending))] + [SeamUnionVariant("error", typeof(ActionAttemptUnlockDoorError))] + [SeamUnionFallback(typeof(ActionAttemptUnlockDoorUnrecognized))] + public abstract record ActionAttemptUnlockDoor : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "UNLOCK_DOOR"; + } + public sealed record ActionAttemptUnlockDoorSuccess : ActionAttemptUnlockDoor + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptUnlockDoorResult Result { get; init; } = default!; + public ActionAttemptUnlockDoorSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptUnlockDoorResult + public sealed record ActionAttemptUnlockDoorSuccessResult { /// /// Indicates whether the device confirmed that the unlock action occurred. @@ -108,43 +140,73 @@ public sealed record ActionAttemptUnlockDoorResult public bool? WasConfirmedByDevice { get; init; } } + public sealed record ActionAttemptUnlockDoorPending : ActionAttemptUnlockDoor { } + + public sealed record ActionAttemptUnlockDoorError : ActionAttemptUnlockDoor + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptUnlockDoorUnrecognized + : ActionAttemptUnlockDoor, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + /// /// Reading credential data from the physical encoder is pending. /// - public sealed record ActionAttemptScanCredential : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptScanCredentialSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptScanCredentialPending))] + [SeamUnionVariant("error", typeof(ActionAttemptScanCredentialError))] + [SeamUnionFallback(typeof(ActionAttemptScanCredentialUnrecognized))] + public abstract record ActionAttemptScanCredential : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "SCAN_CREDENTIAL"; + } + public sealed record ActionAttemptScanCredentialSuccess : ActionAttemptScanCredential + { /// /// Result of scanning a card. If the attempt was successful, includes a snapshot of credential data read from the physical encoder, the corresponding data stored on Seam and the access system, and any associated warnings. /// [JsonPropertyName("result")] - public ActionAttemptScanCredentialResult Result { get; init; } = default!; + public ActionAttemptScanCredentialSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptScanCredentialResult + public sealed record ActionAttemptScanCredentialSuccessResult { /// /// Snapshot of credential data read from the physical encoder. /// [JsonPropertyName("acs_credential_on_encoder")] - public ActionAttemptScanCredentialResultAcsCredentialOnEncoder? AcsCredentialOnEncoder { get; init; } + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnEncoder? AcsCredentialOnEncoder { get; init; } /// /// Corresponding credential data as stored on Seam and the access system. /// [JsonPropertyName("acs_credential_on_seam")] - public ActionAttemptScanCredentialResultAcsCredentialOnSeam? AcsCredentialOnSeam { get; init; } + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeam? AcsCredentialOnSeam { get; init; } /// /// Warnings related to scanning the credential, such as mismatches between the credential data currently encoded on the card and the corresponding data stored on Seam and the access system. /// [JsonPropertyName("warnings")] - public List Warnings { get; init; } = default!; + public List Warnings { get; init; } = + default!; } - public sealed record ActionAttemptScanCredentialResultAcsCredentialOnEncoder + public sealed record ActionAttemptScanCredentialSuccessResultAcsCredentialOnEncoder { /// /// A number or string that physically identifies the card associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). @@ -180,10 +242,10 @@ public sealed record ActionAttemptScanCredentialResultAcsCredentialOnEncoder /// Visionline-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("visionline_metadata")] - public ActionAttemptScanCredentialResultAcsCredentialOnEncoderVisionlineMetadata? VisionlineMetadata { get; init; } + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnEncoderVisionlineMetadata? VisionlineMetadata { get; init; } } - public sealed record ActionAttemptScanCredentialResultAcsCredentialOnEncoderVisionlineMetadata + public sealed record ActionAttemptScanCredentialSuccessResultAcsCredentialOnEncoderVisionlineMetadata { /// /// Format of the card associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). @@ -211,7 +273,7 @@ public enum CardFormatEnum /// Format of the card associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("card_format")] - public ActionAttemptScanCredentialResultAcsCredentialOnEncoderVisionlineMetadata.CardFormatEnum? CardFormat { get; init; } + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnEncoderVisionlineMetadata.CardFormatEnum? CardFormat { get; init; } /// /// Holder of the card associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). @@ -274,7 +336,7 @@ public enum CardFormatEnum public bool? PendingAutoUpdate { get; init; } } - public sealed record ActionAttemptScanCredentialResultAcsCredentialOnSeam + public sealed record ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeam { /// /// Access method for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). Supported values: `code`, `card`, `mobile_key`, `cloud_key`. @@ -354,7 +416,7 @@ public enum ExternalTypeEnum /// Access method for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). Supported values: `code`, `card`, `mobile_key`, `cloud_key`. /// [JsonPropertyName("access_method")] - public ActionAttemptScanCredentialResultAcsCredentialOnSeam.AccessMethodEnum AccessMethod { get; init; } = + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeam.AccessMethodEnum AccessMethod { get; init; } = default!; /// @@ -385,13 +447,13 @@ public enum ExternalTypeEnum /// Akiles-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("akiles_metadata")] - public ActionAttemptScanCredentialResultAcsCredentialOnSeamAkilesMetadata? AkilesMetadata { get; init; } + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamAkilesMetadata? AkilesMetadata { get; init; } /// /// Vostio-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("assa_abloy_vostio_metadata")] - public ActionAttemptScanCredentialResultAcsCredentialOnSeamAssaAbloyVostioMetadata? AssaAbloyVostioMetadata { get; init; } + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamAssaAbloyVostioMetadata? AssaAbloyVostioMetadata { get; init; } /// /// Number of the card associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). @@ -433,14 +495,14 @@ public enum ExternalTypeEnum /// Errors associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("errors")] - public List Errors { get; init; } = + public List Errors { get; init; } = default!; /// /// Brand-specific terminology for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials) type. Supported values: `pti_card`, `brivo_credential`, `hid_credential`, `visionline_card`. /// [JsonPropertyName("external_type")] - public ActionAttemptScanCredentialResultAcsCredentialOnSeam.ExternalTypeEnum? ExternalType { get; init; } + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeam.ExternalTypeEnum? ExternalType { get; init; } /// /// Display name that corresponds to the brand-specific terminology for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials) type. @@ -509,13 +571,13 @@ public enum ExternalTypeEnum /// Visionline-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("visionline_metadata")] - public ActionAttemptScanCredentialResultAcsCredentialOnSeamVisionlineMetadata? VisionlineMetadata { get; init; } + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamVisionlineMetadata? VisionlineMetadata { get; init; } /// /// Warnings associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("warnings")] - public List Warnings { get; init; } = + public List Warnings { get; init; } = default!; /// @@ -525,7 +587,7 @@ public enum ExternalTypeEnum public string WorkspaceId { get; init; } = default!; } - public sealed record ActionAttemptScanCredentialResultAcsCredentialOnSeamAkilesMetadata + public sealed record ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamAkilesMetadata { /// /// ID of the Akiles member PIN. @@ -534,7 +596,7 @@ public sealed record ActionAttemptScanCredentialResultAcsCredentialOnSeamAkilesM public string? MemberPinId { get; init; } } - public sealed record ActionAttemptScanCredentialResultAcsCredentialOnSeamAssaAbloyVostioMetadata + public sealed record ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamAssaAbloyVostioMetadata { /// /// Indicates whether the credential should auto-join. For an auto-join credential, Seam automatically issues an override card if there are no other cards and a joiner card if there are existing cards on the doors. @@ -573,7 +635,7 @@ public sealed record ActionAttemptScanCredentialResultAcsCredentialOnSeamAssaAbl public List? OverrideGuestAcsEntranceIds { get; init; } } - public sealed record ActionAttemptScanCredentialResultAcsCredentialOnSeamErrors + public sealed record ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamErrors { /// /// Date and time at which Seam created the error. @@ -588,7 +650,7 @@ public sealed record ActionAttemptScanCredentialResultAcsCredentialOnSeamErrors public string Message { get; init; } = default!; } - public sealed record ActionAttemptScanCredentialResultAcsCredentialOnSeamVisionlineMetadata + public sealed record ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamVisionlineMetadata { /// /// Card function type in the Visionline access system. @@ -616,7 +678,7 @@ public enum CardFunctionTypeEnum /// Card function type in the Visionline access system. /// [JsonPropertyName("card_function_type")] - public ActionAttemptScanCredentialResultAcsCredentialOnSeamVisionlineMetadata.CardFunctionTypeEnum? CardFunctionType { get; init; } + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamVisionlineMetadata.CardFunctionTypeEnum? CardFunctionType { get; init; } /// /// ID of the card in the Visionline access system. @@ -655,7 +717,7 @@ public enum CardFunctionTypeEnum public List? JoinerAcsCredentialIds { get; init; } } - public sealed record ActionAttemptScanCredentialResultAcsCredentialOnSeamWarnings + public sealed record ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamWarnings { /// /// Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. @@ -704,7 +766,7 @@ public enum WarningCodeEnum /// Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. /// [JsonPropertyName("warning_code")] - public ActionAttemptScanCredentialResultAcsCredentialOnSeamWarnings.WarningCodeEnum WarningCode { get; init; } = + public ActionAttemptScanCredentialSuccessResultAcsCredentialOnSeamWarnings.WarningCodeEnum WarningCode { get; init; } = default!; /// @@ -720,7 +782,7 @@ public enum WarningCodeEnum public string? OriginalCode { get; init; } } - public sealed record ActionAttemptScanCredentialResultWarnings + public sealed record ActionAttemptScanCredentialSuccessResultWarnings { /// /// Indicates a warning related to scanning a credential. @@ -742,7 +804,7 @@ public enum WarningCodeEnum /// Indicates a warning related to scanning a credential. /// [JsonPropertyName("warning_code")] - public ActionAttemptScanCredentialResultWarnings.WarningCodeEnum WarningCode { get; init; } = + public ActionAttemptScanCredentialSuccessResultWarnings.WarningCodeEnum WarningCode { get; init; } = default!; /// @@ -752,22 +814,48 @@ public enum WarningCodeEnum public string WarningMessage { get; init; } = default!; } + public sealed record ActionAttemptScanCredentialPending : ActionAttemptScanCredential { } + + public sealed record ActionAttemptScanCredentialError : ActionAttemptScanCredential + { + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptScanCredentialUnrecognized + : ActionAttemptScanCredential, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + /// /// Encoding credential data from the physical encoder onto a card is pending. /// - public sealed record ActionAttemptEncodeCredential : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptEncodeCredentialSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptEncodeCredentialPending))] + [SeamUnionVariant("error", typeof(ActionAttemptEncodeCredentialError))] + [SeamUnionFallback(typeof(ActionAttemptEncodeCredentialUnrecognized))] + public abstract record ActionAttemptEncodeCredential : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "ENCODE_CREDENTIAL"; + } + public sealed record ActionAttemptEncodeCredentialSuccess : ActionAttemptEncodeCredential + { /// /// Result of an encoding attempt. If the attempt was successful, includes the credential data that was encoded onto the card. /// [JsonPropertyName("result")] - public ActionAttemptEncodeCredentialResult Result { get; init; } = default!; + public ActionAttemptEncodeCredentialSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptEncodeCredentialResult + public sealed record ActionAttemptEncodeCredentialSuccessResult { /// /// Access method for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). Supported values: `code`, `card`, `mobile_key`, `cloud_key`. @@ -847,7 +935,7 @@ public enum ExternalTypeEnum /// Access method for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). Supported values: `code`, `card`, `mobile_key`, `cloud_key`. /// [JsonPropertyName("access_method")] - public ActionAttemptEncodeCredentialResult.AccessMethodEnum AccessMethod { get; init; } = + public ActionAttemptEncodeCredentialSuccessResult.AccessMethodEnum AccessMethod { get; init; } = default!; /// @@ -878,13 +966,13 @@ public enum ExternalTypeEnum /// Akiles-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("akiles_metadata")] - public ActionAttemptEncodeCredentialResultAkilesMetadata? AkilesMetadata { get; init; } + public ActionAttemptEncodeCredentialSuccessResultAkilesMetadata? AkilesMetadata { get; init; } /// /// Vostio-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("assa_abloy_vostio_metadata")] - public ActionAttemptEncodeCredentialResultAssaAbloyVostioMetadata? AssaAbloyVostioMetadata { get; init; } + public ActionAttemptEncodeCredentialSuccessResultAssaAbloyVostioMetadata? AssaAbloyVostioMetadata { get; init; } /// /// Number of the card associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). @@ -926,13 +1014,14 @@ public enum ExternalTypeEnum /// Errors associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("errors")] - public List Errors { get; init; } = default!; + public List Errors { get; init; } = + default!; /// /// Brand-specific terminology for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials) type. Supported values: `pti_card`, `brivo_credential`, `hid_credential`, `visionline_card`. /// [JsonPropertyName("external_type")] - public ActionAttemptEncodeCredentialResult.ExternalTypeEnum? ExternalType { get; init; } + public ActionAttemptEncodeCredentialSuccessResult.ExternalTypeEnum? ExternalType { get; init; } /// /// Display name that corresponds to the brand-specific terminology for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials) type. @@ -1001,13 +1090,14 @@ public enum ExternalTypeEnum /// Visionline-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("visionline_metadata")] - public ActionAttemptEncodeCredentialResultVisionlineMetadata? VisionlineMetadata { get; init; } + public ActionAttemptEncodeCredentialSuccessResultVisionlineMetadata? VisionlineMetadata { get; init; } /// /// Warnings associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("warnings")] - public List Warnings { get; init; } = default!; + public List Warnings { get; init; } = + default!; /// /// ID of the workspace that contains the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). @@ -1016,7 +1106,7 @@ public enum ExternalTypeEnum public string WorkspaceId { get; init; } = default!; } - public sealed record ActionAttemptEncodeCredentialResultAkilesMetadata + public sealed record ActionAttemptEncodeCredentialSuccessResultAkilesMetadata { /// /// ID of the Akiles member PIN. @@ -1025,7 +1115,7 @@ public sealed record ActionAttemptEncodeCredentialResultAkilesMetadata public string? MemberPinId { get; init; } } - public sealed record ActionAttemptEncodeCredentialResultAssaAbloyVostioMetadata + public sealed record ActionAttemptEncodeCredentialSuccessResultAssaAbloyVostioMetadata { /// /// Indicates whether the credential should auto-join. For an auto-join credential, Seam automatically issues an override card if there are no other cards and a joiner card if there are existing cards on the doors. @@ -1064,7 +1154,7 @@ public sealed record ActionAttemptEncodeCredentialResultAssaAbloyVostioMetadata public List? OverrideGuestAcsEntranceIds { get; init; } } - public sealed record ActionAttemptEncodeCredentialResultErrors + public sealed record ActionAttemptEncodeCredentialSuccessResultErrors { /// /// Date and time at which Seam created the error. @@ -1079,7 +1169,7 @@ public sealed record ActionAttemptEncodeCredentialResultErrors public string Message { get; init; } = default!; } - public sealed record ActionAttemptEncodeCredentialResultVisionlineMetadata + public sealed record ActionAttemptEncodeCredentialSuccessResultVisionlineMetadata { /// /// Card function type in the Visionline access system. @@ -1107,7 +1197,7 @@ public enum CardFunctionTypeEnum /// Card function type in the Visionline access system. /// [JsonPropertyName("card_function_type")] - public ActionAttemptEncodeCredentialResultVisionlineMetadata.CardFunctionTypeEnum? CardFunctionType { get; init; } + public ActionAttemptEncodeCredentialSuccessResultVisionlineMetadata.CardFunctionTypeEnum? CardFunctionType { get; init; } /// /// ID of the card in the Visionline access system. @@ -1146,7 +1236,7 @@ public enum CardFunctionTypeEnum public List? JoinerAcsCredentialIds { get; init; } } - public sealed record ActionAttemptEncodeCredentialResultWarnings + public sealed record ActionAttemptEncodeCredentialSuccessResultWarnings { /// /// Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. @@ -1195,7 +1285,7 @@ public enum WarningCodeEnum /// Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. /// [JsonPropertyName("warning_code")] - public ActionAttemptEncodeCredentialResultWarnings.WarningCodeEnum WarningCode { get; init; } = + public ActionAttemptEncodeCredentialSuccessResultWarnings.WarningCodeEnum WarningCode { get; init; } = default!; /// @@ -1211,22 +1301,49 @@ public enum WarningCodeEnum public string? OriginalCode { get; init; } } + public sealed record ActionAttemptEncodeCredentialPending : ActionAttemptEncodeCredential { } + + public sealed record ActionAttemptEncodeCredentialError : ActionAttemptEncodeCredential + { + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptEncodeCredentialUnrecognized + : ActionAttemptEncodeCredential, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + /// /// Scanning a physical card and assigning the credential is pending. /// - public sealed record ActionAttemptScanToAssignCredential : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptScanToAssignCredentialSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptScanToAssignCredentialPending))] + [SeamUnionVariant("error", typeof(ActionAttemptScanToAssignCredentialError))] + [SeamUnionFallback(typeof(ActionAttemptScanToAssignCredentialUnrecognized))] + public abstract record ActionAttemptScanToAssignCredential : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "SCAN_TO_ASSIGN_CREDENTIAL"; + } + public sealed record ActionAttemptScanToAssignCredentialSuccess + : ActionAttemptScanToAssignCredential + { /// /// Result of a scan to assign attempt. If the attempt was successful, includes the credential data that was scanned and assigned. /// [JsonPropertyName("result")] - public ActionAttemptScanToAssignCredentialResult Result { get; init; } = default!; + public ActionAttemptScanToAssignCredentialSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptScanToAssignCredentialResult + public sealed record ActionAttemptScanToAssignCredentialSuccessResult { /// /// Access method for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). Supported values: `code`, `card`, `mobile_key`, `cloud_key`. @@ -1306,7 +1423,7 @@ public enum ExternalTypeEnum /// Access method for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). Supported values: `code`, `card`, `mobile_key`, `cloud_key`. /// [JsonPropertyName("access_method")] - public ActionAttemptScanToAssignCredentialResult.AccessMethodEnum AccessMethod { get; init; } = + public ActionAttemptScanToAssignCredentialSuccessResult.AccessMethodEnum AccessMethod { get; init; } = default!; /// @@ -1337,13 +1454,13 @@ public enum ExternalTypeEnum /// Akiles-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("akiles_metadata")] - public ActionAttemptScanToAssignCredentialResultAkilesMetadata? AkilesMetadata { get; init; } + public ActionAttemptScanToAssignCredentialSuccessResultAkilesMetadata? AkilesMetadata { get; init; } /// /// Vostio-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("assa_abloy_vostio_metadata")] - public ActionAttemptScanToAssignCredentialResultAssaAbloyVostioMetadata? AssaAbloyVostioMetadata { get; init; } + public ActionAttemptScanToAssignCredentialSuccessResultAssaAbloyVostioMetadata? AssaAbloyVostioMetadata { get; init; } /// /// Number of the card associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). @@ -1385,14 +1502,14 @@ public enum ExternalTypeEnum /// Errors associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("errors")] - public List Errors { get; init; } = + public List Errors { get; init; } = default!; /// /// Brand-specific terminology for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials) type. Supported values: `pti_card`, `brivo_credential`, `hid_credential`, `visionline_card`. /// [JsonPropertyName("external_type")] - public ActionAttemptScanToAssignCredentialResult.ExternalTypeEnum? ExternalType { get; init; } + public ActionAttemptScanToAssignCredentialSuccessResult.ExternalTypeEnum? ExternalType { get; init; } /// /// Display name that corresponds to the brand-specific terminology for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials) type. @@ -1464,13 +1581,13 @@ public enum ExternalTypeEnum /// Visionline-specific metadata for the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("visionline_metadata")] - public ActionAttemptScanToAssignCredentialResultVisionlineMetadata? VisionlineMetadata { get; init; } + public ActionAttemptScanToAssignCredentialSuccessResultVisionlineMetadata? VisionlineMetadata { get; init; } /// /// Warnings associated with the [credential](https://docs.seam.co/low-level-apis/access-systems/managing-credentials). /// [JsonPropertyName("warnings")] - public List Warnings { get; init; } = + public List Warnings { get; init; } = default!; /// @@ -1480,7 +1597,7 @@ public enum ExternalTypeEnum public string WorkspaceId { get; init; } = default!; } - public sealed record ActionAttemptScanToAssignCredentialResultAkilesMetadata + public sealed record ActionAttemptScanToAssignCredentialSuccessResultAkilesMetadata { /// /// ID of the Akiles member PIN. @@ -1489,7 +1606,7 @@ public sealed record ActionAttemptScanToAssignCredentialResultAkilesMetadata public string? MemberPinId { get; init; } } - public sealed record ActionAttemptScanToAssignCredentialResultAssaAbloyVostioMetadata + public sealed record ActionAttemptScanToAssignCredentialSuccessResultAssaAbloyVostioMetadata { /// /// Indicates whether the credential should auto-join. For an auto-join credential, Seam automatically issues an override card if there are no other cards and a joiner card if there are existing cards on the doors. @@ -1528,7 +1645,7 @@ public sealed record ActionAttemptScanToAssignCredentialResultAssaAbloyVostioMet public List? OverrideGuestAcsEntranceIds { get; init; } } - public sealed record ActionAttemptScanToAssignCredentialResultErrors + public sealed record ActionAttemptScanToAssignCredentialSuccessResultErrors { /// /// Date and time at which Seam created the error. @@ -1543,7 +1660,7 @@ public sealed record ActionAttemptScanToAssignCredentialResultErrors public string Message { get; init; } = default!; } - public sealed record ActionAttemptScanToAssignCredentialResultVisionlineMetadata + public sealed record ActionAttemptScanToAssignCredentialSuccessResultVisionlineMetadata { /// /// Card function type in the Visionline access system. @@ -1571,7 +1688,7 @@ public enum CardFunctionTypeEnum /// Card function type in the Visionline access system. /// [JsonPropertyName("card_function_type")] - public ActionAttemptScanToAssignCredentialResultVisionlineMetadata.CardFunctionTypeEnum? CardFunctionType { get; init; } + public ActionAttemptScanToAssignCredentialSuccessResultVisionlineMetadata.CardFunctionTypeEnum? CardFunctionType { get; init; } /// /// ID of the card in the Visionline access system. @@ -1610,7 +1727,7 @@ public enum CardFunctionTypeEnum public List? JoinerAcsCredentialIds { get; init; } } - public sealed record ActionAttemptScanToAssignCredentialResultWarnings + public sealed record ActionAttemptScanToAssignCredentialSuccessResultWarnings { /// /// Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. @@ -1659,7 +1776,7 @@ public enum WarningCodeEnum /// Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. /// [JsonPropertyName("warning_code")] - public ActionAttemptScanToAssignCredentialResultWarnings.WarningCodeEnum WarningCode { get; init; } = + public ActionAttemptScanToAssignCredentialSuccessResultWarnings.WarningCodeEnum WarningCode { get; init; } = default!; /// @@ -1675,22 +1792,50 @@ public enum WarningCodeEnum public string? OriginalCode { get; init; } } + public sealed record ActionAttemptScanToAssignCredentialPending + : ActionAttemptScanToAssignCredential { } + + public sealed record ActionAttemptScanToAssignCredentialError + : ActionAttemptScanToAssignCredential + { + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptScanToAssignCredentialUnrecognized + : ActionAttemptScanToAssignCredential, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + /// /// Assigning a credential to an access method is pending. /// - public sealed record ActionAttemptAssignCredential : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptAssignCredentialSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptAssignCredentialPending))] + [SeamUnionVariant("error", typeof(ActionAttemptAssignCredentialError))] + [SeamUnionFallback(typeof(ActionAttemptAssignCredentialUnrecognized))] + public abstract record ActionAttemptAssignCredential : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "ASSIGN_CREDENTIAL"; + } + public sealed record ActionAttemptAssignCredentialSuccess : ActionAttemptAssignCredential + { /// /// Result of assigning a credential. If successful, includes the updated access method with the assigned credential. /// [JsonPropertyName("result")] - public ActionAttemptAssignCredentialResult Result { get; init; } = default!; + public ActionAttemptAssignCredentialSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptAssignCredentialResult + public sealed record ActionAttemptAssignCredentialSuccessResult { /// /// Access method mode. Supported values: `code`, `card`, `mobile_key`, `cloud_key`. @@ -1760,7 +1905,8 @@ public enum ModeEnum /// Errors associated with the [access method](https://docs.seam.co/use-cases/granting-access/creating-an-access-grant). /// [JsonPropertyName("errors")] - public List Errors { get; init; } = default!; + public List Errors { get; init; } = + default!; /// /// URL of the Instant Key for mobile key access methods. @@ -1808,20 +1954,21 @@ public enum ModeEnum /// Access method mode. Supported values: `code`, `card`, `mobile_key`, `cloud_key`. /// [JsonPropertyName("mode")] - public ActionAttemptAssignCredentialResult.ModeEnum Mode { get; init; } = default!; + public ActionAttemptAssignCredentialSuccessResult.ModeEnum Mode { get; init; } = default!; /// /// Pending mutations for the [access method](https://docs.seam.co/use-cases/granting-access/creating-an-access-grant). Indicates operations that are in progress. /// [JsonPropertyName("pending_mutations")] - public List PendingMutations { get; init; } = + public List PendingMutations { get; init; } = default!; /// /// Warnings associated with the [access method](https://docs.seam.co/use-cases/granting-access/creating-an-access-grant). /// [JsonPropertyName("warnings")] - public List Warnings { get; init; } = default!; + public List Warnings { get; init; } = + default!; /// /// ID of the Seam workspace associated with the access method. @@ -1830,7 +1977,7 @@ public enum ModeEnum public string WorkspaceId { get; init; } = default!; } - public sealed record ActionAttemptAssignCredentialResultErrors + public sealed record ActionAttemptAssignCredentialSuccessResultErrors { /// /// Unique identifier of the type of error. Enables quick recognition and categorization of the issue. @@ -1855,7 +2002,7 @@ public enum ErrorCodeEnum /// Unique identifier of the type of error. Enables quick recognition and categorization of the issue. /// [JsonPropertyName("error_code")] - public ActionAttemptAssignCredentialResultErrors.ErrorCodeEnum ErrorCode { get; init; } = + public ActionAttemptAssignCredentialSuccessResultErrors.ErrorCodeEnum ErrorCode { get; init; } = default!; /// @@ -1865,7 +2012,7 @@ public enum ErrorCodeEnum public string Message { get; init; } = default!; } - public sealed record ActionAttemptAssignCredentialResultPendingMutations + public sealed record ActionAttemptAssignCredentialSuccessResultPendingMutations { /// /// Mutation code to indicate that Seam is in the process of updating the access times for this access method. @@ -1896,7 +2043,7 @@ public enum MutationCodeEnum /// Previous access time configuration. /// [JsonPropertyName("from")] - public ActionAttemptAssignCredentialResultPendingMutationsFrom From { get; init; } = + public ActionAttemptAssignCredentialSuccessResultPendingMutationsFrom From { get; init; } = default!; /// @@ -1909,17 +2056,18 @@ public enum MutationCodeEnum /// Mutation code to indicate that Seam is in the process of updating the access times for this access method. /// [JsonPropertyName("mutation_code")] - public ActionAttemptAssignCredentialResultPendingMutations.MutationCodeEnum MutationCode { get; init; } = + public ActionAttemptAssignCredentialSuccessResultPendingMutations.MutationCodeEnum MutationCode { get; init; } = default!; /// /// New access time configuration. /// [JsonPropertyName("to")] - public ActionAttemptAssignCredentialResultPendingMutationsTo To { get; init; } = default!; + public ActionAttemptAssignCredentialSuccessResultPendingMutationsTo To { get; init; } = + default!; } - public sealed record ActionAttemptAssignCredentialResultPendingMutationsFrom + public sealed record ActionAttemptAssignCredentialSuccessResultPendingMutationsFrom { /// /// Previous end time for access. @@ -1934,7 +2082,7 @@ public sealed record ActionAttemptAssignCredentialResultPendingMutationsFrom public string? StartsAt { get; init; } } - public sealed record ActionAttemptAssignCredentialResultPendingMutationsTo + public sealed record ActionAttemptAssignCredentialSuccessResultPendingMutationsTo { /// /// New end time for access. @@ -1949,7 +2097,7 @@ public sealed record ActionAttemptAssignCredentialResultPendingMutationsTo public string? StartsAt { get; init; } } - public sealed record ActionAttemptAssignCredentialResultWarnings + public sealed record ActionAttemptAssignCredentialSuccessResultWarnings { /// /// Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. @@ -1989,7 +2137,7 @@ public enum WarningCodeEnum /// Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. /// [JsonPropertyName("warning_code")] - public ActionAttemptAssignCredentialResultWarnings.WarningCodeEnum WarningCode { get; init; } = + public ActionAttemptAssignCredentialSuccessResultWarnings.WarningCodeEnum WarningCode { get; init; } = default!; /// @@ -1999,169 +2147,472 @@ public enum WarningCodeEnum public string? OriginalAccessMethodId { get; init; } } + public sealed record ActionAttemptAssignCredentialPending : ActionAttemptAssignCredential { } + + public sealed record ActionAttemptAssignCredentialError : ActionAttemptAssignCredential + { + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptAssignCredentialUnrecognized + : ActionAttemptAssignCredential, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + /// /// Resetting a sandbox workspace is pending. /// - public sealed record ActionAttemptResetSandboxWorkspace : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptResetSandboxWorkspaceSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptResetSandboxWorkspacePending))] + [SeamUnionVariant("error", typeof(ActionAttemptResetSandboxWorkspaceError))] + [SeamUnionFallback(typeof(ActionAttemptResetSandboxWorkspaceUnrecognized))] + public abstract record ActionAttemptResetSandboxWorkspace : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "RESET_SANDBOX_WORKSPACE"; + } + public sealed record ActionAttemptResetSandboxWorkspaceSuccess + : ActionAttemptResetSandboxWorkspace + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptResetSandboxWorkspaceResult Result { get; init; } = default!; + public ActionAttemptResetSandboxWorkspaceSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptResetSandboxWorkspaceResult { } + public sealed record ActionAttemptResetSandboxWorkspaceSuccessResult { } + + public sealed record ActionAttemptResetSandboxWorkspacePending + : ActionAttemptResetSandboxWorkspace { } + + public sealed record ActionAttemptResetSandboxWorkspaceError + : ActionAttemptResetSandboxWorkspace + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptResetSandboxWorkspaceUnrecognized + : ActionAttemptResetSandboxWorkspace, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } /// /// Setting the fan mode is pending. /// - public sealed record ActionAttemptSetFanMode : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptSetFanModeSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptSetFanModePending))] + [SeamUnionVariant("error", typeof(ActionAttemptSetFanModeError))] + [SeamUnionFallback(typeof(ActionAttemptSetFanModeUnrecognized))] + public abstract record ActionAttemptSetFanMode : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "SET_FAN_MODE"; + } + public sealed record ActionAttemptSetFanModeSuccess : ActionAttemptSetFanMode + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptSetFanModeResult Result { get; init; } = default!; + public ActionAttemptSetFanModeSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptSetFanModeResult { } + public sealed record ActionAttemptSetFanModeSuccessResult { } + + public sealed record ActionAttemptSetFanModePending : ActionAttemptSetFanMode { } + + public sealed record ActionAttemptSetFanModeError : ActionAttemptSetFanMode + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptSetFanModeUnrecognized + : ActionAttemptSetFanMode, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } /// /// Setting the HVAC mode is pending. /// - public sealed record ActionAttemptSetHvacMode : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptSetHvacModeSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptSetHvacModePending))] + [SeamUnionVariant("error", typeof(ActionAttemptSetHvacModeError))] + [SeamUnionFallback(typeof(ActionAttemptSetHvacModeUnrecognized))] + public abstract record ActionAttemptSetHvacMode : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "SET_HVAC_MODE"; + } + public sealed record ActionAttemptSetHvacModeSuccess : ActionAttemptSetHvacMode + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptSetHvacModeResult Result { get; init; } = default!; + public ActionAttemptSetHvacModeSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptSetHvacModeResult { } + public sealed record ActionAttemptSetHvacModeSuccessResult { } + + public sealed record ActionAttemptSetHvacModePending : ActionAttemptSetHvacMode { } + + public sealed record ActionAttemptSetHvacModeError : ActionAttemptSetHvacMode + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptSetHvacModeUnrecognized + : ActionAttemptSetHvacMode, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } /// /// Activating a climate preset is pending. /// - public sealed record ActionAttemptActivateClimatePreset : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptActivateClimatePresetSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptActivateClimatePresetPending))] + [SeamUnionVariant("error", typeof(ActionAttemptActivateClimatePresetError))] + [SeamUnionFallback(typeof(ActionAttemptActivateClimatePresetUnrecognized))] + public abstract record ActionAttemptActivateClimatePreset : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "ACTIVATE_CLIMATE_PRESET"; + } + public sealed record ActionAttemptActivateClimatePresetSuccess + : ActionAttemptActivateClimatePreset + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptActivateClimatePresetResult Result { get; init; } = default!; + public ActionAttemptActivateClimatePresetSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptActivateClimatePresetResult { } + public sealed record ActionAttemptActivateClimatePresetSuccessResult { } + + public sealed record ActionAttemptActivateClimatePresetPending + : ActionAttemptActivateClimatePreset { } + + public sealed record ActionAttemptActivateClimatePresetError + : ActionAttemptActivateClimatePreset + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptActivateClimatePresetUnrecognized + : ActionAttemptActivateClimatePreset, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } /// /// Simulating a keypad code entry is pending. /// - public sealed record ActionAttemptSimulateKeypadCodeEntry : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptSimulateKeypadCodeEntrySuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptSimulateKeypadCodeEntryPending))] + [SeamUnionVariant("error", typeof(ActionAttemptSimulateKeypadCodeEntryError))] + [SeamUnionFallback(typeof(ActionAttemptSimulateKeypadCodeEntryUnrecognized))] + public abstract record ActionAttemptSimulateKeypadCodeEntry : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "SIMULATE_KEYPAD_CODE_ENTRY"; + } + public sealed record ActionAttemptSimulateKeypadCodeEntrySuccess + : ActionAttemptSimulateKeypadCodeEntry + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptSimulateKeypadCodeEntryResult Result { get; init; } = default!; + public ActionAttemptSimulateKeypadCodeEntrySuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptSimulateKeypadCodeEntryResult { } + public sealed record ActionAttemptSimulateKeypadCodeEntrySuccessResult { } + + public sealed record ActionAttemptSimulateKeypadCodeEntryPending + : ActionAttemptSimulateKeypadCodeEntry { } + + public sealed record ActionAttemptSimulateKeypadCodeEntryError + : ActionAttemptSimulateKeypadCodeEntry + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptSimulateKeypadCodeEntryUnrecognized + : ActionAttemptSimulateKeypadCodeEntry, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } /// /// Simulating a manual lock action using a keypad is pending. /// - public sealed record ActionAttemptSimulateManualLockViaKeypad : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptSimulateManualLockViaKeypadSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptSimulateManualLockViaKeypadPending))] + [SeamUnionVariant("error", typeof(ActionAttemptSimulateManualLockViaKeypadError))] + [SeamUnionFallback(typeof(ActionAttemptSimulateManualLockViaKeypadUnrecognized))] + public abstract record ActionAttemptSimulateManualLockViaKeypad : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "SIMULATE_MANUAL_LOCK_VIA_KEYPAD"; + } + public sealed record ActionAttemptSimulateManualLockViaKeypadSuccess + : ActionAttemptSimulateManualLockViaKeypad + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptSimulateManualLockViaKeypadResult Result { get; init; } = default!; + public ActionAttemptSimulateManualLockViaKeypadSuccessResult Result { get; init; } = + default!; } - public sealed record ActionAttemptSimulateManualLockViaKeypadResult { } + public sealed record ActionAttemptSimulateManualLockViaKeypadSuccessResult { } + + public sealed record ActionAttemptSimulateManualLockViaKeypadPending + : ActionAttemptSimulateManualLockViaKeypad { } + + public sealed record ActionAttemptSimulateManualLockViaKeypadError + : ActionAttemptSimulateManualLockViaKeypad + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptSimulateManualLockViaKeypadUnrecognized + : ActionAttemptSimulateManualLockViaKeypad, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } /// /// Pushing thermostat weekly programs is pending. /// - public sealed record ActionAttemptPushThermostatPrograms : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptPushThermostatProgramsSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptPushThermostatProgramsPending))] + [SeamUnionVariant("error", typeof(ActionAttemptPushThermostatProgramsError))] + [SeamUnionFallback(typeof(ActionAttemptPushThermostatProgramsUnrecognized))] + public abstract record ActionAttemptPushThermostatPrograms : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "PUSH_THERMOSTAT_PROGRAMS"; + } + public sealed record ActionAttemptPushThermostatProgramsSuccess + : ActionAttemptPushThermostatPrograms + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptPushThermostatProgramsResult Result { get; init; } = default!; + public ActionAttemptPushThermostatProgramsSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptPushThermostatProgramsResult { } + public sealed record ActionAttemptPushThermostatProgramsSuccessResult { } + + public sealed record ActionAttemptPushThermostatProgramsPending + : ActionAttemptPushThermostatPrograms { } + + public sealed record ActionAttemptPushThermostatProgramsError + : ActionAttemptPushThermostatPrograms + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptPushThermostatProgramsUnrecognized + : ActionAttemptPushThermostatPrograms, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } /// /// Configuring the auto-lock is pending. /// - public sealed record ActionAttemptConfigureAutoLock : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptConfigureAutoLockSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptConfigureAutoLockPending))] + [SeamUnionVariant("error", typeof(ActionAttemptConfigureAutoLockError))] + [SeamUnionFallback(typeof(ActionAttemptConfigureAutoLockUnrecognized))] + public abstract record ActionAttemptConfigureAutoLock : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "CONFIGURE_AUTO_LOCK"; + } + public sealed record ActionAttemptConfigureAutoLockSuccess : ActionAttemptConfigureAutoLock + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptConfigureAutoLockResult Result { get; init; } = default!; + public ActionAttemptConfigureAutoLockSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptConfigureAutoLockResult { } + public sealed record ActionAttemptConfigureAutoLockSuccessResult { } + + public sealed record ActionAttemptConfigureAutoLockPending : ActionAttemptConfigureAutoLock { } - public sealed record ActionAttemptSyncAccessCodes : ActionAttempt + public sealed record ActionAttemptConfigureAutoLockError : ActionAttemptConfigureAutoLock + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptConfigureAutoLockUnrecognized + : ActionAttemptConfigureAutoLock, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptSyncAccessCodesSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptSyncAccessCodesPending))] + [SeamUnionVariant("error", typeof(ActionAttemptSyncAccessCodesError))] + [SeamUnionFallback(typeof(ActionAttemptSyncAccessCodesUnrecognized))] + public abstract record ActionAttemptSyncAccessCodes : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "SYNC_ACCESS_CODES"; + } + public sealed record ActionAttemptSyncAccessCodesSuccess : ActionAttemptSyncAccessCodes + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptSyncAccessCodesResult Result { get; init; } = default!; + public ActionAttemptSyncAccessCodesSuccessResult Result { get; init; } = default!; + } + + public sealed record ActionAttemptSyncAccessCodesSuccessResult { } + + public sealed record ActionAttemptSyncAccessCodesPending : ActionAttemptSyncAccessCodes { } + + public sealed record ActionAttemptSyncAccessCodesError : ActionAttemptSyncAccessCodes + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; } - public sealed record ActionAttemptSyncAccessCodesResult { } + public sealed record ActionAttemptSyncAccessCodesUnrecognized + : ActionAttemptSyncAccessCodes, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } - public sealed record ActionAttemptCreateAccessCode : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptCreateAccessCodeSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptCreateAccessCodePending))] + [SeamUnionVariant("error", typeof(ActionAttemptCreateAccessCodeError))] + [SeamUnionFallback(typeof(ActionAttemptCreateAccessCodeUnrecognized))] + public abstract record ActionAttemptCreateAccessCode : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "CREATE_ACCESS_CODE"; + } + public sealed record ActionAttemptCreateAccessCodeSuccess : ActionAttemptCreateAccessCode + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptCreateAccessCodeResult Result { get; init; } = default!; + public ActionAttemptCreateAccessCodeSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptCreateAccessCodeResult + public sealed record ActionAttemptCreateAccessCodeSuccessResult { /// /// Created access code. @@ -2170,33 +2621,91 @@ public sealed record ActionAttemptCreateAccessCodeResult public object AccessCode { get; init; } = default!; } - public sealed record ActionAttemptDeleteAccessCode : ActionAttempt + public sealed record ActionAttemptCreateAccessCodePending : ActionAttemptCreateAccessCode { } + + public sealed record ActionAttemptCreateAccessCodeError : ActionAttemptCreateAccessCode + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptCreateAccessCodeUnrecognized + : ActionAttemptCreateAccessCode, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptDeleteAccessCodeSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptDeleteAccessCodePending))] + [SeamUnionVariant("error", typeof(ActionAttemptDeleteAccessCodeError))] + [SeamUnionFallback(typeof(ActionAttemptDeleteAccessCodeUnrecognized))] + public abstract record ActionAttemptDeleteAccessCode : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "DELETE_ACCESS_CODE"; + } + public sealed record ActionAttemptDeleteAccessCodeSuccess : ActionAttemptDeleteAccessCode + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptDeleteAccessCodeResult Result { get; init; } = default!; + public ActionAttemptDeleteAccessCodeSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptDeleteAccessCodeResult { } + public sealed record ActionAttemptDeleteAccessCodeSuccessResult { } + + public sealed record ActionAttemptDeleteAccessCodePending : ActionAttemptDeleteAccessCode { } - public sealed record ActionAttemptUpdateAccessCode : ActionAttempt + public sealed record ActionAttemptDeleteAccessCodeError : ActionAttemptDeleteAccessCode + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptDeleteAccessCodeUnrecognized + : ActionAttemptDeleteAccessCode, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptUpdateAccessCodeSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptUpdateAccessCodePending))] + [SeamUnionVariant("error", typeof(ActionAttemptUpdateAccessCodeError))] + [SeamUnionFallback(typeof(ActionAttemptUpdateAccessCodeUnrecognized))] + public abstract record ActionAttemptUpdateAccessCode : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "UPDATE_ACCESS_CODE"; + } + public sealed record ActionAttemptUpdateAccessCodeSuccess : ActionAttemptUpdateAccessCode + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptUpdateAccessCodeResult Result { get; init; } = default!; + public ActionAttemptUpdateAccessCodeSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptUpdateAccessCodeResult + public sealed record ActionAttemptUpdateAccessCodeSuccessResult { /// /// Updated access code. @@ -2205,19 +2714,49 @@ public sealed record ActionAttemptUpdateAccessCodeResult public object? AccessCode { get; init; } } - public sealed record ActionAttemptCreateNoiseThreshold : ActionAttempt + public sealed record ActionAttemptUpdateAccessCodePending : ActionAttemptUpdateAccessCode { } + + public sealed record ActionAttemptUpdateAccessCodeError : ActionAttemptUpdateAccessCode + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptUpdateAccessCodeUnrecognized + : ActionAttemptUpdateAccessCode, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptCreateNoiseThresholdSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptCreateNoiseThresholdPending))] + [SeamUnionVariant("error", typeof(ActionAttemptCreateNoiseThresholdError))] + [SeamUnionFallback(typeof(ActionAttemptCreateNoiseThresholdUnrecognized))] + public abstract record ActionAttemptCreateNoiseThreshold : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "CREATE_NOISE_THRESHOLD"; + } + public sealed record ActionAttemptCreateNoiseThresholdSuccess + : ActionAttemptCreateNoiseThreshold + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptCreateNoiseThresholdResult Result { get; init; } = default!; + public ActionAttemptCreateNoiseThresholdSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptCreateNoiseThresholdResult + public sealed record ActionAttemptCreateNoiseThresholdSuccessResult { /// /// Created noise threshold. @@ -2226,33 +2765,95 @@ public sealed record ActionAttemptCreateNoiseThresholdResult public object NoiseThreshold { get; init; } = default!; } - public sealed record ActionAttemptDeleteNoiseThreshold : ActionAttempt + public sealed record ActionAttemptCreateNoiseThresholdPending + : ActionAttemptCreateNoiseThreshold { } + + public sealed record ActionAttemptCreateNoiseThresholdError : ActionAttemptCreateNoiseThreshold + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptCreateNoiseThresholdUnrecognized + : ActionAttemptCreateNoiseThreshold, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptDeleteNoiseThresholdSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptDeleteNoiseThresholdPending))] + [SeamUnionVariant("error", typeof(ActionAttemptDeleteNoiseThresholdError))] + [SeamUnionFallback(typeof(ActionAttemptDeleteNoiseThresholdUnrecognized))] + public abstract record ActionAttemptDeleteNoiseThreshold : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "DELETE_NOISE_THRESHOLD"; + } + public sealed record ActionAttemptDeleteNoiseThresholdSuccess + : ActionAttemptDeleteNoiseThreshold + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptDeleteNoiseThresholdResult Result { get; init; } = default!; + public ActionAttemptDeleteNoiseThresholdSuccessResult Result { get; init; } = default!; + } + + public sealed record ActionAttemptDeleteNoiseThresholdSuccessResult { } + + public sealed record ActionAttemptDeleteNoiseThresholdPending + : ActionAttemptDeleteNoiseThreshold { } + + public sealed record ActionAttemptDeleteNoiseThresholdError : ActionAttemptDeleteNoiseThreshold + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; } - public sealed record ActionAttemptDeleteNoiseThresholdResult { } + public sealed record ActionAttemptDeleteNoiseThresholdUnrecognized + : ActionAttemptDeleteNoiseThreshold, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } - public sealed record ActionAttemptUpdateNoiseThreshold : ActionAttempt + [JsonConverter(typeof(SeamUnionConverter))] + [SeamUnion("status")] + [SeamUnionVariant("success", typeof(ActionAttemptUpdateNoiseThresholdSuccess))] + [SeamUnionVariant("pending", typeof(ActionAttemptUpdateNoiseThresholdPending))] + [SeamUnionVariant("error", typeof(ActionAttemptUpdateNoiseThresholdError))] + [SeamUnionFallback(typeof(ActionAttemptUpdateNoiseThresholdUnrecognized))] + public abstract record ActionAttemptUpdateNoiseThreshold : ActionAttempt { [JsonPropertyName("action_type")] public override string ActionType { get; } = "UPDATE_NOISE_THRESHOLD"; + } + public sealed record ActionAttemptUpdateNoiseThresholdSuccess + : ActionAttemptUpdateNoiseThreshold + { /// /// Result of the action. /// [JsonPropertyName("result")] - public ActionAttemptUpdateNoiseThresholdResult Result { get; init; } = default!; + public ActionAttemptUpdateNoiseThresholdSuccessResult Result { get; init; } = default!; } - public sealed record ActionAttemptUpdateNoiseThresholdResult + public sealed record ActionAttemptUpdateNoiseThresholdSuccessResult { /// /// Updated noise threshold. @@ -2261,6 +2862,27 @@ public sealed record ActionAttemptUpdateNoiseThresholdResult public object NoiseThreshold { get; init; } = default!; } + public sealed record ActionAttemptUpdateNoiseThresholdPending + : ActionAttemptUpdateNoiseThreshold { } + + public sealed record ActionAttemptUpdateNoiseThresholdError : ActionAttemptUpdateNoiseThreshold + { + /// + /// Error associated with the action. + /// + [JsonPropertyName("error")] + public ActionAttemptError Error { get; init; } = default!; + } + + public sealed record ActionAttemptUpdateNoiseThresholdUnrecognized + : ActionAttemptUpdateNoiseThreshold, + ISeamUnrecognizedVariant + { + /// The complete raw JSON of the unrecognized payload. + [JsonIgnore] + public JsonElement RawJson { get; set; } + } + public sealed record ActionAttemptUnrecognized : ActionAttempt, ISeamUnrecognizedVariant { [JsonPropertyName("action_type")] diff --git a/src/Seam/Routes/AccessGrants.cs b/src/Seam/Routes/AccessGrants.cs index cda514b4..0317b73d 100644 --- a/src/Seam/Routes/AccessGrants.cs +++ b/src/Seam/Routes/AccessGrants.cs @@ -33,18 +33,6 @@ ActionAttemptWait waitForActionAttemptDefault /// public sealed record CreateRequest { - /// - /// ID of user identity for whom access is being granted. - /// - [JsonPropertyName("user_identity_id")] - public string? UserIdentityId { get; init; } - - /// - /// When used, creates a new user identity with the given details, and grants them access. - /// - [JsonPropertyName("user_identity")] - public CreateRequestUserIdentity? UserIdentity { get; init; } - /// /// Unique key for the access grant within the workspace. /// @@ -115,33 +103,18 @@ public sealed record CreateRequest /// [JsonPropertyName("starts_at")] public string? StartsAt { get; init; } - } - public sealed record CreateRequestUserIdentity - { /// - /// Unique email address for the user identity. - /// - [JsonPropertyName("email_address")] - public Optional EmailAddress { get; init; } - - /// - /// Full name of the user associated with the user identity. - /// - [JsonPropertyName("full_name")] - public Optional FullName { get; init; } - - /// - /// Unique phone number for the user identity in [E.164 format](https://www.itu.int/rec/T-REC-E.164/en) (for example, +15555550100). + /// When used, creates a new user identity with the given details, and grants them access. /// - [JsonPropertyName("phone_number")] - public Optional PhoneNumber { get; init; } + [JsonPropertyName("user_identity")] + public CreateRequestUserIdentity? UserIdentity { get; init; } /// - /// Unique key for the user identity. + /// ID of user identity for whom access is being granted. /// - [JsonPropertyName("user_identity_key")] - public Optional UserIdentityKey { get; init; } + [JsonPropertyName("user_identity_id")] + public string? UserIdentityId { get; init; } } public sealed record CreateRequestLocation @@ -204,6 +177,33 @@ public enum ModeEnum public CreateRequestRequestedAccessMethods.ModeEnum? Mode { get; init; } } + public sealed record CreateRequestUserIdentity + { + /// + /// Unique email address for the user identity. + /// + [JsonPropertyName("email_address")] + public Optional EmailAddress { get; init; } + + /// + /// Full name of the user associated with the user identity. + /// + [JsonPropertyName("full_name")] + public Optional FullName { get; init; } + + /// + /// Unique phone number for the user identity in [E.164 format](https://www.itu.int/rec/T-REC-E.164/en) (for example, +15555550100). + /// + [JsonPropertyName("phone_number")] + public Optional PhoneNumber { get; init; } + + /// + /// Unique key for the user identity. + /// + [JsonPropertyName("user_identity_key")] + public Optional UserIdentityKey { get; init; } + } + public sealed record CreateResponse { /// diff --git a/src/Seam/Routes/AccessMethods.cs b/src/Seam/Routes/AccessMethods.cs index 5d610cc5..c09949a0 100644 --- a/src/Seam/Routes/AccessMethods.cs +++ b/src/Seam/Routes/AccessMethods.cs @@ -92,18 +92,18 @@ public async Task AssignCardAsync( /// public sealed record DeleteRequest { - /// - /// ID of access method to delete. - /// - [JsonPropertyName("access_method_id")] - public string? AccessMethodId { get; init; } - /// /// ID of access grant whose access methods should be deleted. /// [JsonPropertyName("access_grant_id")] public string? AccessGrantId { get; init; } + /// + /// ID of access method to delete. + /// + [JsonPropertyName("access_method_id")] + public string? AccessMethodId { get; init; } + /// /// Reservation key of the access grant whose access methods should be deleted. /// @@ -112,7 +112,7 @@ public sealed record DeleteRequest internal void Validate() { - if (AccessMethodId == null && AccessGrantId == null && ReservationKey == null) + if (AccessGrantId == null && AccessMethodId == null && ReservationKey == null) { throw new ArgumentException( "At least one parameter is required for /access_methods/delete" diff --git a/src/Seam/Routes/AcsEncodersSimulate.cs b/src/Seam/Routes/AcsEncodersSimulate.cs index b941a4ac..aaaba409 100644 --- a/src/Seam/Routes/AcsEncodersSimulate.cs +++ b/src/Seam/Routes/AcsEncodersSimulate.cs @@ -52,6 +52,12 @@ public enum ErrorCodeEnum ActionAttemptExpired = 4, } + /// + /// ID of the `acs_credential` that will fail to be encoded onto a card in the next request. + /// + [JsonPropertyName("acs_credential_id")] + public string? AcsCredentialId { get; init; } + /// /// ID of the `acs_encoder` that will be used in the next request to encode the `acs_credential`. /// @@ -63,12 +69,6 @@ public enum ErrorCodeEnum /// [JsonPropertyName("error_code")] public NextCredentialEncodeWillFailRequest.ErrorCodeEnum? ErrorCode { get; init; } - - /// - /// ID of the `acs_credential` that will fail to be encoded onto a card in the next request. - /// - [JsonPropertyName("acs_credential_id")] - public string? AcsCredentialId { get; init; } } /// @@ -159,6 +159,9 @@ public enum ErrorCodeEnum ActionAttemptExpired = 3, } + [JsonPropertyName("acs_credential_id_on_seam")] + public string? AcsCredentialIdOnSeam { get; init; } + /// /// ID of the `acs_encoder` that will fail to scan the `acs_credential` in the next request. /// @@ -167,9 +170,6 @@ public enum ErrorCodeEnum [JsonPropertyName("error_code")] public NextCredentialScanWillFailRequest.ErrorCodeEnum? ErrorCode { get; init; } - - [JsonPropertyName("acs_credential_id_on_seam")] - public string? AcsCredentialIdOnSeam { get; init; } } /// diff --git a/src/Seam/Routes/Customers.cs b/src/Seam/Routes/Customers.cs index 8133bcca..7116ac29 100644 --- a/src/Seam/Routes/Customers.cs +++ b/src/Seam/Routes/Customers.cs @@ -86,6 +86,9 @@ public enum NavigationModeEnum Restricted = 2, } + [JsonPropertyName("customer_data")] + public CreatePortalRequestCustomerData? CustomerData { get; init; } + /// /// Filter configuration for resources based on their custom_metadata. Each filter specifies a field, operation, and value to match against resource custom_metadata. /// @@ -142,434 +145,249 @@ public enum NavigationModeEnum /// [JsonPropertyName("read_only")] public bool? ReadOnly { get; init; } - - [JsonPropertyName("customer_data")] - public CreatePortalRequestCustomerData? CustomerData { get; init; } } - public sealed record CreatePortalRequestCustomerResourcesFilters + public sealed record CreatePortalRequestCustomerData { /// - /// The comparison operation. Currently only '=' is supported. + /// List of access grants. /// - [JsonConverter(typeof(SeamStringEnumConverter))] - public enum OperationEnum - { - [EnumMember(Value = "unrecognized")] - Unrecognized = 0, - - [EnumMember(Value = "=")] - empty = 1, - } + [JsonPropertyName("access_grants")] + public List? AccessGrants { get; init; } /// - /// The custom_metadata field name to filter on. + /// List of bookings. /// - [JsonPropertyName("field")] - public string? Field { get; init; } + [JsonPropertyName("bookings")] + public List? Bookings { get; init; } /// - /// The comparison operation. Currently only '=' is supported. + /// List of buildings. /// - [JsonPropertyName("operation")] - public CreatePortalRequestCustomerResourcesFilters.OperationEnum? Operation { get; init; } + [JsonPropertyName("buildings")] + public List? Buildings { get; init; } /// - /// The value to compare against. + /// List of shared common areas. /// - [JsonPropertyName("value")] - public string? Value { get; init; } - } - - public sealed record CreatePortalRequestDeepLink - { - [JsonConverter(typeof(SeamStringEnumConverter))] - public enum ResourceTypeEnum - { - [EnumMember(Value = "unrecognized")] - Unrecognized = 0, - - [EnumMember(Value = "reservation")] - Reservation = 1, - - [EnumMember(Value = "space")] - Space = 2, + [JsonPropertyName("common_areas")] + public List? CommonAreas { get; init; } - [EnumMember(Value = "device")] - Device = 3, - } + /// + /// Your unique identifier for the customer. + /// + [JsonPropertyName("customer_key")] + public string? CustomerKey { get; init; } - [JsonPropertyName("resource_key")] - public string? ResourceKey { get; init; } + /// + /// List of gym or fitness facilities. + /// + [JsonPropertyName("facilities")] + public List? Facilities { get; init; } - [JsonPropertyName("resource_type")] - public CreatePortalRequestDeepLink.ResourceTypeEnum? ResourceType { get; init; } + /// + /// List of guests. + /// + [JsonPropertyName("guests")] + public List? Guests { get; init; } - [JsonPropertyName("resource_id")] - public string? ResourceId { get; init; } - } + /// + /// List of property listings. + /// + [JsonPropertyName("listings")] + public List? Listings { get; init; } - public sealed record CreatePortalRequestFeatures - { /// - /// Configuration for the configure feature. + /// List of short-term rental properties. /// - [JsonPropertyName("configure")] - public CreatePortalRequestFeaturesConfigure? Configure { get; init; } + [JsonPropertyName("properties")] + public List? Properties { get; init; } /// - /// Configuration for the connect accounts feature. + /// List of property listings. /// - [JsonPropertyName("connect")] - public CreatePortalRequestFeaturesConnect? Connect { get; init; } + [JsonPropertyName("property_listings")] + public List? PropertyListings { get; init; } /// - /// Configuration for the manage feature. + /// List of reservations. /// - [JsonPropertyName("manage")] - public CreatePortalRequestFeaturesManage? Manage { get; init; } + [JsonPropertyName("reservations")] + public List? Reservations { get; init; } /// - /// Configuration for the manage devices feature. - /// --- - /// deprecated: Use `manage` instead. - /// --- + /// List of residents. /// - [JsonPropertyName("manage_devices")] - public CreatePortalRequestFeaturesManageDevices? ManageDevices { get; init; } + [JsonPropertyName("residents")] + public List? Residents { get; init; } /// - /// Configuration for the organize feature. + /// List of hotel or hospitality rooms. /// - [JsonPropertyName("organize")] - public CreatePortalRequestFeaturesOrganize? Organize { get; init; } - } + [JsonPropertyName("rooms")] + public List? Rooms { get; init; } - public sealed record CreatePortalRequestFeaturesConfigure - { /// - /// Indicates whether the customer can customize the access automation rules for their properties. + /// List of general sites or areas. /// - [JsonPropertyName("allow_access_automation_rule_customization")] - public bool? AllowAccessAutomationRuleCustomization { get; init; } + [JsonPropertyName("sites")] + public List? Sites { get; init; } /// - /// Indicates whether the customer can customize the climate automation rules for their properties. + /// List of general spaces or areas. /// - [JsonPropertyName("allow_climate_automation_rule_customization")] - public bool? AllowClimateAutomationRuleCustomization { get; init; } + [JsonPropertyName("spaces")] + public List? Spaces { get; init; } /// - /// Indicates whether the customer can customize the Instant Key profile for their properties. + /// List of staff members. /// - [JsonPropertyName("allow_instant_key_customization")] - public bool? AllowInstantKeyCustomization { get; init; } + [JsonPropertyName("staff_members")] + public List? StaffMembers { get; init; } /// - /// Whether to exclude this feature from the portal. + /// List of tenants. /// - [JsonPropertyName("exclude")] - public bool? Exclude { get; init; } - } + [JsonPropertyName("tenants")] + public List? Tenants { get; init; } - public sealed record CreatePortalRequestFeaturesConnect - { /// - /// List of provider keys to allow for the connect feature. These providers will be shown when the customer tries to connect an account. + /// List of multi-family residential units. /// - [JsonPropertyName("accepted_providers")] - public List? AcceptedProviders { get; init; } + [JsonPropertyName("units")] + public List? Units { get; init; } /// - /// Whether to exclude this feature from the portal. + /// List of user identities. /// - [JsonPropertyName("exclude")] - public bool? Exclude { get; init; } + [JsonPropertyName("user_identities")] + public List? UserIdentities { get; init; } /// - /// List of provider keys to exclude from the connect feature. These providers will not be shown when the customer tries to connect an account. + /// List of users. /// - [JsonPropertyName("excluded_providers")] - public List? ExcludedProviders { get; init; } + [JsonPropertyName("users")] + public List? Users { get; init; } } - public sealed record CreatePortalRequestFeaturesManage + public sealed record CreatePortalRequestCustomerDataAccessGrants { /// - /// Custom copy for the confirmation modal shown before unmanaged devices are added to a space and begin being managed (and billed). Only takes effect when the MANAGE_DEVICES_CONFIRMATION_MODAL feature flag is enabled for the workspace. Any omitted string falls back to a localized default. + /// Your unique identifier for the access grant. /// - [JsonPropertyName("device_management_confirmation")] - public CreatePortalRequestFeaturesManageDeviceManagementConfirmation? DeviceManagementConfirmation { get; init; } + [JsonPropertyName("access_grant_key")] + public string? AccessGrantKey { get; init; } /// - /// Configuration for event type filtering in the manage feature. + /// Building keys associated with the access grant. /// - [JsonPropertyName("events")] - public CreatePortalRequestFeaturesManageEvents? Events { get; init; } + [JsonPropertyName("building_keys")] + public List? BuildingKeys { get; init; } /// - /// Whether to exclude this feature from the portal. + /// Common area keys associated with the access grant. /// - [JsonPropertyName("exclude")] - public bool? Exclude { get; init; } + [JsonPropertyName("common_area_keys")] + public List? CommonAreaKeys { get; init; } /// - /// Indicates whether the customer can manage reservations for their properties. + /// Ending date and time for the access grant. /// - [JsonPropertyName("exclude_reservation_management")] - public bool? ExcludeReservationManagement { get; init; } + [JsonPropertyName("ends_at")] + public string? EndsAt { get; init; } /// - /// Indicates whether to exclude technical details from reservation views. + /// Facility keys associated with the access grant. /// - [JsonPropertyName("exclude_reservation_technical_details")] - public bool? ExcludeReservationTechnicalDetails { get; init; } + [JsonPropertyName("facility_keys")] + public List? FacilityKeys { get; init; } /// - /// Indicates whether the customer can manage staff for their properties. + /// Guest key associated with the access grant. /// - [JsonPropertyName("exclude_staff_management")] - public bool? ExcludeStaffManagement { get; init; } - } + [JsonPropertyName("guest_key")] + public string? GuestKey { get; init; } - public sealed record CreatePortalRequestFeaturesManageDeviceManagementConfirmation - { /// - /// Custom body text for the confirmation modal. May include the {count} token, which is replaced with the number of devices that will begin being managed. + /// Listing keys associated with the access grant. /// - [JsonPropertyName("body")] - public string? Body { get; init; } + [JsonPropertyName("listing_keys")] + public List? ListingKeys { get; init; } /// - /// Custom label for the cancel button. + /// Your name for this access grant resource. /// - [JsonPropertyName("cancel_button_label")] - public string? CancelButtonLabel { get; init; } + [JsonPropertyName("name")] + public string? Name { get; init; } /// - /// Custom label for the confirm button. + /// Preferred PIN code to use when creating access for this reservation. /// - [JsonPropertyName("confirm_button_label")] - public string? ConfirmButtonLabel { get; init; } + [JsonPropertyName("preferred_code")] + public string? PreferredCode { get; init; } /// - /// Custom title for the confirmation modal. + /// Property keys associated with the access grant. /// - [JsonPropertyName("title")] - public string? Title { get; init; } - } + [JsonPropertyName("property_keys")] + public List? PropertyKeys { get; init; } - public sealed record CreatePortalRequestFeaturesManageEvents - { /// - /// List of event types to show in the events filter. When set, only these event types will be available. Leave empty to show all events. + /// Resident key associated with the access grant. /// - [JsonPropertyName("allowed_events")] - public List? AllowedEvents { get; init; } + [JsonPropertyName("resident_key")] + public string? ResidentKey { get; init; } /// - /// List of event types that are pre-selected in the events filter when the user first loads the events tab. + /// Room keys associated with the access grant. /// - [JsonPropertyName("default_events")] - public List? DefaultEvents { get; init; } - } + [JsonPropertyName("room_keys")] + public List? RoomKeys { get; init; } - public sealed record CreatePortalRequestFeaturesManageDevices - { /// - /// Whether to exclude this feature from the portal. + /// Space keys associated with the access grant. /// - [JsonPropertyName("exclude")] - public bool? Exclude { get; init; } - } - - public sealed record CreatePortalRequestFeaturesOrganize - { - /// - /// Whether to exclude this feature from the portal. - /// - [JsonPropertyName("exclude")] - public bool? Exclude { get; init; } - } - - public sealed record CreatePortalRequestLandingPage - { - [JsonPropertyName("manage")] - public CreatePortalRequestLandingPageManage? Manage { get; init; } - } - - public sealed record CreatePortalRequestLandingPageManage - { - [JsonPropertyName("space_key")] - public string? SpaceKey { get; init; } - - [JsonPropertyName("property_key")] - public string? PropertyKey { get; init; } - - [JsonPropertyName("room_key")] - public string? RoomKey { get; init; } - - [JsonPropertyName("common_area_key")] - public string? CommonAreaKey { get; init; } - - [JsonPropertyName("unit_key")] - public string? UnitKey { get; init; } - - [JsonPropertyName("facility_key")] - public string? FacilityKey { get; init; } - - [JsonPropertyName("building_key")] - public string? BuildingKey { get; init; } - - [JsonPropertyName("listing_key")] - public string? ListingKey { get; init; } - - [JsonPropertyName("property_listing_key")] - public string? PropertyListingKey { get; init; } - - [JsonPropertyName("site_key")] - public string? SiteKey { get; init; } - - [JsonPropertyName("reservation_key")] - public string? ReservationKey { get; init; } - - [JsonPropertyName("booking_key")] - public string? BookingKey { get; init; } - - [JsonPropertyName("access_grant_key")] - public string? AccessGrantKey { get; init; } - } - - public sealed record CreatePortalRequestCustomerData - { - /// - /// List of access grants. - /// - [JsonPropertyName("access_grants")] - public List? AccessGrants { get; init; } - - /// - /// List of bookings. - /// - [JsonPropertyName("bookings")] - public List? Bookings { get; init; } - - /// - /// List of buildings. - /// - [JsonPropertyName("buildings")] - public List? Buildings { get; init; } - - /// - /// List of shared common areas. - /// - [JsonPropertyName("common_areas")] - public List? CommonAreas { get; init; } - - /// - /// Your unique identifier for the customer. - /// - [JsonPropertyName("customer_key")] - public string? CustomerKey { get; init; } - - /// - /// List of gym or fitness facilities. - /// - [JsonPropertyName("facilities")] - public List? Facilities { get; init; } - - /// - /// List of guests. - /// - [JsonPropertyName("guests")] - public List? Guests { get; init; } - - /// - /// List of property listings. - /// - [JsonPropertyName("listings")] - public List? Listings { get; init; } - - /// - /// List of short-term rental properties. - /// - [JsonPropertyName("properties")] - public List? Properties { get; init; } - - /// - /// List of property listings. - /// - [JsonPropertyName("property_listings")] - public List? PropertyListings { get; init; } - - /// - /// List of reservations. - /// - [JsonPropertyName("reservations")] - public List? Reservations { get; init; } - - /// - /// List of residents. - /// - [JsonPropertyName("residents")] - public List? Residents { get; init; } - - /// - /// List of hotel or hospitality rooms. - /// - [JsonPropertyName("rooms")] - public List? Rooms { get; init; } - - /// - /// List of general sites or areas. - /// - [JsonPropertyName("sites")] - public List? Sites { get; init; } - - /// - /// List of general spaces or areas. - /// - [JsonPropertyName("spaces")] - public List? Spaces { get; init; } + [JsonPropertyName("space_keys")] + public List? SpaceKeys { get; init; } /// - /// List of staff members. + /// Starting date and time for the access grant. /// - [JsonPropertyName("staff_members")] - public List? StaffMembers { get; init; } + [JsonPropertyName("starts_at")] + public string? StartsAt { get; init; } /// - /// List of tenants. + /// Tenant key associated with the access grant. /// - [JsonPropertyName("tenants")] - public List? Tenants { get; init; } + [JsonPropertyName("tenant_key")] + public string? TenantKey { get; init; } /// - /// List of multi-family residential units. + /// Unit keys associated with the access grant. /// - [JsonPropertyName("units")] - public List? Units { get; init; } + [JsonPropertyName("unit_keys")] + public List? UnitKeys { get; init; } /// - /// List of user identities. + /// User identity key associated with the access grant. /// - [JsonPropertyName("user_identities")] - public List? UserIdentities { get; init; } + [JsonPropertyName("user_identity_key")] + public string? UserIdentityKey { get; init; } /// - /// List of users. + /// User key associated with the access grant. /// - [JsonPropertyName("users")] - public List? Users { get; init; } + [JsonPropertyName("user_key")] + public string? UserKey { get; init; } } - public sealed record CreatePortalRequestCustomerDataAccessGrants + public sealed record CreatePortalRequestCustomerDataBookings { /// - /// Your unique identifier for the access grant. + /// Your unique identifier for the booking. /// - [JsonPropertyName("access_grant_key")] - public string? AccessGrantKey { get; init; } + [JsonPropertyName("booking_key")] + public string? BookingKey { get; init; } /// /// Building keys associated with the access grant. @@ -674,181 +492,70 @@ public sealed record CreatePortalRequestCustomerDataAccessGrants public string? UserKey { get; init; } } - public sealed record CreatePortalRequestCustomerDataBookings + public sealed record CreatePortalRequestCustomerDataBuildings { /// - /// Your unique identifier for the booking. - /// - [JsonPropertyName("booking_key")] - public string? BookingKey { get; init; } - - /// - /// Building keys associated with the access grant. + /// Your unique identifier for the building. /// - [JsonPropertyName("building_keys")] - public List? BuildingKeys { get; init; } + [JsonPropertyName("building_key")] + public string? BuildingKey { get; init; } /// - /// Common area keys associated with the access grant. + /// Your display name for this location resource. /// - [JsonPropertyName("common_area_keys")] - public List? CommonAreaKeys { get; init; } + [JsonPropertyName("name")] + public string? Name { get; init; } + } + public sealed record CreatePortalRequestCustomerDataCommonAreas + { /// - /// Ending date and time for the access grant. + /// Your unique identifier for the common area. /// - [JsonPropertyName("ends_at")] - public string? EndsAt { get; init; } + [JsonPropertyName("common_area_key")] + public string? CommonAreaKey { get; init; } /// - /// Facility keys associated with the access grant. + /// Your display name for this location resource. /// - [JsonPropertyName("facility_keys")] - public List? FacilityKeys { get; init; } + [JsonPropertyName("name")] + public string? Name { get; init; } /// - /// Guest key associated with the access grant. + /// Your unique identifier for the site. /// - [JsonPropertyName("guest_key")] - public string? GuestKey { get; init; } + [JsonPropertyName("parent_site_key")] + public string? ParentSiteKey { get; init; } + } + public sealed record CreatePortalRequestCustomerDataFacilities + { /// - /// Listing keys associated with the access grant. + /// Your unique identifier for the facility. /// - [JsonPropertyName("listing_keys")] - public List? ListingKeys { get; init; } + [JsonPropertyName("facility_key")] + public string? FacilityKey { get; init; } /// - /// Your name for this access grant resource. + /// Your display name for this location resource. /// [JsonPropertyName("name")] public string? Name { get; init; } + } + public sealed record CreatePortalRequestCustomerDataGuests + { /// - /// Preferred PIN code to use when creating access for this reservation. + /// Email address associated with the user identity. /// - [JsonPropertyName("preferred_code")] - public string? PreferredCode { get; init; } + [JsonPropertyName("email_address")] + public string? EmailAddress { get; init; } /// - /// Property keys associated with the access grant. + /// Your unique identifier for the guest. /// - [JsonPropertyName("property_keys")] - public List? PropertyKeys { get; init; } - - /// - /// Resident key associated with the access grant. - /// - [JsonPropertyName("resident_key")] - public string? ResidentKey { get; init; } - - /// - /// Room keys associated with the access grant. - /// - [JsonPropertyName("room_keys")] - public List? RoomKeys { get; init; } - - /// - /// Space keys associated with the access grant. - /// - [JsonPropertyName("space_keys")] - public List? SpaceKeys { get; init; } - - /// - /// Starting date and time for the access grant. - /// - [JsonPropertyName("starts_at")] - public string? StartsAt { get; init; } - - /// - /// Tenant key associated with the access grant. - /// - [JsonPropertyName("tenant_key")] - public string? TenantKey { get; init; } - - /// - /// Unit keys associated with the access grant. - /// - [JsonPropertyName("unit_keys")] - public List? UnitKeys { get; init; } - - /// - /// User identity key associated with the access grant. - /// - [JsonPropertyName("user_identity_key")] - public string? UserIdentityKey { get; init; } - - /// - /// User key associated with the access grant. - /// - [JsonPropertyName("user_key")] - public string? UserKey { get; init; } - } - - public sealed record CreatePortalRequestCustomerDataBuildings - { - /// - /// Your unique identifier for the building. - /// - [JsonPropertyName("building_key")] - public string? BuildingKey { get; init; } - - /// - /// Your display name for this location resource. - /// - [JsonPropertyName("name")] - public string? Name { get; init; } - } - - public sealed record CreatePortalRequestCustomerDataCommonAreas - { - /// - /// Your unique identifier for the common area. - /// - [JsonPropertyName("common_area_key")] - public string? CommonAreaKey { get; init; } - - /// - /// Your display name for this location resource. - /// - [JsonPropertyName("name")] - public string? Name { get; init; } - - /// - /// Your unique identifier for the site. - /// - [JsonPropertyName("parent_site_key")] - public string? ParentSiteKey { get; init; } - } - - public sealed record CreatePortalRequestCustomerDataFacilities - { - /// - /// Your unique identifier for the facility. - /// - [JsonPropertyName("facility_key")] - public string? FacilityKey { get; init; } - - /// - /// Your display name for this location resource. - /// - [JsonPropertyName("name")] - public string? Name { get; init; } - } - - public sealed record CreatePortalRequestCustomerDataGuests - { - /// - /// Email address associated with the user identity. - /// - [JsonPropertyName("email_address")] - public string? EmailAddress { get; init; } - - /// - /// Your unique identifier for the guest. - /// - [JsonPropertyName("guest_key")] - public string? GuestKey { get; init; } + [JsonPropertyName("guest_key")] + public string? GuestKey { get; init; } /// /// Your display name for this user identity resource. @@ -1364,6 +1071,299 @@ public sealed record CreatePortalRequestCustomerDataUsers public string? UserKey { get; init; } } + public sealed record CreatePortalRequestCustomerResourcesFilters + { + /// + /// The comparison operation. Currently only '=' is supported. + /// + [JsonConverter(typeof(SeamStringEnumConverter))] + public enum OperationEnum + { + [EnumMember(Value = "unrecognized")] + Unrecognized = 0, + + [EnumMember(Value = "=")] + empty = 1, + } + + /// + /// The custom_metadata field name to filter on. + /// + [JsonPropertyName("field")] + public string? Field { get; init; } + + /// + /// The comparison operation. Currently only '=' is supported. + /// + [JsonPropertyName("operation")] + public CreatePortalRequestCustomerResourcesFilters.OperationEnum? Operation { get; init; } + + /// + /// The value to compare against. + /// + [JsonPropertyName("value")] + public string? Value { get; init; } + } + + public sealed record CreatePortalRequestDeepLink + { + [JsonConverter(typeof(SeamStringEnumConverter))] + public enum ResourceTypeEnum + { + [EnumMember(Value = "unrecognized")] + Unrecognized = 0, + + [EnumMember(Value = "reservation")] + Reservation = 1, + + [EnumMember(Value = "space")] + Space = 2, + + [EnumMember(Value = "device")] + Device = 3, + } + + [JsonPropertyName("resource_id")] + public string? ResourceId { get; init; } + + [JsonPropertyName("resource_key")] + public string? ResourceKey { get; init; } + + [JsonPropertyName("resource_type")] + public CreatePortalRequestDeepLink.ResourceTypeEnum? ResourceType { get; init; } + } + + public sealed record CreatePortalRequestFeatures + { + /// + /// Configuration for the configure feature. + /// + [JsonPropertyName("configure")] + public CreatePortalRequestFeaturesConfigure? Configure { get; init; } + + /// + /// Configuration for the connect accounts feature. + /// + [JsonPropertyName("connect")] + public CreatePortalRequestFeaturesConnect? Connect { get; init; } + + /// + /// Configuration for the manage feature. + /// + [JsonPropertyName("manage")] + public CreatePortalRequestFeaturesManage? Manage { get; init; } + + /// + /// Configuration for the manage devices feature. + /// --- + /// deprecated: Use `manage` instead. + /// --- + /// + [JsonPropertyName("manage_devices")] + public CreatePortalRequestFeaturesManageDevices? ManageDevices { get; init; } + + /// + /// Configuration for the organize feature. + /// + [JsonPropertyName("organize")] + public CreatePortalRequestFeaturesOrganize? Organize { get; init; } + } + + public sealed record CreatePortalRequestFeaturesConfigure + { + /// + /// Indicates whether the customer can customize the access automation rules for their properties. + /// + [JsonPropertyName("allow_access_automation_rule_customization")] + public bool? AllowAccessAutomationRuleCustomization { get; init; } + + /// + /// Indicates whether the customer can customize the climate automation rules for their properties. + /// + [JsonPropertyName("allow_climate_automation_rule_customization")] + public bool? AllowClimateAutomationRuleCustomization { get; init; } + + /// + /// Indicates whether the customer can customize the Instant Key profile for their properties. + /// + [JsonPropertyName("allow_instant_key_customization")] + public bool? AllowInstantKeyCustomization { get; init; } + + /// + /// Whether to exclude this feature from the portal. + /// + [JsonPropertyName("exclude")] + public bool? Exclude { get; init; } + } + + public sealed record CreatePortalRequestFeaturesConnect + { + /// + /// List of provider keys to allow for the connect feature. These providers will be shown when the customer tries to connect an account. + /// + [JsonPropertyName("accepted_providers")] + public List? AcceptedProviders { get; init; } + + /// + /// Whether to exclude this feature from the portal. + /// + [JsonPropertyName("exclude")] + public bool? Exclude { get; init; } + + /// + /// List of provider keys to exclude from the connect feature. These providers will not be shown when the customer tries to connect an account. + /// + [JsonPropertyName("excluded_providers")] + public List? ExcludedProviders { get; init; } + } + + public sealed record CreatePortalRequestFeaturesManage + { + /// + /// Custom copy for the confirmation modal shown before unmanaged devices are added to a space and begin being managed (and billed). Only takes effect when the MANAGE_DEVICES_CONFIRMATION_MODAL feature flag is enabled for the workspace. Any omitted string falls back to a localized default. + /// + [JsonPropertyName("device_management_confirmation")] + public CreatePortalRequestFeaturesManageDeviceManagementConfirmation? DeviceManagementConfirmation { get; init; } + + /// + /// Configuration for event type filtering in the manage feature. + /// + [JsonPropertyName("events")] + public CreatePortalRequestFeaturesManageEvents? Events { get; init; } + + /// + /// Whether to exclude this feature from the portal. + /// + [JsonPropertyName("exclude")] + public bool? Exclude { get; init; } + + /// + /// Indicates whether the customer can manage reservations for their properties. + /// + [JsonPropertyName("exclude_reservation_management")] + public bool? ExcludeReservationManagement { get; init; } + + /// + /// Indicates whether to exclude technical details from reservation views. + /// + [JsonPropertyName("exclude_reservation_technical_details")] + public bool? ExcludeReservationTechnicalDetails { get; init; } + + /// + /// Indicates whether the customer can manage staff for their properties. + /// + [JsonPropertyName("exclude_staff_management")] + public bool? ExcludeStaffManagement { get; init; } + } + + public sealed record CreatePortalRequestFeaturesManageDeviceManagementConfirmation + { + /// + /// Custom body text for the confirmation modal. May include the {count} token, which is replaced with the number of devices that will begin being managed. + /// + [JsonPropertyName("body")] + public string? Body { get; init; } + + /// + /// Custom label for the cancel button. + /// + [JsonPropertyName("cancel_button_label")] + public string? CancelButtonLabel { get; init; } + + /// + /// Custom label for the confirm button. + /// + [JsonPropertyName("confirm_button_label")] + public string? ConfirmButtonLabel { get; init; } + + /// + /// Custom title for the confirmation modal. + /// + [JsonPropertyName("title")] + public string? Title { get; init; } + } + + public sealed record CreatePortalRequestFeaturesManageEvents + { + /// + /// List of event types to show in the events filter. When set, only these event types will be available. Leave empty to show all events. + /// + [JsonPropertyName("allowed_events")] + public List? AllowedEvents { get; init; } + + /// + /// List of event types that are pre-selected in the events filter when the user first loads the events tab. + /// + [JsonPropertyName("default_events")] + public List? DefaultEvents { get; init; } + } + + public sealed record CreatePortalRequestFeaturesManageDevices + { + /// + /// Whether to exclude this feature from the portal. + /// + [JsonPropertyName("exclude")] + public bool? Exclude { get; init; } + } + + public sealed record CreatePortalRequestFeaturesOrganize + { + /// + /// Whether to exclude this feature from the portal. + /// + [JsonPropertyName("exclude")] + public bool? Exclude { get; init; } + } + + public sealed record CreatePortalRequestLandingPage + { + [JsonPropertyName("manage")] + public CreatePortalRequestLandingPageManage? Manage { get; init; } + } + + public sealed record CreatePortalRequestLandingPageManage + { + [JsonPropertyName("access_grant_key")] + public string? AccessGrantKey { get; init; } + + [JsonPropertyName("booking_key")] + public string? BookingKey { get; init; } + + [JsonPropertyName("building_key")] + public string? BuildingKey { get; init; } + + [JsonPropertyName("common_area_key")] + public string? CommonAreaKey { get; init; } + + [JsonPropertyName("facility_key")] + public string? FacilityKey { get; init; } + + [JsonPropertyName("listing_key")] + public string? ListingKey { get; init; } + + [JsonPropertyName("property_key")] + public string? PropertyKey { get; init; } + + [JsonPropertyName("property_listing_key")] + public string? PropertyListingKey { get; init; } + + [JsonPropertyName("reservation_key")] + public string? ReservationKey { get; init; } + + [JsonPropertyName("room_key")] + public string? RoomKey { get; init; } + + [JsonPropertyName("site_key")] + public string? SiteKey { get; init; } + + [JsonPropertyName("space_key")] + public string? SpaceKey { get; init; } + + [JsonPropertyName("unit_key")] + public string? UnitKey { get; init; } + } + public sealed record CreatePortalResponse { /// diff --git a/src/Seam/Routes/Thermostats.cs b/src/Seam/Routes/Thermostats.cs index c27b1f1f..633e8707 100644 --- a/src/Seam/Routes/Thermostats.cs +++ b/src/Seam/Routes/Thermostats.cs @@ -917,15 +917,6 @@ public enum HvacModeSettingEnum Eco = 5, } - /// - /// ID of the thermostat device for which you want to set the HVAC mode. - /// - [JsonPropertyName("device_id")] - public required string DeviceId { get; init; } - - [JsonPropertyName("hvac_mode_setting")] - public required SetHvacModeRequest.HvacModeSettingEnum HvacModeSetting { get; init; } - /// /// [Cooling set point](https://docs.seam.co/capability-guides/thermostats/understanding-thermostat-concepts/set-points) in °C that you want to set for the thermostat. You must set one of the `cooling_set_point` parameters. /// @@ -938,6 +929,12 @@ public enum HvacModeSettingEnum [JsonPropertyName("cooling_set_point_fahrenheit")] public float? CoolingSetPointFahrenheit { get; init; } + /// + /// ID of the thermostat device for which you want to set the HVAC mode. + /// + [JsonPropertyName("device_id")] + public required string DeviceId { get; init; } + /// /// [Heating set point](https://docs.seam.co/capability-guides/thermostats/understanding-thermostat-concepts/set-points) in °C that you want to set for the thermostat. You must set one of the `heating_set_point` parameters. /// @@ -949,6 +946,9 @@ public enum HvacModeSettingEnum /// [JsonPropertyName("heating_set_point_fahrenheit")] public float? HeatingSetPointFahrenheit { get; init; } + + [JsonPropertyName("hvac_mode_setting")] + public required SetHvacModeRequest.HvacModeSettingEnum HvacModeSetting { get; init; } } public sealed record SetHvacModeResponse diff --git a/src/Seam/Routes/ThermostatsSimulate.cs b/src/Seam/Routes/ThermostatsSimulate.cs index 533cf2fc..a49b8ae4 100644 --- a/src/Seam/Routes/ThermostatsSimulate.cs +++ b/src/Seam/Routes/ThermostatsSimulate.cs @@ -52,18 +52,6 @@ public enum HvacModeEnum HeatCool = 4, } - /// - /// ID of the thermostat device for which you want to simulate having adjusted the HVAC mode. - /// - [JsonPropertyName("device_id")] - public required string DeviceId { get; init; } - - /// - /// HVAC mode that you want to simulate. - /// - [JsonPropertyName("hvac_mode")] - public required HvacModeAdjustedRequest.HvacModeEnum HvacMode { get; init; } - /// /// Cooling [set point](https://docs.seam.co/capability-guides/thermostats/understanding-thermostat-concepts/set-points) in °C that you want to simulate. You must set `cooling_set_point_celsius` or `cooling_set_point_fahrenheit`. /// @@ -76,6 +64,12 @@ public enum HvacModeEnum [JsonPropertyName("cooling_set_point_fahrenheit")] public float? CoolingSetPointFahrenheit { get; init; } + /// + /// ID of the thermostat device for which you want to simulate having adjusted the HVAC mode. + /// + [JsonPropertyName("device_id")] + public required string DeviceId { get; init; } + /// /// Heating [set point](https://docs.seam.co/capability-guides/thermostats/understanding-thermostat-concepts/set-points) in °C that you want to simulate. You must set `heating_set_point_celsius` or `heating_set_point_fahrenheit`. /// @@ -87,6 +81,12 @@ public enum HvacModeEnum /// [JsonPropertyName("heating_set_point_fahrenheit")] public float? HeatingSetPointFahrenheit { get; init; } + + /// + /// HVAC mode that you want to simulate. + /// + [JsonPropertyName("hvac_mode")] + public required HvacModeAdjustedRequest.HvacModeEnum HvacMode { get; init; } } /// diff --git a/src/Seam/Routes/UserIdentities.cs b/src/Seam/Routes/UserIdentities.cs index f2813941..6b69ed8e 100644 --- a/src/Seam/Routes/UserIdentities.cs +++ b/src/Seam/Routes/UserIdentities.cs @@ -617,18 +617,18 @@ public sealed record MergeRequest [JsonPropertyName("merged_user_identity_ids")] public List? MergedUserIdentityIds { get; init; } - /// - /// ID of the primary user identity to keep. - /// - [JsonPropertyName("user_identity_id")] - public string? UserIdentityId { get; init; } - /// /// Keys of the user identities to merge into the primary user identity. These user identities are deleted. /// [JsonPropertyName("merged_user_identity_keys")] public List? MergedUserIdentityKeys { get; init; } + /// + /// ID of the primary user identity to keep. + /// + [JsonPropertyName("user_identity_id")] + public string? UserIdentityId { get; init; } + /// /// Key of the primary user identity to keep. /// @@ -639,8 +639,8 @@ internal void Validate() { if ( MergedUserIdentityIds == null - && UserIdentityId == null && MergedUserIdentityKeys == null + && UserIdentityId == null && UserIdentityKey == null ) { diff --git a/test/Seam.Test/SerializationTests.cs b/test/Seam.Test/SerializationTests.cs index 3cbb78e2..092f824c 100644 --- a/test/Seam.Test/SerializationTests.cs +++ b/test/Seam.Test/SerializationTests.cs @@ -46,7 +46,6 @@ public void UnknownActionTypeDeserializesToUnrecognizedVariant() Assert.Equal("attempt1", unrecognized.ActionAttemptId); Assert.Equal(ActionAttemptStatus.Pending, unrecognized.Status); - // The raw payload of an unrecognized variant is preserved, not discarded. Assert.Equal( "BRAND_NEW_ACTION", unrecognized.RawJson.GetProperty("action_type").GetString() @@ -63,7 +62,7 @@ public void KnownActionTypeDeserializesToItsVariant() """ ); - Assert.IsType(actionAttempt); + Assert.IsType(actionAttempt); Assert.Equal(ActionAttemptStatus.Success, actionAttempt.Status); Assert.Equal("UNLOCK_DOOR", actionAttempt.ActionType); } @@ -104,7 +103,65 @@ public void UnknownActionAttemptStatusDeserializesToUnrecognized() """ ); + var unrecognized = Assert.IsType(actionAttempt); Assert.Equal(ActionAttemptStatus.Unrecognized, actionAttempt.Status); + Assert.Equal("not_a_status", unrecognized.RawJson.GetProperty("status").GetString()); + } + + [Fact] + public void PendingActionAttemptDeserializesToThePendingSubclass() + { + var actionAttempt = Deserialize( + """ + {"action_type":"LOCK_DOOR","action_attempt_id":"attempt1","status":"pending","result":null,"error":null} + """ + ); + + var lockDoor = Assert.IsType(actionAttempt); + Assert.Equal(ActionAttemptStatus.Pending, lockDoor.Status); + } + + [Fact] + public void SuccessfulActionAttemptDeserializesWithResult() + { + var actionAttempt = Deserialize( + """ + {"action_type":"LOCK_DOOR","action_attempt_id":"attempt1","status":"success","error":null,"result":{"was_confirmed_by_device":true}} + """ + ); + + var lockDoor = Assert.IsType(actionAttempt); + Assert.Equal(ActionAttemptStatus.Success, lockDoor.Status); + Assert.True(lockDoor.Result.WasConfirmedByDevice); + } + + [Fact] + public void FailedActionAttemptDeserializesWithError() + { + var actionAttempt = Deserialize( + """ + {"action_type":"LOCK_DOOR","action_attempt_id":"attempt1","status":"error","result":null,"error":{"type":"foo","message":"Failed"}} + """ + ); + + var lockDoor = Assert.IsType(actionAttempt); + Assert.Equal(ActionAttemptStatus.Error, lockDoor.Status); + Assert.Equal("Failed", lockDoor.Error.Message); + Assert.Equal("foo", lockDoor.Error.Type); + } + + [Fact] + public void FailedActionAttemptExceptionFallsBackWithoutAnErrorObject() + { + var actionAttempt = Deserialize( + """ + {"action_type":"FUTURE_ACTION","action_attempt_id":"attempt1","status":"error"} + """ + ); + + var exception = new SeamActionAttemptFailedException(actionAttempt); + Assert.Equal("Action attempt failed", exception.Message); + Assert.Equal("unknown_error", exception.Code); } [Fact]