var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var AdaptEnvironment_1, AdaptEvaluationUnit_1, AdaptPacketContext_1;
import { createRequire } from 'node:module';
import * as addon from './addon_types.js';
import { AdaptObject, staticImplements, } from '@adapt-toolkit/sdk/common';
export { AdaptObject, AdaptObjectLifetime } from '@adapt-toolkit/sdk/common';
const require = createRequire(import.meta.url);
export const ERR_ADAPT_NO_PREBUILD = 'ERR_ADAPT_NO_PREBUILD';
// Probe for a usable native binding at import time so consumers (notably the
// SDK's `backend-node.js` fallback gateway) can catch the failure and route
// to the WASM backend before any backend code runs. Without an import-time
// probe, the package loads, then explodes later during InitializeAsync.
(() => {
    const platformArch = `${process.platform}-${process.arch}`;
    const candidates = [
        `../prebuilds/${platformArch}/adapt_js.node`,
        `../build/Release/adapt_js.node`,
    ];
    for (const rel of candidates) {
        try {
            require.resolve(rel);
            return; // a candidate exists
        }
        catch {
            /* try next */
        }
    }
    const err = new Error(`@adapt-toolkit/sdk-native: no native binding for ${platformArch}. ` +
        'Currently shipped prebuilds: linux-x64. ' +
        'On other platforms the @adapt-toolkit/sdk package should fall back to the WASM backend.');
    err.code = ERR_ADAPT_NO_PREBUILD;
    throw err;
})();
const AddonTypes = {
    AdaptEnvironment: addon.AdaptEnvironment,
    AdaptValue: addon.AdaptValue,
    AdaptEvaluationUnit: addon.AdaptEvaluationUnit,
    AdaptPacketContext: addon.AdaptPacketContext,
};
function loadNativeAddon() {
    const platformArch = `${process.platform}-${process.arch}`;
    // Adding support for a new architecture is intentionally trivial: drop a
    // prebuilt `adapt_js.node` into `prebuilds/<platform>-<arch>/` and ship it
    // in the tarball via the package's `files` array. The lookup below is
    // ordered: a shipped prebuild wins; the legacy in-tree build path is kept
    // as a development fallback so contributors who just ran `node-gyp rebuild`
    // can still load their fresh artefact without staging it.
    const candidates = [
        `../prebuilds/${platformArch}/adapt_js.node`,
        `../build/Release/adapt_js.node`,
    ];
    const errors = [];
    for (const rel of candidates) {
        try {
            return require(rel);
        }
        catch (err) {
            errors.push(err);
        }
    }
    const err = new Error(`@adapt-toolkit/sdk-native: no native binding for ${platformArch}. ` +
        'Currently shipped prebuilds: linux-x64. ' +
        'On other platforms the @adapt-toolkit/sdk package should fall back to the WASM backend.');
    err.code = ERR_ADAPT_NO_PREBUILD;
    err.cause = errors[0];
    throw err;
}
let AdaptEnvironment = class AdaptEnvironment {
    static { AdaptEnvironment_1 = this; }
    /** @ignore */
    static adapt = undefined;
    /** @ignore */
    constructor() { }
    static DetermineEnvironment = () => {
        if (process.env.ADAPT_NITRO_BUILD)
            return 'nitro';
        return 'native';
    };
    /**
     * Asynchronously initialise ADAPT in either test or release mode.
     *
     * @param test_mode true to initialise in test mode
     */
    static InitializeAsync = async (test_mode) => {
        AdaptEnvironment_1.adapt = loadNativeAddon();
        if (!AdaptEnvironment_1.adapt.Initialize(test_mode)) {
            throw new Error('Failed to invoke initializer in ADAPT environment');
        }
    };
    /**
     * Synchronously initialise ADAPT.
     *
     * @returns true if initialisation succeeded
     */
    static Initialize(test_mode) {
        AdaptEnvironment_1.adapt = loadNativeAddon();
        return AdaptEnvironment_1.adapt.Initialize(test_mode);
    }
    /**
     * Throw if ADAPT has not been initialised.
     */
    static Check() {
        if (this.adapt === undefined) {
            throw new Error('ADAPT environment not initialized');
        }
    }
    /**
     * Create an empty packet that does not carry compiled MUFL code.
     *
     * @param lt lifetime; if undefined, caller is responsible for Destroy()
     * @param secure if true, in-packet primitive calls are forbidden
     */
    static EmptyPacket(lt, secure) {
        if (!AdaptEnvironment_1.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        return new AdaptPacketContext(lt, AdaptEnvironment_1.adapt.EmptyPacket(secure));
    }
    /**
     * Create an ADAPT packet from a loaded MUFL evaluation unit.
     */
    static CreatePacket(lt, unit, seed_phrase, entropy, secure, init_arg) {
        if (!AdaptEnvironment_1.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        return new AdaptPacketContext(lt, AdaptEnvironment_1.adapt.CreatePacket(unit.unit, seed_phrase, entropy, AdaptEnvironment_1.SystemTime(lt).value, secure, new AdaptValue(lt, init_arg).value));
    }
    /**
     * AdaptValue of domain TIME representing the current system time.
     */
    static SystemTime(lt) {
        if (!AdaptEnvironment_1.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        return new AdaptValue(lt, AdaptEnvironment_1.adapt.SystemTime());
    }
    /**
     * Parse a timestamp formatted as `YYYY-MM-DD hh:mm:ss[.nnnnnnnnn] (UTC[+x])`.
     */
    static ParseTime(lt, time) {
        if (!AdaptEnvironment_1.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        return new AdaptValue(lt, AdaptEnvironment_1.adapt.ParseTime(time));
    }
    /**
     * Cryptographically secure random bytes as an AdaptValue of domain BINARY.
     */
    static GetRandomBytes(lt, length) {
        if (!AdaptEnvironment_1.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        return new AdaptValue(lt, AdaptEnvironment_1.adapt.GetRandomBytes(length));
    }
    /**
     * Drain the ADAPT-internal stdout buffer and return its contents.
     */
    static getStdoutContents() {
        if (!AdaptEnvironment_1.adapt) {
            throw new Error("ADAPT environment wasn't initialized (getStdoutContents).");
        }
        return AdaptEnvironment_1.adapt.GetStdoutContents();
    }
    /**
     * Drain the ADAPT-internal stderr buffer and return its contents.
     */
    static getStderrContents() {
        if (!AdaptEnvironment_1.adapt) {
            throw new Error("ADAPT environment wasn't initialized (getStderrContents).");
        }
        return AdaptEnvironment_1.adapt.GetStderrContents();
    }
};
AdaptEnvironment = AdaptEnvironment_1 = __decorate([
    staticImplements()
], AdaptEnvironment);
export { AdaptEnvironment };
/**
 * A compiled MUFL application loaded from a `.muflo` binary file or buffer.
 * Same memory-management contract as {@link AdaptPacketContext} and {@link AdaptValue}.
 */
let AdaptEvaluationUnit = class AdaptEvaluationUnit extends AdaptObject {
    static { AdaptEvaluationUnit_1 = this; }
    /** @ignore */
    unit;
    /** @ignore */
    constructor(lt, unit) {
        if (!AdaptEnvironment.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        super(lt);
        if (AdaptEnvironment.adapt.IsAdaptEvaluationUnit(unit)) {
            this.unit = unit;
        }
        else {
            throw new Error('Invalid AdaptEvaluationUnit constructor parameter');
        }
    }
    /** @ignore */
    ManagedObjects() {
        return [this.unit];
    }
    Clone(lifetime) {
        return new AdaptEvaluationUnit_1(lifetime, this.unit.Clone());
    }
    /**
     * Load a compiled MUFL application from a `.muflo` file.
     */
    static LoadFromFile = (lt, fileName) => {
        if (!AdaptEnvironment.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        return new AdaptEvaluationUnit_1(lt, AdaptEnvironment.adapt.AdaptEvaluationUnit.LoadFromFile(fileName));
    };
    /**
     * Load a compiled MUFL application from raw binary contents.
     */
    static LoadFromContents = (lt, contents) => {
        if (!AdaptEnvironment.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        return new AdaptEvaluationUnit_1(lt, AdaptEnvironment.adapt.AdaptEvaluationUnit.LoadFromContents(asBuffer(contents)));
    };
};
AdaptEvaluationUnit = AdaptEvaluationUnit_1 = __decorate([
    staticImplements()
], AdaptEvaluationUnit);
export { AdaptEvaluationUnit };
/**
 * Wraps a MUFL value. Values must be destroyed via {@link AdaptValue.Destroy}
 * or attached to an {@link AdaptObjectLifetime} that owns their cleanup.
 */
export class AdaptValue extends AdaptObject {
    /** @ignore */
    value;
    constructor(lt, from) {
        if (!AdaptEnvironment.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        if (from instanceof AdaptValue) {
            super(lt);
            this.value = from.value.Clone();
        }
        else {
            super(lt);
            if (AdaptEnvironment.adapt.IsAdaptValue(from)) {
                this.value = from;
            }
            else {
                this.value = new AdaptEnvironment.adapt.AdaptValue(from);
            }
        }
    }
    /** @ignore */
    ManagedObjects() {
        return [this.value];
    }
    Visualize() {
        return this.value.Visualize();
    }
    Serialize() {
        return this.value.Serialize();
    }
    GetHash() {
        return new AdaptValue(this.lifetime, this.value.GetHash());
    }
    Reduce(reducer) {
        return AdaptValue.execute_and_collect_garbage((lt) => {
            return new AdaptValue(this.lifetime, this.value.Reduce(new AdaptValue(lt, reducer).value));
        });
    }
    Mutate(reducer, product) {
        return AdaptValue.execute_and_collect_garbage((lt) => {
            return new AdaptValue(this.lifetime, this.value.Mutate(new AdaptValue(lt, reducer).value, new AdaptValue(lt, product).value));
        });
    }
    GetPacket() {
        return new AdaptPacketContext(this.lifetime, this.value.GetPacket());
    }
    GetNumber() {
        return this.value.GetNumber();
    }
    GetBoolean() {
        return this.value.GetBoolean();
    }
    GetBinary() {
        return this.value.GetBinary();
    }
    IsNil() {
        return this.value.IsNil();
    }
    Equals(rhs) {
        return AdaptValue.execute_and_collect_garbage((lt) => {
            return this.value.Equals(new AdaptValue(lt, rhs).value);
        });
    }
    Less(rhs) {
        return AdaptValue.execute_and_collect_garbage((lt) => {
            return this.value.Less(new AdaptValue(lt, rhs).value);
        });
    }
    Clone(lifetime) {
        return new AdaptValue(lifetime, this.value.Clone());
    }
    GetKeys() {
        return this.value.GetKeys().map((v) => new AdaptValue(this.lifetime, v));
    }
}
/**
 * The ADAPT packet context — a MUFL packet wrapped for use from TypeScript.
 */
let AdaptPacketContext = AdaptPacketContext_1 = class AdaptPacketContext extends AdaptObject {
    /** @ignore */
    packet;
    /** @ignore */
    constructor(lt, from) {
        if (!AdaptEnvironment.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        super(lt);
        if (AdaptEnvironment.adapt.IsAdaptPacketContext(from)) {
            this.packet = from;
        }
        else {
            throw new Error('Invalid constructor parameter for AdaptPacketContext');
        }
    }
    /** @ignore */
    ManagedObjects() {
        return [this.packet];
    }
    static LoadFromFile(lifetime, path) {
        if (!AdaptEnvironment.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        return new AdaptPacketContext_1(lifetime, AdaptEnvironment.adapt.AdaptPacketContext.LoadFromFile(path));
    }
    static LoadFromContents(lifetime, contents) {
        if (!AdaptEnvironment.adapt) {
            throw new Error("ADAPT environment wasn't initialized.");
        }
        return new AdaptPacketContext_1(lifetime, AdaptEnvironment.adapt.AdaptPacketContext.LoadFromContents(asBuffer(contents)));
    }
    Clone(lifetime) {
        return new AdaptPacketContext_1(lifetime, this.packet.Clone());
    }
    ParseValue(value) {
        return new AdaptValue(this.lifetime, this.packet.ParseValue(this.NewBinaryFromBuffer(value).value));
    }
    ParseValueFromJSON(json) {
        return new AdaptValue(this.lifetime, this.packet.ParseValueFromJSON(json));
    }
    CreateDictionary() {
        return new AdaptValue(this.lifetime, this.packet.CreateDictionary());
    }
    NewBinaryFromHex(hex) {
        return new AdaptValue(this.lifetime, this.packet.NewBinaryFromHex(hex));
    }
    NewBinaryFromBuffer(buffer) {
        return new AdaptValue(this.lifetime, this.packet.NewBinaryFromBuffer(asBuffer(buffer)));
    }
    ExecuteTransaction(envelope, entropy_hex, timestamp) {
        return AdaptValue.execute_and_collect_garbage((lt) => {
            let entropy = '';
            // Empty string is special-cased: ` || ` would otherwise treat it as
            // falsy and trigger random-byte generation, masking caller intent.
            if (entropy_hex !== '')
                entropy = entropy_hex || AdaptEnvironment.GetRandomBytes(lt, 256).Visualize().substring(2);
            const time = timestamp ?? AdaptEnvironment.SystemTime(lt);
            return new AdaptValue(this.lifetime, this.packet.ExecuteTransaction(new AdaptValue(lt, envelope).value, entropy, new AdaptValue(lt, time).value));
        });
    }
    ExecuteFunction(func_name, args = [null]) {
        const arglist = (Array.isArray(args) ? args : [args]);
        return AdaptValue.execute_and_collect_garbage((lt) => {
            return new AdaptValue(this.lifetime, this.packet.ExecuteFunction(func_name, arglist.map((val) => new AdaptValue(lt, val).value)));
        });
    }
    GetHash() {
        return new AdaptValue(this.lifetime, this.packet.GetHash());
    }
    GetContainerID() {
        return new AdaptValue(this.lifetime, this.packet.GetContainerID());
    }
    GetCodeID() {
        return new AdaptValue(this.lifetime, this.packet.GetCodeID());
    }
    Serialize() {
        return this.packet.Serialize();
    }
    SaveToFile(_path) {
        throw new Error('Not implemented');
    }
    TransactionsList() {
        return this.packet.TransactionsList();
    }
    Nil() {
        return new AdaptValue(this.lifetime, this.packet.NilObject());
    }
};
AdaptPacketContext = AdaptPacketContext_1 = __decorate([
    staticImplements()
], AdaptPacketContext);
export { AdaptPacketContext };
function asBuffer(data) {
    return Buffer.isBuffer(data) ? data : Buffer.from(data);
}
//# sourceMappingURL=adapt.js.map