/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { IsoBuffer } from "@fluid-internal/client-utils";
import type { Static, TAnySchema, TSchema } from "@sinclair/typebox";
import { JsonCompatibleReadOnly } from "../util";
/**
 * @alpha
 */
export interface IEncoder<TDecoded, TEncoded> {
    /**
     * Encodes `obj` into some encoded format. Typically paired with an {@link IDecoder}.
     */
    encode(obj: TDecoded): TEncoded;
}
/**
 * @alpha
 */
export interface IDecoder<TDecoded, TEncoded> {
    /**
     * Decodes `obj` from some encoded format. Typically paired with an {@link IEncoder}.
     */
    decode(obj: TEncoded): TDecoded;
}
/**
 * Validates data complies with some particular schema.
 * Implementations are typically created by a {@link JsonValidator}.
 * @alpha
 */
export interface SchemaValidationFunction<Schema extends TSchema> {
    /**
     * @returns Whether the data matches a schema.
     */
    check(data: unknown): data is Static<Schema>;
}
/**
 * JSON schema validator compliant with draft 6 schema. See https://json-schema.org.
 * @alpha
 */
export interface JsonValidator {
    /**
     * Compiles the provided JSON schema into a validator for that schema.
     * @param schema - A valid draft 6 JSON schema
     * @remarks Fluid handles--which have circular property references--are used in various places in the persisted
     * format. Handles should only be contained in sections of data which are validated against the empty schema `{}`
     * (see https://datatracker.ietf.org/doc/html/draft-wright-json-schema-01#section-4.4).
     *
     * Implementations of `JsonValidator` must therefore tolerate these values, despite the input not being valid JSON.
     */
    compile<Schema extends TSchema>(schema: Schema): SchemaValidationFunction<Schema>;
}
/**
 * Options relating to handling of persisted data.
 * @alpha
 */
export interface ICodecOptions {
    /**
     * JSON Validator which should be used to validated persisted data SharedTree handles.
     * See {@link noopValidator} and {@link typeboxValidator} for out-of-the-box implementations.
     *
     * SharedTree users are encouraged to use a non-trivial validator (i.e. not `noopValidator`) whenever
     * reasonable: it gives better fail-fast behavior when unexpected encoded data is found, which reduces
     * the risk of further data corruption.
     */
    readonly jsonValidator: JsonValidator;
}
/**
 * @alpha
 * @remarks `TEncoded` should always be valid Json (i.e. not contain functions), but due to TypeScript's handling
 * of index signatures and `JsonCompatibleReadOnly`'s index signature in the Json object case, specifying this as a
 * type-system level constraint makes code that uses this interface more difficult to write.
 */
export interface IJsonCodec<TDecoded, TEncoded = JsonCompatibleReadOnly> extends IEncoder<TDecoded, TEncoded>, IDecoder<TDecoded, TEncoded> {
    encodedSchema?: TAnySchema;
}
/**
 * @remarks TODO: We might consider using DataView or some kind of writer instead of IsoBuffer.
 * @alpha
 */
export interface IBinaryCodec<TDecoded> extends IEncoder<TDecoded, IsoBuffer>, IDecoder<TDecoded, IsoBuffer> {
}
/**
 * Contains knowledge of how to encode some in-memory type into JSON and binary formats,
 * as well as how to decode those representations.
 *
 * @remarks Codecs are typically used in shared-tree to convert data into some persisted format.
 * For this common use case, any format for encoding that was ever actually used needs to
 * be supported for decoding in all future code versions.
 *
 * Using an {@link ICodecFamily} is the recommended strategy for managing this support, keeping in
 * mind evolution of encodings over time.
 *
 * @alpha
 */
export interface IMultiFormatCodec<TDecoded, TJsonEncoded extends JsonCompatibleReadOnly = JsonCompatibleReadOnly> {
    json: IJsonCodec<TDecoded, TJsonEncoded>;
    binary: IBinaryCodec<TDecoded>;
    /** Ensures multi-format codecs cannot also be single-format codecs. */
    encode?: never;
    /** Ensures multi-format codecs cannot also be single-format codecs. */
    decode?: never;
}
/**
 * Represents a family of codecs that can be used to encode and decode data in different formats.
 * The family is identified by a format version, which is typically used to select the codec to use.
 *
 * Separating codecs into families rather than having a single codec support multiple versions (i.e. currying
 * the `formatVersion` parameter)
 * allows avoiding some duplicate work at encode/decode time, since the vast majority of document usage will not
 * involve mixed format versions.
 * @alpha
 */
