UNPKG

@ueberbrot/effect-api-query

Version:

Type-safe TanStack Query utilities derived from Effect RPC and HTTP API contracts.

1,818 lines • 72.9 kB
import { CancelledError, experimental_streamedQuery, hashKey, replaceEqualDeep, skipToken, skipToken as skipToken$1 } from "@tanstack/query-core";
import { Array as Array$1, Cause, Duration, Effect, Exit, Function, Option, Order, Predicate, Pull, Result, Schema, SchemaAST, Scope, Stream } from "effect";
import { Rpc, RpcSchema } from "effect/rpc";
import { HttpApi, HttpApiSchema } from "effect/http-api";
//#region src/core/canonical-key.ts
const canonicalizeArray = (value, seen = /* @__PURE__ */ new WeakSet()) => {
	if (seen.has(value)) throw new TypeError("Key values must not contain cycles");
	seen.add(value);
	const copy = [];
	for (let index = 0; index < value.length; index += 1) {
		if (!Object.hasOwn(value, index)) throw new TypeError("Key values must not contain sparse arrays");
		copy.push(canonicalize(value[index], seen));
	}
	seen.delete(value);
	return Object.freeze(copy);
};
const canonicalizeObject = (value, seen) => {
	const prototype = Object.getPrototypeOf(value);
	if (prototype !== Object.prototype && prototype !== null) throw new TypeError("Key values must contain only plain objects");
	const copy = {};
	for (const key of Array$1.sort(Object.keys(value), Order.String)) {
		if (key === "__proto__" || key === "constructor") throw new TypeError("Key objects must not contain __proto__ or constructor properties");
		copy[key] = canonicalize(value[key], seen);
	}
	seen.delete(value);
	return Object.freeze(copy);
};
/** Copies strict JSON into the immutable representation used by keys and filters. */
const canonicalize = (value, seen = /* @__PURE__ */ new WeakSet()) => {
	if (value === null || Predicate.isString(value) || Predicate.isBoolean(value)) return value;
	if (Predicate.isNumber(value)) {
		if (!Number.isFinite(value)) throw new TypeError("Key values must contain only finite numbers");
		return Object.is(value, -0) ? 0 : value;
	}
	if (!Predicate.isObjectOrArray(value)) throw new TypeError("Key values must be JSON-safe");
	if (Array.isArray(value)) return canonicalizeArray(value, seen);
	if (seen.has(value)) throw new TypeError("Key values must not contain cycles");
	seen.add(value);
	return canonicalizeObject(value, seen);
};
//#endregion
//#region src/core/metadata-query.ts
const isStructuralSharing = (policy) => Predicate.isFunction(policy);
const shareQueryData = (previous, data, policy) => {
	if (policy === false) return data;
	if (isStructuralSharing(policy)) return policy(previous, data);
	return replaceEqualDeep(previous, data);
};
const fetchedPolicies = /* @__PURE__ */ new WeakMap();
const preserveMetadataPolicy = (previous, data) => {
	if (Predicate.isObject(previous) && Predicate.isObject(data)) {
		const policy = fetchedPolicies.get(previous);
		if (policy !== void 0) fetchedPolicies.set(data, policy);
	}
	return data;
};
const prepareMetadataExecution = (description, options, runPromiseExit, requestOptions, skipped) => {
	const hasLocalPolicy = Object.hasOwn(options, "structuralSharing");
	const localPolicy = options["structuralSharing"];
	if (!skipped) options["structuralSharing"] = (previous, data) => {
		const produced = Predicate.isObject(data) ? fetchedPolicies.get(data) : void 0;
		if (Predicate.isObject(data)) fetchedPolicies.delete(data);
		const shared = shareQueryData(previous, data, produced === void 0 ? localPolicy : produced.policy);
		return produced === void 0 ? shared : description.finalizeData(shared);
	};
	return (input) => async ({ client, queryKey, signal }) => {
		const policy = hasLocalPolicy ? localPolicy : client.defaultQueryOptions({ queryKey }).structuralSharing;
		const exit = await runPromiseExit(description.invoke(input, requestOptions), { signal });
		if (Exit.isFailure(exit)) throw description.executionError("metadata", exit.cause);
		const data = exit.value === void 0 ? null : exit.value;
		if (Predicate.isObject(data)) fetchedPolicies.set(data, { policy });
		return data;
	};
};
//#endregion
//#region src/core/prepared-input.ts
const values = /* @__PURE__ */ new WeakMap();
const owners = /* @__PURE__ */ new WeakMap();
const registerInputOwner = (key, input, encoder) => {
	owners.set(key, {
		input,
		encoder
	});
};
const inputKind = (key) => owners.get(key)?.input._tag;
const readPreparedInput = (owner, input) => {
	const prepared = Predicate.isObject(input) ? values.get(input) : void 0;
	if (prepared !== void 0 && prepared.owner !== owner) throw new TypeError("Prepared input belongs to another utility leaf");
	return prepared;
};
/** Constructs and encodes once for repeated keys/options on this utility leaf. */
const prepareInput = (leaf, input) => {
	const owner = owners.get(leaf.key);
	if (owner === void 0 || owner.input._tag === "Inputless") throw new TypeError("Prepared inputs require a generated input-bearing query leaf");
	const prepared = owner.input.prepare(input, owner.encoder);
	let keyValue;
	try {
		keyValue = canonicalize(prepared.keyValue);
	} catch (error) {
		throw owner.input.invalidKey(error);
	}
	const token = Object.freeze({ "~effect-api-query/PreparedInput": Object.freeze({}) });
	values.set(token, {
		owner: owner.input,
		input: prepared.input,
		keyValue
	});
	return token;
};
//#endregion
//#region src/core/utility-tree.ts
const reservedPathSegments = /* @__PURE__ */ new Set([
	"__proto__",
	"constructor",
	"infiniteKey",
	"infiniteOptions",
	"key",
	"liveKey",
	"liveOptions",
	"metadataKey",
	"metadataOptions",
	"mutationKey",
	"mutationOptions",
	"prototype",
	"queryKey",
	"queryOptions",
	"streamedKey",
	"streamedOptions"
]);
const freezeKey = (parts) => Object.freeze(parts);
const normalizePrefix = (prefix, errors) => {
	if (!Array.isArray(prefix) || prefix.length === 0) throw errors.invalidPrefix("Shape");
	try {
		return canonicalizeArray(prefix);
	} catch (error) {
		throw errors.invalidPrefix("Value", error);
	}
};
const planPaths = (operations, errors) => {
	const branchPaths = /* @__PURE__ */ new Map();
	const leafPaths = /* @__PURE__ */ new Set();
	const plan = [];
	for (const operation of operations) {
		const segments = operation.path;
		if (!Array$1.isReadonlyArrayNonEmpty(segments) || segments.some((segment) => segment.length === 0 || reservedPathSegments.has(segment))) throw errors.invalidPath(operation.id);
		const pathKey = JSON.stringify(segments);
		if (leafPaths.has(pathKey)) throw errors.pathCollision(operation.id, segments, "duplicates");
		const descendantPath = branchPaths.get(pathKey);
		if (descendantPath !== void 0) throw errors.pathCollision(operation.id, descendantPath, "collides with");
		const parents = [];
		for (let index = 1; index < segments.length; index += 1) {
			const parent = segments.slice(0, index);
			const parentKey = JSON.stringify(parent);
			if (leafPaths.has(parentKey)) throw errors.pathCollision(operation.id, parent, "collides with");
			parents.push(parentKey);
		}
		for (const parent of parents) if (!branchPaths.has(parent)) branchPaths.set(parent, segments);
		leafPaths.add(pathKey);
		plan.push({
			operation,
			segments
		});
	}
	return plan;
};
const execute = async (description, operation, input, runPromiseExit, requestOptions, signal) => {
	const exit = await runPromiseExit(description.invoke(input, requestOptions), signal === void 0 ? void 0 : { signal });
	if (Exit.isFailure(exit)) throw description.executionError(operation, exit.cause);
	return operation !== "mutation" && exit.value === void 0 ? null : exit.value;
};
const prepareQuery = (description, input, operationKey, keyEncoder, identity = []) => {
	if (description.input._tag === "Inputless") return {
		input: void 0,
		key: identity.length === 0 ? operationKey : freezeKey([...operationKey, ...identity])
	};
	const reused = readPreparedInput(description.input, input);
	const prepared = reused ?? description.input.prepare(input, keyEncoder);
	try {
		return {
			input: prepared.input,
			key: freezeKey([
				...operationKey,
				reused === void 0 ? canonicalize(prepared.keyValue) : reused.keyValue,
				...identity
			])
		};
	} catch (error) {
		throw description.input.invalidKey(error);
	}
};
const prepareQueryOptions = (description, argument) => {
	if (argument !== void 0 && !Predicate.isObject(argument)) throw new TypeError("Query options must be an object");
	const options = { ...argument };
	for (const option of ["queryKeyHashFn", "queryHash"]) if (Object.hasOwn(options, option)) throw description.unsupportedQueryHash(option);
	const { input } = options;
	delete options["input"];
	return {
		input,
		options,
		requestOptions: description.takeOptions(options)
	};
};
const finalizeQueryOptions = (options, queryKey, queryFn) => ({
	...options,
	queryFn,
	queryKey
});
const createQueryBuilders = (description, operationKey, keyEncoder, prepareOptions, prepareIdentity) => ({
	key: (input, policy) => {
		const options = description.input._tag === "Inputless" ? input : policy;
		const identity = prepareIdentity?.(Predicate.isObject(options) ? { ...options } : {}) ?? [];
		return prepareQuery(description, input, operationKey, keyEncoder, identity).key;
	},
	options: (argument) => {
		const { input, options, requestOptions } = prepareQueryOptions(description, argument);
		const { identity, makeQuery } = prepareOptions(options, requestOptions, input);
		if (description.input._tag !== "Inputless" && input === skipToken$1) return finalizeQueryOptions(options, operationKey, skipToken$1);
		const prepared = prepareQuery(description, input, operationKey, keyEncoder, identity);
		return finalizeQueryOptions(options, prepared.key, makeQuery(prepared.input));
	}
});
const createInfiniteBuilders = (description, operationKey, keyEncoder, runPromiseExit) => {
	const infiniteOperationKey = freezeKey([...operationKey, "infinite"]);
	const infiniteKey = (input) => prepareQuery(description, input, infiniteOperationKey, keyEncoder).key;
	const infiniteOptions = (argument) => {
		const { input, options, requestOptions } = prepareQueryOptions(description, argument);
		if (description.input._tag !== "Inputless" && input === skipToken$1) return finalizeQueryOptions(options, infiniteOperationKey, skipToken$1);
		const { initialPageParam } = options;
		const inputForPage = description.input._tag === "Inputless" ? () => void 0 : input;
		if (!Predicate.isFunction(inputForPage)) throw new TypeError("Infinite query input must be a page input function");
		const pageInput = inputForPage;
		const initialInput = pageInput(initialPageParam);
		const prepared = prepareQuery(description, initialInput, infiniteOperationKey, keyEncoder);
		return finalizeQueryOptions(options, prepared.key, async ({ pageParam, signal }) => {
			const pageRequest = pageInput(pageParam);
			const executionInput = description.input._tag === "Input" ? description.input.pageInput(pageRequest) : void 0;
			return execute(description, "infinite", executionInput, runPromiseExit, requestOptions, signal);
		});
	};
	return {
		infiniteKey,
		infiniteOptions
	};
};
const createMutationBuilders = (description, operationKey, runPromiseExit) => {
	const mutationKey = freezeKey([...operationKey, "mutation"]);
	const mutationOptions = (argument = {}) => {
		const options = { ...argument };
		const requestOptions = description.takeOptions(options);
		return {
			...options,
			mutationFn: async (variables) => execute(description, "mutation", variables, runPromiseExit, requestOptions),
			mutationKey
		};
	};
	return {
		mutationKey: () => mutationKey,
		mutationOptions
	};
};
const createUnaryBuilders = (description, operationKey, keyEncoder, runPromiseExit) => {
	const queryOperationKey = freezeKey([...operationKey, "query"]);
	const query = createQueryBuilders(description, queryOperationKey, keyEncoder, (_options, requestOptions) => ({
		identity: [],
		makeQuery: (input) => async ({ signal }) => execute(description, "query", input, runPromiseExit, requestOptions, signal)
	}));
	const { metadata } = description;
	const metadataQuery = metadata === void 0 ? void 0 : createQueryBuilders(description, freezeKey([...operationKey, "metadata"]), keyEncoder, (options, requestOptions, input) => ({
		identity: [],
		makeQuery: prepareMetadataExecution(metadata, options, runPromiseExit, requestOptions, description.input._tag !== "Inputless" && input === skipToken$1)
	}));
	return {
		...createInfiniteBuilders(description, operationKey, keyEncoder, runPromiseExit),
		...createMutationBuilders(description, operationKey, runPromiseExit),
		queryKey: query.key,
		queryOptions: query.options,
		...metadataQuery === void 0 ? void 0 : {
			metadataKey: metadataQuery.key,
			metadataOptions: metadataQuery.options
		}
	};
};
const createStreamingBuilders = (description, operationKey, keyEncoder, runPromiseExit) => {
	const createView = (operation) => {
		const prepare = (options, requestOptions) => description.prepareStream(options, operation, runPromiseExit, requestOptions);
		return createQueryBuilders(description, freezeKey([...operationKey, operation]), keyEncoder, prepare, (options) => prepare(options).identity);
	};
	const live = createView("live");
	const streamed = createView("streamed");
	return {
		liveKey: live.key,
		liveOptions: live.options,
		streamedKey: streamed.key,
		streamedOptions: streamed.options
	};
};
const deepFreezeTree = (value) => {
	for (const child of Object.values(value)) if (Predicate.isObject(child)) deepFreezeTree(child);
	return Object.freeze(value);
};
const validateKeyEncoders = (operations, keyEncoders, errors) => {
	const supportedIds = new Set(operations.filter((operation) => operation.kind !== "Mutation" && operation.input._tag !== "Inputless").map((operation) => operation.id));
	for (const id of keyEncoders.keys()) if (!supportedIds.has(id)) throw errors.unknownEncoder(id);
	for (const operation of operations) if (operation.kind !== "Mutation" && operation.input._tag === "Input" && operation.input.requiresEncoder && !Predicate.isFunction(keyEncoders.get(operation.id))) throw errors.missingEncoder(operation.id);
};
const insertLeaf = (tree, prefix, path, keyEncoder, runPromiseExit) => {
	const { segments } = path;
	const operation = path.operation.kind === "Mutation" ? path.operation : {
		...path.operation,
		input: { ...path.operation.input }
	};
	let branch = tree;
	for (let index = 0; index < segments.length - 1; index += 1) {
		const segment = segments[index];
		if (segment === void 0) throw new TypeError("Validated operation paths must have defined segments");
		const candidate = Object.hasOwn(branch, segment) ? branch[segment] : void 0;
		let child = Predicate.isObject(candidate) ? candidate : void 0;
		if (child === void 0) {
			const key = freezeKey([...prefix, ...segments.slice(0, index + 1)]);
			child = { key: () => key };
			branch[segment] = child;
		}
		branch = child;
	}
	const leafName = segments.at(-1);
	if (leafName === void 0) throw new TypeError("Validated operation paths must have a leaf");
	const operationKey = freezeKey([...prefix, ...segments]);
	let builders;
	if (operation.kind === "Mutation") builders = createMutationBuilders(operation, operationKey, runPromiseExit);
	else if (operation.kind === "Streaming") builders = createStreamingBuilders(operation, operationKey, keyEncoder, runPromiseExit);
	else builders = createUnaryBuilders(operation, operationKey, keyEncoder, runPromiseExit);
	const leaf = {
		key: () => operationKey,
		...builders
	};
	if (operation.kind !== "Mutation") registerInputOwner(leaf.key, operation.input, keyEncoder);
	branch[leafName] = leaf;
};
const createTree = (prefix, paths, keyEncoders, runPromiseExit) => {
	const tree = { key: () => prefix };
	for (const path of paths) insertLeaf(tree, prefix, path, keyEncoders.get(path.operation.id), runPromiseExit);
	return deepFreezeTree(tree);
};
const createUtilityTree = (operations, options) => {
	const prefix = freezeKey([...normalizePrefix(options.keyPrefix, options.errors), ...options.keyNamespace]);
	const paths = planPaths(operations, options.errors);
	validateKeyEncoders(operations, options.keyEncoders, options.errors);
	const runner = options.runPromiseExit ?? Effect.runPromiseExit;
	return createTree(prefix, paths, options.keyEncoders, runner);
};
//#endregion
//#region src/core/schema-key.ts
const safeAsts = /* @__PURE__ */ new WeakSet();
const encodings = /* @__PURE__ */ new WeakMap();
const inspectKeyEncoding = (value, seen) => {
	if (!Predicate.isObjectOrArray(value) || seen.has(value) || safeAsts.has(value)) return "Safe";
	seen.add(value);
	if (Predicate.hasProperty(value, "_tag") && value._tag === "Middleware") return !Predicate.hasProperty(value, "encode") || value.encode !== Function.identity ? "RequiresEncoder" : "Safe";
	if (SchemaAST.isAST(value)) {
		const representation = value.annotations?.["representation"];
		if (Predicate.hasProperty(representation, "id") && representation.id === "effect/schema/Redacted") return "RequiresEncoder";
		if (SchemaAST.isSuspend(value)) try {
			const analysis = inspectKeyEncoding(value.thunk(), seen);
			if (analysis !== "Safe") return analysis;
		} catch {
			return "Retry";
		}
	}
	for (const child of Object.values(value)) {
		const analysis = inspectKeyEncoding(child, seen);
		if (analysis !== "Safe") return analysis;
	}
	return "Safe";
};
const createSchemaKeyEncoding = (schema) => {
	const cached = encodings.get(schema);
	if (cached !== void 0) return cached;
	const seen = /* @__PURE__ */ new Set();
	const analysis = inspectKeyEncoding(schema.ast, seen);
	let defaultEncode;
	const encoding = {
		requiresEncoder: analysis !== "Safe",
		cacheable: analysis !== "Retry",
		encode: (input) => {
			if (defaultEncode === void 0) {
				const encodingSchema = schema;
				defaultEncode = Schema.encodeUnknownSync(encodingSchema);
			}
			return defaultEncode(input);
		}
	};
	if (analysis === "Safe") {
		for (const node of seen) if (SchemaAST.isAST(node)) safeAsts.add(node);
	}
	if (encoding.cacheable) encodings.set(schema, encoding);
	return encoding;
};
//#endregion
//#region src/rpc/errors.ts
/**
* Wraps a failed RPC Exit for TanStack while preserving its complete Effect Cause.
*
* Runner rejections pass through unchanged; this class wraps failed Exits.
*/
var EffectRpcQueryError = class extends Error {
	/** Identifies this error without relying on `instanceof`. */
	_tag = "EffectRpcQueryError";
	/** The literal tag of the RPC that failed. */
	rpcTag;
	/** The operation that ran the RPC. */
	operation;
	/** The original Cause returned by the Effect runner. */
	cause;
	constructor(rpcTag, operation, cause) {
		super(`RPC ${rpcTag} ${operation} failed`, { cause });
		this.name = "EffectRpcQueryError";
		this.rpcTag = rpcTag;
		this.operation = operation;
		this.cause = cause;
	}
};
/** Reports a live RPC stream that completed before emitting its first value. */
var EffectRpcQueryEmptyStreamError = class extends Error {
	/** Identifies this error without relying on `instanceof`. */
	_tag = "EffectRpcQueryEmptyStreamError";
	/** The streaming RPC that completed empty. */
	rpcTag;
	constructor(rpcTag) {
		super(`RPC ${rpcTag} live stream completed without a value`);
		this.name = "EffectRpcQueryEmptyStreamError";
		this.rpcTag = rpcTag;
	}
};
/** Reports invalid factory, builder, or stream cache configuration. */
var EffectRpcQueryConfigError = class extends Error {
	/** Identifies this error without relying on `instanceof`. */
	_tag = "EffectRpcQueryConfigError";
	/** A stable, machine-readable description of the failure. */
	code;
	/** The underlying failure, when one exists. */
	cause;
	/** The existing projected path associated with a collision. */
	path;
	/** The RPC or encoder tag associated with the invalid configuration. */
	rpcTag;
	constructor(code, message, options = {}) {
		super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
		this.name = "EffectRpcQueryConfigError";
		this.code = code;
		this.cause = options.cause;
		this.path = options.path;
		this.rpcTag = options.rpcTag;
	}
};
/** Reports synchronous payload construction, encoding, or canonicalization failures. */
var EffectRpcQueryKeyError = class extends Error {
	/** Identifies this error without relying on `instanceof`. */
	_tag = "EffectRpcQueryKeyError";
	/** A stable, machine-readable description of the failure. */
	code;
	/** The RPC whose query key could not be prepared. */
	rpcTag;
	/** The underlying failure, when one exists. */
	cause;
	constructor(code, rpcTag, message, cause) {
		super(message, cause === void 0 ? void 0 : { cause });
		this.name = "EffectRpcQueryKeyError";
		this.code = code;
		this.rpcTag = rpcTag;
		this.cause = cause;
	}
};
/** Returns whether a value is an RPC execution error from this JavaScript realm. */
const isEffectRpcQueryError = (value) => value instanceof EffectRpcQueryError;
//#endregion
//#region src/core/stream-hash-index.ts
const indexes = /* @__PURE__ */ new WeakMap();
const cacheIndex = (cache) => {
	const existing = indexes.get(cache);
	if (existing !== void 0) return existing;
	const index = {
		queries: /* @__PURE__ */ new Map(),
		groups: /* @__PURE__ */ new Map()
	};
	let nextOrder = 0;
	const remove = (queryHash) => {
		const previous = index.queries.get(queryHash);
		if (previous === void 0) return;
		const group = index.groups.get(previous.hash);
		group?.delete(queryHash);
		if (group?.size === 0) index.groups.delete(previous.hash);
		index.queries.delete(queryHash);
	};
	const update = (query) => {
		const previous = index.queries.get(query.queryHash);
		const hash = query.options.queryKeyHashFn;
		if (previous?.query === query && previous.hash === hash) return;
		remove(query.queryHash);
		const entry = {
			query,
			hash,
			order: previous?.query === query ? previous.order : nextOrder
		};
		if (previous?.query !== query) nextOrder += 1;
		index.queries.set(query.queryHash, entry);
		let group = index.groups.get(hash);
		if (group === void 0) {
			group = /* @__PURE__ */ new Map();
			index.groups.set(hash, group);
		}
		group.set(query.queryHash, entry);
	};
	for (const query of cache.getAll()) update(query);
	const unsubscribe = cache.subscribe((event) => {
		const query = cache.get(event.query.queryHash);
		if (query === void 0) remove(event.query.queryHash);
		else update(query);
		if (index.queries.size === 0) {
			unsubscribe();
			indexes.delete(cache);
		}
	});
	indexes.set(cache, index);
	return index;
};
const validateStreamHash = ({ client, queryKey }, unsupportedHash) => {
	const { queryHash, queryKeyHashFn } = client.defaultQueryOptions({ queryKey });
	if (queryHash !== (queryKeyHashFn ?? hashKey)(queryKey)) throw unsupportedHash();
	const cache = client.getQueryCache();
	const index = cacheIndex(cache);
	const current = cache.get(queryHash);
	const currentOrder = current === void 0 ? Infinity : index.queries.get(current.queryHash)?.order ?? Infinity;
	let canonical;
	for (const [hash, queries] of index.groups) {
		if (hash === queryKeyHashFn) continue;
		let candidate;
		try {
			candidate = queries.get((hash ?? hashKey)(queryKey));
		} catch (error) {
			for (const entry of queries.values()) if (entry.order < currentOrder) throw error;
			continue;
		}
		if (candidate === void 0 || candidate.query === current) continue;
		if (candidate.order < currentOrder) throw unsupportedHash();
		try {
			canonical ??= hashKey(queryKey);
			if (hashKey(candidate.query.queryKey) !== canonical) continue;
		} catch {
			continue;
		}
		throw unsupportedHash();
	}
	return current;
};
//#endregion
//#region src/core/stream-publication.ts
const streamPublicationBatches = async function* streamPublicationBatches(source, batchSize, signal, maxWaitMs) {
	const iterator = source[Symbol.asyncIterator]();
	let first = true;
	let pending = [];
	let pull;
	let timer;
	let deadline;
	let closing;
	const close = async () => {
		closing ??= (async () => {
			await iterator.return?.();
		})();
		await closing;
	};
	const onAbort = () => {
		close().catch(() => {});
	};
	signal.addEventListener("abort", onAbort, { once: true });
	const clearDeadline = () => {
		clearTimeout(timer);
		timer = void 0;
		deadline = void 0;
	};
	const pullNext = async () => {
		try {
			return {
				kind: "value",
				result: await iterator.next()
			};
		} catch (error) {
			return {
				kind: "error",
				error
			};
		}
	};
	const startDeadline = (milliseconds) => {
		deadline = new Promise((resolve) => {
			timer = setTimeout(() => {
				resolve("deadline");
			}, milliseconds);
		});
	};
	try {
		while (!signal.aborted) {
			pull ??= pullNext();
			const result = await (deadline === void 0 ? pull : Promise.race([pull, deadline]));
			if (result !== "deadline" && result.kind === "error") throw result.error;
			if (signal.aborted) return;
			if (result === "deadline") {
				const batch = pending;
				pending = [];
				clearDeadline();
				yield batch;
				continue;
			}
			pull = void 0;
			if (result.result.done === true) break;
			pending.push(result.result.value);
			if (first || pending.length === batchSize) {
				first = false;
				const batch = pending;
				pending = [];
				clearDeadline();
				yield batch;
			} else if (deadline === void 0 && maxWaitMs !== void 0) startDeadline(maxWaitMs);
		}
	} catch (error) {
		clearDeadline();
		if (pending.length > 0 && !signal.aborted) {
			yield pending;
			pending = [];
		}
		throw error;
	} finally {
		clearDeadline();
		signal.removeEventListener("abort", onAbort);
		await close();
		const remaining = await pull;
		if (remaining?.kind === "error") throw remaining.error;
	}
	if (pending.length > 0 && !signal.aborted) yield pending;
};
//#endregion
//#region src/core/streamed-query.ts
const validatePublicationDeadline = (publicationMaxWaitMs) => {
	if (publicationMaxWaitMs !== void 0 && (!Predicate.isNumber(publicationMaxWaitMs) || !Number.isSafeInteger(publicationMaxWaitMs) || publicationMaxWaitMs <= 0 || publicationMaxWaitMs > 2147483647)) throw new RangeError("publicationMaxWaitMs must be an integer from 1 to 2147483647");
};
const prepareStreamPolicy = (options, operation, invalid) => {
	let policy;
	if (operation === "streamed") {
		const { maxChunks, refetchMode = "reset", publicationBatchSize = 1, publicationMaxWaitMs } = options;
		if (maxChunks !== "unbounded" && (!Predicate.isNumber(maxChunks) || !Number.isSafeInteger(maxChunks) || maxChunks <= 0)) throw invalid("InvalidMaxChunks", "maxChunks must be a positive safe integer or 'unbounded'");
		if (refetchMode !== "reset" && refetchMode !== "append" && refetchMode !== "replace") throw invalid("InvalidRefetchMode", "refetchMode must be reset, append, or replace");
		if (!Predicate.isNumber(publicationBatchSize) || !Number.isSafeInteger(publicationBatchSize) || publicationBatchSize <= 0) throw new RangeError("publicationBatchSize must be a positive safe integer");
		validatePublicationDeadline(publicationMaxWaitMs);
		policy = {
			_tag: "Accumulated",
			maxChunks: maxChunks === "unbounded" ? void 0 : maxChunks,
			refetchMode,
			publicationBatchSize,
			publicationMaxWaitMs
		};
	} else policy = { _tag: "Live" };
	delete options["refetchMode"];
	delete options["maxChunks"];
	delete options["publicationBatchSize"];
	delete options["publicationMaxWaitMs"];
	return {
		policy,
		history: policy._tag === "Live" ? void 0 : {
			maxChunks: policy.maxChunks ?? null,
			refetchMode: policy.refetchMode,
			...policy.publicationBatchSize === 1 ? void 0 : { publicationBatchSize: policy.publicationBatchSize },
			...policy.publicationMaxWaitMs === void 0 ? void 0 : { publicationMaxWaitMs: policy.publicationMaxWaitMs }
		}
	};
};
const streamQueryIterable = (source, signal, emptyError) => ({ [Symbol.asyncIterator]() {
	const iterator = source[Symbol.asyncIterator]();
	let closePromise;
	let emitted = false;
	const detach = () => {
		signal.removeEventListener("abort", onAbort);
	};
	const close = async () => {
		closePromise ??= (async () => {
			try {
				return await iterator.return?.() ?? {
					done: true,
					value: void 0
				};
			} finally {
				detach();
			}
		})();
		return await closePromise;
	};
	const onAbort = () => {
		Promise.resolve().then(close).catch(detach);
	};
	signal.addEventListener("abort", onAbort, { once: true });
	return {
		async next() {
			let result;
			if (signal.aborted) result = await close();
			else try {
				result = await iterator.next();
			} catch (error) {
				detach();
				throw error;
			}
			if (result.done === true) {
				detach();
				if (!emitted && emptyError !== void 0) throw emptyError();
			}
			emitted = true;
			return result;
		},
		return: close,
		async throw(cause) {
			detach();
			if (iterator.throw !== void 0) return await iterator.throw(cause);
			await close();
			throw cause;
		}
	};
} });
const makeStreamQuery = ({ policy, source, executionError, unsupportedHash, emptyError, runPromiseExit }) => {
	const validateHash = (context) => validateStreamHash(context, unsupportedHash);
	const streamFn = async ({ signal }) => {
		const stream = Stream.unwrap(Effect.gen(function* consumeStream() {
			const scope = yield* Scope.make();
			yield* Effect.addFinalizer((exit) => Scope.close(scope, exit).pipe(Effect.catchCause((cause) => Effect.die(executionError(cause)))));
			const pull = yield* Stream.toPull(source).pipe(Scope.provide(scope));
			return Stream.fromPull(Effect.succeed(Effect.uninterruptibleMask((restore) => restore(pull).pipe(Effect.onError((cause) => Scope.close(scope, Pull.doneExitFromCause(cause))), Effect.catchCause((cause) => {
				const completion = Pull.filterDone(cause);
				if (Result.isFailure(completion) && (!signal.aborted || !Cause.hasInterruptsOnly(completion.failure))) return Effect.fail(executionError(completion.failure));
				return Effect.failCause(cause);
			})))));
		}));
		const exit = await runPromiseExit(Stream.toAsyncIterableEffect(stream), { signal });
		if (Exit.isFailure(exit)) throw executionError(exit.cause);
		return streamQueryIterable(exit.value, signal, policy._tag === "Live" ? emptyError : void 0);
	};
	if (policy._tag === "Live") {
		const queryFn = experimental_streamedQuery({
			initialValue: null,
			reducer: (_latest, value) => value === void 0 ? null : value,
			streamFn
		});
		return async (context) => {
			validateHash(context);
			return await queryFn(context);
		};
	}
	const { maxChunks, refetchMode, publicationBatchSize, publicationMaxWaitMs } = policy;
	return async (context) => {
		const query = validateHash(context);
		const reset = refetchMode === "reset" && query?.isFetched() === true;
		let emitted = false;
		const result = await experimental_streamedQuery({
			initialValue: [],
			reducer: (values, batch) => {
				const history = reset && !emitted ? [] : values;
				emitted = true;
				if (maxChunks === void 0) return [...history, ...batch];
				const start = Math.max(0, history.length + batch.length - maxChunks);
				const next = new Array(history.length + batch.length - start);
				for (let index = start; index < history.length + batch.length; index += 1) next[index - start] = index < history.length ? history[index] : batch[index - history.length];
				return next;
			},
			refetchMode,
			streamFn: async (streamContext) => streamPublicationBatches(await streamFn(streamContext), publicationBatchSize, streamContext.signal, publicationMaxWaitMs)
		})(context);
		return reset && !emitted ? [] : result;
	};
};
//#endregion
//#region src/rpc/streamed-query.ts
const createStreamPreparation = (rpc) => (options, operation, runPromiseExit, requestOptions) => {
	const { policy, history } = prepareStreamPolicy(options, operation, (code, message) => new EffectRpcQueryConfigError(code, message, { rpcTag: rpc.tag }));
	return {
		identity: history === void 0 ? [] : [Object.freeze(history)],
		makeQuery: (input) => makeStreamQuery({
			policy,
			source: Stream.suspend(() => rpc.invoke(input, requestOptions)),
			executionError: (cause) => new EffectRpcQueryError(rpc.tag, operation, cause),
			unsupportedHash: () => new EffectRpcQueryConfigError("UnsupportedQueryHash", "Stream queries require consistent QueryClient hashing", { rpcTag: rpc.tag }),
			emptyError: () => new EffectRpcQueryEmptyStreamError(rpc.tag),
			runPromiseExit
		})
	};
};
//#endregion
//#region src/rpc/operation.ts
const rpcInputs = /* @__PURE__ */ new WeakMap();
const compileRpcInput = (definition) => {
	const { payloadSchema, _tag: rpcTag } = definition;
	if (SchemaAST.isVoid(payloadSchema.ast)) return { _tag: "Inputless" };
	const keyEncoding = createSchemaKeyEncoding(payloadSchema);
	return {
		_tag: "Input",
		requiresEncoder: keyEncoding.requiresEncoder,
		cacheable: keyEncoding.cacheable,
		pageInput: (input) => payloadSchema.make(input),
		invalidKey: (cause) => new EffectRpcQueryKeyError("InvalidKeyValue", rpcTag, `The key payload for RPC ${rpcTag} is not JSON-safe`, cause),
		prepare: (input, encoder) => {
			let normalized;
			try {
				normalized = payloadSchema.make(input);
			} catch (error) {
				throw new EffectRpcQueryKeyError("PayloadConstructionFailed", rpcTag, `Could not construct the payload for RPC ${rpcTag}`, error);
			}
			let keyValue;
			try {
				keyValue = encoder ? encoder(normalized) : keyEncoding.encode(normalized);
			} catch (error) {
				throw new EffectRpcQueryKeyError(encoder ? "KeyEncoderFailed" : "PayloadEncodingFailed", rpcTag, `Could not encode the key payload for RPC ${rpcTag}`, error);
			}
			return {
				input: normalized,
				keyValue
			};
		}
	};
};
const createRpcInput = (definition) => {
	let input = rpcInputs.get(definition);
	if (input === void 0) {
		input = compileRpcInput(definition);
		if (input._tag === "Inputless" || input.cacheable) rpcInputs.set(definition, input);
	}
	return input;
};
const takeRpcOptions = (options) => {
	const { rpcOptions } = options;
	delete options["rpcOptions"];
	return rpcOptions;
};
const describeRpc = (definition, client) => {
	const rpcTag = definition._tag;
	const identity = {
		id: rpcTag,
		path: rpcTag.split("."),
		input: createRpcInput(definition),
		unsupportedQueryHash: (option) => new EffectRpcQueryConfigError("UnsupportedQueryHash", `${option} must be configured through QueryClient defaults`, { rpcTag }),
		takeOptions: takeRpcOptions
	};
	if (!RpcSchema.isStreamSchema(definition.successSchema)) {
		const invoke = client;
		return {
			...identity,
			kind: "Unary",
			invoke: (input, options) => invoke(rpcTag, input, options),
			executionError: (operation, cause) => new EffectRpcQueryError(rpcTag, operation, cause)
		};
	}
	const invoke = client;
	return {
		...identity,
		kind: "Streaming",
		prepareStream: createStreamPreparation({
			tag: rpcTag,
			invoke: (input, options) => invoke(rpcTag, input, options)
		})
	};
};
const extractRpcs = (group, client) => {
	if (!Predicate.hasProperty(group, "requests") || !Predicate.isMap(group.requests)) throw new TypeError("Expected an Effect RPC group with a request map");
	return Array.from(group.requests.values(), (value) => {
		if (!Rpc.isRpc(value)) throw new TypeError("Expected an Effect RPC declaration");
		return describeRpc(value, client);
	});
};
const rpcTreeErrors = {
	invalidPrefix: (reason, cause) => new EffectRpcQueryConfigError("InvalidKeyPrefix", reason === "Shape" ? "keyPrefix must be a non-empty readonly tuple of JSON-safe values" : "keyPrefix must contain only JSON-safe values", { cause }),
	invalidPath: (rpcTag) => new EffectRpcQueryConfigError("InvalidRpcPath", `RPC tag ${rpcTag} cannot be projected into a utility path`, { rpcTag }),
	pathCollision: (rpcTag, segments, relation) => {
		const path = segments.join(".");
		return new EffectRpcQueryConfigError("RpcPathCollision", `RPC tag ${rpcTag} ${relation} utility path ${path}`, {
			path,
			rpcTag
		});
	},
	unknownEncoder: (rpcTag) => new EffectRpcQueryConfigError("UnknownKeyEncoder", `No payload-bearing RPC exists for key encoder ${rpcTag}`, { rpcTag }),
	missingEncoder: (rpcTag) => new EffectRpcQueryConfigError("MissingKeyEncoder", `RPC ${rpcTag} requires a safe custom key encoder`, { rpcTag })
};
//#endregion
//#region src/rpc/create-utils.ts
/**
* Derives an eager, frozen TanStack Query utility tree from an Effect RPC group.
*
* Dotted RPC tags become nested properties with unary or streaming utility leaves.
* The caller retains ownership of the ready client's Scope and lifecycle.
*
* @throws {@link EffectRpcQueryConfigError} if the prefix, paths, or encoders are invalid.
*/
const createRpcQueryUtils = (group, options) => {
	const rpcs = extractRpcs(group, options.client);
	const runPromiseExit = options.runPromiseExit;
	return createUtilityTree(rpcs, {
		keyPrefix: options.keyPrefix,
		keyNamespace: ["rpc"],
		keyEncoders: new Map(Object.entries(options.keyEncoders ?? {})),
		runPromiseExit,
		errors: rpcTreeErrors
	});
};
//#endregion
//#region src/http/errors.ts
/** Preserves the complete failed Exit Cause with declaration-only metadata. */
var EffectHttpApiQueryError = class extends Error {
	_tag = "EffectHttpApiQueryError";
	apiId;
	groupId;
	endpoint;
	method;
	operation;
	cause;
	constructor(identity, operation, cause) {
		super(`HTTP ${identity.method} ${identity.groupId}/${identity.endpoint} ${operation} failed`, { cause });
		this.name = "EffectHttpApiQueryError";
		this.apiId = identity.apiId;
		this.groupId = identity.groupId;
		this.endpoint = identity.endpoint;
		this.method = identity.method;
		this.operation = operation;
		this.cause = cause;
	}
};
var EffectHttpApiQueryEmptyStreamError = class extends Error {
	_tag = "EffectHttpApiQueryEmptyStreamError";
	apiId;
	groupId;
	endpoint;
	method;
	operation = "live";
	constructor(identity) {
		super(`HTTP ${identity.method} ${identity.groupId}/${identity.endpoint} live stream completed without a value`);
		this.name = "EffectHttpApiQueryEmptyStreamError";
		this.apiId = identity.apiId;
		this.groupId = identity.groupId;
		this.endpoint = identity.endpoint;
		this.method = identity.method;
	}
};
/** Reports invalid factory, builder, or stream cache configuration. */
var EffectHttpApiQueryConfigError = class extends Error {
	_tag = "EffectHttpApiQueryConfigError";
	code;
	apiId;
	groupId;
	endpoint;
	method;
	path;
	cause;
	constructor(code, message, options) {
		super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
		this.name = "EffectHttpApiQueryConfigError";
		this.code = code;
		this.apiId = options.apiId;
		this.groupId = options.groupId;
		this.endpoint = options.endpoint;
		this.method = options.method;
		this.path = options.path;
		this.cause = options.cause;
	}
};
/** Reports synchronous request encoding and key canonicalization failures. */
var EffectHttpApiQueryKeyError = class extends Error {
	_tag = "EffectHttpApiQueryKeyError";
	code;
	apiId;
	groupId;
	endpoint;
	method;
	cause;
	constructor(code, identity, message, cause) {
		super(message, cause === void 0 ? void 0 : { cause });
		this.name = "EffectHttpApiQueryKeyError";
		this.code = code;
		this.apiId = identity.apiId;
		this.groupId = identity.groupId;
		this.endpoint = identity.endpoint;
		this.method = identity.method;
		this.cause = cause;
	}
};
/** Recognizes HTTP execution errors from this JavaScript realm. */
const isEffectHttpApiQueryError = (value) => value instanceof EffectHttpApiQueryError;
//#endregion
//#region src/http/request.ts
const multipartBrands = (schema) => {
	const brands = /* @__PURE__ */ new Set();
	const visited = /* @__PURE__ */ new WeakSet();
	let current = schema;
	while (Schema.isSchema(current) && !visited.has(current)) {
		visited.add(current);
		if (Predicate.hasProperty(current, "identifier") && (current.identifier === HttpApiSchema.MultipartTypeId || current.identifier === HttpApiSchema.MultipartStreamTypeId)) brands.add(current.identifier);
		current = Predicate.hasProperty(current, "schema") ? current.schema : void 0;
	}
	return brands;
};
const classifyEndpoint = (endpoint, identity) => {
	const payloads = [];
	let multipart = false;
	let multipartStream = false;
	for (const { encoding, schemas } of endpoint.payload.values()) for (const schema of schemas) {
		const brands = multipartBrands(schema);
		const buffered = brands.has(HttpApiSchema.MultipartTypeId);
		const streamed = brands.has(HttpApiSchema.MultipartStreamTypeId);
		const expectedBuffered = encoding._tag === "Multipart" && encoding.mode === "buffered";
		const expectedStreamed = encoding._tag === "Multipart" && encoding.mode === "stream";
		if (!(buffered === expectedBuffered && streamed === expectedStreamed)) throw new EffectHttpApiQueryConfigError("UnsupportedEndpointMetadata", `HTTP endpoint ${identity.groupId}/${identity.endpoint} has contradictory multipart metadata`, identity);
		multipart ||= expectedBuffered;
		multipartStream ||= expectedStreamed;
		payloads.push(schema);
	}
	if (multipartStream) return;
	const successes = [...endpoint.success];
	if (successes.filter((schema) => Predicate.hasProperty(HttpApiSchema.isWithHeaders(schema) ? schema.schema : schema, "~effect/http-api/HttpApiSchema/Stream")).length > 0) {
		const [success] = successes;
		const body = HttpApiSchema.isWithHeaders(success) ? success.schema : success;
		if (multipart || successes.length !== 1 || !Predicate.hasProperty(body, "_tag") || body._tag !== "StreamSse") return;
		return {
			kind: "Streaming",
			schemas: payloads
		};
	}
	return multipart ? { kind: "Mutation" } : {
		kind: "Unary",
		schemas: payloads
	};
};
const omitUndefined = (value, seen = /* @__PURE__ */ new WeakSet()) => {
	if (!Predicate.isObjectOrArray(value)) return value;
	if (seen.has(value)) throw new TypeError("Key values must not contain cycles");
	seen.add(value);
	let result = value;
	if (Array.isArray(value)) {
		let copy;
		for (let index = 0; index < value.length; index += 1) {
			if (!Object.hasOwn(value, index)) throw new TypeError("Key values must not contain sparse arrays");
			const item = value[index];
			const next = omitUndefined(item, seen);
			if (copy !== void 0) copy.push(next);
			else if (next !== item) {
				copy = Array.from({ length: index }, (_, offset) => value[offset]);
				copy.push(next);
			}
		}
		result = copy ?? value;
	} else if (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) {
		let copy;
		const entries = Object.entries(value);
		for (const [index, [name, item]] of entries.entries()) if (item === void 0) copy ??= entries.slice(0, index);
		else {
			const next = omitUndefined(item, seen);
			if (next !== item) copy ??= entries.slice(0, index);
			copy?.push([name, next]);
		}
		result = copy === void 0 ? value : Object.fromEntries(copy);
	}
	seen.delete(value);
	return result;
};
const normalizeRequestKey = (value) => {
	const request = omitUndefined(value);
	if (!Predicate.isObject(request)) throw new TypeError("Encoded HTTP requests must be objects");
	if (Predicate.isObject(request["headers"])) {
		const headers = Object.create(null);
		for (const [name, headerValue] of Object.entries(request["headers"])) {
			const lower = name.toLowerCase();
			if (Object.hasOwn(headers, lower) && JSON.stringify(headers[lower]) !== JSON.stringify(headerValue)) throw new TypeError("Encoded header names must not have conflicting values");
			headers[lower] = headerValue;
		}
		return {
			...request,
			headers
		};
	}
	return request;
};
const createHttpRequest = (endpoint, identity) => {
	const classified = classifyEndpoint(endpoint, identity);
	if (classified === void 0 || classified.kind === "Mutation") return classified;
	const payloads = classified.schemas;
	const fields = {};
	if (endpoint.params !== void 0) fields["params"] = endpoint.params;
	if (endpoint.query !== void 0) fields["query"] = endpoint.query;
	if (endpoint.headers !== void 0) fields["headers"] = endpoint.headers;
	if (payloads.length > 0) fields["payload"] = Schema.Union(payloads);
	if (Object.keys(fields).length === 0) return {
		kind: classified.kind,
		input: { _tag: "Inputless" }
	};
	const schema = Schema.Struct(fields);
	const keyEncoding = createSchemaKeyEncoding(schema);
	const invalidKey = (cause) => new EffectHttpApiQueryKeyError("InvalidKeyValue", identity, `The HTTP key for ${identity.groupId}/${identity.endpoint} is not JSON-safe`, cause);
	return {
		kind: classified.kind,
		input: {
			_tag: "Input",
			requiresEncoder: payloads.length > 1 || keyEncoding.requiresEncoder,
			cacheable: keyEncoding.cacheable,
			pageInput: (input) => input,
			invalidKey,
			prepare: (input, encoder) => {
				let keyValue;
				try {
					keyValue = encoder ? encoder(input) : keyEncoding.encode(input);
				} catch (error) {
					throw new EffectHttpApiQueryKeyError(encoder ? "KeyEncoderFailed" : "RequestEncodingFailed", identity, `Could not encode the HTTP key for ${identity.groupId}/${identity.endpoint}`, error);
				}
				try {
					return {
						input,
						keyValue: encoder ? keyValue : normalizeRequestKey(keyValue)
					};
				} catch (error) {
					throw invalidKey(error);
				}
			}
		}
	};
};
//#endregion
//#region src/http/streamed-query.ts
const decoderOptions = (identity, options) => {
	const { sseOptions } = options;
	const decoder = Predicate.isObject(sseOptions) ? sseOptions : void 0;
	const maxEventSize = decoder?.["maxEventSize"];
	const dispatchEmptyNamedEvents = decoder?.["dispatchEmptyNamedEvents"];
	const limit = maxEventSize === void 0 ? 10485760 : maxEventSize;
	if (!Predicate.isNumber(limit) || !Number.isSafeInteger(limit) || limit <= 0) throw new EffectHttpApiQueryConfigError("InvalidMaxEventSize", "sseOptions.maxEventSize must be a positive safe integer", identity);
	if (dispatchEmptyNamedEvents !== void 0 && !Predicate.isBoolean(dispatchEmptyNamedEvents)) throw new EffectHttpApiQueryConfigError("InvalidSseOptions", "sseOptions.dispatchEmptyNamedEvents must be a boolean", identity);
	return Object.freeze({
		maxEventSize: limit,
		dispatchEmptyNamedEvents: dispatchEmptyNamedEvents ?? false
	});
};
const createHttpStreamPreparation = (identity, invoke) => (options, operation, runPromiseExit) => {
	const { policy, history } = prepareStreamPolicy(options, operation, (code, message) => new EffectHttpApiQueryConfigError(code, message, identity));
	const sseOptions = decoderOptions(identity, options);
	delete options["sseOptions"];
	return {
		identity: [Object.freeze({
			...history,
			maxEventSize: sseOptions.maxEventSize,
			...sseOptions.dispatchEmptyNamedEvents === true ? { dispatchEmptyNamedEvents: true } : void 0
		})],
		makeQuery: (input) => makeStreamQuery({
			policy,
			source: Stream.unwrap(Effect.suspend(() => invoke(input, sseOptions)).pipe(Effect.map((response) => {
				if (Predicate.hasProperty(response, "body") && Predicate.hasProperty(response, "headers") && Stream.isStream(response.body)) return response.body.pipe(Stream.map((body) => HttpApiSchema.withHeaders({
					body,
					headers: response.headers
				})));
				if (!Stream.isStream(response)) throw new TypeError("HTTP SSE clients must return a Stream");
				return response;
			}))),
			executionError: (cause) => new EffectHttpApiQueryError(identity, operation, cause),
			unsupportedHash: () => new EffectHttpApiQueryConfigError("UnsupportedQueryHash", "Stream queries require consistent QueryClient hashing", identity),
			emptyError: () => new EffectHttpApiQueryEmptyStreamError(identity),
			runPromiseExit
		})
	};
};
//#endregion
//#region src/http/operation.ts
const freezeMetadata = (data) => {
	if (!Predicate.isObject(data)) return data;
	const { headers } = data;
	const snapshot = Predicate.isObject(headers) && (!Object.isFrozen(headers) || Object.getPrototypeOf(headers) !== Object.prototype) ? Object.freeze({ ...headers }) : headers;
	return Object.isFrozen(data) && snapshot === headers ? data : Object.freeze({
		...data,
		headers: snapshot
	});
};
const httpContracts = /* @__PURE__ */ new WeakMap();
const describeHttpEndpoints = (api) => {
	const cached = httpContracts.get(api);
	if (cached !== void 0) return cached;
	const descriptions = [];
	for (const group of Object.values(api.groups)) for (const endpoint of Object.values(group.endpoints)) {
		const identity = {
			apiId: api.identifier,
			groupId: group.identifier,
			endpoint: endpoint.identifier,
			method: endpoint.method
		};
		const request = createHttpRequest(endpoint, identity);
		if (request === void 0) continue;
		descriptions.push({
			identity,
			topLevel: group.topLevel,
			request
		});
	}
	if (descriptions.every(({ request }) => request.kind === "Mutation" || request.input._tag === "Inputless" || request.input.cacheable)) httpContracts.set(api, descriptions);
	return descriptions;
};
const extractHttpEndpoints = (api, client) => {
	const operations = [];
	for (const { identity, topLevel, request } of describeHttpEndpoints(api)) {
		let target = client;
		if (!topLevel) target = Predicate.hasProperty(client, identity.groupId) ? client[identity.groupId] : void 0;
		const invoke = (requestInput, responseMode, sseOptions) => {
			const method = Predicate.hasProperty(target, identity.endpoint) ? target[identity.endpoint] : void 0;
			if (method === void 0) throw new TypeError(`Missing HTTP client endpoint ${identity.endpoint}`);
			return method.bind(target)({
				...Predicate.isObject(requestInput) ? requestInput : void 0,
				responseMode,
				...sseOptions === void 0 ? void 0 : { sseOptions }
			});
		};
		const common = {
			identity,
			id: JSON.stringify([identity.groupId, identity.endpoint]),
			path: topLevel ? [identity.endpoint] : [identity.groupId, identity.endpoint],
			unsupportedQueryHash: (option) => new EffectHttpApiQueryConfigError("UnsupportedQueryHash", `${option} must be configured through QueryClient defaults`, identity),
			takeOptions: () => null
		};
		if (request.kind === "Streaming") operations.push({
			...common,
			...request,
			kind: "Streaming",
			prepareStream: createHttpStreamPreparation(identity, (requestInput, sseOptions) => invoke(requestInput, "decoded-only", sseOptions))
		});
		else operations.push({
			...common,
			...request,
			invoke: (requestInput) => invoke(requestInput, "decoded-only"),
			...request.kind === "Unary" ? { metadata: {
				invoke: (requestInput) => Effect.map(invoke(requestInput, "decoded-and-response"), ([data, response]) => freezeMetadata({
					data: data === void 0 ? null : data,
					status: response.status,
					headers: response.headers
				})),
				executionError: (operation, cause) => new EffectHttpApiQueryError(identity, operation, cause),
				finalizeData: freezeMetadata
			} } : void 0,
			executionError: (operation, cause) => new EffectHttpApiQueryError(identity, operation, cause)
		});
	}
	return operations;
};
const httpTreeErrors = (api, operations) => {
	const identities = new Map(operations.map((operation) => [operation.id, operation.identity]));
	const identity = (id) => identities.get(id) ?? { apiId: api.identifier };
	return {
		invalidPrefix: (reason, cause) => new EffectHttpApiQueryConfigError("InvalidKeyPrefix", reason === "Shape" ? "keyPrefix must be a non-empty readonly tuple of JSON-safe values" : "keyPrefix must contain only JSON-safe values", {
			apiId: api.identifier,
			cause
		}),
		invalidPath: (id) => new EffectHttpApiQueryConfigError("InvalidEndpointPath", `HTTP endpoint ${id} cannot be projected into a utility path`, identity(id)),
		pathCollision: (id, path, relation) => new EffectHttpApiQueryConfigError("EndpointPathCollision", `HTTP endpoint ${id} ${relation} utility path ${JSON.stringify(path)}`, {
			...identity(id),
			path
		}),
		unknownEncoder: (id) => new EffectHttpApiQueryConfigError("UnknownKeyEncoder", `No query-enabled HTTP endpoint exists for key encoder ${id}`, identity(id)),
		missingEncoder: (id) => new EffectHttpApiQueryConfigError("MissingKeyEncoder", `HTTP endpoint ${id} requires a safe custom key encoder`, identity(id))
	};
};
const compileHttpOperations = (api, client, suppliedEncoders) => {
	const operations = extractHttpEndpoints(api, client);
	const errors = httpTreeErrors(api, operations);
	const encoderGroups = new Set(operations.filter((operation) => operation.kind !== "Mutation" && operation.input._tag === "Input").map((operation) => operation.identity.groupId));
	const keyEncoders = /* @__PURE__ */ new Map();
	for (const [groupId, endpoints] of Object.entries(Predicate.isObject(suppliedEncoders) ? suppliedEncoders : {})) {
		if (!encoderGroups.has(groupId)) throw errors.unknownEncoder(JSON.stringify([groupId]));
		if (!Predicate.isObject(endpoints)) throw new TypeError("HTTP key encoders must be grouped by endpoint");
		for (const [endpoint, encoder] of Object.entries(endpoints)) keyEncoders.set(JSON.stringify([groupId, endpoint]), encoder);
	}
	return {
		operations,
		errors,
		keyEncoders
	};
};
//#endregion
//#region src/http/create-utils.ts
const createHttpApiQueryUtils = (api, options) => {
	if (!HttpApi.isHttpApi(api)) throw new TypeError("Expected an Effect HttpApi declaration");
	const { operations, errors, keyEncoders } = compileHttpOperations(api, options.client, options.keyEncoders);
	const runPromiseExit = options.runPromiseExit;
	return createUtilityTree(operations, {
		keyPrefix: options.keyPrefix,
		keyNamespace: ["http", api.identifier],
		keyEncoders,
		runPromiseExit,
		errors
	});
};
//#endregion
//#region src/core/stream-snapshot.ts
const validateSnapshotControls = (options, timeoutMs) => {
	if (Object.hasOwn(options, "queryHash") || Object.hasOwn(options, "queryKeyHashFn")) throw new TypeError("Stream snapshots inherit hashing from QueryClient defaults");
	if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647) throw new RangeError("timeoutMs must be positive and at most 2147483647");
};
const fetchStreamSnapshot = async (queryClient, options, { mode = "fresh", signal, timeoutMs = 1e4 } = {}) => {
	signal?.throwIfAborted();
	validateSnapshotControls(options, timeoutMs);
	if (!Predicate.isFunction(options.queryFn)) throw new TypeError("Stream snapshots require a callable query function");
	const cache = queryClient.getQueryCache();
	const { queryHash } = queryClient.defaultQueryOptions(options);
	const existing = cache.get(queryHash);
	if (mode === "cached" && existing?.state.status === "success") return await queryClient.query({
		...options,
		queryHash,
		staleTime: "static"
	});
	if (existing !== void 0 && (existing.state.fetchStatus !== "idle" || existing.getObserversCount() > 0)) throw new Error("Stream snapshots require an idle query without observers");
	let published = false;
	let started = false;
	let executionSignal;
	let failed = false;
	let failure;
	let cleanup = Promise.resolve();
	let cancellation;
	const cancel = async () => {
		cancellation ??= queryClient.cancelQueries({ predicate: (query) => query.queryHash === queryHash });
		await cancellation;
	};
	let ready;
	let rejectPublication;
	const publication = new Promise((resolve, reject) => {
		ready = resolve;
		rejectPublication = reject;
	});
	const stop = cache.subscribe((event) => {
		if (event.query.queryHash === queryHash && event.type === "updated" && event.action.type === "success" && event.action.manual === true) {
			published = true;
			ready();
			cancel();
		}
	});
	const onAbort = () => {
		rejectPublication(signal?.reason);
	};
	signal?.addEventListener("abort", onAbort, { once: true });
	const timer = setTimeout(() => {
		rejectPublication(new DOMException("Stream snapshot timed out", "TimeoutError"));
	}, timeoutMs);
	let result;
	try {
		queryClient.invalidateQueries({
			predicate: (query) => query.queryHash === queryHash,
			refetchType: "none"
		});
		signal?.throwIfAborted();
		const fetching = queryClient.query({
			...options,
			queryHash,
			staleTime: 0,
			initialDataUpdatedAt: 0,
			queryFn: async (context) => {
				started = true;
				failed = false;
				failure = void 0;
				executionSignal = context.signal;
				let finished;
				cleanup = new Promise((resolve) => {
					finished = resolve;
				});
				try {
					return await options.queryFn(context);
				} catch (error) {
					failed = true;
					failure = error;
					throw error;
				} finally {
					finished();
				}
			}
		});
		await Promise.race([publication, fetching]);
		result = await fetching;
		if (!published && (!started || executionSignal?.aborted === true)) throw new CancelledError({ revert: true });
	} finally {
		stop();
		clearTimeout(timer);
		signal?.removeEventListener("abort", onAbort);
		await cancel();
		await cleanup;
	}
	if (failed) throw failure;
	return result;
};
//#endregion
//#region src/core/view-prefix.ts
/** Selects every input and stream policy for one leaf's query view. */
const viewPrefix = (leaf, view) => Object.freeze([...leaf.key(), view]);
//#endregion
//#region src/core/query-filter.ts
function createQueryFilter(leaf, view, encode) {
	const prefix = viewPrefix(leaf, view);
	if (encode === void 0) return (options) => ({
		...options,
		queryKey: prefix
	});
	return (input, options) => ({
		...options,
		queryKey: Object.freeze([...prefix, canonicalize(encode(input))])
	});
}
//#endregion
//#region src/core/hydration.ts
const makeCodec = (prefix, schema) => {
	const hash = hashKey(prefix);
	return Object.freeze({
		prefix,
		schema,
		matches: (key) => key.length >= prefix.length && hashKey(key.slice(0, prefix.length)) === hash
	});
};
/** Registers a codec whose decoded type matches the generated cached representation. */
const queryViewCodec = (leaf, view, schema) => makeCodec(viewPrefix(leaf, view), schema);
/** Infinite data needs an explicit page-parameter codec in addition to its page codec. */
const infiniteQueryCodec = (leaf, codecs) => makeCodec(Object.freeze([...leaf.key(), "infinite"]), Schema.Struct({
	pages: Schema.Array(codecs.page),
	pageParams: Schema.Array(codecs.pageParam)
}));
/** Native synchronous callbacks for a single service-free leaf/view snapshot. */
const hydrationCallbacks = (codec) => ({
	serializeData: Schema.encodeUnknownSync(codec.schema),
	deserializeData: Schema.decodeUnknownSync(codec.schema)
});
var HydrationCodecError = class extends Error {
	_tag = "HydrationCodecError";
	code;
	constructor(code) {
		super({
			DuplicateCodec: "A hydration codec is already registered for this leaf and view",
			UnknownQuery: "No hydration codec is registered for this query",
			UnsettledQuery: "Hydration codecs require successful queries without pending promises"
		}[code]);
		this.name = "HydrationCodecError";
		this.code = code;
	}
};
/** Indexes explicit leaf/view codecs without owning a QueryClient, runner, or serialization. */
const createHydrationRegistry = (entries) => {
	const byLength = /* @__PURE__ */ new Map();
	const codecs = entries;
	for (const codec of codecs) {
		const lengthCodecs = byLength.get(codec.prefix.length) ?? /* @__PURE__ */ new Map();
		const hash = hashKey(codec.prefix);
		if (lengthCodecs.has(hash)) throw new HydrationCodecError("DuplicateCodec");
		lengthCodecs.set(hash, codec);
		byLength.set(codec.prefix.length, lengthCodecs);
	}
	const lengths = Array$1.sort(byLength.keys(), Order.flip(Order.Number));
	const codecFor = (key) => {
		for (const length of lengths) if (key.length >= length) {
			const codec = byLength.get(length)?.get(hashKey(key.slice(0, length)));
			if (codec !== void 0) return codec;
		}
	};
	const transform = (queries, convert) => Effect.forEach(Effect.fnUntraced(function* transformQuery(query) {
		if (query.state.status !== "success" || query.promise !== void 0) return yield* Effect.fail(new HydrationCodecError("UnsettledQuery"));
		const codec = codecFor(query.queryKey);
		if (codec === void 0) return yield* Effect.fail(new HydrationCodecError("UnknownQuery"));
		const data = yield* convert(codec, query.state.data);
		return {
			...query,
			state: {
				...query.state,
				data
			}
		};
	}))(queries);
	return {
		matches: (key) => codecFor(key) !== void 0,
		encodeQueries: (queries) => transform(queries, (codec, data) => Schema.encodeUnknownEffect(codec.schema)(data)),
		decodeQueries: (queries) => transform(queries, (codec, data) => Schema.decodeUnknownEffect(codec.schema)(data))
	};
};
//#endregion
//#region src/core/stream-recovery.ts
const checkedCursor = (cursor) => {
	if (!Number.isSafeInteger(cursor) || cursor < 0) throw new RangeError("Stream recovery cursors must be nonnegative safe integers");
	return cursor;
};
/** Restarts a decoded stream without putting attempt-specific resume state in a query key. */
const recoverStream = (options) => Stream.suspend(() => {
	let cursor = checkedCursor(options.initialCursor ?? 0);
	const state = (value) => options.onState?.(value) ?? Effect.void;
	const connect = (attempt) => Stream.unwrap(Effect.gen(function* connectStream() {
		yield* state({
			status: "connecting",
			cursor,
			attempt
		});
		const scope = yield* Scope.make();
		yield* Effect.addFinalizer((exit) => Scope.close(scope, exit));
		const source = Stream.suspend(() => options.connect(cursor)).pipe(Stream.rechunk(1), Stream.mapEffect(Effect.fnUntraced(function* trackCursor(value) {
			const next = checkedCursor(options.cursor(value));
			if (next <= cursor) return Option.none();
			if (next > cursor + 1) yield* options.onGap?.(cursor, next) ?? Effect.void;
			cursor = next;
			yield* state({
				status: "connected",
				cursor,
				attempt
			});
			return Option.some(value);
		})), Stream.filter(Option.isSome), Stream.map((value) => value.value));
		const pull = yield* Stream.toPull(source).pipe(Scope.provide(scope));
		return Stream.fromPull(Effect.succeed(Effect.uninterruptibleMask((restore) => restore(pull).pipe(Effect.onError((cause) => Scope.close(scope, Pull.doneExitFromCause(cause))), Effect.catchCause((cause) => {
			const completion = Pull.filterDone(cause);
			return Effect.failCause(Result.isFailure(completion) ? completion.failure : cause);
		})))));
	})).pipe(Stream.catchCause((cause) => {
		if (Cause.hasInterrupts(cause)) return Stream.failCause(cause);
		return Stream.unwrap(Effect.gen(function* recoverConnection() {
			const nextAttempt = attempt + 1;
			const delayInput = options.retryDelay(cause, nextAttempt);
			const expired = options.isReplayExpired?.(cause) === true;
			if (delayInput === void 0 || expired && options.onReplayExpired === void 0) return yield* Effect.failCause(cause);
			const delay = Duration.fromInputUnsafe(delayInput);
			yield* state({
				status: "backing-off",
				cursor,
				attempt: nextAttempt,
				delay,
				cause
			});
			yield* Effect.sleep(delay);
			if (expired && options.onReplayExpired !== void 0) {
				yield* state({
					status: "refreshing",
					cursor,
					attempt: nextAttempt,
					cause
				});
				cursor = checkedCursor(yield* options.onReplayExpired(cause));
			}
			return connect(nextAttempt);
		}));
	}));
	return connect(0).pipe(Stream.onExit((exit) => {
		if (Exit.isSuccess(exit)) return state({
			status: "completed",
			cursor
		});
		return state(Cause.hasInterrupts(exit.cause) ? {
			status: "stopped",
			cursor
		} : {
			status: "failed",
			cursor,
			cause: exit.cause
		});
	}));
});
//#endregion
//#region src/core/configure.ts
const isCallback = (value) => Predicate.isFunction(value);
const once = (next) => {
	let called = false;
	return async () => {
		if (called) throw new Error("An execution interceptor may call next only once per attempt");
		called = true;
		return await next();
	};
};
const configureQuery = (builder, view, configuration) => {
	let build = builder;
	for (const candidate of Array$1.reverse(configuration.interceptors ?? [])) {
		if (!Predicate.isFunction(candidate)) throw new TypeError("Query interceptors must be functions");
		const interceptor = candidate;
		const previous = build;
		build = (options) => {
			const built = previous(options);
			const { queryFn } = built;
			if (queryFn === skipToken$1) return built;
			return {
				...built,
				queryFn: async (context) => {
					let original;
					const result = await interceptor({
						context,
						next: once(async () => {
							const data = await queryFn(context);
							original = data;
							return data;
						})
					});
					return view === "metadata" ? preserveMetadataPolicy(original, result) : result;
				}
			};
		};
	}
	const { policy } = configuration;
	if (policy !== void 0 && Object.keys(policy).length > 0) {
		const previous = build;
		build = (options) => previous({
			...policy,
			...options
		});
	}
	return build;
};
const configureMutation = (builder, configuration) => {
	let build = builder;
	for (const candidate of Array$1.reverse(configuration.interceptors ?? [])) {
		if (!Predicate.isFunction(candidate)) throw new TypeError("Mutation interceptors must be functions");
		const interceptor = candidate;
		const previous = build;
		build = (options) => {
			const built = previous(options);
			return {
				...built,
				mutationFn: async (input, context) => await interceptor({
					input,
					context,
					next: once(async () => await built.mutationFn(input, context))
				})
			};
		};
	}
	const { policy } = configuration;
	if (policy !== void 0 && Object.keys(policy).length > 0) {
		const previous = build;
		build = configuration.callbacks === "compose" ? (options = {}) => {
			const merged = {
				...policy,
				...options
			};
			for (const name of [
				"onSuccess",
				"onError",
				"onSettled"
			]) {
				const before = policy[name];
				const after = options[name];
				if (Object.hasOwn(options, name) && after === void 0) continue;
				if (isCallback(before)) merged[name] = async (...args) => {
					await before(...args);
					if (isCallback(after)) await after(...args);
				};
			}
			return previous(merged);
		} : (options) => previous({
			...policy,
			...options
		});
	}
	return build;
};
//#endregion
//#region src/core/configure-utils.ts
const configuredLeaves = /* @__PURE__ */ new WeakMap();
const views = [
	"query",
	"infinite",
	"metadata",
	"live",
	"streamed"
];
const snapshotConfiguration = (configuration) => {
	const snapshot = {};
	for (const view of [...views, "mutation"]) {
		const entry = configuration[view];
		if (entry !== void 0) snapshot[view] = Object.freeze({
			...entry,
			policy: entry.policy === void 0 ? void 0 : Object.freeze({ ...entry.policy }),
			interceptors: entry.interceptors === void 0 ? void 0 : Object.freeze([...entry.interceptors])
		});
	}
	return Object.freeze(snapshot);
};
const scopeConfigurations = (layers) => {
	const scopes = /* @__PURE__ */ new Map();
	for (const { depth, options } of layers) {
		const scope = scopes.get(depth) ?? {};
		for (const view of [...views, "mutation"]) {
			const entry = options[view];
			if (entry === void 0) continue;
			const previous = scope[view];
			scope[view] = {
				policy: {
					...previous?.policy,
					...entry.policy
				},
				interceptors: [...previous?.interceptors ?? [], ...entry.interceptors ?? []],
				callbacks: entry.callbacks ?? previous?.callbacks
			};
		}
		scopes.set(depth, scope);
	}
	return [...scopes.values()];
};
const configureLeaf = (node, configurations) => {
	const configured = { ...node };
	for (const view of views) {
		if (!Object.hasOwn(node, `${view}Options`)) continue;
		const inherited = configurations.flatMap((entry) => entry[view] === void 0 ? [] : [entry[view]]);
		if (inherited.length === 0) continue;
		const policy = {};
		for (const entry of inherited) Object.assign(policy, entry.policy);
		const name = `${view}Options`;
		const builder = node[name];
		if (!Predicate.isFunction(builder)) throw new TypeError(`${name} must be a function`);
		configured[name] = configureQuery(builder, view, {
			policy,
			interceptors: inherited.flatMap((entry) => entry.interceptors ?? [])
		});
		if (view === "streamed") {
			const { streamedKey } = node;
			if (!Predicate.isFunction(streamedKey)) throw new TypeError("Streamed queries require a key builder");
			const buildKey = streamedKey;
			const history = Object.fromEntries(Object.entries(policy).filter(([option]) => [
				"maxChunks",
				"refetchMode",
				"publicationBatchSize",
				"publicationMaxWaitMs"
			].includes(option)));
			configured["streamedKey"] = inputKind(node.key) === "Inputless" ? (options) => buildKey({
				...history,
				...options
			}) : (input, options) => buildKey(input, {
				...history,
				...options
			});
		}
	}
	if (Object.hasOwn(node, "mutationOptions")) {
		const mutations = configurations.flatMap((entry) => entry.mutation === void 0 ? [] : [entry.mutation]);
		if (mutations.length > 0) {
			const candidate = node["mutationOptions"];
			if (!Predicate.isFunction(candidate)) throw new TypeError("mutationOptions must be a function");
			let builder = candidate;
			for (const entry of mutations) builder = configureMutation(builder, {
				policy: entry.policy,
				callbacks: entry.callbacks
			});
			const interceptors = mutations.flatMap((entry) => entry.interceptors ?? []);
			if (interceptors.length > 0) builder = configureMutation(builder, { interceptors });
			configured["mutationOptions"] = builder;
		}
	}
	return configured;
};
const configureNode = (node, inherited, configuration) => {
	const configurations = [...inherited, {
		depth: node.key().length,
		options: snapshotConfiguration(configuration)
	}];
	const children = Object.entries(node).filter((entry) => Predicate.hasProperty(entry[1], "key") && Predicate.isFunction(entry[1].key));
	for (const name of Object.keys(configuration.scoped ?? {})) if (!children.some(([key]) => key === name)) throw new TypeError(`Unknown utility scope: ${name}`);
	if (children.length === 0) {
		const previous = configuredLeaves.get(node);
		const original = previous?.original ?? node;
		const layers = Array$1.sortWith([...previous?.layers ?? [], ...configurations], (layer) => layer.depth, Order.Number);
		const configured = Object.freeze({ ...configureLeaf(original, scopeConfigurations(layers)) });
		configuredLeaves.set(configured, {
			original,
			layers
		});
		return configured;
	}
	return Object.freeze({
		...node,
		...Object.fromEntries(children.map(([key, child]) => [key, configureNode(child, configurations, configuration.scoped !== void 0 && Object.hasOwn(configuration.scoped, key) ? configuration.scoped[key] ?? {} : {})]))
	});
};
/** Applies root, branch, and leaf configuration while preserving generated cache identity. */
const configureUtils = (tree, configuration) => {
	return configureNode(tree, [], configuration);
};
//#endregion
//#region src/core/branch-filter.ts
const isBranchNode = (node) => Predicate.hasProperty(node, "key") && Predicate.isFunction(node.key);
/** Selects one view across a generated root, branch or leaf without changing cache keys. */
const createBranchQueryFilter = (branch, view) => {
	const byLength = /* @__PURE__ */ new Map();
	const seen = /* @__PURE__ */ new WeakSet();
	const visit = (node) => {
		if (seen.has(node)) return;
		seen.add(node);
		if (Predicate.hasProperty(node, `${view}Options`)) {
			const prefix = [...node.key(), view];
			const entries = byLength.get(prefix.length) ?? /* @__PURE__ */ new Set();
			entries.add(hashKey(prefix));
			byLength.set(prefix.length, entries);
		}
		for (const child of Object.values(node)) if (isBranchNode(child)) visit(child);
	};
	visit(branch);
	const queryKey = branch.key();
	return (options = {}) => ({
		...options,
		queryKey,
		predicate: (query) => {
			for (const [length, prefixes] of byLength) if (query.queryKey.length >= length && prefixes.has(hashKey(query.queryKey.slice(0, length)))) return options.predicate?.(query) ?? true;
			return false;
		}
	});
};
//#endregion
//#region src/core/declared-error.ts
/** Matches one typed failure only; defects, interruptions and composite Causes never match. */
const findDeclaredError = (error, tag) => {
	if (!isEffectRpcQueryError(error) && !isEffectHttpApiQueryError(error)) return Option.none();
	const [reason] = error.cause.reasons;
	if (error.cause.reasons.length !== 1 || reason?._tag !== "Fail") return Option.none();
	const failure = reason.error;
	if (!Predicate.hasProperty(failure, "_tag") || failure._tag !== tag) return Option.none();
	const matched = failure;
	return Option.some(matched);
};
//#endregion
//#region src/core/consume-events.ts
/** Consumes events sequentially without retaining history or owning a runtime or cache. */
const consumeEvents = (source, options) => Effect.suspend(() => (options.onStart ?? Effect.void).pipe(Effect.andThen(Stream.runForEach(source, options.onEvent)), Effect.onExit((exit) => options.onExit?.(exit) ?? Effect.void)));
//#endregion
export { EffectHttpApiQueryConfigError, EffectHttpApiQueryEmptyStreamError, EffectHttpApiQueryError, EffectHttpApiQueryKeyError, EffectRpcQueryConfigError, EffectRpcQueryEmptyStreamError, EffectRpcQueryError, EffectRpcQueryKeyError, HydrationCodecError, configureUtils, consumeEvents, createBranchQueryFilter, createHttpApiQueryUtils, createHydrationRegistry, createQueryFilter, createRpcQueryUtils, fetchStreamSnapshot, findDeclaredError, hydrationCallbacks, infiniteQueryCodec, isEffectHttpApiQueryError, isEffectRpcQueryError, prepareInput, queryViewCodec, recoverStream, skipToken, viewPrefix };

//# sourceMappingURL=index.mjs.map