airfoil 0.4.0 → 0.4.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.
Files changed (38) hide show
  1. package/dist/index.js +401 -739
  2. package/package.json +9 -6
  3. package/src/commands/cluster/index.ts +13 -37
  4. package/src/commands/cluster/namespace/create.ts +278 -61
  5. package/src/commands/cluster/namespace/delete.ts +9 -13
  6. package/src/commands/cluster/namespace/get.ts +12 -14
  7. package/src/commands/cluster/namespace/list.ts +16 -34
  8. package/src/commands/cluster/{topic → table}/create.ts +79 -96
  9. package/src/commands/cluster/{tenant → table}/delete.ts +15 -17
  10. package/src/commands/cluster/table/get.ts +62 -0
  11. package/src/commands/cluster/table/list.ts +61 -0
  12. package/src/commands/dev.ts +17 -13
  13. package/src/commands/sql.ts +13 -23
  14. package/src/index.ts +6 -6
  15. package/src/utils/client.ts +3 -3
  16. package/src/utils/docker.ts +101 -7
  17. package/src/utils/options.ts +1 -1
  18. package/src/utils/wings.ts +18 -14
  19. package/src/commands/cluster/data-lake/create-iceberg.ts +0 -59
  20. package/src/commands/cluster/data-lake/create-parquet.ts +0 -59
  21. package/src/commands/cluster/data-lake/create.ts +0 -10
  22. package/src/commands/cluster/data-lake/delete.ts +0 -54
  23. package/src/commands/cluster/data-lake/get.ts +0 -40
  24. package/src/commands/cluster/data-lake/list.ts +0 -62
  25. package/src/commands/cluster/object-store/create-aws.ts +0 -104
  26. package/src/commands/cluster/object-store/create-azure.ts +0 -96
  27. package/src/commands/cluster/object-store/create-google.ts +0 -87
  28. package/src/commands/cluster/object-store/create-s3.ts +0 -114
  29. package/src/commands/cluster/object-store/create.ts +0 -21
  30. package/src/commands/cluster/object-store/delete.ts +0 -56
  31. package/src/commands/cluster/object-store/get.ts +0 -49
  32. package/src/commands/cluster/object-store/list.ts +0 -62
  33. package/src/commands/cluster/tenant/create.ts +0 -44
  34. package/src/commands/cluster/tenant/get.ts +0 -40
  35. package/src/commands/cluster/tenant/list.ts +0 -53
  36. package/src/commands/cluster/topic/delete.ts +0 -65
  37. package/src/commands/cluster/topic/get.ts +0 -51
  38. package/src/commands/cluster/topic/list.ts +0 -61
