@ductape/cli 0.2.13 → 0.2.15

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.
@@ -361,7 +361,7 @@ export async function runDbSchemaPush(opts) {
361
361
  try {
362
362
  const raw = await proxy.execute('schema.list', [null], dbContext);
363
363
  if (Array.isArray(raw)) {
364
- tableNames = raw.map((r) => typeof r === 'string' ? r : String(r.name ?? '')).filter(Boolean);
364
+ tableNames = raw.map((r) => typeof r === 'string' ? r : String(r.name ?? '')).filter((n) => Boolean(n) && !n.startsWith('_ductape_'));
365
365
  }
366
366
  }
367
367
  catch (e) {
@@ -1,5 +1,10 @@
1
1
  import { type CommandInteractiveFlags } from '../lib/interactive-opts.js';
2
2
  export declare function runResourcesList(json: boolean): void;
3
+ export declare function runEventTopicCrud(verb: string, opts: {
4
+ tag?: string;
5
+ file?: string;
6
+ json?: boolean;
7
+ } & CommandInteractiveFlags, extraArgs: string[]): Promise<void>;
3
8
  export declare function runResourceCrud(typeName: string, verb: string, opts: {
4
9
  tag?: string;
5
10
  file?: string;
@@ -9,6 +9,58 @@ const CRUD_VERBS = ['create', 'list', 'get', 'update', 'delete', 'connect'];
9
9
  export function runResourcesList(json) {
10
10
  printJson({ resource_types: listResourceTypes() }, json);
11
11
  }
12
+ export async function runEventTopicCrud(verb, opts, extraArgs) {
13
+ const crud = verb.toLowerCase();
14
+ if (!CRUD_VERBS.includes(crud)) {
15
+ throw new Error(`Unknown verb "${verb}". Use: ${CRUD_VERBS.join(', ')}`);
16
+ }
17
+ const session = requireSession();
18
+ const productTag = session.project.product_tag;
19
+ const interactive = toInteractiveOpts(opts);
20
+ let tag = opts.tag ?? extraArgs[0];
21
+ if (!tag && ['get', 'update', 'delete', 'list'].includes(crud) && isInteractive(interactive)) {
22
+ tag = await promptTag(crud === 'list' ? 'Broker tag' : 'Topic tag (broker:topic)');
23
+ }
24
+ const method = crud === 'get' ? 'topics.fetch' : `topics.${crud}`;
25
+ const needsBody = crud === 'create' || crud === 'update';
26
+ const body = needsBody
27
+ ? await resolveBody({
28
+ ...interactive,
29
+ file: opts.file,
30
+ schema: undefined,
31
+ patch: crud === 'update',
32
+ requireBody: crud === 'create',
33
+ })
34
+ : undefined;
35
+ if (crud === 'create' && (!body || Object.keys(body).length === 0)) {
36
+ throw new Error(`create requires a body. ${bodyRequiredHint('messageBrokers:topics:create')}`);
37
+ }
38
+ let params;
39
+ if (crud === 'create') {
40
+ params = [productTag, body ?? {}];
41
+ }
42
+ else if (crud === 'list') {
43
+ if (!tag)
44
+ throw new Error('--tag <broker-tag> is required for list');
45
+ params = [productTag, tag];
46
+ }
47
+ else if (crud === 'get' || crud === 'delete') {
48
+ if (!tag)
49
+ throw new Error('--tag <broker:topic> is required');
50
+ params = [productTag, tag];
51
+ }
52
+ else if (crud === 'update') {
53
+ if (!tag)
54
+ throw new Error('--tag <broker:topic> is required');
55
+ params = [productTag, tag, body ?? {}];
56
+ }
57
+ else {
58
+ throw new Error(`Unsupported verb "${crud}" for events topics`);
59
+ }
60
+ const proxy = getSdkProxy(session);
61
+ const result = await proxy.execute('messageBrokers', method, params);
62
+ printJson(result, Boolean(opts.json));
63
+ }
12
64
  export async function runResourceCrud(typeName, verb, opts, extraArgs) {
13
65
  const crud = verb.toLowerCase();
14
66
  if (!CRUD_VERBS.includes(crud)) {
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import { runUnlink } from './commands/unlink.js';
12
12
  import { runInit } from './commands/init.js';
13
13
  import { runInstall } from './commands/install.js';
14
14
  import { runStart, runStop, runStatus } from './commands/platform.js';
15
- import { runResourceCrud, runResourcesList } from './commands/resources.js';
15
+ import { runResourceCrud, runResourcesList, runEventTopicCrud } from './commands/resources.js';
16
16
  import { runCloud } from './commands/cloud.js';
17
17
  import { runDb, runDbContext } from './commands/db.js';
18
18
  import { runDbMigrate, runDbMigrateStatus, runDbMigrateRollback } from './commands/db-migrate.js';
@@ -244,6 +244,16 @@ apps
244
244
  version: opts.version,
245
245
  json: opts.json,
246
246
  })));
247
+ const events = program.command('events').description('Message broker CRUD (sdk-proxy, requires access key login)');
248
+ const eventTopics = events.command('topics').description('Topic CRUD for a message broker');
249
+ eventTopics
250
+ .argument('<verb>', 'list | get | create | update | delete')
251
+ .option('-t, --tag <tag>', 'Broker tag (list) or topic tag in broker:topic form (get, update, delete)')
252
+ .option('-f, --file <path>', 'JSON body (create, update)')
253
+ .option('-i, --interactive', 'Prompt for fields (default in TTY when -f omitted)')
254
+ .option('--no-interactive', 'Require -f JSON for create/update')
255
+ .option('--json', 'JSON output')
256
+ .action(wrap((verb, opts) => runEventTopicCrud(verb, opts, [])));
247
257
  const resources = program.command('resources').description('Component CRUD (sdk-proxy)');
248
258
  resources.command('types').option('--json', 'JSON output').action(wrap((opts) => runResourcesList(Boolean(opts.json))));
249
259
  resources
@@ -28,6 +28,8 @@ export async function pushDatabaseSchema(apiUrl, creds, opts) {
28
28
  'x-access-key': creds.public_key,
29
29
  },
30
30
  body: JSON.stringify({
31
+ user_id: creds.user_id,
32
+ public_key: creds.public_key,
31
33
  workspace_id: opts.workspace_id,
32
34
  product_tag: opts.product_tag,
33
35
  database_tag: opts.database_tag,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ductape/cli",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "Ductape CLI — local platform, login, link projects, and manage resources via the proxy (Workbench-compatible)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -370,7 +370,7 @@ export async function runDbSchemaPush(opts: SchemaPushOpts): Promise<void> {
370
370
  if (Array.isArray(raw)) {
371
371
  tableNames = (raw as unknown[]).map((r) =>
372
372
  typeof r === 'string' ? r : String((r as Record<string, unknown>).name ?? ''),
373
- ).filter(Boolean);
373
+ ).filter((n) => Boolean(n) && !n.startsWith('_ductape_'));
374
374
  }
375
375
  } catch (e) {
376
376
  throw new Error(`Failed to list tables: ${(e as Error).message}. Make sure the database is connected.`);
@@ -18,6 +18,61 @@ export function runResourcesList(json: boolean): void {
18
18
  printJson({ resource_types: listResourceTypes() }, json);
19
19
  }
20
20
 
21
+ export async function runEventTopicCrud(
22
+ verb: string,
23
+ opts: { tag?: string; file?: string; json?: boolean } & CommandInteractiveFlags,
24
+ extraArgs: string[],
25
+ ): Promise<void> {
26
+ const crud = verb.toLowerCase() as CrudVerb;
27
+ if (!CRUD_VERBS.includes(crud)) {
28
+ throw new Error(`Unknown verb "${verb}". Use: ${CRUD_VERBS.join(', ')}`);
29
+ }
30
+
31
+ const session = requireSession();
32
+ const productTag = session.project.product_tag;
33
+ const interactive = toInteractiveOpts(opts);
34
+ let tag = opts.tag ?? extraArgs[0];
35
+ if (!tag && ['get', 'update', 'delete', 'list'].includes(crud) && isInteractive(interactive)) {
36
+ tag = await promptTag(crud === 'list' ? 'Broker tag' : 'Topic tag (broker:topic)');
37
+ }
38
+
39
+ const method = crud === 'get' ? 'topics.fetch' : `topics.${crud}`;
40
+ const needsBody = crud === 'create' || crud === 'update';
41
+ const body = needsBody
42
+ ? await resolveBody({
43
+ ...interactive,
44
+ file: opts.file,
45
+ schema: undefined,
46
+ patch: crud === 'update',
47
+ requireBody: crud === 'create',
48
+ })
49
+ : undefined;
50
+
51
+ if (crud === 'create' && (!body || Object.keys(body).length === 0)) {
52
+ throw new Error(`create requires a body. ${bodyRequiredHint('messageBrokers:topics:create')}`);
53
+ }
54
+
55
+ let params: unknown[];
56
+ if (crud === 'create') {
57
+ params = [productTag, body ?? {}];
58
+ } else if (crud === 'list') {
59
+ if (!tag) throw new Error('--tag <broker-tag> is required for list');
60
+ params = [productTag, tag];
61
+ } else if (crud === 'get' || crud === 'delete') {
62
+ if (!tag) throw new Error('--tag <broker:topic> is required');
63
+ params = [productTag, tag];
64
+ } else if (crud === 'update') {
65
+ if (!tag) throw new Error('--tag <broker:topic> is required');
66
+ params = [productTag, tag, body ?? {}];
67
+ } else {
68
+ throw new Error(`Unsupported verb "${crud}" for events topics`);
69
+ }
70
+
71
+ const proxy = getSdkProxy(session);
72
+ const result = await proxy.execute('messageBrokers', method, params);
73
+ printJson(result, Boolean(opts.json));
74
+ }
75
+
21
76
  export async function runResourceCrud(
22
77
  typeName: string,
23
78
  verb: string,
package/src/index.ts CHANGED
@@ -12,7 +12,7 @@ import { runUnlink } from './commands/unlink.js';
12
12
  import { runInit } from './commands/init.js';
13
13
  import { runInstall } from './commands/install.js';
14
14
  import { runStart, runStop, runStatus } from './commands/platform.js';
15
- import { runResourceCrud, runResourcesList } from './commands/resources.js';
15
+ import { runResourceCrud, runResourcesList, runEventTopicCrud } from './commands/resources.js';
16
16
  import { runCloud } from './commands/cloud.js';
17
17
  import { runDb, runDbContext } from './commands/db.js';
18
18
  import { runDbMigrate, runDbMigrateStatus, runDbMigrateRollback } from './commands/db-migrate.js';
@@ -317,6 +317,19 @@ apps
317
317
  ),
318
318
  );
319
319
 
320
+ const events = program.command('events').description('Message broker CRUD (sdk-proxy, requires access key login)');
321
+
322
+ const eventTopics = events.command('topics').description('Topic CRUD for a message broker');
323
+
324
+ eventTopics
325
+ .argument('<verb>', 'list | get | create | update | delete')
326
+ .option('-t, --tag <tag>', 'Broker tag (list) or topic tag in broker:topic form (get, update, delete)')
327
+ .option('-f, --file <path>', 'JSON body (create, update)')
328
+ .option('-i, --interactive', 'Prompt for fields (default in TTY when -f omitted)')
329
+ .option('--no-interactive', 'Require -f JSON for create/update')
330
+ .option('--json', 'JSON output')
331
+ .action(wrap((verb: string, opts) => runEventTopicCrud(verb, opts, [])));
332
+
320
333
  const resources = program.command('resources').description('Component CRUD (sdk-proxy)');
321
334
 
322
335
  resources.command('types').option('--json', 'JSON output').action(wrap((opts) => runResourcesList(Boolean(opts.json))));
@@ -82,6 +82,8 @@ export async function pushDatabaseSchema(
82
82
  'x-access-key': creds.public_key,
83
83
  },
84
84
  body: JSON.stringify({
85
+ user_id: creds.user_id,
86
+ public_key: creds.public_key,
85
87
  workspace_id: opts.workspace_id,
86
88
  product_tag: opts.product_tag,
87
89
  database_tag: opts.database_tag,