1import * as Effect from "effect/Effect";
2import * as Binding from "../Binding.ts";
3import type { RuntimeContext } from "../RuntimeContext.ts";
4import type { Object, ObjectDecodeError } from "./Object.ts";
5import type { ReadBucketClient } from "./ReadBucket.ts";
6import type { StorageBindingOptions } from "./StorageBinding.ts";
7
8export type ObjectValue<T> = [T] extends [never] ? Uint8Array : T;
9export interface ReadObjectClient<T> {
10 /** Decode typed JSON, or return bytes for a raw body/file resource. */
11 get(): Effect.Effect<
12 ObjectValue<T> | undefined,
13 | Effect.Error<ReturnType<ReadBucketClient["get"]>>
14 | ObjectDecodeError
15 | Error,
16 RuntimeContext
17 >;
18 /** Always read exact bytes, including for JSON resources. */
19 bytes(): Effect.Effect<
20 Uint8Array | undefined,
21 Effect.Error<ReturnType<ReadBucketClient["get"]>> | Error,
22 RuntimeContext
23 >;
24}
25
26/**
27 * Bind an object's key and JSON type without repeating either. A TypeScript
28 * generic is an application contract, not runtime validation; an optional schema
29 * rejects invalid external writes. No object-only credential scope is claimed.
30 *
31 * ### Typed Reads
32 * **Example:** Read the inferred settings shape
33 * ```typescript
34 * const settings = yield* Neon.ReadObject(settingsObject);
35 * const value = yield* settings.get();
36 * ```
37 *
38 * @binding
39 * @product Bucket
40 */
41export interface ReadObject extends Binding.Service<
42 ReadObject,
43 "Neon.ReadObject",
44 <T>(
45 object: Object<T>,
46 options?: StorageBindingOptions,
47 ) => Effect.Effect<ReadObjectClient<T>>
48> {
49 <T>(
50 object: Object<T>,
51 options?: StorageBindingOptions,
52 ): Effect.Effect<ReadObjectClient<T>, never, ReadObject>;
53}
54export const ReadObject = Binding.Service<ReadObject>("Neon.ReadObject");