@alvera-ai/platform-sdk 0.2.4 → 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 (48) hide show
  1. package/README.md +82 -13
  2. package/dist/cli.js +424 -15
  3. package/dist/cli.js.map +1 -1
  4. package/dist/client.d.ts +190 -3
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +169 -7
  7. package/dist/client.js.map +1 -1
  8. package/dist/config.d.ts +5 -1
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +21 -4
  11. package/dist/config.js.map +1 -1
  12. package/dist/environments.generated.d.ts +21 -0
  13. package/dist/environments.generated.d.ts.map +1 -0
  14. package/dist/environments.generated.js +8 -0
  15. package/dist/environments.generated.js.map +1 -0
  16. package/dist/generated/client/client.gen.d.ts.map +1 -1
  17. package/dist/generated/client/client.gen.js +3 -3
  18. package/dist/generated/client/client.gen.js.map +1 -1
  19. package/dist/generated/client/types.gen.d.ts +1 -1
  20. package/dist/generated/client/utils.gen.js +1 -1
  21. package/dist/generated/client/utils.gen.js.map +1 -1
  22. package/dist/generated/core/pathSerializer.gen.d.ts +1 -1
  23. package/dist/generated/core/pathSerializer.gen.d.ts.map +1 -1
  24. package/dist/generated/core/serverSentEvents.gen.d.ts +1 -1
  25. package/dist/generated/core/serverSentEvents.gen.d.ts.map +1 -1
  26. package/dist/generated/core/serverSentEvents.gen.js +3 -4
  27. package/dist/generated/core/serverSentEvents.gen.js.map +1 -1
  28. package/dist/generated/core/types.gen.d.ts +1 -1
  29. package/dist/generated/core/utils.gen.js +1 -1
  30. package/dist/generated/core/utils.gen.js.map +1 -1
  31. package/dist/generated/index.d.ts +2 -2
  32. package/dist/generated/index.d.ts.map +1 -1
  33. package/dist/generated/index.js +1 -1
  34. package/dist/generated/index.js.map +1 -1
  35. package/dist/generated/sdk.gen.d.ts +325 -121
  36. package/dist/generated/sdk.gen.d.ts.map +1 -1
  37. package/dist/generated/sdk.gen.js +1030 -263
  38. package/dist/generated/sdk.gen.js.map +1 -1
  39. package/dist/generated/types.gen.d.ts +8749 -3536
  40. package/dist/generated/types.gen.d.ts.map +1 -1
  41. package/dist/generated/valibot.gen.d.ts +31944 -11564
  42. package/dist/generated/valibot.gen.d.ts.map +1 -1
  43. package/dist/generated/valibot.gen.js +4888 -2247
  44. package/dist/generated/valibot.gen.js.map +1 -1
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js.map +1 -1
  48. package/package.json +9 -8
package/README.md CHANGED
@@ -16,9 +16,9 @@ pnpm add @alvera-ai/platform-sdk
16
16
  ## Quick start
17
17
 
