@ductape/cli 0.3.8 → 0.3.9
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/CHANGELOG.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
- `ductape workspaces current`, `workspaces switch`, `workspaces refresh`
|
|
21
21
|
- `ductape login --workspace`, `--skip-workspace-select`
|
|
22
22
|
- `ductape link` defaults to active workspace; `whoami` shows `active_workspace`
|
|
23
|
-
- Switching workspaces updates linked
|
|
23
|
+
- Switching workspaces updates linked `ductape/config.json` when present
|
|
24
24
|
|
|
25
25
|
## 0.2.0
|
|
26
26
|
|
package/dist/commands/link.js
CHANGED
|
@@ -57,5 +57,5 @@ export async function runLink(opts) {
|
|
|
57
57
|
};
|
|
58
58
|
saveProjectConfig(targetDir, config);
|
|
59
59
|
setActiveWorkspace(workspaceIdValue, workspaceLabel(workspaceSummary), workspaceTagValue);
|
|
60
|
-
success(`Linked project in ${path.join(targetDir, '
|
|
60
|
+
success(`Linked project in ${path.join(targetDir, 'ductape/config.json')}`);
|
|
61
61
|
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { type CommandInteractiveFlags } from '../lib/interactive-opts.js';
|
|
2
|
+
import type { SDKModule } from '../lib/proxy/sdk-proxy.js';
|
|
3
|
+
export declare function resolveResourceProductTag(override: string | undefined, linkedProductTag: string): string;
|
|
4
|
+
type ResourceProxy = {
|
|
5
|
+
execute<T>(module: SDKModule, method: string, params?: unknown[]): Promise<T>;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Session inventories on older platform versions can fail when the component does not exist.
|
|
9
|
+
* Confirm the state through the product catalogue before treating that failure as an empty list,
|
|
10
|
+
* so transport, authentication, and genuine server failures are never silently swallowed.
|
|
11
|
+
*/
|
|
12
|
+
export declare function listSessionsWithProductFallback(proxy: ResourceProxy, productTag: string): Promise<unknown[]>;
|
|
2
13
|
export declare function runResourcesList(json: boolean): void;
|
|
3
14
|
export declare function runEventTopicCrud(verb: string, opts: {
|
|
4
15
|
tag?: string;
|
|
@@ -13,6 +24,8 @@ export declare function runNotificationMessageCrud(verb: string, opts: {
|
|
|
13
24
|
}): Promise<void>;
|
|
14
25
|
export declare function runResourceCrud(typeName: string, verb: string, opts: {
|
|
15
26
|
tag?: string;
|
|
27
|
+
product?: string;
|
|
16
28
|
file?: string;
|
|
17
29
|
json?: boolean;
|
|
18
30
|
} & CommandInteractiveFlags, extraArgs: string[]): Promise<void>;
|
|
31
|
+
export {};
|
|
@@ -6,6 +6,43 @@ import { bodyRequiredHint, resolveBody } from '../lib/read-body.js';
|
|
|
6
6
|
import { requireSession, getSdkProxy } from '../lib/proxy/context.js';
|
|
7
7
|
import { printJson } from '../lib/output.js';
|
|
8
8
|
const CRUD_VERBS = ['create', 'list', 'get', 'update', 'delete', 'connect'];
|
|
9
|
+
export function resolveResourceProductTag(override, linkedProductTag) {
|
|
10
|
+
return override?.trim() || linkedProductTag;
|
|
11
|
+
}
|
|
12
|
+
function unwrapArray(value) {
|
|
13
|
+
if (Array.isArray(value))
|
|
14
|
+
return value;
|
|
15
|
+
if (value && typeof value === 'object' && Array.isArray(value.data)) {
|
|
16
|
+
return value.data;
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Session inventories on older platform versions can fail when the component does not exist.
|
|
22
|
+
* Confirm the state through the product catalogue before treating that failure as an empty list,
|
|
23
|
+
* so transport, authentication, and genuine server failures are never silently swallowed.
|
|
24
|
+
*/
|
|
25
|
+
export async function listSessionsWithProductFallback(proxy, productTag) {
|
|
26
|
+
try {
|
|
27
|
+
const result = await proxy.execute('sessions', 'list', [productTag]);
|
|
28
|
+
return unwrapArray(result) ?? [];
|
|
29
|
+
}
|
|
30
|
+
catch (listError) {
|
|
31
|
+
try {
|
|
32
|
+
const fetched = await proxy.execute('product', 'fetch', [productTag]);
|
|
33
|
+
const product = fetched && typeof fetched === 'object' && 'data' in fetched
|
|
34
|
+
? fetched.data
|
|
35
|
+
: fetched;
|
|
36
|
+
if (!product || typeof product !== 'object')
|
|
37
|
+
throw listError;
|
|
38
|
+
const sessions = unwrapArray(product.sessions) ?? [];
|
|
39
|
+
return sessions.filter((session) => !session || typeof session !== 'object' || session.deleted !== true);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw listError;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
9
46
|
export function runResourcesList(json) {
|
|
10
47
|
printJson({ resource_types: listResourceTypes() }, json);
|
|
11
48
|
}
|
|
@@ -168,11 +205,28 @@ export async function runResourceCrud(typeName, verb, opts, extraArgs) {
|
|
|
168
205
|
tag,
|
|
169
206
|
};
|
|
170
207
|
}
|
|
171
|
-
const
|
|
208
|
+
const productTag = resolveResourceProductTag(opts.product, session.project.product_tag);
|
|
209
|
+
const params = buildCrudParams(module, method, productTag, {
|
|
172
210
|
tag,
|
|
173
211
|
body: payload,
|
|
174
212
|
});
|
|
175
213
|
const proxy = getSdkProxy(session);
|
|
214
|
+
if (crud === 'list' && module === 'sessions') {
|
|
215
|
+
printJson(await listSessionsWithProductFallback(proxy, productTag), Boolean(opts.json));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
176
218
|
const result = await proxy.execute(module, method, params);
|
|
219
|
+
if (crud === 'create' && module === 'sessions') {
|
|
220
|
+
const createdTag = String(body?.tag ?? '').trim();
|
|
221
|
+
if (!createdTag) {
|
|
222
|
+
throw new Error('Session creation could not be verified because body.tag is missing');
|
|
223
|
+
}
|
|
224
|
+
const verified = await proxy.execute(module, 'fetch', buildCrudParams(module, 'fetch', productTag, { tag: createdTag }));
|
|
225
|
+
if (!verified) {
|
|
226
|
+
throw new Error(`Session creation returned without an error, but "${createdTag}" was not found during verification`);
|
|
227
|
+
}
|
|
228
|
+
printJson({ created: true, session: verified }, Boolean(opts.json));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
177
231
|
printJson(result, Boolean(opts.json));
|
|
178
232
|
}
|
package/dist/index.js
CHANGED
|
@@ -112,7 +112,7 @@ workspaces
|
|
|
112
112
|
.action(wrap((opts) => runWorkspacesCurrent(Boolean(opts.json))));
|
|
113
113
|
workspaces
|
|
114
114
|
.command('use [selector]')
|
|
115
|
-
.description('Switch active workspace (interactive picker). Updates linked
|
|
115
|
+
.description('Switch active workspace (interactive picker). Updates linked ductape/config.json if present')
|
|
116
116
|
.option('--profile <name>')
|
|
117
117
|
.option('-C, --dir <path>', 'Project directory to sync', process.cwd())
|
|
118
118
|
.option('--json', 'JSON output')
|
|
@@ -661,6 +661,7 @@ resources
|
|
|
661
661
|
.argument('<type>', 'Resource type (e.g. storage, database, cache …)')
|
|
662
662
|
.argument('<verb>', 'list | get | create | update | delete | connect')
|
|
663
663
|
.option('-t, --tag <tag>')
|
|
664
|
+
.option('--product <tag>', 'Product tag (defaults to linked project)')
|
|
664
665
|
.option('-f, --file <path>', 'JSON body (or use interactive prompts)')
|
|
665
666
|
.option('-i, --interactive', 'Prompt for fields (default in TTY when -f omitted)')
|
|
666
667
|
.option('--no-interactive', 'Require -f JSON for create/update/connect')
|
package/dist/lib/config.js
CHANGED
|
@@ -9,6 +9,7 @@ export const GLOBAL_CONFIG_PATH = path.join(GLOBAL_DIR, 'config.json');
|
|
|
9
9
|
export const HUB_PLATFORM_DIR = path.join(GLOBAL_DIR, 'platform');
|
|
10
10
|
export const PROJECT_CONFIG_DIR = 'ductape';
|
|
11
11
|
export const PROJECT_CONFIG_PATH = path.join(PROJECT_CONFIG_DIR, 'config.json');
|
|
12
|
+
const LEGACY_PROJECT_CONFIG_PATH = path.join('.ductape', 'config.json');
|
|
12
13
|
const DEFAULT_GLOBAL = {
|
|
13
14
|
default_profile: 'cloud',
|
|
14
15
|
profiles: {
|
|
@@ -114,10 +115,13 @@ export function findProjectConfig(startDir = process.cwd()) {
|
|
|
114
115
|
let dir = startDir;
|
|
115
116
|
const root = path.parse(dir).root;
|
|
116
117
|
while (true) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
// The CLI writes ductape/config.json. Read the former hidden path only as
|
|
119
|
+
// an upgrade fallback; canonical config always wins when both exist.
|
|
120
|
+
for (const relativePath of [PROJECT_CONFIG_PATH, LEGACY_PROJECT_CONFIG_PATH]) {
|
|
121
|
+
const cfg = readJson(path.join(dir, relativePath));
|
|
122
|
+
if (cfg?.product_tag && (cfg.workspace_tag || cfg.workspace_id)) {
|
|
123
|
+
return { dir, config: cfg };
|
|
124
|
+
}
|
|
121
125
|
}
|
|
122
126
|
if (dir === root)
|
|
123
127
|
break;
|
package/package.json
CHANGED