/** * @license * Copyright 2022-2026 Matter.js Authors * SPDX-License-Identifier: Apache-2.0 */ import type { ValueSupervisor } from "#behavior/supervision/ValueSupervisor.js"; import { asJson, Bytes } from "@matter/general"; import { DataModelPath } from "@matter/model"; import { StatusResponse, TlvOfModel } from "@matter/types"; /** * Api data envelope packages used for request and response. * * This allows for transparent conversion between our three "native" formats -- JS values, serialized JSON and * serialized TLV. */ export class Envelope { #supervisor: ValueSupervisor; #js?: T; #json?: string; #tlv?: Bytes; constructor({ supervisor, js, json, tlv }: Envelope.Definition) { this.#supervisor = supervisor; this.#js = js; this.#json = json; this.#tlv = tlv; } /** * Validate against the schema. Casts to appropriate types if necessary. */ validate(session: ValueSupervisor.Session, path?: DataModelPath) { if (!path) { path = new DataModelPath(this.#supervisor.schema.path); } this.#js = this.#supervisor.cast(this.#js) as T; this.#supervisor.validate?.(this.js, session, { path }); } /** * Convert a {@link js} value to {@link JSON}. * * This acts as a deep copy and optimizes JSON access. If TLV becomes a priority then we can make this conversion * configurable. */ convertToJson() { if (this.#js !== undefined) { void this.json; } this.#js = undefined; } /** * Native JS format. */ get js() { if (this.#js === undefined) { if (this.#json) { try { this.#js = JSON.parse(this.#json) as T; } catch (e) { if (e instanceof SyntaxError) { throw new StatusResponse.FailureError(`Unparseable JSON: ${e.message}`); } throw e; } } else if (this.#tlv) { this.#js = TlvOfModel(this.#supervisor.schema).decode(this.#tlv) as T; } else { this.#js = null as T; } } return this.#js; } /** * JSON format. */ get json() { if (this.#json === undefined) { this.#json = asJson(this.js); } return this.#json; } /** * Serialized TLV format. */ get tlv() { if (this.#tlv === undefined) { this.#tlv = TlvOfModel(this.#supervisor.schema).encode(this.#js); } return this.#tlv; } } export namespace Envelope { export interface Data { id?: string; js?: T; json?: string; tlv?: Bytes; } export interface Definition extends Data { supervisor: ValueSupervisor; } }