18
18
  ```ts
19
- import { createPlatformApi, createSession } from '@alvera-ai/platform-sdk';
19
+ import { createPlatformApi, createSession, ENVIRONMENTS } from '@alvera-ai/platform-sdk';
20
20
 
21
- const baseUrl = 'https://admin.alvera.ai';
21
+ const baseUrl = ENVIRONMENTS.prod.base_url; // or ENVIRONMENTS.local / ENVIRONMENTS.demo
22
22
 
23
23
  // 1. Exchange credentials for a session token
24
24
  const session = await createSession({
@@ -79,6 +79,36 @@ await revokeSession();
79
79
  `session.expiresAt` is an ISO-8601 timestamp — check it before long-running
80
80
  work and re-authenticate if needed.
81
81
 
82
+ ## Environments
83
+
84
+ The base URLs ship with the package, derived at build time from the
85
+ `servers[]` block of the committed OpenAPI spec (`spec/openapi.yaml`). The
86
+ generated map is exported as `ENVIRONMENTS`:
87
+
88
+ ```ts
89
+ import { ENVIRONMENTS, DEFAULT_ENVIRONMENT } from '@alvera-ai/platform-sdk';
90
+
91
+ ENVIRONMENTS.local.base_url; // http://localhost:4000
92
+ ENVIRONMENTS.demo.base_url; // https://platform-hh.alvera.ai
93
+ ENVIRONMENTS.prod.base_url; // https://app.alvera.ai
94
+
95
+ DEFAULT_ENVIRONMENT; // 'prod'
96
+ ```
97
+
98
+ The CLI resolves a base URL with this precedence (highest first):
99
+
100
+ 1. `ALVERA_BASE_URL` env var (explicit URL override — useful for tunnels /
101
+ ephemeral servers)
102
+ 2. `base_url` pinned in the profile (written when the user passes a custom URL
103
+ to `alvera configure` or `alvera login --base-url …`)
104
+ 3. `ENVIRONMENTS[env].base_url` where `env` is the first of: `--env <name>`
105
+ flag, `ALVERA_ENV` env var, the profile's `environment` entry, or
106
+ `DEFAULT_ENVIRONMENT`
107
+
108
+ Adding, renaming, or removing environments happens in the platform repo (the
109
+ `servers/0` function in `lib/platform_api/api_spec.ex`); rerun
110
+ `pnpm regen` in the SDK to pick up the change.
111
+
82
112
  ## Resources
83
113
 
84
114
  | Resource | Operations |
@@ -140,14 +170,16 @@ alvera --help
140
170
  Both files are INI. The default profile is `[default]`; additional profiles
141
171
  live under `[profile <name>]` in `config` and `[<name>]` in `credentials`.
142
172
 
143
- Every command accepts `--profile <name>`. Environment variables
144
- (`ALVERA_PROFILE`, `ALVERA_BASE_URL`, `ALVERA_TENANT`, `ALVERA_EMAIL`,
145
- `ALVERA_PASSWORD`, `ALVERA_SESSION_TOKEN`) take precedence over file values.
173
+ Every command accepts `--profile <name>` and `--env <name>`. Environment
174
+ variables (`ALVERA_PROFILE`, `ALVERA_ENV`, `ALVERA_BASE_URL`, `ALVERA_TENANT`,
175
+ `ALVERA_EMAIL`, `ALVERA_PASSWORD`, `ALVERA_SESSION_TOKEN`) take precedence
176
+ over file values.
146
177
 
147
178
  ### Getting started
148
179
 
149
180
  ```bash
150
- alvera configure # set base URL + default tenant
181
+ alvera env list # show local / demo / prod
182
+ alvera configure # pick environment + default tenant
151
183
  alvera login --email me@acme.com --tenant acme
152
184
  alvera ping
153
185
  alvera datalakes list
@@ -155,13 +187,26 @@ alvera tools create --body-file tool.json
155
187
  alvera logout
156
188
  ```
157
189
 
158
- Multiple environments via profiles:
190
+ Per-command env switch (no profile edit):
159
191
 
160
192
  ```bash
161
- alvera --profile staging login --base-url https://admin.staging.alvera.ai --tenant acme
193
+ alvera --env local ping
194
+ ALVERA_ENV=demo alvera datalakes list
195
+ ```
196
+
197
+ Pin an env into a profile:
198
+
199
+ ```bash
200
+ alvera --profile staging env use demo
162
201
  alvera --profile staging datalakes list
163
202
  ```
164
203
 
204
+ Override the base URL for an ad-hoc host (tunnels, local branches):
205
+
206
+ ```bash
207
+ ALVERA_BASE_URL=https://pr-123.preview.alvera.ai alvera ping
208
+ ```
209
+
165
210
  ### Command surface
166
211
 
167
212
  ```
@@ -170,6 +215,7 @@ alvera login [--email] [--password] [--tenant] [--base-url] [--expires-in]
170
215
  alvera logout
171
216
  alvera whoami
172
217
  alvera ping
218
+ alvera env list | use <name>
173
219
 
174
220
  alvera datalakes list | get <id> | create
175
221
  alvera data-sources list <datalake> | create <datalake> | update <datalake> <id>
@@ -196,16 +242,39 @@ status messages and prompts go to stderr so responses stay pipeable.
196
242
 
197
243
  ## Regenerating the typed client
198
244
 
