airfoil 0.4.5 → 0.4.7
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/LICENSE.txt +201 -0
- package/README.md +24 -0
- package/dist/index.mjs +283 -0
- package/package.json +24 -21
- package/src/commands/catalog.ts +48 -0
- package/src/commands/namespace.ts +75 -0
- package/src/commands/table.ts +111 -0
- package/src/index.ts +12 -6
- package/src/utils/iceberg.ts +58 -0
- package/src/utils/json.ts +48 -0
- package/src/utils/logger.ts +67 -0
- package/src/utils/options.ts +17 -31
- package/dist/index.js +0 -855
- package/src/commands/cluster/index.ts +0 -25
- package/src/commands/cluster/namespace/create.ts +0 -314
- package/src/commands/cluster/namespace/delete.ts +0 -54
- package/src/commands/cluster/namespace/get.ts +0 -46
- package/src/commands/cluster/namespace/list.ts +0 -53
- package/src/commands/cluster/table/create.ts +0 -279
- package/src/commands/cluster/table/delete.ts +0 -54
- package/src/commands/cluster/table/get.ts +0 -62
- package/src/commands/cluster/table/list.ts +0 -61
- package/src/commands/dev.ts +0 -136
- package/src/commands/sql.ts +0 -90
- package/src/utils/client.ts +0 -6
- package/src/utils/docker.ts +0 -137
- package/src/utils/wings.ts +0 -124
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Effect, Option } from "effect";
|
|
2
|
+
import { Argument, Command, Flag } from "effect/cli";
|
|
3
|
+
|
|
4
|
+
import { getIcebergCatalog, parseNamespaceIdentifier } from "../utils/iceberg";
|
|
5
|
+
import { catalogFlag } from "../utils/options";
|
|
6
|
+
|
|
7
|
+
const namespaceArgument = Argument.String("namespace").pipe(
|
|
8
|
+
Argument.withDescription("Namespace name. Use dot-separated notation for nested namespaces"),
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const parentFlag = Flag.String("parent").pipe(
|
|
12
|
+
Flag.withDescription("Parent namespace. Use dot-separated notation for nested namespaces"),
|
|
13
|
+
Flag.optional,
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const createCommand = Command.make(
|
|
17
|
+
"create",
|
|
18
|
+
{ namespace: namespaceArgument, catalog: catalogFlag },
|
|
19
|
+
({ namespace, catalog }) =>
|
|
20
|
+
Effect.gen(function* () {
|
|
21
|
+
const id = yield* parseNamespaceIdentifier(namespace);
|
|
22
|
+
const iceberg = yield* getIcebergCatalog(catalog);
|
|
23
|
+
const created = yield* iceberg.createNamespace(id);
|
|
24
|
+
|
|
25
|
+
yield* Effect.log(created);
|
|
26
|
+
}),
|
|
27
|
+
).pipe(Command.withDescription("Create a new namespace"));
|
|
28
|
+
|
|
29
|
+
const getCommand = Command.make(
|
|
30
|
+
"get",
|
|
31
|
+
{ namespace: namespaceArgument, catalog: catalogFlag },
|
|
32
|
+
({ namespace, catalog }) =>
|
|
33
|
+
Effect.gen(function* () {
|
|
34
|
+
const id = yield* parseNamespaceIdentifier(namespace);
|
|
35
|
+
const iceberg = yield* getIcebergCatalog(catalog);
|
|
36
|
+
const metadata = yield* iceberg.loadNamespaceMetadata(id);
|
|
37
|
+
|
|
38
|
+
yield* Effect.log({ ...id, ...metadata });
|
|
39
|
+
}),
|
|
40
|
+
).pipe(Command.withDescription("Get a namespace"));
|
|
41
|
+
|
|
42
|
+
const deleteCommand = Command.make(
|
|
43
|
+
"delete",
|
|
44
|
+
{ namespace: namespaceArgument, catalog: catalogFlag },
|
|
45
|
+
({ namespace, catalog }) =>
|
|
46
|
+
Effect.gen(function* () {
|
|
47
|
+
const id = yield* parseNamespaceIdentifier(namespace);
|
|
48
|
+
const iceberg = yield* getIcebergCatalog(catalog);
|
|
49
|
+
|
|
50
|
+
yield* iceberg.dropNamespace(id);
|
|
51
|
+
yield* Effect.log(id);
|
|
52
|
+
}),
|
|
53
|
+
).pipe(Command.withDescription("Delete a namespace"));
|
|
54
|
+
|
|
55
|
+
const listCommand = Command.make(
|
|
56
|
+
"list",
|
|
57
|
+
{ parent: parentFlag, catalog: catalogFlag },
|
|
58
|
+
({ parent, catalog }) =>
|
|
59
|
+
Effect.gen(function* () {
|
|
60
|
+
const iceberg = yield* getIcebergCatalog(catalog);
|
|
61
|
+
const parentName = Option.getOrUndefined(parent);
|
|
62
|
+
const parentId =
|
|
63
|
+
parentName === undefined ? undefined : yield* parseNamespaceIdentifier(parentName);
|
|
64
|
+
const result = yield* iceberg.listNamespaces(
|
|
65
|
+
parentId === undefined ? undefined : { parent: parentId },
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
yield* Effect.log(result);
|
|
69
|
+
}),
|
|
70
|
+
).pipe(Command.withDescription("List namespaces"));
|
|
71
|
+
|
|
72
|
+
export const namespaceCommand = Command.make("namespace").pipe(
|
|
73
|
+
Command.withDescription("Manage namespaces"),
|
|
74
|
+
Command.withSubcommands([createCommand, getCommand, deleteCommand, listCommand]),
|
|
75
|
+
);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Effect, Option } from "effect";
|
|
2
|
+
import { Argument, CliError, Command, Flag } from "effect/cli";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
getIcebergCatalog,
|
|
6
|
+
listAllNamespaces,
|
|
7
|
+
listAllTables,
|
|
8
|
+
parseNamespaceIdentifier,
|
|
9
|
+
parseTableIdentifier,
|
|
10
|
+
} from "../utils/iceberg";
|
|
11
|
+
import { parseTableFields } from "../utils/json";
|
|
12
|
+
import { catalogFlag } from "../utils/options";
|
|
13
|
+
|
|
14
|
+
const tableArgument = Argument.String("table").pipe(
|
|
15
|
+
Argument.withDescription("Fully qualified table name"),
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const namespaceArgument = Argument.String("namespace").pipe(
|
|
19
|
+
Argument.withDescription("Namespace name. Use dot-separated notation for nested namespaces"),
|
|
20
|
+
Argument.optional,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const allFlag = Flag.Boolean("all").pipe(
|
|
24
|
+
Flag.withDescription("List tables from all namespaces"),
|
|
25
|
+
Flag.withDefault(false),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const schemaFlag = Flag.String("schema").pipe(
|
|
29
|
+
Flag.withDescription("Iceberg table fields as a JSON array"),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const createCommand = Command.make(
|
|
33
|
+
"create",
|
|
34
|
+
{ table: tableArgument, schema: schemaFlag, catalog: catalogFlag },
|
|
35
|
+
({ table, schema, catalog }) =>
|
|
36
|
+
Effect.gen(function* () {
|
|
37
|
+
const id = yield* parseTableIdentifier(table);
|
|
38
|
+
const fields = yield* parseTableFields(schema);
|
|
39
|
+
const iceberg = yield* getIcebergCatalog(catalog);
|
|
40
|
+
const metadata = yield* iceberg.createTable(
|
|
41
|
+
{ namespace: id.namespace },
|
|
42
|
+
{ name: id.name, schema: { type: "struct", fields } },
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
yield* Effect.log({ ...id, metadata });
|
|
46
|
+
}),
|
|
47
|
+
).pipe(Command.withDescription("Create a new table"));
|
|
48
|
+
|
|
49
|
+
const getCommand = Command.make(
|
|
50
|
+
"get",
|
|
51
|
+
{ table: tableArgument, catalog: catalogFlag },
|
|
52
|
+
({ table, catalog }) =>
|
|
53
|
+
Effect.gen(function* () {
|
|
54
|
+
const id = yield* parseTableIdentifier(table);
|
|
55
|
+
const iceberg = yield* getIcebergCatalog(catalog);
|
|
56
|
+
const metadata = yield* iceberg.loadTable(id);
|
|
57
|
+
|
|
58
|
+
yield* Effect.log({ ...id, metadata });
|
|
59
|
+
}),
|
|
60
|
+
).pipe(Command.withDescription("Get a table"));
|
|
61
|
+
|
|
62
|
+
const deleteCommand = Command.make(
|
|
63
|
+
"delete",
|
|
64
|
+
{ table: tableArgument, catalog: catalogFlag },
|
|
65
|
+
({ table, catalog }) =>
|
|
66
|
+
Effect.gen(function* () {
|
|
67
|
+
const id = yield* parseTableIdentifier(table);
|
|
68
|
+
const iceberg = yield* getIcebergCatalog(catalog);
|
|
69
|
+
|
|
70
|
+
yield* iceberg.dropTable(id);
|
|
71
|
+
yield* Effect.log(id);
|
|
72
|
+
}),
|
|
73
|
+
).pipe(Command.withDescription("Delete a table"));
|
|
74
|
+
|
|
75
|
+
const listCommand = Command.make(
|
|
76
|
+
"list",
|
|
77
|
+
{ namespace: namespaceArgument, all: allFlag, catalog: catalogFlag },
|
|
78
|
+
({ namespace, all, catalog }) =>
|
|
79
|
+
Effect.gen(function* () {
|
|
80
|
+
const namespaceName = Option.getOrUndefined(namespace);
|
|
81
|
+
|
|
82
|
+
if (namespaceName === undefined && !all) {
|
|
83
|
+
return yield* new CliError.UserError({
|
|
84
|
+
cause: "Missing table list selector",
|
|
85
|
+
userMessage: "Provide a namespace or use --all",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (namespaceName !== undefined && all) {
|
|
90
|
+
return yield* new CliError.UserError({
|
|
91
|
+
cause: "Conflicting table list selectors",
|
|
92
|
+
userMessage: "Provide either a namespace or --all, not both",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const iceberg = yield* getIcebergCatalog(catalog);
|
|
97
|
+
const tables =
|
|
98
|
+
namespaceName === undefined
|
|
99
|
+
? (yield* Effect.forEach(yield* listAllNamespaces(iceberg), (namespace) =>
|
|
100
|
+
listAllTables(iceberg, namespace),
|
|
101
|
+
)).flat()
|
|
102
|
+
: yield* listAllTables(iceberg, yield* parseNamespaceIdentifier(namespaceName));
|
|
103
|
+
|
|
104
|
+
yield* Effect.log({ namespace: namespaceName, tables });
|
|
105
|
+
}),
|
|
106
|
+
).pipe(Command.withDescription("List tables"));
|
|
107
|
+
|
|
108
|
+
export const tableCommand = Command.make("table").pipe(
|
|
109
|
+
Command.withDescription("Manage tables"),
|
|
110
|
+
Command.withSubcommands([createCommand, getCommand, deleteCommand, listCommand]),
|
|
111
|
+
);
|
package/src/index.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { NodeRuntime, NodeServices } from "@effect/platform-node";
|
|
3
3
|
import { Effect, Layer } from "effect";
|
|
4
|
-
import { Command } from "effect/
|
|
5
|
-
import { FetchHttpClient } from "effect/
|
|
4
|
+
import { Command } from "effect/cli";
|
|
5
|
+
import { FetchHttpClient } from "effect/http";
|
|
6
6
|
|
|
7
7
|
import packageJson from "../package.json";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { catalogCommand } from "./commands/catalog";
|
|
9
|
+
import { namespaceCommand } from "./commands/namespace";
|
|
10
|
+
import { tableCommand } from "./commands/table";
|
|
11
|
+
import { OutputLogger, reportError } from "./utils/logger";
|
|
12
|
+
import { EngineUri, Output } from "./utils/options";
|
|
11
13
|
|
|
12
14
|
const version = packageJson.version;
|
|
13
15
|
|
|
14
16
|
const program = Command.make("airfoil", {}, () => Effect.void).pipe(
|
|
15
|
-
Command.withSubcommands([
|
|
17
|
+
Command.withSubcommands([catalogCommand, namespaceCommand, tableCommand]),
|
|
18
|
+
Command.provide(OutputLogger),
|
|
19
|
+
Command.withGlobalFlags([EngineUri, Output]),
|
|
16
20
|
);
|
|
17
21
|
|
|
18
22
|
const cli = Command.run(program, {
|
|
@@ -23,5 +27,7 @@ NodeRuntime.runMain(
|
|
|
23
27
|
cli.pipe(
|
|
24
28
|
Effect.provide(Layer.mergeAll(FetchHttpClient.layer, NodeServices.layer)),
|
|
25
29
|
Effect.scoped,
|
|
30
|
+
Effect.tapCause(reportError),
|
|
26
31
|
),
|
|
32
|
+
{ disableErrorReporting: true },
|
|
27
33
|
);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { IcebergCatalog } from "@useairfoil/effect-iceberg";
|
|
2
|
+
|
|
3
|
+
import { CatalogManager } from "@useairfoil/api";
|
|
4
|
+
import { Effect, Schema } from "effect";
|
|
5
|
+
|
|
6
|
+
import { EngineUri } from "./options";
|
|
7
|
+
|
|
8
|
+
const NamespaceSegments = Schema.NonEmptyArray(Schema.NonEmptyString);
|
|
9
|
+
const TableSegments = Schema.Array(Schema.NonEmptyString).check(Schema.isMinLength(2));
|
|
10
|
+
|
|
11
|
+
export const parseNamespaceIdentifier = (name: string) =>
|
|
12
|
+
Schema.decodeUnknownEffect(NamespaceSegments)(name.split(".")).pipe(
|
|
13
|
+
Effect.map((namespace) => ({ namespace: Array.from(namespace) })),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
export const parseTableIdentifier = (qualifiedName: string) =>
|
|
17
|
+
Schema.decodeUnknownEffect(TableSegments)(qualifiedName.split(".")).pipe(
|
|
18
|
+
Effect.map((segments) => ({
|
|
19
|
+
namespace: segments.slice(0, -1),
|
|
20
|
+
name: segments[segments.length - 1]!,
|
|
21
|
+
})),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const getIcebergCatalog = Effect.fn("getIcebergCatalog")(function* (catalogId: string) {
|
|
25
|
+
const engineUri = yield* EngineUri;
|
|
26
|
+
const manager = yield* CatalogManager.make({ engineUri });
|
|
27
|
+
|
|
28
|
+
return yield* manager.getIcebergCatalog(catalogId);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const listAllNamespaces = Effect.fn("listAllNamespaces")(function* (
|
|
32
|
+
iceberg: IcebergCatalog.Service,
|
|
33
|
+
) {
|
|
34
|
+
let page = yield* iceberg.listNamespaces();
|
|
35
|
+
const namespaces = [...page.namespaces];
|
|
36
|
+
|
|
37
|
+
while (page.nextPageToken !== undefined) {
|
|
38
|
+
page = yield* iceberg.listNamespaces({ pageToken: page.nextPageToken });
|
|
39
|
+
namespaces.push(...page.namespaces);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return namespaces;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const listAllTables = Effect.fn("listAllTables")(function* (
|
|
46
|
+
iceberg: IcebergCatalog.Service,
|
|
47
|
+
namespace: Parameters<IcebergCatalog.Service["listTables"]>[0],
|
|
48
|
+
) {
|
|
49
|
+
let page = yield* iceberg.listTables(namespace);
|
|
50
|
+
const identifiers = [...page.identifiers];
|
|
51
|
+
|
|
52
|
+
while (page.nextPageToken !== undefined) {
|
|
53
|
+
page = yield* iceberg.listTables(namespace, { pageToken: page.nextPageToken });
|
|
54
|
+
identifiers.push(...page.identifiers);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return identifiers;
|
|
58
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { IcebergType, TableField } from "iceberg-js";
|
|
2
|
+
|
|
3
|
+
import { CatalogManager } from "@useairfoil/api";
|
|
4
|
+
import { Schema } from "effect";
|
|
5
|
+
|
|
6
|
+
const RestCatalogConfigJson = Schema.fromJsonString(CatalogManager.RestCatalogConfig);
|
|
7
|
+
|
|
8
|
+
const DefaultValue = Schema.Union([Schema.Boolean, Schema.Number, Schema.String]);
|
|
9
|
+
|
|
10
|
+
const IcebergTypeSchema: Schema.Codec<IcebergType> = Schema.suspend(() =>
|
|
11
|
+
Schema.Union([
|
|
12
|
+
Schema.String,
|
|
13
|
+
Schema.Struct({
|
|
14
|
+
type: Schema.Literal("struct"),
|
|
15
|
+
fields: Schema.mutable(Schema.Array(TableFieldSchema)),
|
|
16
|
+
}),
|
|
17
|
+
Schema.Struct({
|
|
18
|
+
type: Schema.Literal("list"),
|
|
19
|
+
"element-id": Schema.Int,
|
|
20
|
+
element: IcebergTypeSchema,
|
|
21
|
+
"element-required": Schema.Boolean,
|
|
22
|
+
}),
|
|
23
|
+
Schema.Struct({
|
|
24
|
+
type: Schema.Literal("map"),
|
|
25
|
+
"key-id": Schema.Int,
|
|
26
|
+
key: IcebergTypeSchema,
|
|
27
|
+
"value-id": Schema.Int,
|
|
28
|
+
value: IcebergTypeSchema,
|
|
29
|
+
"value-required": Schema.Boolean,
|
|
30
|
+
}),
|
|
31
|
+
]),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const TableFieldSchema: Schema.Codec<TableField> = Schema.Struct({
|
|
35
|
+
id: Schema.Int,
|
|
36
|
+
name: Schema.NonEmptyString,
|
|
37
|
+
type: IcebergTypeSchema,
|
|
38
|
+
required: Schema.Boolean,
|
|
39
|
+
doc: Schema.optional(Schema.String),
|
|
40
|
+
"initial-default": Schema.optional(DefaultValue),
|
|
41
|
+
"write-default": Schema.optional(DefaultValue),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const TableFieldsJson = Schema.fromJsonString(Schema.mutable(Schema.Array(TableFieldSchema)));
|
|
45
|
+
|
|
46
|
+
export const parseRestCatalogConfig = Schema.decodeUnknownEffect(RestCatalogConfigJson);
|
|
47
|
+
|
|
48
|
+
export const parseTableFields = Schema.decodeUnknownEffect(TableFieldsJson);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { encode } from "@toon-format/toon";
|
|
2
|
+
import { Cause, Console, Effect, Formatter, Layer, Logger, Result, Runtime, Schema } from "effect";
|
|
3
|
+
|
|
4
|
+
import { Output } from "./options";
|
|
5
|
+
|
|
6
|
+
const decodeJson = Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Unknown));
|
|
7
|
+
|
|
8
|
+
export type OutputFormat = "default" | "json";
|
|
9
|
+
|
|
10
|
+
export const formatStructured = (value: unknown, output: OutputFormat) => {
|
|
11
|
+
const json = Formatter.formatJson(value);
|
|
12
|
+
|
|
13
|
+
return output === "json" ? json : encode(decodeJson(json));
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const messageValue = (message: unknown) =>
|
|
17
|
+
Array.isArray(message) && message.length === 1 ? message[0] : message;
|
|
18
|
+
|
|
19
|
+
const structuredLogger = (output: OutputFormat) =>
|
|
20
|
+
Logger.make<unknown, string>(({ message }) =>
|
|
21
|
+
formatStructured(messageValue(message), output),
|
|
22
|
+
).pipe(Logger.withConsoleLog);
|
|
23
|
+
|
|
24
|
+
// Errors are reported after the command ends, when its flags are gone. Keep the format here.
|
|
25
|
+
let errorFormat: OutputFormat = "default";
|
|
26
|
+
|
|
27
|
+
export const OutputLogger = Layer.unwrap(
|
|
28
|
+
Effect.map(Output, (output) => {
|
|
29
|
+
errorFormat = output;
|
|
30
|
+
|
|
31
|
+
return Logger.layer([structuredLogger(output)]);
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// Turns an error and its causes into plain JSON, so we do not walk the chain ourselves.
|
|
36
|
+
const encodeError = Schema.encodeSync(Schema.Defect());
|
|
37
|
+
const encodeErrorWithStack = Schema.encodeSync(Schema.Defect({ includeStack: true }));
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Prints a failed command as `error: message: ... cause: ...` instead of the stack dump
|
|
41
|
+
* `runMain` prints by default.
|
|
42
|
+
*
|
|
43
|
+
* Says nothing about Ctrl+C, or about errors the CLI already printed itself.
|
|
44
|
+
*/
|
|
45
|
+
export const reportError = (cause: Cause.Cause<unknown>) => {
|
|
46
|
+
if (Cause.hasInterruptsOnly(cause)) return Effect.void;
|
|
47
|
+
|
|
48
|
+
const error = Cause.squash(cause);
|
|
49
|
+
|
|
50
|
+
if (!Runtime.getErrorReported(error)) return Effect.void;
|
|
51
|
+
|
|
52
|
+
// Only an unexpected defect is worth a stack. A failure is explained by its message chain.
|
|
53
|
+
const defect = Cause.findDefect(cause);
|
|
54
|
+
const stack =
|
|
55
|
+
Result.isSuccess(defect) && defect.success instanceof Error ? defect.success.stack : undefined;
|
|
56
|
+
|
|
57
|
+
if (errorFormat === "json") {
|
|
58
|
+
const encode = stack === undefined ? encodeError : encodeErrorWithStack;
|
|
59
|
+
|
|
60
|
+
return Console.error(formatStructured({ error: encode(error) }, "json"));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Toon has no multi-line string, so the stack only reads well under the block.
|
|
64
|
+
const block = formatStructured({ error: encodeError(error) }, "default");
|
|
65
|
+
|
|
66
|
+
return Console.error(stack === undefined ? block : `${block}\n\n${stack}`);
|
|
67
|
+
};
|
package/src/utils/options.ts
CHANGED
|
@@ -1,35 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Config } from "effect";
|
|
2
|
+
import { Flag, GlobalFlag } from "effect/cli";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
);
|
|
10
|
-
|
|
11
|
-
export const portOption = Flag.integer("port").pipe(
|
|
12
|
-
Flag.withDescription("Server port"),
|
|
13
|
-
Flag.withAlias("p"),
|
|
14
|
-
Flag.withDefault(7777),
|
|
15
|
-
);
|
|
4
|
+
export const EngineUri = GlobalFlag.Setting("uri")({
|
|
5
|
+
flag: Flag.String("uri").pipe(
|
|
6
|
+
Flag.withDefault("http://localhost:7777"),
|
|
7
|
+
Flag.withDescription("Engine URI"),
|
|
8
|
+
),
|
|
9
|
+
});
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
export const pageTokenOption = Flag.optional(
|
|
26
|
-
Flag.string("page-token").pipe(Flag.withDescription("Continuation token for pagination")),
|
|
27
|
-
);
|
|
11
|
+
export const Output = GlobalFlag.Setting("output")({
|
|
12
|
+
flag: Flag.Literals("output", ["default", "json"] as const).pipe(
|
|
13
|
+
Flag.withDefault("default"),
|
|
14
|
+
Flag.withDescription("Log output format"),
|
|
15
|
+
),
|
|
16
|
+
});
|
|
28
17
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
export const forceOption = Flag.boolean("force").pipe(
|
|
33
|
-
Flag.withDescription("Skip confirmation prompt"),
|
|
34
|
-
Flag.withDefault(false),
|
|
18
|
+
export const catalogFlag = Flag.String("catalog").pipe(
|
|
19
|
+
Flag.withDescription("Catalog ID. Alternatively, use the AIRFOIL_CATALOG environment variable"),
|
|
20
|
+
Flag.withFallbackConfig(Config.NonEmptyString("AIRFOIL_CATALOG")),
|
|
35
21
|
);
|