export interface ICodecFamily<TDecoded> {
    /**
     * @returns a codec that can be used to encode and decode data in the specified format.
     * @throws - if the format version is not supported by this family.
     * @remarks Implementations should typically emit telemetry (either indirectly by throwing a well-known error with
     * logged properties or directly using some logger) when a format version is requested that is not supported.
     * This ensures that applications can diagnose compatibility issues.
     */
    resolve(formatVersion: number): IMultiFormatCodec<TDecoded>;
    /**
     * @returns an iterable of all format versions supported by this family.
     */
    getSupportedFormats(): Iterable<number>;
}
/**
 * Creates a codec family from a registry of codecs.
 * Any codec that is not a {@link IMultiFormatCodec} will be wrapped with a default binary encoding.
 */
export declare function makeCodecFamily<TDecoded>(registry: Iterable<[
    formatVersion: number,
    codec: IMultiFormatCodec<TDecoded> | IJsonCodec<TDecoded>
]>): ICodecFamily<TDecoded>;
/**
 * Constructs a {@link IMultiFormatCodec} from a `IJsonCodec` using a generic binary encoding that simply writes
 * the json representation of the object to a buffer.
 */
export declare function withDefaultBinaryEncoding<TDecoded>(jsonCodec: IJsonCodec<TDecoded>): IMultiFormatCodec<TDecoded>;
/**
 * Ensures that the provided single or multi-format codec has a binary encoding.
 * Adapts the json encoding using {@link withDefaultBinaryEncoding} if necessary.
 */
export declare function ensureBinaryEncoding<TDecoded>(codec: IMultiFormatCodec<TDecoded> | IJsonCodec<TDecoded>): IMultiFormatCodec<TDecoded>;
/**
 * Codec for objects which carry no information.
 */
export declare const unitCodec: IMultiFormatCodec<0>;
/**
 * Creates a json codec for objects which are just a json compatible value
 * and can be serialized as-is.
 *
 * This type of encoding is only appropriate if the persisted type (which should be defined in a persisted format file)
 * happens to be convenient for in-memory usage as well.
 *
 * @remarks Beware that this API can cause accidental extraneous data in the persisted format.
 * Consider the following example:
 * ```typescript
 * interface MyPersistedType {
 *     foo: string;
 *     id: number;
 * }
 * const MyPersistedType = Type.Object({
 *     foo: Type.String(),
 *     id: Type.Number()
 * });
 *
 * const codec = makeValueCodec<MyPersistedType>();
 *
 * // Later, in some other file...
 * interface SomeInMemoryType extends MyPersistedType {
 *     someOtherProperty: string;
 * }
 *
 * const someInMemoryObject: SomeInMemoryType = {
 *     foo:	"bar",
 *     id: 0,
 *     someOtherProperty: "this shouldn't be here and ends up in the persisted format"
 * }
 *
 * const encoded = codec.encode(someInMemoryObject);
 * ```
 * This all typechecks and passes at runtime, but the persisted format will contain the extraneous
 * `someOtherProperty` field.
 * It's unlikely a real-life example would be this simple, but the principle is the same.
 *
 * This issue can be avoided by using JSON schema that doesn't accept additional properties:
 *
 * ```typescript
 * const MyPersistedType = Type.Object({
 *     foo: Type.String(),
 *     id: Type.Number()
 * }, {
 *     additionalProperties: false
 * });
 * ```
 */
export declare function makeValueCodec<Schema extends TSchema>(schema: Schema, validator?: JsonValidator): IJsonCodec<Static<Schema>>;
/**
 * Wraps a codec with JSON schema validation for its encoded type.
 * @returns An {@link IJsonCodec} which validates the data it encodes and decodes matches the provided schema.
 */
export declare function withSchemaValidation<TInMemoryFormat, EncodedSchema extends TSchema, TEncodedFormat = JsonCompatibleReadOnly>(schema: EncodedSchema, codec: IJsonCodec<TInMemoryFormat, TEncodedFormat>, validator?: JsonValidator): IJsonCodec<TInMemoryFormat, TEncodedFormat>;
//# sourceMappingURL=codec.d.ts.map