199
- The typed client is generated from the live OpenAPI spec at
200
- `https://admin.alvera.ai/api/openapi` using
201
- [`@hey-api/openapi-ts`](https://heyapi.dev/).
245
+ The typed client is generated from `spec/openapi.yaml` using
246
+ [`@hey-api/openapi-ts`](https://heyapi.dev/). The spec is produced by the
247
+ platform repo and committed here, so this repo is fully self-contained at CI
248
+ time.
249
+
250
+ To pull a newer spec from the sibling platform repo:
202
251
 
203
252
  ```bash
204
- pnpm regen # fetch latest spec + regenerate
205
- pnpm codegen # regenerate from the pinned openapi.json
253
+ # in the platform repo
254
+ mix openapi.spec.yaml --spec PlatformApi.ApiSpec openapi.yaml
255
+ git commit -am "feat(api): …"
256
+
257
+ # in this repo
258
+ cp ../platform/openapi.yaml spec/openapi.yaml
259
+ pnpm regen # gen-environments + codegen + check-coverage
206
260
  pnpm build # compile to dist/
261
+ git commit -am "chore: sync openapi spec"
207
262
  ```
208
263
 
264
+ `pnpm regen` runs `gen-environments` (rebuilds
265
+ `src/environments.generated.ts` from `servers[]`), then `codegen`, then
266
+ `check-coverage`.
267
+
268
+ ## Releases
269
+
270
+ This package uses
271
+ [release-please](https://github.com/googleapis/release-please) plus
272
+ [Conventional Commits](https://www.conventionalcommits.org/). Commits on
273
+ `main` of the form `feat: …`, `fix: …`, `chore: …` feed into an automated
274
+ "chore(main): release X.Y.Z" PR that bumps `package.json` and updates
275
+ `CHANGELOG.md`. Merging that PR tags `vX.Y.Z`, which in turn triggers the
276
+ existing npm publish workflow.
277
+
209
278
  ## License
210
279
 
211
280
  MIT
package/dist/cli.js CHANGED
@@ -8,7 +8,8 @@ import { ValiError } from 'valibot';
8
8
  import { createPlatformApi, createSession, revokeSession } from './client.js';
9
9
  const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
10
10
  const { version: packageVersion } = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
11
- import { CONFIG_PATHS, clearProfileCreds, getProfileName, resolveProfile, writeProfileConfig, writeProfileCreds, } from './config.js';
11
+ import { CONFIG_PATHS, DEFAULT_ENVIRONMENT, ENVIRONMENTS, clearProfileCreds, getProfileName, readProfileConfig, resolveProfile, writeProfileConfig, writeProfileCreds, } from './config.js';
12
+ const ENVIRONMENT_NAMES = Object.keys(ENVIRONMENTS);
12
13
  // ---------------------------------------------------------------------------
13
14
  // Helpers
14
15
  // ---------------------------------------------------------------------------
@@ -123,18 +124,47 @@ program
123
124
  .description('Alvera platform CLI')
124
125
  .version(packageVersion, '-v, --version', 'print the installed version')
125
126
  .addOption(new Option('--profile <name>', 'config profile to use').default('default'))
126
- .showHelpAfterError();
127
+ .addOption(new Option('--env <name>', `environment from spec/openapi.yaml (${ENVIRONMENT_NAMES.join(', ')})`))
128
+ .showHelpAfterError()
129
+ .hook('preAction', (thisCommand) => {
130
+ const env = thisCommand.optsWithGlobals().env;
131
+ if (env !== undefined)
132
+ process.env.ALVERA_ENV = env;
133
+ const candidate = process.env.ALVERA_ENV;
134
+ if (candidate !== undefined && !ENVIRONMENT_NAMES.includes(candidate)) {
135
+ die(`unknown environment "${candidate}". Valid: ${ENVIRONMENT_NAMES.join(', ')}`);
136
+ }
137
+ });
127
138
  // -- configure --------------------------------------------------------------
128
139
  program
129
140
  .command('configure')
130
- .description('Interactively set defaults (base URL, tenant) for a profile')
141
+ .description('Interactively set defaults (environment, tenant, email) for a profile')
131
142
  .action(async () => {
132
143
  const profile = getProfileName(program.opts().profile);
133
144
  const current = resolveProfile(profile);
134
- const baseUrl = (await prompt(`Base URL [${current.baseUrl}]: `)) || current.baseUrl;
135
- const tenantSlug = (await prompt(`Default tenant slug [${current.tenantSlug ?? ''}]: `)) || current.tenantSlug || '';
136
- const email = (await prompt(`Email [${current.email ?? ''}]: `)) || current.email || '';
137
- writeProfileConfig(profile, { base_url: baseUrl, tenant_slug: tenantSlug, email });
145
+ const currentCfg = readProfileConfig(profile);
146
+ const options = ENVIRONMENT_NAMES.map((name) => `${name} (${ENVIRONMENTS[name].base_url})`).join(', ');
147
+ const defaultChoice = currentCfg.environment ?? current.environment;
148
+ const envInput = (await prompt(`Environment [${defaultChoice}] one of: ${options}, or a custom URL: `)) ||
149
+ defaultChoice;
150
+ const patch = {};
151
+ const unset = [];
152
+ if (ENVIRONMENT_NAMES.includes(envInput)) {
153
+ patch.environment = envInput;
154
+ unset.push('base_url');
155
+ }
156
+ else if (/^https?:\/\//.test(envInput)) {
157
+ patch.base_url = envInput;
158
+ unset.push('environment');
159
+ }
160
+ else {
161
+ die(`"${envInput}" is not a known environment or a URL. ` +
162
+ `Valid: ${ENVIRONMENT_NAMES.join(', ')} or http(s)://…`);
163
+ }
164
+ patch.tenant_slug =
165
+ (await prompt(`Default tenant slug [${current.tenantSlug ?? ''}]: `)) || current.tenantSlug || '';
166
+ patch.email = (await prompt(`Email [${current.email ?? ''}]: `)) || current.email || '';
167
+ writeProfileConfig(profile, patch, unset);
138
168
  process.stderr.write(`Saved profile "${profile}" → ${CONFIG_PATHS.config}\n`);
139
169
  });
140
170
  // -- login ------------------------------------------------------------------
@@ -163,7 +193,13 @@ program
163
193
  tenantSlug: tenant,
164
194
  expiresIn: opts.expiresIn ? Number(opts.expiresIn) : undefined,
165
195
  });
166
- writeProfileConfig(profile, { base_url: baseUrl, tenant_slug: tenant, email });
196
+ // Only pin base_url into the profile when the user explicitly overrode it.
197
+ // Otherwise the environment selection (profile.environment) keeps driving baseUrl.
198
+ writeProfileConfig(profile, {
199
+ ...(opts.baseUrl ? { base_url: baseUrl } : {}),
200
+ tenant_slug: tenant,
201
+ email,
202
+ });
167
203
  writeProfileCreds(profile, {
168
204
  session_token: session.sessionToken,
169
205
  expires_at: session.expiresAt ?? '',
@@ -202,6 +238,7 @@ program
202
238
  const resolved = resolveProfile(profile);
203
239
  out({
204
240
  profile: resolved.profile,
241
+ environment: resolved.environment,
205
242
  baseUrl: resolved.baseUrl,
206
243
  tenantSlug: resolved.tenantSlug,
207
244
  email: resolved.email,
@@ -220,6 +257,38 @@ program
220
257
  return data;
221
258
  });
222
259
  });
260
+ // -- env --------------------------------------------------------------------
261
+ // Environments are baked from spec/openapi.yaml servers[] at build time.
262
+ // Default (prod / or last-in-list) is chosen in scripts/gen-environments.mjs.
263
+ const envCmd = program
264
+ .command('env')
265
+ .description('List and switch Alvera API environments');
266
+ envCmd
267
+ .command('list')
268
+ .description('List available environments (from spec/openapi.yaml)')
269
+ .action(() => {
270
+ const profile = getProfileName(program.opts().profile);
271
+ const resolved = resolveProfile(profile);
272
+ out(ENVIRONMENT_NAMES.map((name) => ({
273
+ name,
274
+ baseUrl: ENVIRONMENTS[name].base_url,
275
+ description: ENVIRONMENTS[name].description,
276
+ default: name === DEFAULT_ENVIRONMENT,
277
+ active: name === resolved.environment,
278
+ })));
279
+ });
280
+ envCmd
281
+ .command('use <name>')
282
+ .description('Persist the selected environment to the profile (clears any custom base_url)')
283
+ .action((name) => {
284
+ if (!ENVIRONMENT_NAMES.includes(name)) {
285
+ die(`unknown environment "${name}". Valid: ${ENVIRONMENT_NAMES.join(', ')}`);
286
+ }
287
+ const profile = getProfileName(program.opts().profile);
288
+ writeProfileConfig(profile, { environment: name }, ['base_url']);
289
+ process.stderr.write(`Profile "${profile}" now uses environment "${name}" ` +
290
+ `(${ENVIRONMENTS[name].base_url}).\n`);
291
+ });
223
292
  // -- tenants ----------------------------------------------------------------
224
293
  const tenants = program.command('tenants').description('Manage tenants');
225
294
  tenants
@@ -540,22 +609,109 @@ bodyOption(connectedApps
540
609
  });
541
610
  });
