@useairfoil/effect-iceberg 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # @useairfoil/effect-iceberg
2
+
3
+ Effect wrapper for [`iceberg-js`](https://github.com/supabase/iceberg-js), the Apache Iceberg REST Catalog client.
4
+
5
+ This package provides an Effect service, layers, accessors, and typed errors around `iceberg-js`. It does not replace the `iceberg-js` API or type surface. Import Apache Iceberg domain types directly from `iceberg-js`.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ pnpm add @useairfoil/effect-iceberg iceberg-js effect
11
+ ```
12
+
13
+ `iceberg-js` and `effect` are peer dependencies so your application owns their versions.
14
+
15
+ ## Imports
16
+
17
+ ```typescript
18
+ import { IcebergCatalog, IcebergError } from "@useairfoil/effect-iceberg";
19
+ import type { CreateTableRequest, TableIdentifier } from "iceberg-js";
20
+ ```
21
+
22
+ `@useairfoil/effect-iceberg` exports wrapper modules only:
23
+
24
+ - `IcebergCatalog` contains the service tag, constructors, layers, and accessor functions.
25
+ - `IcebergError` contains the Effect error type and mapper for failures from `iceberg-js`.
26
+
27
+ Use `iceberg-js` directly for catalog options, request/response types, metadata types, table update unions, and helpers.
28
+
29
+ ## Layer
30
+
31
+ Create a layer from normal `iceberg-js` catalog options:
32
+
33
+ ```typescript
34
+ import { IcebergCatalog } from "@useairfoil/effect-iceberg";
35
+
36
+ const IcebergLive = IcebergCatalog.layer({
37
+ baseUrl: "https://catalog.example.com",
38
+ warehouse: "warehouse",
39
+ auth: { type: "bearer", token: process.env.ICEBERG_TOKEN ?? "" },
40
+ accessDelegation: ["vended-credentials"],
41
+ });
42
+ ```
43
+
44
+ Or build a layer from Effect `Config` values:
45
+
46
+ ```typescript
47
+ import { Config } from "effect";
48
+ import { IcebergCatalog } from "@useairfoil/effect-iceberg";
49
+ import type { AuthConfig } from "iceberg-js";
50
+
51
+ const IcebergLive = IcebergCatalog.layerConfig({
52
+ baseUrl: Config.string("ICEBERG_REST_URL"),
53
+ warehouse: Config.string("ICEBERG_WAREHOUSE"),
54
+ auth: Config.string("ICEBERG_TOKEN").pipe(
55
+ Config.map((token): AuthConfig => ({ type: "bearer", token })),
56
+ ),
57
+ });
58
+ ```
59
+
60
+ ## Usage
61
+
62
+ Use the accessor functions for most application code. They read the `IcebergCatalog` service from the Effect context and delegate to the underlying `iceberg-js` client.
63
+
64
+ ```typescript
65
+ import { Effect } from "effect";
66
+ import { IcebergCatalog } from "@useairfoil/effect-iceberg";
67
+ import type { TableIdentifier } from "iceberg-js";
68
+
69
+ const IcebergLive = IcebergCatalog.layer({
70
+ baseUrl: "https://catalog.example.com",
71
+ warehouse: "warehouse",
72
+ auth: { type: "bearer", token: process.env.ICEBERG_TOKEN ?? "" },
73
+ });
74
+
75
+ const program = Effect.gen(function* () {
76
+ const id: TableIdentifier = { namespace: ["analytics"], name: "events" };
77
+ return yield* IcebergCatalog.loadTable(id);
78
+ });
79
+
80
+ await Effect.runPromise(program.pipe(Effect.provide(IcebergLive)));
81
+ ```
82
+
83
+ ## Catalog Operations
84
+
85
+ The `IcebergCatalog` module mirrors the public `iceberg-js` `IcebergRestCatalog` methods as Effect accessors:
86
+
87
+ ```typescript
88
+ const program = Effect.gen(function* () {
89
+ const namespaces = yield* IcebergCatalog.listNamespaces();
90
+
91
+ const tables = yield* IcebergCatalog.listTables({ namespace: ["analytics"] });
92
+
93
+ const table = yield* IcebergCatalog.loadTable({
94
+ namespace: ["analytics"],
95
+ name: "events",
96
+ });
97
+
98
+ return { namespaces, tables, table };
99
+ });
100
+ ```
101
+
102
+ Create tables with request types from `iceberg-js`:
103
+
104
+ ```typescript
105
+ import type { CreateTableRequest } from "iceberg-js";
106
+
107
+ const request: CreateTableRequest = {
108
+ name: "events",
109
+ schema: {
110
+ type: "struct",
111
+ "schema-id": 0,
112
+ fields: [{ id: 1, name: "id", type: "string", required: true }],
113
+ },
114
+ };
115
+
116
+ const program = Effect.gen(function* () {
117
+ return yield* IcebergCatalog.createTable({ namespace: ["analytics"] }, request);
118
+ });
119
+ ```
120
+
121
+ Use `loadTableResult`, `createTableResult`, or `registerTableResult` when you need the full spec-aligned result, including server config, storage credentials, metadata location, and ETag:
122
+
123
+ ```typescript
124
+ const program = Effect.gen(function* () {
125
+ const result = yield* IcebergCatalog.loadTableResult({
126
+ namespace: ["analytics"],
127
+ name: "events",
128
+ });
129
+
130
+ if (result) {
131
+ console.log(result.etag);
132
+ console.log(result["storage-credentials"]);
133
+ }
134
+
135
+ return result;
136
+ });
137
+ ```
138
+
139
+ Conditional table loads return `null` when the server responds with `304 Not Modified`:
140
+
141
+ ```typescript
142
+ const program = Effect.gen(function* () {
143
+ return yield* IcebergCatalog.loadTable(
144
+ { namespace: ["analytics"], name: "events" },
145
+ { ifNoneMatch: "abc123" },
146
+ );
147
+ });
148
+ ```
149
+
150
+ ## Service Access
151
+
152
+ For advanced use cases, access the service directly. This is useful when you want the underlying `iceberg-js` client or want to call several methods from one service value.
153
+
154
+ ```typescript
155
+ const program = Effect.gen(function* () {
156
+ const catalog = yield* IcebergCatalog.IcebergCatalog;
157
+ const client = catalog.getCatalogClient();
158
+
159
+ yield* catalog.loadConfig();
160
+ return client;
161
+ });
162
+ ```
163
+
164
+ ## Errors
165
+
166
+ Failures thrown by `iceberg-js` are mapped to `IcebergError.IcebergError`. The wrapper preserves the important Iceberg fields: HTTP `status`, Iceberg exception `type` / `code`, `details`, and `isCommitStateUnknown`.
167
+
168
+ ```typescript
169
+ import { Effect } from "effect";
170
+ import { IcebergError } from "@useairfoil/effect-iceberg";
171
+
172
+ const handled = program.pipe(
173
+ Effect.catchTag("IcebergError", (error: IcebergError.IcebergError) =>
174
+ Effect.succeed({ status: error.status, type: error.icebergType }),
175
+ ),
176
+ );
177
+ ```
178
+
179
+ You can also inspect commit-state ambiguity from the Iceberg REST spec:
180
+
181
+ ```typescript
182
+ const safeCommit = IcebergCatalog.commitTable(id, request).pipe(
183
+ Effect.catchTag("IcebergError", (error) => {
184
+ if (error.isCommitStateUnknown) {
185
+ return Effect.fail(error);
186
+ }
187
+ return Effect.fail(error);
188
+ }),
189
+ );
190
+ ```
191
+
192
+ ## Direct `iceberg-js` Types
193
+
194
+ Keep domain types close to `iceberg-js`:
195
+
196
+ ```typescript
197
+ import type {
198
+ CommitTableRequest,
199
+ LoadTableResultWithEtag,
200
+ NamespaceIdentifier,
201
+ TableIdentifier,
202
+ TableMetadata,
203
+ TableUpdate,
204
+ } from "iceberg-js";
205
+ ```
206
+
207
+ This keeps your application aligned with the exact `iceberg-js` version you install, while `@useairfoil/effect-iceberg` provides the Effect integration layer.
@@ -0,0 +1,13 @@
1
+ //#region rolldown:runtime
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (all) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ return target;
10
+ };
11
+
12
+ //#endregion
13
+ export { __export as t };
@@ -0,0 +1,133 @@
1
+ import { Config, Context, Effect, Layer } from "effect";
2
+ import { CatalogConfig, CommitTableRequest, CommitTableResponse, CreateNamespaceResponse, CreateTableRequest, DropTableRequest, IcebergRestCatalog, IcebergRestCatalogOptions, ListNamespacesOptions, ListNamespacesResult, ListTablesOptions, ListTablesResult, LoadTableOptions, LoadTableResultWithEtag, NamespaceIdentifier, NamespaceMetadata, RegisterTableRequest, RenameTableRequest, TableIdentifier, TableMetadata, UpdateNamespacePropertiesRequest, UpdateNamespacePropertiesResponse, UpdateTableRequest } from "iceberg-js";
3
+ import * as effect_Types0 from "effect/Types";
4
+ import * as effect_Cause0 from "effect/Cause";
5
+
6
+ //#region src/errors.d.ts
7
+ declare namespace errors_d_exports {
8
+ export { IcebergError$1 as IcebergError, mapIcebergError };
9
+ }
10
+ declare const IcebergError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => effect_Cause0.YieldableError & {
11
+ readonly _tag: "IcebergError";
12
+ } & Readonly<A>;
13
+ /** Error type used by the Effect wrapper around `iceberg-js`. */
14
+ declare class IcebergError$1 extends IcebergError_base<{
15
+ readonly message: string;
16
+ readonly status?: number;
17
+ readonly icebergType?: string;
18
+ readonly icebergCode?: number;
19
+ readonly details?: unknown;
20
+ readonly isCommitStateUnknown?: boolean;
21
+ readonly cause?: unknown;
22
+ }> {}
23
+ /** Maps errors thrown by `iceberg-js` into `IcebergError`. */
24
+ declare const mapIcebergError: (error: unknown) => IcebergError$1;
25
+ declare namespace catalog_d_exports {
26
+ export { IcebergCatalog, Service, commitTable, createNamespace, createNamespaceIfNotExists, createTable, createTableIfNotExists, createTableResult, dropNamespace, dropTable, getCatalogClient, layer, layerConfig, listNamespaces, listTables, loadConfig, loadNamespaceMetadata, loadTable, loadTableResult, make, namespaceExists, registerTable, registerTableResult, renameTable, tableExists, updateNamespaceProperties, updateTable };
27
+ }
28
+ interface Service {
29
+ /**
30
+ * Returns the underlying `iceberg-js` catalog client.
31
+ *
32
+ * Use this for advanced cases that need direct access to the Promise-based API.
33
+ */
34
+ readonly getCatalogClient: () => IcebergRestCatalog;
35
+ /**
36
+ * Fetch and cache the server's catalog configuration. Calling this is optional;
37
+ * catalog operations trigger it lazily when a warehouse is configured.
38
+ */
39
+ readonly loadConfig: () => Effect.Effect<CatalogConfig, IcebergError$1>;
40
+ /** Lists all namespaces in the catalog. */
41
+ readonly listNamespaces: (options?: ListNamespacesOptions) => Effect.Effect<ListNamespacesResult, IcebergError$1>;
42
+ /** Creates a new namespace in the catalog. */
43
+ readonly createNamespace: (id: NamespaceIdentifier, metadata?: NamespaceMetadata) => Effect.Effect<CreateNamespaceResponse, IcebergError$1>;
44
+ /**
45
+ * Drops a namespace from the catalog.
46
+ *
47
+ * The namespace must be empty before it can be dropped.
48
+ */
49
+ readonly dropNamespace: (id: NamespaceIdentifier) => Effect.Effect<void, IcebergError$1>;
50
+ /** Loads metadata for a namespace. */
51
+ readonly loadNamespaceMetadata: (id: NamespaceIdentifier) => Effect.Effect<NamespaceMetadata, IcebergError$1>;
52
+ /** Sets or removes properties on a namespace. */
53
+ readonly updateNamespaceProperties: (id: NamespaceIdentifier, request: UpdateNamespacePropertiesRequest) => Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError$1>;
54
+ /** Lists tables in a namespace. */
55
+ readonly listTables: (namespace: NamespaceIdentifier, options?: ListTablesOptions) => Effect.Effect<ListTablesResult, IcebergError$1>;
56
+ /** Creates a new table in the catalog. */
57
+ readonly createTable: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<TableMetadata, IcebergError$1>;
58
+ /**
59
+ * Creates a table and returns the full spec-aligned `LoadTableResult`, including
60
+ * server config, storage credentials, and the response ETag.
61
+ */
62
+ readonly createTableResult: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<LoadTableResultWithEtag, IcebergError$1>;
63
+ /** Commits updates to a table using the spec-aligned `{ requirements, updates }` shape. */
64
+ readonly updateTable: (id: TableIdentifier, request: UpdateTableRequest) => Effect.Effect<CommitTableResponse, IcebergError$1>;
65
+ /** Spec-aligned alias for `updateTable`. */
66
+ readonly commitTable: (id: TableIdentifier, request: CommitTableRequest) => Effect.Effect<CommitTableResponse, IcebergError$1>;
67
+ /** Drops a table from the catalog. */
68
+ readonly dropTable: (id: TableIdentifier, options?: DropTableRequest) => Effect.Effect<void, IcebergError$1>;
69
+ /**
70
+ * Loads metadata for a table.
71
+ *
72
+ * Pass `ifNoneMatch` in options to perform a conditional GET. If the server
73
+ * returns 304 Not Modified, the result is `null`.
74
+ */
75
+ readonly loadTable: {
76
+ (id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError$1>;
77
+ (id: TableIdentifier, options: LoadTableOptions): Effect.Effect<TableMetadata | null, IcebergError$1>;
78
+ };
79
+ /**
80
+ * Loads the full spec-aligned `LoadTableResult`, including server config,
81
+ * storage credentials, and the response ETag. Returns `null` on 304.
82
+ */
83
+ readonly loadTableResult: (id: TableIdentifier, options?: LoadTableOptions) => Effect.Effect<LoadTableResultWithEtag | null, IcebergError$1>;
84
+ /** Checks if a namespace exists in the catalog. */
85
+ readonly namespaceExists: (id: NamespaceIdentifier) => Effect.Effect<boolean, IcebergError$1>;
86
+ /** Checks if a table exists in the catalog. */
87
+ readonly tableExists: (id: TableIdentifier) => Effect.Effect<boolean, IcebergError$1>;
88
+ /** Creates a namespace if it does not exist. */
89
+ readonly createNamespaceIfNotExists: (id: NamespaceIdentifier, metadata?: NamespaceMetadata) => Effect.Effect<CreateNamespaceResponse | void, IcebergError$1>;
90
+ /** Creates a table if it does not exist. */
91
+ readonly createTableIfNotExists: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<TableMetadata, IcebergError$1>;
92
+ /** Registers an existing metadata file as a table in the given namespace. */
93
+ readonly registerTable: (namespace: NamespaceIdentifier, request: RegisterTableRequest) => Effect.Effect<TableMetadata, IcebergError$1>;
94
+ /** Returns the full spec-aligned `LoadTableResult` for `registerTable`. */
95
+ readonly registerTableResult: (namespace: NamespaceIdentifier, request: RegisterTableRequest) => Effect.Effect<LoadTableResultWithEtag, IcebergError$1>;
96
+ /** Renames a table. Servers may or may not support cross-namespace renames. */
97
+ readonly renameTable: (request: RenameTableRequest) => Effect.Effect<void, IcebergError$1>;
98
+ }
99
+ declare const IcebergCatalog_base: Context.ServiceClass<IcebergCatalog, "@useairfoil/effect-iceberg/IcebergCatalog", Service>;
100
+ /** Service for the Effect wrapper around `iceberg-js`'s `IcebergRestCatalog`. */
101
+ declare class IcebergCatalog extends IcebergCatalog_base {}
102
+ /** Creates an `IcebergCatalog` service from `iceberg-js` catalog options. */
103
+ declare const make: (options: IcebergRestCatalogOptions) => Service;
104
+ declare const getCatalogClient: Effect.Effect<IcebergRestCatalog, never, IcebergCatalog>;
105
+ declare const loadConfig: Effect.Effect<CatalogConfig, IcebergError$1, IcebergCatalog>;
106
+ declare const listNamespaces: (options?: ListNamespacesOptions) => Effect.Effect<ListNamespacesResult, IcebergError$1, IcebergCatalog>;
107
+ declare const createNamespace: (id: NamespaceIdentifier, metadata?: NamespaceMetadata) => Effect.Effect<CreateNamespaceResponse, IcebergError$1, IcebergCatalog>;
108
+ declare const dropNamespace: (id: NamespaceIdentifier) => Effect.Effect<void, IcebergError$1, IcebergCatalog>;
109
+ declare const loadNamespaceMetadata: (id: NamespaceIdentifier) => Effect.Effect<NamespaceMetadata, IcebergError$1, IcebergCatalog>;
110
+ declare const updateNamespaceProperties: (id: NamespaceIdentifier, request: UpdateNamespacePropertiesRequest) => Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError$1, IcebergCatalog>;
111
+ declare const listTables: (namespace: NamespaceIdentifier, options?: ListTablesOptions) => Effect.Effect<ListTablesResult, IcebergError$1, IcebergCatalog>;
112
+ declare const createTable: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<TableMetadata, IcebergError$1, IcebergCatalog>;
113
+ declare const createTableResult: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<LoadTableResultWithEtag, IcebergError$1, IcebergCatalog>;
114
+ declare const updateTable: (id: TableIdentifier, request: UpdateTableRequest) => Effect.Effect<CommitTableResponse, IcebergError$1, IcebergCatalog>;
115
+ declare const commitTable: (id: TableIdentifier, request: CommitTableRequest) => Effect.Effect<CommitTableResponse, IcebergError$1, IcebergCatalog>;
116
+ declare const dropTable: (id: TableIdentifier, options?: DropTableRequest) => Effect.Effect<void, IcebergError$1, IcebergCatalog>;
117
+ declare function loadTable(id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError$1, IcebergCatalog>;
118
+ declare function loadTable(id: TableIdentifier, options: LoadTableOptions): Effect.Effect<TableMetadata | null, IcebergError$1, IcebergCatalog>;
119
+ declare const loadTableResult: (id: TableIdentifier, options?: LoadTableOptions) => Effect.Effect<LoadTableResultWithEtag | null, IcebergError$1, IcebergCatalog>;
120
+ declare const namespaceExists: (id: NamespaceIdentifier) => Effect.Effect<boolean, IcebergError$1, IcebergCatalog>;
121
+ declare const tableExists: (id: TableIdentifier) => Effect.Effect<boolean, IcebergError$1, IcebergCatalog>;
122
+ declare const createNamespaceIfNotExists: (id: NamespaceIdentifier, metadata?: NamespaceMetadata) => Effect.Effect<CreateNamespaceResponse | void, IcebergError$1, IcebergCatalog>;
123
+ declare const createTableIfNotExists: (namespace: NamespaceIdentifier, request: CreateTableRequest) => Effect.Effect<TableMetadata, IcebergError$1, IcebergCatalog>;
124
+ declare const registerTable: (namespace: NamespaceIdentifier, request: RegisterTableRequest) => Effect.Effect<TableMetadata, IcebergError$1, IcebergCatalog>;
125
+ declare const registerTableResult: (namespace: NamespaceIdentifier, request: RegisterTableRequest) => Effect.Effect<LoadTableResultWithEtag, IcebergError$1, IcebergCatalog>;
126
+ declare const renameTable: (request: RenameTableRequest) => Effect.Effect<void, IcebergError$1, IcebergCatalog>;
127
+ /** Creates an `IcebergCatalog` layer from concrete `iceberg-js` catalog options. */
128
+ declare const layer: (options: IcebergRestCatalogOptions) => Layer.Layer<IcebergCatalog>;
129
+ /** Creates an `IcebergCatalog` layer from Effect `Config` values. */
130
+ declare const layerConfig: (config: Config.Wrap<IcebergRestCatalogOptions>) => Layer.Layer<IcebergCatalog, Config.ConfigError>;
131
+ //#endregion
132
+ export { catalog_d_exports as IcebergCatalog, errors_d_exports as IcebergError };
133
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,130 @@
1
+ import { t as __export } from "./chunk-Bp6m_JJh.js";
2
+ import { Config, Context, Data, Effect, Layer } from "effect";
3
+ import { IcebergError, IcebergRestCatalog } from "iceberg-js";
4
+
5
+ //#region src/errors.ts
6
+ var errors_exports = /* @__PURE__ */ __export({
7
+ IcebergError: () => IcebergError$1,
8
+ mapIcebergError: () => mapIcebergError
9
+ });
10
+ /** Error type used by the Effect wrapper around `iceberg-js`. */
11
+ var IcebergError$1 = class extends Data.TaggedError("IcebergError") {};
12
+ /** Maps errors thrown by `iceberg-js` into `IcebergError`. */
13
+ const mapIcebergError = (error) => {
14
+ if (error instanceof IcebergError) return new IcebergError$1({
15
+ message: error.message,
16
+ status: error.status,
17
+ icebergType: error.icebergType,
18
+ icebergCode: error.icebergCode,
19
+ details: error.details,
20
+ isCommitStateUnknown: error.isCommitStateUnknown,
21
+ cause: error
22
+ });
23
+ return new IcebergError$1({
24
+ message: error instanceof Error ? error.message : String(error),
25
+ cause: error
26
+ });
27
+ };
28
+
29
+ //#endregion
30
+ //#region src/catalog.ts
31
+ var catalog_exports = /* @__PURE__ */ __export({
32
+ IcebergCatalog: () => IcebergCatalog,
33
+ commitTable: () => commitTable,
34
+ createNamespace: () => createNamespace,
35
+ createNamespaceIfNotExists: () => createNamespaceIfNotExists,
36
+ createTable: () => createTable,
37
+ createTableIfNotExists: () => createTableIfNotExists,
38
+ createTableResult: () => createTableResult,
39
+ dropNamespace: () => dropNamespace,
40
+ dropTable: () => dropTable,
41
+ getCatalogClient: () => getCatalogClient,
42
+ layer: () => layer,
43
+ layerConfig: () => layerConfig,
44
+ listNamespaces: () => listNamespaces,
45
+ listTables: () => listTables,
46
+ loadConfig: () => loadConfig,
47
+ loadNamespaceMetadata: () => loadNamespaceMetadata,
48
+ loadTable: () => loadTable,
49
+ loadTableResult: () => loadTableResult,
50
+ make: () => make,
51
+ namespaceExists: () => namespaceExists,
52
+ registerTable: () => registerTable,
53
+ registerTableResult: () => registerTableResult,
54
+ renameTable: () => renameTable,
55
+ tableExists: () => tableExists,
56
+ updateNamespaceProperties: () => updateNamespaceProperties,
57
+ updateTable: () => updateTable
58
+ });
59
+ /** Service for the Effect wrapper around `iceberg-js`'s `IcebergRestCatalog`. */
60
+ var IcebergCatalog = class extends Context.Service()("@useairfoil/effect-iceberg/IcebergCatalog") {};
61
+ const tryCatalog = (evaluate) => Effect.tryPromise({
62
+ try: evaluate,
63
+ catch: mapIcebergError
64
+ });
65
+ /** Creates an `IcebergCatalog` service from `iceberg-js` catalog options. */
66
+ const make = (options) => {
67
+ const catalog = new IcebergRestCatalog(options);
68
+ function loadTable$1(id, loadOptions) {
69
+ return tryCatalog(() => loadOptions === void 0 ? catalog.loadTable(id) : catalog.loadTable(id, loadOptions));
70
+ }
71
+ return IcebergCatalog.of({
72
+ getCatalogClient: () => catalog,
73
+ loadConfig: () => tryCatalog(() => catalog.loadConfig()),
74
+ listNamespaces: (listOptions) => tryCatalog(() => catalog.listNamespaces(listOptions)),
75
+ createNamespace: (id, metadata) => tryCatalog(() => catalog.createNamespace(id, metadata)),
76
+ dropNamespace: (id) => tryCatalog(() => catalog.dropNamespace(id)),
77
+ loadNamespaceMetadata: (id) => tryCatalog(() => catalog.loadNamespaceMetadata(id)),
78
+ updateNamespaceProperties: (id, request) => tryCatalog(() => catalog.updateNamespaceProperties(id, request)),
79
+ listTables: (namespace, listOptions) => tryCatalog(() => catalog.listTables(namespace, listOptions)),
80
+ createTable: (namespace, request) => tryCatalog(() => catalog.createTable(namespace, request)),
81
+ createTableResult: (namespace, request) => tryCatalog(() => catalog.createTableResult(namespace, request)),
82
+ updateTable: (id, request) => tryCatalog(() => catalog.updateTable(id, request)),
83
+ commitTable: (id, request) => tryCatalog(() => catalog.commitTable(id, request)),
84
+ dropTable: (id, dropOptions) => tryCatalog(() => catalog.dropTable(id, dropOptions)),
85
+ loadTable: loadTable$1,
86
+ loadTableResult: (id, loadOptions) => tryCatalog(() => catalog.loadTableResult(id, loadOptions)),
87
+ namespaceExists: (id) => tryCatalog(() => catalog.namespaceExists(id)),
88
+ tableExists: (id) => tryCatalog(() => catalog.tableExists(id)),
89
+ createNamespaceIfNotExists: (id, metadata) => tryCatalog(() => catalog.createNamespaceIfNotExists(id, metadata)),
90
+ createTableIfNotExists: (namespace, request) => tryCatalog(() => catalog.createTableIfNotExists(namespace, request)),
91
+ registerTable: (namespace, request) => tryCatalog(() => catalog.registerTable(namespace, request)),
92
+ registerTableResult: (namespace, request) => tryCatalog(() => catalog.registerTableResult(namespace, request)),
93
+ renameTable: (request) => tryCatalog(() => catalog.renameTable(request))
94
+ });
95
+ };
96
+ const service = Effect.service(IcebergCatalog);
97
+ const getCatalogClient = Effect.map(service, (catalog) => catalog.getCatalogClient());
98
+ const loadConfig = Effect.flatMap(service, (catalog) => catalog.loadConfig());
99
+ const listNamespaces = (options) => Effect.flatMap(service, (catalog) => catalog.listNamespaces(options));
100
+ const createNamespace = (id, metadata) => Effect.flatMap(service, (catalog) => catalog.createNamespace(id, metadata));
101
+ const dropNamespace = (id) => Effect.flatMap(service, (catalog) => catalog.dropNamespace(id));
102
+ const loadNamespaceMetadata = (id) => Effect.flatMap(service, (catalog) => catalog.loadNamespaceMetadata(id));
103
+ const updateNamespaceProperties = (id, request) => Effect.flatMap(service, (catalog) => catalog.updateNamespaceProperties(id, request));
104
+ const listTables = (namespace, options) => Effect.flatMap(service, (catalog) => catalog.listTables(namespace, options));
105
+ const createTable = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.createTable(namespace, request));
106
+ const createTableResult = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.createTableResult(namespace, request));
107
+ const updateTable = (id, request) => Effect.flatMap(service, (catalog) => catalog.updateTable(id, request));
108
+ const commitTable = (id, request) => Effect.flatMap(service, (catalog) => catalog.commitTable(id, request));
109
+ const dropTable = (id, options) => Effect.flatMap(service, (catalog) => catalog.dropTable(id, options));
110
+ function loadTable(id, options) {
111
+ return Effect.flatMap(service, (catalog) => options === void 0 ? catalog.loadTable(id) : catalog.loadTable(id, options));
112
+ }
113
+ const loadTableResult = (id, options) => Effect.flatMap(service, (catalog) => catalog.loadTableResult(id, options));
114
+ const namespaceExists = (id) => Effect.flatMap(service, (catalog) => catalog.namespaceExists(id));
115
+ const tableExists = (id) => Effect.flatMap(service, (catalog) => catalog.tableExists(id));
116
+ const createNamespaceIfNotExists = (id, metadata) => Effect.flatMap(service, (catalog) => catalog.createNamespaceIfNotExists(id, metadata));
117
+ const createTableIfNotExists = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.createTableIfNotExists(namespace, request));
118
+ const registerTable = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.registerTable(namespace, request));
119
+ const registerTableResult = (namespace, request) => Effect.flatMap(service, (catalog) => catalog.registerTableResult(namespace, request));
120
+ const renameTable = (request) => Effect.flatMap(service, (catalog) => catalog.renameTable(request));
121
+ /** Creates an `IcebergCatalog` layer from concrete `iceberg-js` catalog options. */
122
+ const layer = (options) => Layer.succeed(IcebergCatalog)(make(options));
123
+ /** Creates an `IcebergCatalog` layer from Effect `Config` values. */
124
+ const layerConfig = (config) => Layer.effect(IcebergCatalog, Effect.gen(function* () {
125
+ return make(yield* Config.unwrap(config));
126
+ }));
127
+
128
+ //#endregion
129
+ export { catalog_exports as IcebergCatalog, errors_exports as IcebergError };
130
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["IcebergError","IcebergJsError","loadTable","getCatalogClient: Effect.Effect<IcebergRestCatalog, never, IcebergCatalog>","loadConfig: Effect.Effect<CatalogConfig, IcebergError, IcebergCatalog>"],"sources":["../src/errors.ts","../src/catalog.ts"],"sourcesContent":["import { Data } from \"effect\";\nimport { IcebergError as IcebergJsError } from \"iceberg-js\";\n\n/** Error type used by the Effect wrapper around `iceberg-js`. */\nexport class IcebergError extends Data.TaggedError(\"IcebergError\")<{\n readonly message: string;\n readonly status?: number;\n readonly icebergType?: string;\n readonly icebergCode?: number;\n readonly details?: unknown;\n readonly isCommitStateUnknown?: boolean;\n readonly cause?: unknown;\n}> {}\n\n/** Maps errors thrown by `iceberg-js` into `IcebergError`. */\nexport const mapIcebergError = (error: unknown): IcebergError => {\n if (error instanceof IcebergJsError) {\n return new IcebergError({\n message: error.message,\n status: error.status,\n icebergType: error.icebergType,\n icebergCode: error.icebergCode,\n details: error.details,\n isCommitStateUnknown: error.isCommitStateUnknown,\n cause: error,\n });\n }\n\n return new IcebergError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n};\n","import type {\n CatalogConfig,\n CommitTableRequest,\n CommitTableResponse,\n CreateNamespaceResponse,\n CreateTableRequest,\n DropTableRequest,\n IcebergRestCatalogOptions,\n ListNamespacesOptions,\n ListNamespacesResult,\n ListTablesOptions,\n ListTablesResult,\n LoadTableOptions,\n LoadTableResultWithEtag,\n NamespaceIdentifier,\n NamespaceMetadata,\n RegisterTableRequest,\n RenameTableRequest,\n TableIdentifier,\n TableMetadata,\n UpdateNamespacePropertiesRequest,\n UpdateNamespacePropertiesResponse,\n UpdateTableRequest,\n} from \"iceberg-js\";\n\nimport { Config, Context, Effect, Layer } from \"effect\";\nimport { IcebergRestCatalog } from \"iceberg-js\";\n\nimport type { IcebergError } from \"./errors\";\n\nimport { mapIcebergError } from \"./errors\";\n\nexport interface Service {\n /**\n * Returns the underlying `iceberg-js` catalog client.\n *\n * Use this for advanced cases that need direct access to the Promise-based API.\n */\n readonly getCatalogClient: () => IcebergRestCatalog;\n\n /**\n * Fetch and cache the server's catalog configuration. Calling this is optional;\n * catalog operations trigger it lazily when a warehouse is configured.\n */\n readonly loadConfig: () => Effect.Effect<CatalogConfig, IcebergError>;\n\n /** Lists all namespaces in the catalog. */\n readonly listNamespaces: (\n options?: ListNamespacesOptions,\n ) => Effect.Effect<ListNamespacesResult, IcebergError>;\n\n /** Creates a new namespace in the catalog. */\n readonly createNamespace: (\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata,\n ) => Effect.Effect<CreateNamespaceResponse, IcebergError>;\n\n /**\n * Drops a namespace from the catalog.\n *\n * The namespace must be empty before it can be dropped.\n */\n readonly dropNamespace: (id: NamespaceIdentifier) => Effect.Effect<void, IcebergError>;\n\n /** Loads metadata for a namespace. */\n readonly loadNamespaceMetadata: (\n id: NamespaceIdentifier,\n ) => Effect.Effect<NamespaceMetadata, IcebergError>;\n\n /** Sets or removes properties on a namespace. */\n readonly updateNamespaceProperties: (\n id: NamespaceIdentifier,\n request: UpdateNamespacePropertiesRequest,\n ) => Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError>;\n\n /** Lists tables in a namespace. */\n readonly listTables: (\n namespace: NamespaceIdentifier,\n options?: ListTablesOptions,\n ) => Effect.Effect<ListTablesResult, IcebergError>;\n\n /** Creates a new table in the catalog. */\n readonly createTable: (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n ) => Effect.Effect<TableMetadata, IcebergError>;\n\n /**\n * Creates a table and returns the full spec-aligned `LoadTableResult`, including\n * server config, storage credentials, and the response ETag.\n */\n readonly createTableResult: (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n ) => Effect.Effect<LoadTableResultWithEtag, IcebergError>;\n\n /** Commits updates to a table using the spec-aligned `{ requirements, updates }` shape. */\n readonly updateTable: (\n id: TableIdentifier,\n request: UpdateTableRequest,\n ) => Effect.Effect<CommitTableResponse, IcebergError>;\n\n /** Spec-aligned alias for `updateTable`. */\n readonly commitTable: (\n id: TableIdentifier,\n request: CommitTableRequest,\n ) => Effect.Effect<CommitTableResponse, IcebergError>;\n\n /** Drops a table from the catalog. */\n readonly dropTable: (\n id: TableIdentifier,\n options?: DropTableRequest,\n ) => Effect.Effect<void, IcebergError>;\n\n /**\n * Loads metadata for a table.\n *\n * Pass `ifNoneMatch` in options to perform a conditional GET. If the server\n * returns 304 Not Modified, the result is `null`.\n */\n readonly loadTable: {\n (id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError>;\n (\n id: TableIdentifier,\n options: LoadTableOptions,\n ): Effect.Effect<TableMetadata | null, IcebergError>;\n };\n\n /**\n * Loads the full spec-aligned `LoadTableResult`, including server config,\n * storage credentials, and the response ETag. Returns `null` on 304.\n */\n readonly loadTableResult: (\n id: TableIdentifier,\n options?: LoadTableOptions,\n ) => Effect.Effect<LoadTableResultWithEtag | null, IcebergError>;\n\n /** Checks if a namespace exists in the catalog. */\n readonly namespaceExists: (id: NamespaceIdentifier) => Effect.Effect<boolean, IcebergError>;\n\n /** Checks if a table exists in the catalog. */\n readonly tableExists: (id: TableIdentifier) => Effect.Effect<boolean, IcebergError>;\n\n /** Creates a namespace if it does not exist. */\n readonly createNamespaceIfNotExists: (\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata,\n ) => Effect.Effect<CreateNamespaceResponse | void, IcebergError>;\n\n /** Creates a table if it does not exist. */\n readonly createTableIfNotExists: (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n ) => Effect.Effect<TableMetadata, IcebergError>;\n\n /** Registers an existing metadata file as a table in the given namespace. */\n readonly registerTable: (\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest,\n ) => Effect.Effect<TableMetadata, IcebergError>;\n\n /** Returns the full spec-aligned `LoadTableResult` for `registerTable`. */\n readonly registerTableResult: (\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest,\n ) => Effect.Effect<LoadTableResultWithEtag, IcebergError>;\n\n /** Renames a table. Servers may or may not support cross-namespace renames. */\n readonly renameTable: (request: RenameTableRequest) => Effect.Effect<void, IcebergError>;\n}\n\n/** Service for the Effect wrapper around `iceberg-js`'s `IcebergRestCatalog`. */\nexport class IcebergCatalog extends Context.Service<IcebergCatalog, Service>()(\n \"@useairfoil/effect-iceberg/IcebergCatalog\",\n) {}\n\nconst tryCatalog = <A>(evaluate: () => Promise<A>): Effect.Effect<A, IcebergError> =>\n Effect.tryPromise({\n try: evaluate,\n catch: mapIcebergError,\n });\n\n/** Creates an `IcebergCatalog` service from `iceberg-js` catalog options. */\nexport const make = (options: IcebergRestCatalogOptions): Service => {\n const catalog = new IcebergRestCatalog(options);\n\n function loadTable(id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError>;\n function loadTable(\n id: TableIdentifier,\n loadOptions: LoadTableOptions,\n ): Effect.Effect<TableMetadata | null, IcebergError>;\n function loadTable(id: TableIdentifier, loadOptions?: LoadTableOptions) {\n return tryCatalog(() =>\n loadOptions === undefined ? catalog.loadTable(id) : catalog.loadTable(id, loadOptions),\n );\n }\n\n return IcebergCatalog.of({\n getCatalogClient: () => catalog,\n loadConfig: () => tryCatalog(() => catalog.loadConfig()),\n\n listNamespaces: (listOptions) => tryCatalog(() => catalog.listNamespaces(listOptions)),\n createNamespace: (id, metadata) => tryCatalog(() => catalog.createNamespace(id, metadata)),\n dropNamespace: (id) => tryCatalog(() => catalog.dropNamespace(id)),\n loadNamespaceMetadata: (id) => tryCatalog(() => catalog.loadNamespaceMetadata(id)),\n updateNamespaceProperties: (id, request) =>\n tryCatalog(() => catalog.updateNamespaceProperties(id, request)),\n\n listTables: (namespace, listOptions) =>\n tryCatalog(() => catalog.listTables(namespace, listOptions)),\n createTable: (namespace, request) => tryCatalog(() => catalog.createTable(namespace, request)),\n createTableResult: (namespace, request) =>\n tryCatalog(() => catalog.createTableResult(namespace, request)),\n updateTable: (id, request) => tryCatalog(() => catalog.updateTable(id, request)),\n commitTable: (id, request) => tryCatalog(() => catalog.commitTable(id, request)),\n dropTable: (id, dropOptions) => tryCatalog(() => catalog.dropTable(id, dropOptions)),\n loadTable,\n loadTableResult: (id, loadOptions) =>\n tryCatalog(() => catalog.loadTableResult(id, loadOptions)),\n namespaceExists: (id) => tryCatalog(() => catalog.namespaceExists(id)),\n tableExists: (id) => tryCatalog(() => catalog.tableExists(id)),\n createNamespaceIfNotExists: (id, metadata) =>\n tryCatalog(() => catalog.createNamespaceIfNotExists(id, metadata)),\n createTableIfNotExists: (namespace, request) =>\n tryCatalog(() => catalog.createTableIfNotExists(namespace, request)),\n registerTable: (namespace, request) =>\n tryCatalog(() => catalog.registerTable(namespace, request)),\n registerTableResult: (namespace, request) =>\n tryCatalog(() => catalog.registerTableResult(namespace, request)),\n renameTable: (request) => tryCatalog(() => catalog.renameTable(request)),\n });\n};\n\nconst service = Effect.service(IcebergCatalog);\n\nexport const getCatalogClient: Effect.Effect<IcebergRestCatalog, never, IcebergCatalog> =\n Effect.map(service, (catalog) => catalog.getCatalogClient());\n\nexport const loadConfig: Effect.Effect<CatalogConfig, IcebergError, IcebergCatalog> =\n Effect.flatMap(service, (catalog) => catalog.loadConfig());\n\nexport const listNamespaces = (\n options?: ListNamespacesOptions,\n): Effect.Effect<ListNamespacesResult, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.listNamespaces(options));\n\nexport const createNamespace = (\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata,\n): Effect.Effect<CreateNamespaceResponse, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createNamespace(id, metadata));\n\nexport const dropNamespace = (\n id: NamespaceIdentifier,\n): Effect.Effect<void, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.dropNamespace(id));\n\nexport const loadNamespaceMetadata = (\n id: NamespaceIdentifier,\n): Effect.Effect<NamespaceMetadata, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.loadNamespaceMetadata(id));\n\nexport const updateNamespaceProperties = (\n id: NamespaceIdentifier,\n request: UpdateNamespacePropertiesRequest,\n): Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.updateNamespaceProperties(id, request));\n\nexport const listTables = (\n namespace: NamespaceIdentifier,\n options?: ListTablesOptions,\n): Effect.Effect<ListTablesResult, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.listTables(namespace, options));\n\nexport const createTable = (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createTable(namespace, request));\n\nexport const createTableResult = (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n): Effect.Effect<LoadTableResultWithEtag, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createTableResult(namespace, request));\n\nexport const updateTable = (\n id: TableIdentifier,\n request: UpdateTableRequest,\n): Effect.Effect<CommitTableResponse, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.updateTable(id, request));\n\nexport const commitTable = (\n id: TableIdentifier,\n request: CommitTableRequest,\n): Effect.Effect<CommitTableResponse, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.commitTable(id, request));\n\nexport const dropTable = (\n id: TableIdentifier,\n options?: DropTableRequest,\n): Effect.Effect<void, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.dropTable(id, options));\n\nexport function loadTable(\n id: TableIdentifier,\n): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog>;\nexport function loadTable(\n id: TableIdentifier,\n options: LoadTableOptions,\n): Effect.Effect<TableMetadata | null, IcebergError, IcebergCatalog>;\nexport function loadTable(id: TableIdentifier, options?: LoadTableOptions) {\n return Effect.flatMap(service, (catalog) =>\n options === undefined ? catalog.loadTable(id) : catalog.loadTable(id, options),\n );\n}\n\nexport const loadTableResult = (\n id: TableIdentifier,\n options?: LoadTableOptions,\n): Effect.Effect<LoadTableResultWithEtag | null, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.loadTableResult(id, options));\n\nexport const namespaceExists = (\n id: NamespaceIdentifier,\n): Effect.Effect<boolean, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.namespaceExists(id));\n\nexport const tableExists = (\n id: TableIdentifier,\n): Effect.Effect<boolean, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.tableExists(id));\n\nexport const createNamespaceIfNotExists = (\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata,\n): Effect.Effect<CreateNamespaceResponse | void, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createNamespaceIfNotExists(id, metadata));\n\nexport const createTableIfNotExists = (\n namespace: NamespaceIdentifier,\n request: CreateTableRequest,\n): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.createTableIfNotExists(namespace, request));\n\nexport const registerTable = (\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest,\n): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.registerTable(namespace, request));\n\nexport const registerTableResult = (\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest,\n): Effect.Effect<LoadTableResultWithEtag, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.registerTableResult(namespace, request));\n\nexport const renameTable = (\n request: RenameTableRequest,\n): Effect.Effect<void, IcebergError, IcebergCatalog> =>\n Effect.flatMap(service, (catalog) => catalog.renameTable(request));\n\n/** Creates an `IcebergCatalog` layer from concrete `iceberg-js` catalog options. */\nexport const layer = (options: IcebergRestCatalogOptions): Layer.Layer<IcebergCatalog> =>\n Layer.succeed(IcebergCatalog)(make(options));\n\n/** Creates an `IcebergCatalog` layer from Effect `Config` values. */\nexport const layerConfig = (\n config: Config.Wrap<IcebergRestCatalogOptions>,\n): Layer.Layer<IcebergCatalog, Config.ConfigError> =>\n Layer.effect(\n IcebergCatalog,\n Effect.gen(function* () {\n const options = yield* Config.unwrap(config);\n return make(options);\n }),\n );\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,49 @@
1
1
  {
2
2
  "name": "@useairfoil/effect-iceberg",
3
- "version": "0.0.0",
4
- "description": "",
5
- "main": "index.js",
3
+ "version": "0.0.1",
4
+ "keywords": [
5
+ "effect",
6
+ "iceberg"
7
+ ],
8
+ "repository": "useairfoil/typescript-sdk",
9
+ "files": [
10
+ "dist",
11
+ "src",
12
+ "README.md"
13
+ ],
14
+ "type": "module",
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "default": "./dist/index.js"
22
+ }
23
+ },
6
24
  "scripts": {
25
+ "build": "tsdown",
26
+ "test": "vitest",
27
+ "test:ci": "vitest run",
28
+ "typecheck": "tsc --noEmit"
29
+ },
30
+ "devDependencies": {
31
+ "@effect/vitest": "4.0.0-beta.83",
32
+ "@types/node": "^24.2.0",
33
+ "iceberg-js": "^1.0.0",
34
+ "tsdown": "^0.15.6",
35
+ "vitest": "^3.2.4"
36
+ },
37
+ "peerDependencies": {
38
+ "effect": "4.0.0-beta.83",
39
+ "iceberg-js": "^1.0.0"
7
40
  },
8
- "keywords": [],
9
- "author": "",
10
- "license": "ISC",
11
- "packageManager": "pnpm@10.28.0"
41
+ "peerDependenciesMeta": {
42
+ "effect": {
43
+ "optional": false
44
+ },
45
+ "iceberg-js": {
46
+ "optional": false
47
+ }
48
+ }
12
49
  }
package/src/catalog.ts ADDED
@@ -0,0 +1,377 @@
1
+ import type {
2
+ CatalogConfig,
3
+ CommitTableRequest,
4
+ CommitTableResponse,
5
+ CreateNamespaceResponse,
6
+ CreateTableRequest,
7
+ DropTableRequest,
8
+ IcebergRestCatalogOptions,
9
+ ListNamespacesOptions,
10
+ ListNamespacesResult,
11
+ ListTablesOptions,
12
+ ListTablesResult,
13
+ LoadTableOptions,
14
+ LoadTableResultWithEtag,
15
+ NamespaceIdentifier,
16
+ NamespaceMetadata,
17
+ RegisterTableRequest,
18
+ RenameTableRequest,
19
+ TableIdentifier,
20
+ TableMetadata,
21
+ UpdateNamespacePropertiesRequest,
22
+ UpdateNamespacePropertiesResponse,
23
+ UpdateTableRequest,
24
+ } from "iceberg-js";
25
+
26
+ import { Config, Context, Effect, Layer } from "effect";
27
+ import { IcebergRestCatalog } from "iceberg-js";
28
+
29
+ import type { IcebergError } from "./errors";
30
+
31
+ import { mapIcebergError } from "./errors";
32
+
33
+ export interface Service {
34
+ /**
35
+ * Returns the underlying `iceberg-js` catalog client.
36
+ *
37
+ * Use this for advanced cases that need direct access to the Promise-based API.
38
+ */
39
+ readonly getCatalogClient: () => IcebergRestCatalog;
40
+
41
+ /**
42
+ * Fetch and cache the server's catalog configuration. Calling this is optional;
43
+ * catalog operations trigger it lazily when a warehouse is configured.
44
+ */
45
+ readonly loadConfig: () => Effect.Effect<CatalogConfig, IcebergError>;
46
+
47
+ /** Lists all namespaces in the catalog. */
48
+ readonly listNamespaces: (
49
+ options?: ListNamespacesOptions,
50
+ ) => Effect.Effect<ListNamespacesResult, IcebergError>;
51
+
52
+ /** Creates a new namespace in the catalog. */
53
+ readonly createNamespace: (
54
+ id: NamespaceIdentifier,
55
+ metadata?: NamespaceMetadata,
56
+ ) => Effect.Effect<CreateNamespaceResponse, IcebergError>;
57
+
58
+ /**
59
+ * Drops a namespace from the catalog.
60
+ *
61
+ * The namespace must be empty before it can be dropped.
62
+ */
63
+ readonly dropNamespace: (id: NamespaceIdentifier) => Effect.Effect<void, IcebergError>;
64
+
65
+ /** Loads metadata for a namespace. */
66
+ readonly loadNamespaceMetadata: (
67
+ id: NamespaceIdentifier,
68
+ ) => Effect.Effect<NamespaceMetadata, IcebergError>;
69
+
70
+ /** Sets or removes properties on a namespace. */
71
+ readonly updateNamespaceProperties: (
72
+ id: NamespaceIdentifier,
73
+ request: UpdateNamespacePropertiesRequest,
74
+ ) => Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError>;
75
+
76
+ /** Lists tables in a namespace. */
77
+ readonly listTables: (
78
+ namespace: NamespaceIdentifier,
79
+ options?: ListTablesOptions,
80
+ ) => Effect.Effect<ListTablesResult, IcebergError>;
81
+
82
+ /** Creates a new table in the catalog. */
83
+ readonly createTable: (
84
+ namespace: NamespaceIdentifier,
85
+ request: CreateTableRequest,
86
+ ) => Effect.Effect<TableMetadata, IcebergError>;
87
+
88
+ /**
89
+ * Creates a table and returns the full spec-aligned `LoadTableResult`, including
90
+ * server config, storage credentials, and the response ETag.
91
+ */
92
+ readonly createTableResult: (
93
+ namespace: NamespaceIdentifier,
94
+ request: CreateTableRequest,
95
+ ) => Effect.Effect<LoadTableResultWithEtag, IcebergError>;
96
+
97
+ /** Commits updates to a table using the spec-aligned `{ requirements, updates }` shape. */
98
+ readonly updateTable: (
99
+ id: TableIdentifier,
100
+ request: UpdateTableRequest,
101
+ ) => Effect.Effect<CommitTableResponse, IcebergError>;
102
+
103
+ /** Spec-aligned alias for `updateTable`. */
104
+ readonly commitTable: (
105
+ id: TableIdentifier,
106
+ request: CommitTableRequest,
107
+ ) => Effect.Effect<CommitTableResponse, IcebergError>;
108
+
109
+ /** Drops a table from the catalog. */
110
+ readonly dropTable: (
111
+ id: TableIdentifier,
112
+ options?: DropTableRequest,
113
+ ) => Effect.Effect<void, IcebergError>;
114
+
115
+ /**
116
+ * Loads metadata for a table.
117
+ *
118
+ * Pass `ifNoneMatch` in options to perform a conditional GET. If the server
119
+ * returns 304 Not Modified, the result is `null`.
120
+ */
121
+ readonly loadTable: {
122
+ (id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError>;
123
+ (
124
+ id: TableIdentifier,
125
+ options: LoadTableOptions,
126
+ ): Effect.Effect<TableMetadata | null, IcebergError>;
127
+ };
128
+
129
+ /**
130
+ * Loads the full spec-aligned `LoadTableResult`, including server config,
131
+ * storage credentials, and the response ETag. Returns `null` on 304.
132
+ */
133
+ readonly loadTableResult: (
134
+ id: TableIdentifier,
135
+ options?: LoadTableOptions,
136
+ ) => Effect.Effect<LoadTableResultWithEtag | null, IcebergError>;
137
+
138
+ /** Checks if a namespace exists in the catalog. */
139
+ readonly namespaceExists: (id: NamespaceIdentifier) => Effect.Effect<boolean, IcebergError>;
140
+
141
+ /** Checks if a table exists in the catalog. */
142
+ readonly tableExists: (id: TableIdentifier) => Effect.Effect<boolean, IcebergError>;
143
+
144
+ /** Creates a namespace if it does not exist. */
145
+ readonly createNamespaceIfNotExists: (
146
+ id: NamespaceIdentifier,
147
+ metadata?: NamespaceMetadata,
148
+ ) => Effect.Effect<CreateNamespaceResponse | void, IcebergError>;
149
+
150
+ /** Creates a table if it does not exist. */
151
+ readonly createTableIfNotExists: (
152
+ namespace: NamespaceIdentifier,
153
+ request: CreateTableRequest,
154
+ ) => Effect.Effect<TableMetadata, IcebergError>;
155
+
156
+ /** Registers an existing metadata file as a table in the given namespace. */
157
+ readonly registerTable: (
158
+ namespace: NamespaceIdentifier,
159
+ request: RegisterTableRequest,
160
+ ) => Effect.Effect<TableMetadata, IcebergError>;
161
+
162
+ /** Returns the full spec-aligned `LoadTableResult` for `registerTable`. */
163
+ readonly registerTableResult: (
164
+ namespace: NamespaceIdentifier,
165
+ request: RegisterTableRequest,
166
+ ) => Effect.Effect<LoadTableResultWithEtag, IcebergError>;
167
+
168
+ /** Renames a table. Servers may or may not support cross-namespace renames. */
169
+ readonly renameTable: (request: RenameTableRequest) => Effect.Effect<void, IcebergError>;
170
+ }
171
+
172
+ /** Service for the Effect wrapper around `iceberg-js`'s `IcebergRestCatalog`. */
173
+ export class IcebergCatalog extends Context.Service<IcebergCatalog, Service>()(
174
+ "@useairfoil/effect-iceberg/IcebergCatalog",
175
+ ) {}
176
+
177
+ const tryCatalog = <A>(evaluate: () => Promise<A>): Effect.Effect<A, IcebergError> =>
178
+ Effect.tryPromise({
179
+ try: evaluate,
180
+ catch: mapIcebergError,
181
+ });
182
+
183
+ /** Creates an `IcebergCatalog` service from `iceberg-js` catalog options. */
184
+ export const make = (options: IcebergRestCatalogOptions): Service => {
185
+ const catalog = new IcebergRestCatalog(options);
186
+
187
+ function loadTable(id: TableIdentifier): Effect.Effect<TableMetadata, IcebergError>;
188
+ function loadTable(
189
+ id: TableIdentifier,
190
+ loadOptions: LoadTableOptions,
191
+ ): Effect.Effect<TableMetadata | null, IcebergError>;
192
+ function loadTable(id: TableIdentifier, loadOptions?: LoadTableOptions) {
193
+ return tryCatalog(() =>
194
+ loadOptions === undefined ? catalog.loadTable(id) : catalog.loadTable(id, loadOptions),
195
+ );
196
+ }
197
+
198
+ return IcebergCatalog.of({
199
+ getCatalogClient: () => catalog,
200
+ loadConfig: () => tryCatalog(() => catalog.loadConfig()),
201
+
202
+ listNamespaces: (listOptions) => tryCatalog(() => catalog.listNamespaces(listOptions)),
203
+ createNamespace: (id, metadata) => tryCatalog(() => catalog.createNamespace(id, metadata)),
204
+ dropNamespace: (id) => tryCatalog(() => catalog.dropNamespace(id)),
205
+ loadNamespaceMetadata: (id) => tryCatalog(() => catalog.loadNamespaceMetadata(id)),
206
+ updateNamespaceProperties: (id, request) =>
207
+ tryCatalog(() => catalog.updateNamespaceProperties(id, request)),
208
+
209
+ listTables: (namespace, listOptions) =>
210
+ tryCatalog(() => catalog.listTables(namespace, listOptions)),
211
+ createTable: (namespace, request) => tryCatalog(() => catalog.createTable(namespace, request)),
212
+ createTableResult: (namespace, request) =>
213
+ tryCatalog(() => catalog.createTableResult(namespace, request)),
214
+ updateTable: (id, request) => tryCatalog(() => catalog.updateTable(id, request)),
215
+ commitTable: (id, request) => tryCatalog(() => catalog.commitTable(id, request)),
216
+ dropTable: (id, dropOptions) => tryCatalog(() => catalog.dropTable(id, dropOptions)),
217
+ loadTable,
218
+ loadTableResult: (id, loadOptions) =>
219
+ tryCatalog(() => catalog.loadTableResult(id, loadOptions)),
220
+ namespaceExists: (id) => tryCatalog(() => catalog.namespaceExists(id)),
221
+ tableExists: (id) => tryCatalog(() => catalog.tableExists(id)),
222
+ createNamespaceIfNotExists: (id, metadata) =>
223
+ tryCatalog(() => catalog.createNamespaceIfNotExists(id, metadata)),
224
+ createTableIfNotExists: (namespace, request) =>
225
+ tryCatalog(() => catalog.createTableIfNotExists(namespace, request)),
226
+ registerTable: (namespace, request) =>
227
+ tryCatalog(() => catalog.registerTable(namespace, request)),
228
+ registerTableResult: (namespace, request) =>
229
+ tryCatalog(() => catalog.registerTableResult(namespace, request)),
230
+ renameTable: (request) => tryCatalog(() => catalog.renameTable(request)),
231
+ });
232
+ };
233
+
234
+ const service = Effect.service(IcebergCatalog);
235
+
236
+ export const getCatalogClient: Effect.Effect<IcebergRestCatalog, never, IcebergCatalog> =
237
+ Effect.map(service, (catalog) => catalog.getCatalogClient());
238
+
239
+ export const loadConfig: Effect.Effect<CatalogConfig, IcebergError, IcebergCatalog> =
240
+ Effect.flatMap(service, (catalog) => catalog.loadConfig());
241
+
242
+ export const listNamespaces = (
243
+ options?: ListNamespacesOptions,
244
+ ): Effect.Effect<ListNamespacesResult, IcebergError, IcebergCatalog> =>
245
+ Effect.flatMap(service, (catalog) => catalog.listNamespaces(options));
246
+
247
+ export const createNamespace = (
248
+ id: NamespaceIdentifier,
249
+ metadata?: NamespaceMetadata,
250
+ ): Effect.Effect<CreateNamespaceResponse, IcebergError, IcebergCatalog> =>
251
+ Effect.flatMap(service, (catalog) => catalog.createNamespace(id, metadata));
252
+
253
+ export const dropNamespace = (
254
+ id: NamespaceIdentifier,
255
+ ): Effect.Effect<void, IcebergError, IcebergCatalog> =>
256
+ Effect.flatMap(service, (catalog) => catalog.dropNamespace(id));
257
+
258
+ export const loadNamespaceMetadata = (
259
+ id: NamespaceIdentifier,
260
+ ): Effect.Effect<NamespaceMetadata, IcebergError, IcebergCatalog> =>
261
+ Effect.flatMap(service, (catalog) => catalog.loadNamespaceMetadata(id));
262
+
263
+ export const updateNamespaceProperties = (
264
+ id: NamespaceIdentifier,
265
+ request: UpdateNamespacePropertiesRequest,
266
+ ): Effect.Effect<UpdateNamespacePropertiesResponse, IcebergError, IcebergCatalog> =>
267
+ Effect.flatMap(service, (catalog) => catalog.updateNamespaceProperties(id, request));
268
+
269
+ export const listTables = (
270
+ namespace: NamespaceIdentifier,
271
+ options?: ListTablesOptions,
272
+ ): Effect.Effect<ListTablesResult, IcebergError, IcebergCatalog> =>
273
+ Effect.flatMap(service, (catalog) => catalog.listTables(namespace, options));
274
+
275
+ export const createTable = (
276
+ namespace: NamespaceIdentifier,
277
+ request: CreateTableRequest,
278
+ ): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>
279
+ Effect.flatMap(service, (catalog) => catalog.createTable(namespace, request));
280
+
281
+ export const createTableResult = (
282
+ namespace: NamespaceIdentifier,
283
+ request: CreateTableRequest,
284
+ ): Effect.Effect<LoadTableResultWithEtag, IcebergError, IcebergCatalog> =>
285
+ Effect.flatMap(service, (catalog) => catalog.createTableResult(namespace, request));
286
+
287
+ export const updateTable = (
288
+ id: TableIdentifier,
289
+ request: UpdateTableRequest,
290
+ ): Effect.Effect<CommitTableResponse, IcebergError, IcebergCatalog> =>
291
+ Effect.flatMap(service, (catalog) => catalog.updateTable(id, request));
292
+
293
+ export const commitTable = (
294
+ id: TableIdentifier,
295
+ request: CommitTableRequest,
296
+ ): Effect.Effect<CommitTableResponse, IcebergError, IcebergCatalog> =>
297
+ Effect.flatMap(service, (catalog) => catalog.commitTable(id, request));
298
+
299
+ export const dropTable = (
300
+ id: TableIdentifier,
301
+ options?: DropTableRequest,
302
+ ): Effect.Effect<void, IcebergError, IcebergCatalog> =>
303
+ Effect.flatMap(service, (catalog) => catalog.dropTable(id, options));
304
+
305
+ export function loadTable(
306
+ id: TableIdentifier,
307
+ ): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog>;
308
+ export function loadTable(
309
+ id: TableIdentifier,
310
+ options: LoadTableOptions,
311
+ ): Effect.Effect<TableMetadata | null, IcebergError, IcebergCatalog>;
312
+ export function loadTable(id: TableIdentifier, options?: LoadTableOptions) {
313
+ return Effect.flatMap(service, (catalog) =>
314
+ options === undefined ? catalog.loadTable(id) : catalog.loadTable(id, options),
315
+ );
316
+ }
317
+
318
+ export const loadTableResult = (
319
+ id: TableIdentifier,
320
+ options?: LoadTableOptions,
321
+ ): Effect.Effect<LoadTableResultWithEtag | null, IcebergError, IcebergCatalog> =>
322
+ Effect.flatMap(service, (catalog) => catalog.loadTableResult(id, options));
323
+
324
+ export const namespaceExists = (
325
+ id: NamespaceIdentifier,
326
+ ): Effect.Effect<boolean, IcebergError, IcebergCatalog> =>
327
+ Effect.flatMap(service, (catalog) => catalog.namespaceExists(id));
328
+
329
+ export const tableExists = (
330
+ id: TableIdentifier,
331
+ ): Effect.Effect<boolean, IcebergError, IcebergCatalog> =>
332
+ Effect.flatMap(service, (catalog) => catalog.tableExists(id));
333
+
334
+ export const createNamespaceIfNotExists = (
335
+ id: NamespaceIdentifier,
336
+ metadata?: NamespaceMetadata,
337
+ ): Effect.Effect<CreateNamespaceResponse | void, IcebergError, IcebergCatalog> =>
338
+ Effect.flatMap(service, (catalog) => catalog.createNamespaceIfNotExists(id, metadata));
339
+
340
+ export const createTableIfNotExists = (
341
+ namespace: NamespaceIdentifier,
342
+ request: CreateTableRequest,
343
+ ): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>
344
+ Effect.flatMap(service, (catalog) => catalog.createTableIfNotExists(namespace, request));
345
+
346
+ export const registerTable = (
347
+ namespace: NamespaceIdentifier,
348
+ request: RegisterTableRequest,
349
+ ): Effect.Effect<TableMetadata, IcebergError, IcebergCatalog> =>
350
+ Effect.flatMap(service, (catalog) => catalog.registerTable(namespace, request));
351
+
352
+ export const registerTableResult = (
353
+ namespace: NamespaceIdentifier,
354
+ request: RegisterTableRequest,
355
+ ): Effect.Effect<LoadTableResultWithEtag, IcebergError, IcebergCatalog> =>
356
+ Effect.flatMap(service, (catalog) => catalog.registerTableResult(namespace, request));
357
+
358
+ export const renameTable = (
359
+ request: RenameTableRequest,
360
+ ): Effect.Effect<void, IcebergError, IcebergCatalog> =>
361
+ Effect.flatMap(service, (catalog) => catalog.renameTable(request));
362
+
363
+ /** Creates an `IcebergCatalog` layer from concrete `iceberg-js` catalog options. */
364
+ export const layer = (options: IcebergRestCatalogOptions): Layer.Layer<IcebergCatalog> =>
365
+ Layer.succeed(IcebergCatalog)(make(options));
366
+
367
+ /** Creates an `IcebergCatalog` layer from Effect `Config` values. */
368
+ export const layerConfig = (
369
+ config: Config.Wrap<IcebergRestCatalogOptions>,
370
+ ): Layer.Layer<IcebergCatalog, Config.ConfigError> =>
371
+ Layer.effect(
372
+ IcebergCatalog,
373
+ Effect.gen(function* () {
374
+ const options = yield* Config.unwrap(config);
375
+ return make(options);
376
+ }),
377
+ );
package/src/errors.ts ADDED
@@ -0,0 +1,33 @@
1
+ import { Data } from "effect";
2
+ import { IcebergError as IcebergJsError } from "iceberg-js";
3
+
4
+ /** Error type used by the Effect wrapper around `iceberg-js`. */
5
+ export class IcebergError extends Data.TaggedError("IcebergError")<{
6
+ readonly message: string;
7
+ readonly status?: number;
8
+ readonly icebergType?: string;
9
+ readonly icebergCode?: number;
10
+ readonly details?: unknown;
11
+ readonly isCommitStateUnknown?: boolean;
12
+ readonly cause?: unknown;
13
+ }> {}
14
+
15
+ /** Maps errors thrown by `iceberg-js` into `IcebergError`. */
16
+ export const mapIcebergError = (error: unknown): IcebergError => {
17
+ if (error instanceof IcebergJsError) {
18
+ return new IcebergError({
19
+ message: error.message,
20
+ status: error.status,
21
+ icebergType: error.icebergType,
22
+ icebergCode: error.icebergCode,
23
+ details: error.details,
24
+ isCommitStateUnknown: error.isCommitStateUnknown,
25
+ cause: error,
26
+ });
27
+ }
28
+
29
+ return new IcebergError({
30
+ message: error instanceof Error ? error.message : String(error),
31
+ cause: error,
32
+ });
33
+ };
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * as IcebergCatalog from "./catalog";
2
+ export * as IcebergError from "./errors";