@@ -1,87 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { printTable } from "console-table-printer";
4
- import { Effect, Option } from "effect";
5
- import { Command, Flag } from "effect/unstable/cli";
6
-
7
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
8
- import { hostOption, portOption } from "../../../utils/options.js";
9
-
10
- const parentOption = Flag.string("parent").pipe(
11
- Flag.withDescription("Parent tenant in format: tenants/{tenant}"),
12
- );
13
-
14
- const objectStoreIdOption = Flag.string("object-store-id").pipe(
15
- Flag.withDescription("Unique identifier for the object store"),
16
- );
17
-
18
- const bucketNameOption = Flag.string("bucket-name").pipe(
19
- Flag.withDescription("Google Cloud Storage bucket name"),
20
- );
21
-
22
- const prefixOption = Flag.string("prefix").pipe(
23
- Flag.withDescription("Bucket prefix (optional)"),
24
- Flag.optional,
25
- );
26
-
27
- const serviceAccountOption = Flag.string("service-account").pipe(
28
- Flag.withDescription("GOOGLE_SERVICE_ACCOUNT"),
29
- );
30
-
31
- const serviceAccountKeyOption = Flag.string("service-account-key").pipe(
32
- Flag.withDescription("GOOGLE_SERVICE_ACCOUNT_KEY"),
33
- );
34
-
35
- export const createObjectStoreGoogleCommand = Command.make(
36
- "google",
37
- {
38
- parent: parentOption,
39
- objectStoreId: objectStoreIdOption,
40
- bucketName: bucketNameOption,
41
- prefix: prefixOption,
42
- serviceAccount: serviceAccountOption,
43
- serviceAccountKey: serviceAccountKeyOption,
44
- host: hostOption,
45
- port: portOption,
46
- },
47
- ({ parent, objectStoreId, bucketName, prefix, serviceAccount, serviceAccountKey, host, port }) =>
48
- Effect.gen(function* () {
49
- p.intro("🗄️ Create Google Cloud Storage Object Store");
50
-
51
- const layer = makeClusterMetadataLayer(host, port);
52
-
53
- const s = p.spinner();
54
- s.start("Creating Google Cloud Storage object store...");
55
-
56
- const result = yield* WingsClusterMetadata.createObjectStore({
57
- parent,
58
- objectStoreId,
59
- objectStoreConfig: {
60
- _tag: "google",
61
- google: {
62
- bucketName,
63
- prefix: Option.getOrUndefined(prefix),
64
- serviceAccount,
65
- serviceAccountKey,
66
- },
67
- },
68
- }).pipe(
69
- Effect.provide(layer),
70
- Effect.tapError(() => Effect.sync(() => s.stop("Failed to create Google object store"))),
71
- );
72
-
73
- s.stop("Google Cloud Storage object store created successfully");
74
-
75
- yield* Effect.sync(() => {
76
- printTable([
77
- {
78
- name: result.name,
79
- type: "Google Cloud",
80
- bucket: bucketName,
81
- service_account: serviceAccount,
82
- },
83
- ]);
84
- p.outro("✓ Done");
85
- });
86
- }),
87
- ).pipe(Command.withDescription("Create a new Google Cloud Storage object store"));
@@ -1,114 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { printTable } from "console-table-printer";
4
- import { Effect, Option } from "effect";
5
- import { Command, Flag } from "effect/unstable/cli";
6
-
7
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
8
- import { hostOption, portOption } from "../../../utils/options.js";
9
-
10
- const parentOption = Flag.string("parent").pipe(
11
- Flag.withDescription("Parent tenant in format: tenants/{tenant}"),
12
- );
13
-
14
- const objectStoreIdOption = Flag.string("object-store-id").pipe(
15
- Flag.withDescription("Unique identifier for the object store"),
16
- );
17
-
18
- const bucketNameOption = Flag.string("bucket-name").pipe(Flag.withDescription("S3 bucket name"));
19
-
20
- const prefixOption = Flag.string("prefix").pipe(
21
- Flag.withDescription("Bucket prefix (optional)"),
22
- Flag.optional,
23
- );
24
-
25
- const accessKeyIdOption = Flag.string("access-key-id").pipe(
26
- Flag.withDescription("AWS_ACCESS_KEY_ID"),
27
- );
28
-
29
- const secretAccessKeyOption = Flag.string("secret-access-key").pipe(
30
- Flag.withDescription("AWS_SECRET_ACCESS_KEY"),
31
- );
32
-
33
- const regionOption = Flag.string("region").pipe(
34
- Flag.withDescription("AWS_DEFAULT_REGION"),
35
- Flag.optional,
36
- );
37
-
38
- const endpointOption = Flag.string("endpoint").pipe(
39
- Flag.withDescription("AWS_ENDPOINT (e.g., https://nyc3.digitaloceanspaces.com)"),
40
- );
41
-
42
- export const createObjectStoreS3Command = Command.make(
43
- "s3",
44
- {
45
- parent: parentOption,
46
- objectStoreId: objectStoreIdOption,
47
- bucketName: bucketNameOption,
48
- prefix: prefixOption,
49
- accessKeyId: accessKeyIdOption,
50
- secretAccessKey: secretAccessKeyOption,
51
- region: regionOption,
52
- endpoint: endpointOption,
53
- host: hostOption,
54
- port: portOption,
55
- },
56
- ({
57
- parent,
58
- objectStoreId,
59
- bucketName,
60
- prefix,
61
- accessKeyId,
62
- secretAccessKey,
63
- region,
64
- endpoint,
65
- host,
66
- port,
67
- }) =>
68
- Effect.gen(function* () {
69
- p.intro("🗄️ Create S3-Compatible Object Store");
70
-
71
- const layer = makeClusterMetadataLayer(host, port);
72
-
73
- const s = p.spinner();
74
- s.start("Creating S3-compatible object store...");
75
-
76
- const result = yield* WingsClusterMetadata.createObjectStore({
77
- parent,
78
- objectStoreId,
79
- objectStoreConfig: {
80
- _tag: "s3Compatible",
81
- s3Compatible: {
82
- bucketName,
83
- prefix: Option.getOrUndefined(prefix),
84
- accessKeyId,
85
- secretAccessKey,
86
- region: Option.getOrUndefined(region),
87
- endpoint,
88
- allowHttp: false,
89
- },
90
- },
91
- }).pipe(
92
- Effect.provide(layer),
93
- Effect.tapError(() =>
94
- Effect.sync(() => s.stop("Failed to create S3-compatible object store")),
95
- ),
96
- );
97
-
98
- s.stop("S3-compatible object store created successfully");
99
-
100
- yield* Effect.sync(() => {
101
- printTable([
102
- {
103
- name: result.name,
104
- type: "S3-Compatible",
105
- bucket: bucketName,
106
- endpoint,
107
- },
108
- ]);
109
- p.outro("✓ Done");
110
- });
111
- }),
112
- ).pipe(
113
- Command.withDescription("Create a new S3-compatible object store (MinIO, DigitalOcean, etc.)"),
114
- );
@@ -1,21 +0,0 @@
1
- import { Effect } from "effect";
2
- import { Command } from "effect/unstable/cli";
3
-
4
- import { createObjectStoreAwsCommand } from "./create-aws.js";
5
- import { createObjectStoreAzureCommand } from "./create-azure.js";
6
- import { createObjectStoreGoogleCommand } from "./create-google.js";
7
- import { createObjectStoreS3Command } from "./create-s3.js";
8
-
9
- export const createObjectStoreCommand = Command.make(
10
- "create-object-store",
11
- {},
12
- () => Effect.void,
13
- ).pipe(
14
- Command.withDescription("Create a new object store"),
15
- Command.withSubcommands([
16
- createObjectStoreAwsCommand,
17
- createObjectStoreAzureCommand,
18
- createObjectStoreGoogleCommand,
19
- createObjectStoreS3Command,
20
- ]),
21
- );
@@ -1,56 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { Effect } from "effect";
4
- import { Command, Flag } from "effect/unstable/cli";
5
-
6
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
7
- import { forceOption, hostOption, portOption } from "../../../utils/options.js";
8
-
9
- const nameOption = Flag.string("name").pipe(
10
- Flag.withDescription(
11
- "Object store name in format: tenants/{tenant}/object-stores/{object-store}",
12
- ),
13
- );
14
-
15
- export const deleteObjectStoreCommand = Command.make(
16
- "delete-object-store",
17
- {
18
- name: nameOption,
19
- force: forceOption,
20
- host: hostOption,
21
- port: portOption,
22
- },
23
- ({ name, force, host, port }) =>
24
- Effect.gen(function* () {
25
- p.intro("🗑️ Delete Object Store");
26
-
27
- if (!force) {
28
- const confirm = yield* Effect.tryPromise({
29
- try: () =>
30
- p.confirm({
31
- message: `Are you sure you want to delete object store ${name}?`,
32
- initialValue: false,
33
- }),
34
- catch: () => new Error("Failed to confirm deletion"),
35
- });
36
-
37
- if (p.isCancel(confirm) || !confirm) {
38
- p.cancel("Deletion cancelled");
39
- process.exit(0);
40
- }
41
- }
42
-
43
- const layer = makeClusterMetadataLayer(host, port);
44
-
45
- const s = p.spinner();
46
- s.start("Deleting object store...");
47
-
48
- yield* WingsClusterMetadata.deleteObjectStore({ name }).pipe(
49
- Effect.provide(layer),
50
- Effect.tapError(() => Effect.sync(() => s.stop("Failed to delete object store"))),
51
- );
52
-
53
- s.stop("Object store deleted successfully");
54
- p.outro("✓ Done");
55
- }),
56
- ).pipe(Command.withDescription("Delete an object store from the cluster"));
@@ -1,49 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { printTable } from "console-table-printer";
4
- import { Effect } from "effect";
5
- import { Command, Flag } from "effect/unstable/cli";
6
-
7
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
8
- import { hostOption, portOption } from "../../../utils/options.js";
9
-
10
- const nameOption = Flag.string("name").pipe(
11
- Flag.withDescription(
12
- "Object store name in format: tenants/{tenant}/object-stores/{object-store}",
13
- ),
14
- );
15
-
16
- export const getObjectStoreCommand = Command.make(
17
- "get-object-store",
18
- {
19
- name: nameOption,
20
- host: hostOption,
21
- port: portOption,
22
- },
23
- ({ name, host, port }) =>
24
- Effect.gen(function* () {
25
- const layer = makeClusterMetadataLayer(host, port);
26
-
27
- const s = p.spinner();
28
- s.start("Fetching object store...");
29
-
30
- const objectStore = yield* WingsClusterMetadata.getObjectStore({
31
- name,
32
- }).pipe(
33
- Effect.provide(layer),
34
- Effect.tapError(() => Effect.sync(() => s.stop("Failed to get object store"))),
35
- );
36
-
37
- s.stop("Object store retrieved");
38
-
39
- yield* Effect.sync(() => {
40
- printTable([
41
- {
42
- name: objectStore.name,
43
- type: objectStore.objectStoreConfig._tag || "-",
44
- },
45
- ]);
46
- p.outro("✓ Done");
47
- });
48
- }),
49
- ).pipe(Command.withDescription("Get details of a specific object store"));
@@ -1,62 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { printTable } from "console-table-printer";
4
- import { Effect, Option } from "effect";
5
- import { Command, Flag } from "effect/unstable/cli";
6
-
7
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
8
- import { hostOption, pageSizeOption, pageTokenOption, portOption } from "../../../utils/options.js";
9
-
10
- const parentOption = Flag.string("parent").pipe(
11
- Flag.withDescription("Parent tenant in format: tenants/{tenant}"),
12
- );
13
-
14
- export const listObjectStoresCommand = Command.make(
15
- "list-object-stores",
16
- {
17
- parent: parentOption,
18
- pageSize: pageSizeOption,
19
- pageToken: pageTokenOption,
20
- host: hostOption,
21
- port: portOption,
22
- },
23
- ({ parent, pageSize, pageToken, host, port }) =>
24
- Effect.gen(function* () {
25
- const layer = makeClusterMetadataLayer(host, port);
26
-
27
- const s = p.spinner();
28
- s.start("Fetching object stores...");
29
-
30
- const response = yield* WingsClusterMetadata.listObjectStores({
31
- parent,
32
- pageSize,
33
- pageToken: Option.getOrUndefined(pageToken),
34
- }).pipe(
35
- Effect.provide(layer),
36
- Effect.tapError(() => Effect.sync(() => s.stop("Failed to list object stores"))),
37
- );
38
-
39
- s.stop(`Found ${response.objectStores.length} object store(s)`);
40
-
41
- yield* Effect.sync(() => {
42
- if (response.objectStores.length === 0) {
43
- p.log.warn("No object stores found");
44
- } else {
45
- printTable(
46
- response.objectStores.map(
47
- (objectStore: { name: string; objectStoreConfig: { _tag?: string | null } }) => ({
48
- name: objectStore.name,
49
- type: objectStore.objectStoreConfig._tag || "-",
50
- }),
51
- ),
52
- );
53
- }
54
-
55
- if (response.nextPageToken) {
56
- p.log.info(`Next page token: ${response.nextPageToken}`);
57
- }
58
-
59
- p.outro("✓ Done");
60
- });
61
- }),
62
- ).pipe(Command.withDescription("List all object stores belonging to a tenant"));
@@ -1,44 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { printTable } from "console-table-printer";
4
- import { Effect } from "effect";
5
- import { Command, Flag } from "effect/unstable/cli";
6
-
7
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
8
- import { hostOption, portOption } from "../../../utils/options.js";
9
-
10
- const tenantIdOption = Flag.string("tenant-id").pipe(
11
- Flag.withDescription("Unique identifier for the tenant (e.g., 'acme-corp')"),
12
- );
13
-
14
- export const createTenantCommand = Command.make(
15
- "create-tenant",
16
- {
17
- tenantId: tenantIdOption,
18
- host: hostOption,
19
- port: portOption,
20
- },
21
- ({ tenantId, host, port }) =>
22
- Effect.gen(function* () {
23
- p.intro("🏢 Create Tenant");
24
-
25
- const layer = makeClusterMetadataLayer(host, port);
26
-
27
- const s = p.spinner();
28
- s.start("Creating tenant...");
29
-
30
- const tenant = yield* WingsClusterMetadata.createTenant({
31
- tenantId,
32
- }).pipe(
33
- Effect.provide(layer),
34
- Effect.tapError(() => Effect.sync(() => s.stop("Failed to create tenant"))),
35
- );
36
-
37
- s.stop("Tenant created successfully");
38
-
39
- yield* Effect.sync(() => {
40
- printTable([{ name: tenant.name }]);
41
- p.outro("✓ Done");
42
- });
43
- }),
44
- ).pipe(Command.withDescription("Create a new tenant in the cluster"));
@@ -1,40 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { printTable } from "console-table-printer";
4
- import { Effect } from "effect";
5
- import { Command, Flag } from "effect/unstable/cli";
6
-
7
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
8
- import { hostOption, portOption } from "../../../utils/options.js";
9
-
10
- const nameOption = Flag.string("name").pipe(
11
- Flag.withDescription("Tenant name in format: tenants/{tenant} (e.g., 'tenants/acme-corp')"),
12
- );
13
-
14
- export const getTenantCommand = Command.make(
15
- "get-tenant",
16
- {
17
- name: nameOption,
18
- host: hostOption,
19
- port: portOption,
20
- },
21
- ({ name, host, port }) =>
22
- Effect.gen(function* () {
23
- const layer = makeClusterMetadataLayer(host, port);
24
-
25
- const s = p.spinner();
26
- s.start("Fetching tenant...");
27
-
28
- const tenant = yield* WingsClusterMetadata.getTenant({ name }).pipe(
29
- Effect.provide(layer),
30
- Effect.tapError(() => Effect.sync(() => s.stop("Failed to get tenant"))),
31
- );
32
-
33
- s.stop("Tenant retrieved");
34
-
35
- yield* Effect.sync(() => {
36
- printTable([{ name: tenant.name }]);
37
- p.outro("✓ Done");
38
- });
39
- }),
40
- ).pipe(Command.withDescription("Get details of a specific tenant"));
@@ -1,53 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { printTable } from "console-table-printer";
4
- import { Effect, Option } from "effect";
5
- import { Command } from "effect/unstable/cli";
6
-
7
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
8
- import { hostOption, pageSizeOption, pageTokenOption, portOption } from "../../../utils/options.js";
9
-
10
- export const listTenantsCommand = Command.make(
11
- "list-tenants",
12
- {
13
- pageSize: pageSizeOption,
14
- pageToken: pageTokenOption,
15
- host: hostOption,
16
- port: portOption,
17
- },
18
- ({ pageSize, pageToken, host, port }) =>
19
- Effect.gen(function* () {
20
- const layer = makeClusterMetadataLayer(host, port);
21
-
22
- const s = p.spinner();
23
- s.start("Fetching tenants...");
24
-
25
- const response = yield* WingsClusterMetadata.listTenants({
26
- pageSize,
27
- pageToken: Option.getOrUndefined(pageToken),
28
- }).pipe(
29
- Effect.provide(layer),
30
- Effect.tapError(() => Effect.sync(() => s.stop("Failed to list tenants"))),
31
- );
32
-
33
- s.stop(`Found ${response.tenants.length} tenant(s)`);
34
-
35
- yield* Effect.sync(() => {
36
- if (response.tenants.length === 0) {
37
- p.log.warn("No tenants found");
38
- } else {
39
- printTable(
40
- response.tenants.map((tenant: { name: string }) => ({
41
- name: tenant.name,
42
- })),
43
- );
44
- }
45
-
46
- if (response.nextPageToken) {
47
- p.log.info(`Next page token: ${response.nextPageToken}`);
48
- }
49
-
50
- p.outro("✓ Done");
51
- });
52
- }),
53
- ).pipe(Command.withDescription("List all tenants in the cluster"));
@@ -1,65 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { Effect } from "effect";
4
- import { Command, Flag } from "effect/unstable/cli";
5
-
6
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
7
- import { forceOption, hostOption, portOption } from "../../../utils/options.js";
8
-
9
- const nameOption = Flag.string("name").pipe(
10
- Flag.withDescription(
11
- "Topic name in format: tenants/{tenant}/namespaces/{namespace}/topics/{topic}",
12
- ),
13
- );
14
-
15
- const forceDeleteOption = Flag.boolean("force-delete").pipe(
16
- Flag.withDescription("Also delete data associated with the topic"),
17
- Flag.withDefault(false),
18
- );
19
-
20
- export const deleteTopicCommand = Command.make(
21
- "delete-topic",
22
- {
23
- name: nameOption,
24
- forceDelete: forceDeleteOption,
25
- force: forceOption,
26
- host: hostOption,
27
- port: portOption,
28
- },
29
- ({ name, forceDelete, force, host, port }) =>
30
- Effect.gen(function* () {
31
- p.intro("🗑️ Delete Topic");
32
-
33
- if (!force) {
34
- const confirm = yield* Effect.tryPromise({
35
- try: () =>
36
- p.confirm({
37
- message: `Are you sure you want to delete topic ${name}?${forceDelete ? " (including all data)" : ""}`,
38
- initialValue: false,
39
- }),
40
- catch: () => new Error("Failed to confirm deletion"),
41
- });
42
-
43
- if (p.isCancel(confirm) || !confirm) {
44
- p.cancel("Deletion cancelled");
45
- process.exit(0);
46
- }
47
- }
48
-
49
- const layer = makeClusterMetadataLayer(host, port);
50
-
51
- const s = p.spinner();
52
- s.start("Deleting topic...");
53
-
54
- yield* WingsClusterMetadata.deleteTopic({
55
- name,
56
- force: forceDelete,
57
- }).pipe(
58
- Effect.provide(layer),
59
- Effect.tapError(() => Effect.sync(() => s.stop("Failed to delete topic"))),
60
- );
61
-
62
- s.stop("Topic deleted successfully");
63
- p.outro("✓ Done");
64
- }),
65
- ).pipe(Command.withDescription("Delete a topic from the cluster"));
@@ -1,51 +0,0 @@
1
- import * as p from "@clack/prompts";
2
- import { WingsClusterMetadata } from "@useairfoil/wings";
3
- import { printTable } from "console-table-printer";
4
- import { Effect } from "effect";
5
- import { Command, Flag } from "effect/unstable/cli";
6
-
7
- import { makeClusterMetadataLayer } from "../../../utils/client.js";
8
- import { hostOption, portOption } from "../../../utils/options.js";
9
-
10
- const nameOption = Flag.string("name").pipe(
11
- Flag.withDescription(
12
- "Topic name in format: tenants/{tenant}/namespaces/{namespace}/topics/{topic}",
13
- ),
14
- );
15
-
16
- export const getTopicCommand = Command.make(
17
- "get-topic",
18
- {
19
- name: nameOption,
20
- host: hostOption,
21
- port: portOption,
22
- },
23
- ({ name, host, port }) =>
24
- Effect.gen(function* () {
25
- const layer = makeClusterMetadataLayer(host, port);
26
-
27
- const s = p.spinner();
28
- s.start("Fetching topic...");
29
-
30
- const topic = yield* WingsClusterMetadata.getTopic({ name }).pipe(
31
- Effect.provide(layer),
32
- Effect.tapError(() => Effect.sync(() => s.stop("Failed to get topic"))),
33
- );
34
-
35
- s.stop("Topic retrieved");
36
-
37
- yield* Effect.sync(() => {
38
- printTable([
39
- {
40
- name: topic.name,
41
- description: topic.description || "-",
42
- partition_key: topic.partitionKey?.toString() || "-",
43
- freshness_seconds: topic.compaction.freshnessSeconds.toString(),
44
- ttl_seconds: topic.compaction.ttlSeconds?.toString() || "-",
45
- },
46
- ]);
47
-
48
- p.outro("✓ Done");
49
- });
50
- }),
51
- ).pipe(Command.withDescription("Get details of a specific topic"));