542
611
  // -- data-activation-clients -----------------------------------------------
543
- const dac = program.command('data-activation-clients').description('Data activation client actions');
544
- bodyOption(dac.command('ingest <slug> [tenant]').description('Ingest a JSON payload'))
545
- .action(async (slug, tenant, opts) => {
612
+ const dac = program.command('data-activation-clients').description('Manage data activation clients');
613
+ dac
614
+ .command('list <datalake> [tenant]')
615
+ .description('List data activation clients in a datalake')
616
+ .action(async (datalake, tenant) => {
617
+ await run(async () => {
618
+ const { api, resolved } = authedApi(program.opts());
619
+ const { data } = await api.dataActivationClients.list(resolveTenant(tenant, resolved.tenantSlug), datalake);
620
+ return data;
621
+ });
622
+ });
623
+ dac
624
+ .command('get <datalake> <slug> [tenant]')
625
+ .description('Get a data activation client by slug')
626
+ .action(async (datalake, slug, tenant) => {
627
+ await run(async () => {
628
+ const { api, resolved } = authedApi(program.opts());
629
+ const { data } = await api.dataActivationClients.get(resolveTenant(tenant, resolved.tenantSlug), datalake, slug);
630
+ return data;
631
+ });
632
+ });
633
+ bodyOption(dac.command('create <datalake> [tenant]').description('Create a data activation client'))
634
+ .action(async (datalake, tenant, opts) => {
635
+ await run(async () => {
636
+ const { api, resolved } = authedApi(program.opts());
637
+ const { data } = await api.dataActivationClients.create(resolveTenant(tenant, resolved.tenantSlug), datalake, readBody(opts.body, opts.bodyFile));
638
+ return data;
639
+ });
640
+ });
641
+ bodyOption(dac.command('update <datalake> <slug> [tenant]').description('Update a data activation client'))
642
+ .action(async (datalake, slug, tenant, opts) => {
643
+ await run(async () => {
644
+ const { api, resolved } = authedApi(program.opts());
645
+ const { data } = await api.dataActivationClients.update(resolveTenant(tenant, resolved.tenantSlug), datalake, slug, readBody(opts.body, opts.bodyFile));
646
+ return data;
647
+ });
648
+ });
649
+ dac
650
+ .command('delete <datalake> <slug> [tenant]')
651
+ .description('Delete a data activation client')
652
+ .action(async (datalake, slug, tenant) => {
546
653
  await run(async () => {
547
654
  const { api, resolved } = authedApi(program.opts());
548
- const { data } = await api.dataActivationClients.ingest(resolveTenant(tenant, resolved.tenantSlug), slug, readBody(opts.body, opts.bodyFile));
655
+ const { data } = await api.dataActivationClients.delete(resolveTenant(tenant, resolved.tenantSlug), datalake, slug);
549
656
  return data;
550
657
  });
551
658
  });
552
659
  dac
553
- .command('ingest-file <slug> <key> [tenant]')
660
+ .command('metadata <datalake> <slug> [tenant]')
661
+ .description('Get markdown metadata for a data activation client')
662
+ .action(async (datalake, slug, tenant) => {
663
+ await run(async () => {
664
+ const { api, resolved } = authedApi(program.opts());
665
+ const { data } = await api.dataActivationClients.metadata(resolveTenant(tenant, resolved.tenantSlug), datalake, slug);
666
+ return data;
667
+ });
668
+ });
669
+ bodyOption(dac
670
+ .command('run-manually <datalake> <slug> [tenant]')
671
+ .description('Trigger a manual run (optional --body for tool_call override)'))
672
+ .action(async (datalake, slug, tenant, opts) => {
673
+ await run(async () => {
674
+ const { api, resolved } = authedApi(program.opts());
675
+ const body = opts.body || opts.bodyFile ? readBody(opts.body, opts.bodyFile) : undefined;
676
+ const { data } = await api.dataActivationClients.runManually(resolveTenant(tenant, resolved.tenantSlug), datalake, slug, body);
677
+ return data;
678
+ });
679
+ });
680
+ bodyOption(dac.command('ingest <datalake> <slug> [tenant]').description('Ingest a JSON payload'))
681
+ .action(async (datalake, slug, tenant, opts) => {
682
+ await run(async () => {
683
+ const { api, resolved } = authedApi(program.opts());
684
+ const { data } = await api.dataActivationClients.ingest(resolveTenant(tenant, resolved.tenantSlug), datalake, slug, readBody(opts.body, opts.bodyFile));
685
+ return data;
686
+ });
687
+ });
688
+ dac
689
+ .command('ingest-file <datalake> <slug> <key> [tenant]')
554
690
  .description('Ingest a previously uploaded file (key from upload-link)')
555
- .action(async (slug, key, tenant) => {
691
+ .action(async (datalake, slug, key, tenant) => {
692
+ await run(async () => {
693
+ const { api, resolved } = authedApi(program.opts());
694
+ const { data } = await api.dataActivationClients.ingestFile(resolveTenant(tenant, resolved.tenantSlug), datalake, slug, { key });
695
+ return data;
696
+ });
697
+ });
698
+ dac
699
+ .command('logs <datalake> <slug> [tenant]')
700
+ .description('List execution logs for a data activation client')
701
+ .action(async (datalake, slug, tenant) => {
556
702
  await run(async () => {
557
703
  const { api, resolved } = authedApi(program.opts());
558
- const { data } = await api.dataActivationClients.ingestFile(resolveTenant(tenant, resolved.tenantSlug), slug, { key });
704
+ const { data } = await api.dataActivationClients.logs.list(resolveTenant(tenant, resolved.tenantSlug), datalake, slug);
705
+ return data;
706
+ });
707
+ });
708
+ dac
709
+ .command('log-get <datalake> <slug> <id> [tenant]')
710
+ .description('Get a single execution log by id')
711
+ .action(async (datalake, slug, id, tenant) => {
712
+ await run(async () => {
713
+ const { api, resolved } = authedApi(program.opts());
714
+ const { data } = await api.dataActivationClients.logs.get(resolveTenant(tenant, resolved.tenantSlug), datalake, slug, id);
559
715
  return data;
560
716
  });
561
717
  });
@@ -575,6 +731,16 @@ datalakes
575
731
  return data;
576
732
  });
577
733
  });
