/**
 * NOTE: Added reference types here to avoid a `pnpm` bug during build.
 * https://github.com/enboxorg/enbox/pull/507
 */
/// <reference types="@enbox/dwn-sdk-js" />
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { getRecordAuthor } from '@enbox/agent';
import { Convert, Stream } from '@enbox/common';
/**
 * An immutable, read-only view of a DWN record.
 *
 * `ReadOnlyRecord` is returned by {@link DwnReaderApi} methods and provides
 * access to the record's metadata and data without any mutation capabilities.
 * There are no `update()`, `delete()`, `send()`, `store()`, or `import()`
 * methods — the compiler prevents accidental writes.
 *
 * Data access works identically to the full {@link Record} class:
 * - If the data was inlined (small payloads from query replies), it is
 *   available immediately.
 * - If the data was not inlined, `data.stream()` / `data.text()` / etc.
 *   automatically perform an anonymous `RecordsRead` to fetch it.
 *
 * @beta
 */
export class ReadOnlyRecord {
    constructor(options) {
        var _a, _b;
        const { rawMessage, initialWrite, encodedData, data, remoteOrigin, anonymousDwn } = options;
        this._anonymousDwn = anonymousDwn;
        this._remoteOrigin = remoteOrigin;
        // Extract the author DID from the authorization signature. The author is
        // the DID that signed the most recent RecordsWrite message. For records
        // returned from anonymous queries, the authorization will be present (the
        // remote DWN always returns the full message), but we guard against
        // malformed messages gracefully.
        try {
            this._author = (_a = getRecordAuthor(rawMessage)) !== null && _a !== void 0 ? _a : 'unknown';
        }
        catch (_c) {
            this._author = 'unknown';
        }
        try {
            this._creator = initialWrite ? ((_b = getRecordAuthor(initialWrite)) !== null && _b !== void 0 ? _b : this._author) : this._author;
        }
        catch (_d) {
            this._creator = this._author;
        }
        this._descriptor = rawMessage.descriptor;
        this._recordId = rawMessage.recordId;
        this._contextId = rawMessage.contextId;
        this._initialWrite = initialWrite;
        this._authorization = rawMessage.authorization;
        this._attestation = rawMessage.attestation;
        this._encryption = rawMessage.encryption;
        if (encodedData) {
            this._encodedData = new Blob([Convert.base64Url(encodedData).toUint8Array()], { type: this.dataFormat });
        }
        if (data) {
            this._readableStream = data;
        }
    }
    // ---------------------------------------------------------------------------
    // Immutable record properties
    // ---------------------------------------------------------------------------
    /** Record's unique identifier. */
    get id() { return this._recordId; }
    /** Record's context ID. */
    get contextId() { return this._contextId; }
    /** Record's creation date. */
    get dateCreated() { return this._descriptor.dateCreated; }
    /** Record's parent ID. */
    get parentId() { return this._descriptor.parentId; }
    /** Record's protocol URI. */
    get protocol() { return this._descriptor.protocol; }
    /** Record's protocol path. */
    get protocolPath() { return this._descriptor.protocolPath; }
    /** Record's recipient. */
    get recipient() { return this._descriptor.recipient; }
    /** Record's schema. */
    get schema() { return this._descriptor.schema; }
    // ---------------------------------------------------------------------------
    // Mutable descriptor properties
    // ---------------------------------------------------------------------------
    /** Record's data format / MIME type. */
    get dataFormat() { return this._descriptor.dataFormat; }
    /** Record's data CID. */
    get dataCid() { return this._descriptor.dataCid; }
    /** Record's data size in bytes. */
    get dataSize() { return this._descriptor.dataSize; }
    /** Record's published date. */
    get datePublished() { return this._descriptor.datePublished; }
    /** Whether the record is published. */
    get published() { return this._descriptor.published; }
    /** Tags associated with the record. */
    get tags() { return this._descriptor.tags; }
    // ---------------------------------------------------------------------------
    // State-dependent properties
    // ---------------------------------------------------------------------------
    /** DID that is the logical author of the record. */
    get author() { return this._author; }
    /** DID that originally created the record. */
    get creator() { return this._creator; }
    /** Record's message timestamp (time of most recent create/update). */
    get timestamp() { return this._descriptor.messageTimestamp; }
    /** Record's encryption metadata, if encrypted. */
    get encryption() { return this._encryption; }
    /** Record's authorization. */
    get authorization() { return this._authorization; }
    /** Record's attestation signatures. */
    get attestation() { return this._attestation; }
    /** The initial write message, if the record has been updated. */
    get initialWrite() { return this._initialWrite; }
    /** The DID of the remote DWN this record was fetched from. */
    get remoteOrigin() { return this._remoteOrigin; }
    // ---------------------------------------------------------------------------
    // Data access
    // ---------------------------------------------------------------------------
    /**
     * Returns the data of the current record.
     * If the data is not available in-memory, it is fetched from the remote DWN
     * using an anonymous `RecordsRead`.
     *
     * @returns A data accessor with `blob()`, `bytes()`, `json()`, `text()`, and `stream()` methods.
     *
     * @beta
     */
    get data() {
        const self = this;
        const dataObj = {
            blob() {
                return __awaiter(this, void 0, void 0, function* () {
                    return new Blob([yield Stream.consumeToBytes({ readableStream: yield this.stream() })], { type: self.dataFormat });
                });
            },
            bytes() {
                return __awaiter(this, void 0, void 0, function* () {
                    return yield Stream.consumeToBytes({ readableStream: yield this.stream() });
                });
            },
            json() {
                return __awaiter(this, void 0, void 0, function* () {
                    return yield Stream.consumeToJson({ readableStream: yield this.stream() });
                });
            },
            text() {
                return __awaiter(this, void 0, void 0, function* () {
                    return yield Stream.consumeToText({ readableStream: yield this.stream() });
                });
            },
            stream() {
                return __awaiter(this, void 0, void 0, function* () {
                    if (self._encodedData) {
                        return Stream.fromBlob(self._encodedData);
                    }
                    else if (self._readableStream) {
                        const currentStream = self._readableStream;
                        self._readableStream = undefined;
                        return currentStream;
                    }
                    else {
                        // Re-fetch the data from the remote DWN using an anonymous RecordsRead.
                        return yield self.readRecordData();
                    }
                });
            },
            then(onFulfilled, onRejected) {
                return this.stream().then(onFulfilled, onRejected);
            },
            catch(onRejected) {
                return this.stream().catch(onRejected);
            },
        };
        return dataObj;
    }
    // ---------------------------------------------------------------------------
    // Serialization
    // ---------------------------------------------------------------------------
    /**
     * Returns a JSON representation of the record.
     * Called by `JSON.stringify(...)` automatically.
     */
    toJSON() {
        return {
            attestation: this.attestation,
            author: this.author,
            authorization: this.authorization,
            contextId: this.contextId,
            dataCid: this.dataCid,
            dataFormat: this.dataFormat,
            dataSize: this.dataSize,
            dateCreated: this.dateCreated,
            datePublished: this.datePublished,
            encryption: this.encryption,
            parentId: this.parentId,
            protocol: this.protocol,
            protocolPath: this.protocolPath,
            published: this.published,
            recipient: this.recipient,
            recordId: this.id,
            schema: this.schema,
            tags: this.tags,
            timestamp: this.timestamp,
        };
    }
    /**
     * Convenience string representation.
     */
    toString() {
        let str = 'ReadOnlyRecord: {\n';
        str += `  ID: ${this.id}\n`;
        str += this.contextId ? `  Context ID: ${this.contextId}\n` : '';
        str += this.protocol ? `  Protocol: ${this.protocol}\n` : '';
        str += this.schema ? `  Schema: ${this.schema}\n` : '';
        str += `  Data CID: ${this.dataCid}\n`;
        str += `  Data Format: ${this.dataFormat}\n`;
        str += `  Data Size: ${this.dataSize}\n`;
        str += `  Created: ${this.dateCreated}\n`;
        str += `  Timestamp: ${this.timestamp}\n`;
        str += '}';
        return str;
    }
    // ---------------------------------------------------------------------------
    // Private helpers
    // ---------------------------------------------------------------------------
    /**
     * Fetches the record's data from the remote DWN using an anonymous `RecordsRead`.
     */
    readRecordData() {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            try {
                const reply = yield this._anonymousDwn.recordsRead(this._remoteOrigin, {
                    filter: { recordId: this._recordId },
                });
                if (reply.status.code !== 200 || !((_a = reply.entry) === null || _a === void 0 ? void 0 : _a.data)) {
                    throw new Error(`${reply.status.code}: ${reply.status.detail}`);
                }
                return reply.entry.data;
            }
            catch (error) {
                const message = (error instanceof Error) ? error.message : 'Unknown error';
                throw new Error(`ReadOnlyRecord: Error reading data for record '${this._recordId}': ${message}`);
            }
        });
    }
}
//# sourceMappingURL=read-only-record.js.map