734
+ datalakes
735
+ .command('download-link <datalake> <bucket> <key> [tenant]')
736
+ .description('Create a presigned download URL for a datalake object')
737
+ .action(async (datalake, bucket, key, tenant) => {
738
+ await run(async () => {
739
+ const { api, resolved } = authedApi(program.opts());
740
+ const { data } = await api.datalakes.createDownloadLink(resolveTenant(tenant, resolved.tenantSlug), datalake, { bucket, key });
741
+ return data;
742
+ });
743
+ });
578
744
  // -- mdm --------------------------------------------------------------------
579
745
  const mdm = program.command('mdm').description('Master data management');
580
746
  bodyOption(mdm.command('verify <datalake> [tenant]').description('Fuzzy-verify an identity against MDM'))
@@ -585,8 +751,161 @@ bodyOption(mdm.command('verify <datalake> [tenant]').description('Fuzzy-verify a
585
751
  return data;
586
752
  });
587
753
  });
754
+ // -- datalakes metadata + datasets metadata --------------------------------
755
+ datalakes
756
+ .command('metadata <datalake> [tenant]')
757
+ .description('Get markdown metadata for a datalake')
758
+ .action(async (datalake, tenant) => {
759
+ await run(async () => {
760
+ const { api, resolved } = authedApi(program.opts());
761
+ const { data } = await api.datalakes.metadata(resolveTenant(tenant, resolved.tenantSlug), datalake);
762
+ return data;
763
+ });
764
+ });
765
+ datasets
766
+ .command('metadata <dataset-type>')
767
+ .description('Get markdown schema metadata for a dataset type')
768
+ .option('--datalake-id <id>', 'restrict to a specific datalake')
769
+ .option('--generic-table-id <id>', 'required when dataset-type is generic_table')
770
+ .action(async (datasetType, opts) => {
771
+ await run(async () => {
772
+ const { api } = authedApi(program.opts());
773
+ const { data } = await api.datasets.metadata(datasetType, {
774
+ datalakeId: opts.datalakeId,
775
+ genericTableId: opts.genericTableId,
776
+ });
777
+ return data;
778
+ });
779
+ });
780
+ // -- interoperability-contracts --------------------------------------------
781
+ const interop = program
782
+ .command('interoperability-contracts')
783
+ .alias('interop')
784
+ .description('Manage interoperability contracts');
785
+ interop
786
+ .command('list <datalake> [tenant]')
787
+ .description('List interoperability contracts in a datalake')
788
+ .action(async (datalake, tenant) => {
789
+ await run(async () => {
790
+ const { api, resolved } = authedApi(program.opts());
791
+ const { data } = await api.interoperabilityContracts.list(resolveTenant(tenant, resolved.tenantSlug), datalake);
792
+ return data;
793
+ });
794
+ });
795
+ interop
796
+ .command('get <datalake> <slug> [tenant]')
797
+ .description('Get a contract by slug')
798
+ .action(async (datalake, slug, tenant) => {
799
+ await run(async () => {
800
+ const { api, resolved } = authedApi(program.opts());
801
+ const { data } = await api.interoperabilityContracts.get(resolveTenant(tenant, resolved.tenantSlug), datalake, slug);
802
+ return data;
803
+ });
804
+ });
805
+ bodyOption(interop.command('create <datalake> [tenant]').description('Create a contract'))
806
+ .action(async (datalake, tenant, opts) => {
807
+ await run(async () => {
808
+ const { api, resolved } = authedApi(program.opts());
809
+ const { data } = await api.interoperabilityContracts.create(resolveTenant(tenant, resolved.tenantSlug), datalake, readBody(opts.body, opts.bodyFile));
810
+ return data;
811
+ });
812
+ });
813
+ bodyOption(interop.command('update <datalake> <slug> [tenant]').description('Update a contract'))
814
+ .action(async (datalake, slug, tenant, opts) => {
815
+ await run(async () => {
816
+ const { api, resolved } = authedApi(program.opts());
817
+ const { data } = await api.interoperabilityContracts.update(resolveTenant(tenant, resolved.tenantSlug), datalake, slug, readBody(opts.body, opts.bodyFile));
818
+ return data;
819
+ });
820
+ });
821
+ interop
822
+ .command('delete <datalake> <slug> [tenant]')
823
+ .description('Delete a contract')
824
+ .action(async (datalake, slug, tenant) => {
825
+ await run(async () => {
826
+ const { api, resolved } = authedApi(program.opts());
827
+ const { data } = await api.interoperabilityContracts.delete(resolveTenant(tenant, resolved.tenantSlug), datalake, slug);
828
+ return data;
829
+ });
830
+ });
831
+ interop
832
+ .command('metadata <datalake> <slug> [tenant]')
833
+ .description('Get markdown metadata for a contract')
834
+ .action(async (datalake, slug, tenant) => {
835
+ await run(async () => {
836
+ const { api, resolved } = authedApi(program.opts());
837
+ const { data } = await api.interoperabilityContracts.metadata(resolveTenant(tenant, resolved.tenantSlug), datalake, slug);
838
+ return data;
839
+ });
840
+ });
841
+ bodyOption(interop
842
+ .command('run <datalake> <slug> [tenant]')
843
+ .description('Execute a contract against a raw source row'))
844
+ .action(async (datalake, slug, tenant, opts) => {
845
+ await run(async () => {
846
+ const { api, resolved } = authedApi(program.opts());
847
+ const { data } = await api.interoperabilityContracts.run(resolveTenant(tenant, resolved.tenantSlug), datalake, slug, readBody(opts.body, opts.bodyFile));
848
+ return data;
849
+ });
850
+ });
588
851
  // -- workflows --------------------------------------------------------------
589
852
  const workflows = program.command('workflows').description('Agentic workflows');
853
+ workflows
854
+ .command('list <datalake> [tenant]')
855
+ .description('List workflow definitions in a datalake')
856
+ .action(async (datalake, tenant) => {
857
+ await run(async () => {
858
+ const { api, resolved } = authedApi(program.opts());
859
+ const { data } = await api.workflows.list(resolveTenant(tenant, resolved.tenantSlug), datalake);
860
+ return data;
861
+ });
862
+ });
863
+ workflows
864
+ .command('get <datalake> <id> [tenant]')
865
+ .description('Get a workflow by id')
866
+ .action(async (datalake, id, tenant) => {
867
+ await run(async () => {
868
+ const { api, resolved } = authedApi(program.opts());
869
+ const { data } = await api.workflows.get(resolveTenant(tenant, resolved.tenantSlug), datalake, id);
870
+ return data;
871
+ });
872
+ });
873
+ bodyOption(workflows.command('create <datalake> [tenant]').description('Create a workflow'))
874
+ .action(async (datalake, tenant, opts) => {
875
+ await run(async () => {
876
+ const { api, resolved } = authedApi(program.opts());
877
+ const { data } = await api.workflows.create(resolveTenant(tenant, resolved.tenantSlug), datalake, readBody(opts.body, opts.bodyFile));
878
+ return data;
879
+ });
880
+ });
881
+ bodyOption(workflows.command('update <datalake> <id> [tenant]').description('Update a workflow'))
882
+ .action(async (datalake, id, tenant, opts) => {
883
+ await run(async () => {
884
+ const { api, resolved } = authedApi(program.opts());
885
+ const { data } = await api.workflows.update(resolveTenant(tenant, resolved.tenantSlug), datalake, id, readBody(opts.body, opts.bodyFile));
886
+ return data;
887
+ });
888
+ });
889
+ workflows
890
+ .command('delete <datalake> <id> [tenant]')
891
+ .description('Delete a workflow')
892
+ .action(async (datalake, id, tenant) => {
893
+ await run(async () => {
894
+ const { api, resolved } = authedApi(program.opts());
895
+ const { data } = await api.workflows.delete(resolveTenant(tenant, resolved.tenantSlug), datalake, id);
896
+ return data;
897
+ });
898
+ });
899
+ workflows
900
+ .command('metadata <datalake> <id> [tenant]')
901
+ .description('Get markdown metadata for a workflow')
902
+ .action(async (datalake, id, tenant) => {
903
+ await run(async () => {
904
+ const { api, resolved } = authedApi(program.opts());
905
+ const { data } = await api.workflows.metadata(resolveTenant(tenant, resolved.tenantSlug), datalake, id);
906
+ return data;
907
+ });
908
+ });
590
909
  bodyOption(workflows.command('execute <workflow-slug> [tenant]').description('Execute an agentic workflow'))
591
910
  .action(async (workflowSlug, tenant, opts) => {
592
911
  await run(async () => {
@@ -595,5 +914,95 @@ bodyOption(workflows.command('execute <workflow-slug> [tenant]').description('Ex
595
914
  return data;
596
915
  });
597
916
  });
917
+ bodyOption(workflows
918
+ .command('run <workflow-slug> [tenant]')
919
+ .description('Run a workflow across records matched by a SQL WHERE clause'))
920
+ .action(async (workflowSlug, tenant, opts) => {
921
+ await run(async () => {
922
+ const { api, resolved } = authedApi(program.opts());
923
+ const { data } = await api.workflows.run(resolveTenant(tenant, resolved.tenantSlug), workflowSlug, readBody(opts.body, opts.bodyFile));
924
+ return data;
925
+ });
926
+ });
927
+ workflows
928
+ .command('batch-logs <workflow-slug> [tenant]')
929
+ .description('List batch logs for a workflow')
930
+ .action(async (workflowSlug, tenant) => {
931
+ await run(async () => {
932
+ const { api, resolved } = authedApi(program.opts());
933
+ const { data } = await api.workflows.batchLogs.list(resolveTenant(tenant, resolved.tenantSlug), workflowSlug);
934
+ return data;
935
+ });
936
+ });
937
+ workflows
938
+ .command('batch-log <workflow-slug> <id> [tenant]')
939
+ .description('Get a single batch log by id')
940
+ .action(async (workflowSlug, id, tenant) => {
941
+ await run(async () => {
942
+ const { api, resolved } = authedApi(program.opts());
943
+ const { data } = await api.workflows.batchLogs.get(resolveTenant(tenant, resolved.tenantSlug), workflowSlug, id);
944
+ return data;
945
+ });
946
+ });
947
+ workflows
948
+ .command('batch-log-start <workflow-slug> <id> [tenant]')
949
+ .description('Start polling a batch log')
950
+ .action(async (workflowSlug, id, tenant) => {
951
+ await run(async () => {
952
+ const { api, resolved } = authedApi(program.opts());
953
+ const { data } = await api.workflows.batchLogs.start(resolveTenant(tenant, resolved.tenantSlug), workflowSlug, id);
954
+ return data;
955
+ });
956
+ });
957
+ workflows
958
+ .command('batch-log-stop <workflow-slug> <id> [tenant]')
959
+ .description('Stop polling a batch log')
960
+ .action(async (workflowSlug, id, tenant) => {
961
+ await run(async () => {
962
+ const { api, resolved } = authedApi(program.opts());
963
+ const { data } = await api.workflows.batchLogs.stop(resolveTenant(tenant, resolved.tenantSlug), workflowSlug, id);
964
+ return data;
965
+ });
966
+ });
967
+ workflows
968
+ .command('batch-log-refresh <workflow-slug> <id> [tenant]')
969
+ .description('Force-refresh a batch log')
970
+ .action(async (workflowSlug, id, tenant) => {
971
+ await run(async () => {
972
+ const { api, resolved } = authedApi(program.opts());
973
+ const { data } = await api.workflows.batchLogs.refresh(resolveTenant(tenant, resolved.tenantSlug), workflowSlug, id);
974
+ return data;
975
+ });
976
+ });
977
+ workflows
978
+ .command('workflow-logs <workflow-slug> [tenant]')
979
+ .description('List execution logs for a workflow')
980
+ .action(async (workflowSlug, tenant) => {
981
+ await run(async () => {
982
+ const { api, resolved } = authedApi(program.opts());
983
+ const { data } = await api.workflows.workflowLogs.list(resolveTenant(tenant, resolved.tenantSlug), workflowSlug);
984
+ return data;
985
+ });
986
+ });
987
+ workflows
988
+ .command('workflow-log <workflow-slug> <id> [tenant]')
989
+ .description('Get a single execution log by id')
990
+ .action(async (workflowSlug, id, tenant) => {
991
+ await run(async () => {
992
+ const { api, resolved } = authedApi(program.opts());
993
+ const { data } = await api.workflows.workflowLogs.get(resolveTenant(tenant, resolved.tenantSlug), workflowSlug, id);
994
+ return data;
995
+ });
996
+ });
997
+ workflows
998
+ .command('workflow-log-download <workflow-slug> <id> [tenant]')
999
+ .description('Get a presigned download URL for an execution log')
1000
+ .action(async (workflowSlug, id, tenant) => {
1001
+ await run(async () => {
1002
+ const { api, resolved } = authedApi(program.opts());
1003
+ const { data } = await api.workflows.workflowLogs.download(resolveTenant(tenant, resolved.tenantSlug), workflowSlug, id);
1004
+ return data;
1005
+ });
1006
+ });
598
1007
  program.parseAsync();
599
1008
  //# sourceMappingURL=cli.js.map