@liquidmetal-ai/raindrop 0.4.11 → 0.4.13
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/README.md +209 -53
- package/dist/base-command.d.ts +6 -0
- package/dist/base-command.d.ts.map +1 -1
- package/dist/base-command.js +16 -1
- package/dist/codegen.js +3 -3
- package/dist/codegen.test.js +6 -6
- package/dist/commands/bucket/create-credential.d.ts +25 -0
- package/dist/commands/bucket/create-credential.d.ts.map +1 -0
- package/dist/commands/bucket/create-credential.js +171 -0
- package/dist/commands/bucket/delete-credential.d.ts +24 -0
- package/dist/commands/bucket/delete-credential.d.ts.map +1 -0
- package/dist/commands/bucket/delete-credential.js +140 -0
- package/dist/commands/bucket/get-credential.d.ts +24 -0
- package/dist/commands/bucket/get-credential.d.ts.map +1 -0
- package/dist/commands/bucket/get-credential.js +149 -0
- package/dist/commands/bucket/list-credentials.d.ts +23 -0
- package/dist/commands/bucket/list-credentials.d.ts.map +1 -0
- package/dist/commands/bucket/list-credentials.js +146 -0
- package/dist/commands/build/branch.d.ts +1 -0
- package/dist/commands/build/branch.d.ts.map +1 -1
- package/dist/commands/build/branch.js +17 -0
- package/dist/commands/build/deploy.d.ts +1 -0
- package/dist/commands/build/deploy.d.ts.map +1 -1
- package/dist/commands/build/deploy.js +17 -0
- package/dist/commands/build/find.d.ts +2 -0
- package/dist/commands/build/find.d.ts.map +1 -1
- package/dist/commands/build/find.js +181 -16
- package/dist/commands/build/list.d.ts +6 -0
- package/dist/commands/build/list.d.ts.map +1 -1
- package/dist/commands/build/list.js +280 -99
- package/dist/commands/build/status.d.ts +0 -4
- package/dist/commands/build/status.d.ts.map +1 -1
- package/dist/commands/build/status.js +32 -82
- package/dist/commands/object/delete.d.ts.map +1 -1
- package/dist/commands/object/delete.js +10 -8
- package/dist/commands/object/get.d.ts.map +1 -1
- package/dist/commands/object/get.js +9 -8
- package/dist/commands/object/list.d.ts.map +1 -1
- package/dist/commands/object/list.js +8 -6
- package/dist/commands/object/put.d.ts.map +1 -1
- package/dist/commands/object/put.js +12 -10
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/status.d.ts +21 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +137 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/oclif.manifest.json +2214 -1199
- package/package.json +4 -3
package/dist/codegen.test.js
CHANGED
|
@@ -130,10 +130,10 @@ test('kebabCaseToCamelCase', () => {
|
|
|
130
130
|
test('kebabCaseToUpperCamelCase', () => {
|
|
131
131
|
expect(kebabCaseToUpperCamelCase('my-variable')).toEqual('MyVariable');
|
|
132
132
|
});
|
|
133
|
-
test('generates
|
|
133
|
+
test('generates SmartMemory type bindings', async () => {
|
|
134
134
|
const apps = await mustManifestFromString(`
|
|
135
135
|
application "test-app" {
|
|
136
|
-
|
|
136
|
+
smartmemory "user-memory" {}
|
|
137
137
|
|
|
138
138
|
service "test-service" {}
|
|
139
139
|
}
|
|
@@ -141,10 +141,10 @@ test('generates AgentMemory type bindings', async () => {
|
|
|
141
141
|
const app = apps[0];
|
|
142
142
|
const service = app.service[0];
|
|
143
143
|
const generated = gatherEnvForHandler(service, app);
|
|
144
|
-
// Should include
|
|
145
|
-
expect(generated).toMatch(/import\s+{[^}]*
|
|
146
|
-
// Should include
|
|
147
|
-
expect(generated).toMatch(/USER_MEMORY:\s*
|
|
144
|
+
// Should include SmartMemory import
|
|
145
|
+
expect(generated).toMatch(/import\s+{[^}]*SmartMemory[^}]*}\s+from\s+'@liquidmetal-ai\/raindrop-framework'/);
|
|
146
|
+
// Should include SmartMemory type binding with constant case naming
|
|
147
|
+
expect(generated).toMatch(/USER_MEMORY:\s*SmartMemory/);
|
|
148
148
|
});
|
|
149
149
|
test('generates SmartBucket type bindings', async () => {
|
|
150
150
|
const apps = await mustManifestFromString(`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class CreateCredential extends BaseCommand<typeof CreateCredential> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
bucket: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'expires-at': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'api-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
application: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
version: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
impersonate: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
manifest: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
config: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
rainbowAuthService: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
raindropCatalogService: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
rainbowAuthToken: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
rainbowOrganizationId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
rainbowUserId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
sendVersionMetadata: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
|
+
};
|
|
23
|
+
run(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=create-credential.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-credential.d.ts","sourceRoot":"","sources":["../../../src/commands/bucket/create-credential.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,WAAW,CAAC,OAAO,gBAAgB,CAAC;IAChF,MAAM,CAAC,WAAW,SAAwC;IAE1D,MAAM,CAAC,QAAQ,WAUb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;;;;;;;;MAqDV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA8G3B"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { toJsonString } from '@bufbuild/protobuf';
|
|
2
|
+
import { timestampDate, timestampFromDate } from '@bufbuild/protobuf/wkt';
|
|
3
|
+
import { valueOf } from '@liquidmetal-ai/drizzle/appify/build';
|
|
4
|
+
import { CreateCredentialResponseSchema } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/bucket_api_pb';
|
|
5
|
+
import { Flags } from '@oclif/core';
|
|
6
|
+
import { BaseCommand } from '../../base-command.js';
|
|
7
|
+
export default class CreateCredential extends BaseCommand {
|
|
8
|
+
static description = 'Create S3 credentials for a bucket';
|
|
9
|
+
static examples = [
|
|
10
|
+
`<%= config.bin %> bucket create-credential --bucket my-bucket --name "My API Key"
|
|
11
|
+
Create a new S3 credential for my-bucket
|
|
12
|
+
`,
|
|
13
|
+
`<%= config.bin %> bucket create-credential --bucket my-bucket --name "Temp Key" --expires-at "2024-12-31"
|
|
14
|
+
Create a credential that expires on Dec 31, 2024
|
|
15
|
+
`,
|
|
16
|
+
`<%= config.bin %> bucket create-credential --api-url https://bucket.example.com --name "Direct API Key"
|
|
17
|
+
Create a credential using a direct API URL
|
|
18
|
+
`,
|
|
19
|
+
];
|
|
20
|
+
static flags = {
|
|
21
|
+
...BaseCommand.HIDDEN_FLAGS,
|
|
22
|
+
bucket: Flags.string({
|
|
23
|
+
char: 'b',
|
|
24
|
+
description: 'bucket name',
|
|
25
|
+
required: false,
|
|
26
|
+
exclusive: ['api-url'],
|
|
27
|
+
}),
|
|
28
|
+
name: Flags.string({
|
|
29
|
+
char: 'n',
|
|
30
|
+
description: 'credential name',
|
|
31
|
+
required: true,
|
|
32
|
+
}),
|
|
33
|
+
'expires-at': Flags.string({
|
|
34
|
+
description: 'expiration date (ISO 8601 format)',
|
|
35
|
+
required: false,
|
|
36
|
+
}),
|
|
37
|
+
'api-url': Flags.string({
|
|
38
|
+
description: 'direct API URL (bypasses bucket discovery)',
|
|
39
|
+
required: false,
|
|
40
|
+
exclusive: ['bucket', 'application', 'version'],
|
|
41
|
+
}),
|
|
42
|
+
application: Flags.string({
|
|
43
|
+
char: 'a',
|
|
44
|
+
description: 'application name',
|
|
45
|
+
required: false,
|
|
46
|
+
exclusive: ['api-url'],
|
|
47
|
+
}),
|
|
48
|
+
version: Flags.string({
|
|
49
|
+
char: 'v',
|
|
50
|
+
description: 'application version',
|
|
51
|
+
required: false,
|
|
52
|
+
exclusive: ['api-url'],
|
|
53
|
+
}),
|
|
54
|
+
output: Flags.string({
|
|
55
|
+
char: 'o',
|
|
56
|
+
description: 'output format',
|
|
57
|
+
default: 'text',
|
|
58
|
+
options: ['text', 'json'],
|
|
59
|
+
}),
|
|
60
|
+
impersonate: Flags.string({
|
|
61
|
+
char: 'i',
|
|
62
|
+
description: 'impersonate organization',
|
|
63
|
+
required: false,
|
|
64
|
+
hidden: true,
|
|
65
|
+
}),
|
|
66
|
+
manifest: Flags.string({
|
|
67
|
+
char: 'M',
|
|
68
|
+
description: 'project manifest',
|
|
69
|
+
required: false,
|
|
70
|
+
default: 'raindrop.manifest',
|
|
71
|
+
hidden: true,
|
|
72
|
+
}),
|
|
73
|
+
};
|
|
74
|
+
async run() {
|
|
75
|
+
const { flags } = await this.parse(CreateCredential);
|
|
76
|
+
// Validate that we have either api-url or bucket
|
|
77
|
+
if (!flags['api-url'] && !flags.bucket) {
|
|
78
|
+
this.error('Either --api-url or --bucket must be specified');
|
|
79
|
+
}
|
|
80
|
+
let apiUrl;
|
|
81
|
+
let bucketName;
|
|
82
|
+
if (flags['api-url']) {
|
|
83
|
+
// Direct API URL provided, skip discovery
|
|
84
|
+
apiUrl = flags['api-url'];
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Need to discover the bucket
|
|
88
|
+
bucketName = flags.bucket;
|
|
89
|
+
// Get application info from flags or config/manifest
|
|
90
|
+
let applicationName = flags.application;
|
|
91
|
+
let applicationVersionId = flags.version;
|
|
92
|
+
if (!applicationVersionId) {
|
|
93
|
+
const config = await this.loadConfig();
|
|
94
|
+
applicationVersionId = config.versionId;
|
|
95
|
+
}
|
|
96
|
+
if (!applicationName) {
|
|
97
|
+
const apps = await this.loadManifest();
|
|
98
|
+
const app = apps[0];
|
|
99
|
+
if (app === undefined) {
|
|
100
|
+
this.error('No application provided or found in manifest', { exit: 1 });
|
|
101
|
+
}
|
|
102
|
+
applicationName = valueOf(app.name);
|
|
103
|
+
}
|
|
104
|
+
// Query for the bucket module
|
|
105
|
+
const { client: catalogService, userId, organizationId: defaultOrganizationId } = await this.catalogService();
|
|
106
|
+
const organizationId = flags.impersonate ?? defaultOrganizationId;
|
|
107
|
+
const modulesResp = await catalogService.queryModules({
|
|
108
|
+
userId,
|
|
109
|
+
applicationName,
|
|
110
|
+
applicationVersionId,
|
|
111
|
+
organizationId,
|
|
112
|
+
moduleType: 'bucket',
|
|
113
|
+
});
|
|
114
|
+
// Find the specific bucket
|
|
115
|
+
const bucketModule = modulesResp.modules.find(m => m.name === bucketName && m.type === 'bucket');
|
|
116
|
+
if (!bucketModule) {
|
|
117
|
+
this.error(`Bucket '${bucketName}' not found in application ${applicationName}@${applicationVersionId}`);
|
|
118
|
+
}
|
|
119
|
+
// Extract the API URL from the bucket module
|
|
120
|
+
apiUrl = bucketModule.bucket?.s3?.apiUrl;
|
|
121
|
+
if (!apiUrl) {
|
|
122
|
+
this.error(`Bucket '${bucketName}' does not have an API URL configured`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Parse expires_at if provided
|
|
126
|
+
let expiresAt;
|
|
127
|
+
if (flags['expires-at']) {
|
|
128
|
+
const expiresDate = new Date(flags['expires-at']);
|
|
129
|
+
if (isNaN(expiresDate.getTime())) {
|
|
130
|
+
this.error('Invalid expiration date format. Use ISO 8601 format (e.g., 2024-12-31 or 2024-12-31T23:59:59Z)');
|
|
131
|
+
}
|
|
132
|
+
if (expiresDate <= new Date()) {
|
|
133
|
+
this.error('Expiration date must be in the future');
|
|
134
|
+
}
|
|
135
|
+
expiresAt = timestampFromDate(expiresDate);
|
|
136
|
+
}
|
|
137
|
+
// Create the S3 credential service client
|
|
138
|
+
const { client: credentialService } = await this.bucketApiService(apiUrl);
|
|
139
|
+
try {
|
|
140
|
+
const response = await credentialService.createCredential({
|
|
141
|
+
name: flags.name,
|
|
142
|
+
expiresAt,
|
|
143
|
+
});
|
|
144
|
+
// Output the result
|
|
145
|
+
if (flags.output === 'json') {
|
|
146
|
+
console.log(toJsonString(CreateCredentialResponseSchema, response, { prettySpaces: 2 }));
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
const cred = response.credential;
|
|
150
|
+
if (!cred) {
|
|
151
|
+
this.error('No credential returned from service');
|
|
152
|
+
}
|
|
153
|
+
console.log(`Successfully created S3 credential${bucketName ? ` for bucket '${bucketName}'` : ''}`);
|
|
154
|
+
console.log(`\nAccess Key: ${cred.accessKey}`);
|
|
155
|
+
console.log(`Secret Key: ${cred.secretKey}`);
|
|
156
|
+
console.log(`Name: ${cred.name}`);
|
|
157
|
+
if (cred.createdAt) {
|
|
158
|
+
console.log(`Created: ${timestampDate(cred.createdAt).toISOString()}`);
|
|
159
|
+
}
|
|
160
|
+
if (cred.expiresAt) {
|
|
161
|
+
console.log(`Expires: ${timestampDate(cred.expiresAt).toISOString()}`);
|
|
162
|
+
}
|
|
163
|
+
console.log('\n⚠️ Save these credentials securely - the secret key cannot be retrieved again!');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
const err = error;
|
|
168
|
+
this.error(`Failed to create credential: ${err.message}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class DeleteCredential extends BaseCommand<typeof DeleteCredential> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
bucket: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'access-key': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'api-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
application: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
version: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
impersonate: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
manifest: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
config: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
rainbowAuthService: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
raindropCatalogService: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
rainbowAuthToken: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
rainbowOrganizationId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
rainbowUserId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
sendVersionMetadata: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
};
|
|
22
|
+
run(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=delete-credential.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete-credential.d.ts","sourceRoot":"","sources":["../../../src/commands/bucket/delete-credential.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,WAAW,CAAC,OAAO,gBAAgB,CAAC;IAChF,MAAM,CAAC,WAAW,SAA6B;IAE/C,MAAM,CAAC,QAAQ,WAOb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;;;;;;;MAgDV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAqF3B"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { toJsonString } from '@bufbuild/protobuf';
|
|
2
|
+
import { valueOf } from '@liquidmetal-ai/drizzle/appify/build';
|
|
3
|
+
import { DeleteCredentialResponseSchema } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/bucket_api_pb';
|
|
4
|
+
import { Flags } from '@oclif/core';
|
|
5
|
+
import { BaseCommand } from '../../base-command.js';
|
|
6
|
+
export default class DeleteCredential extends BaseCommand {
|
|
7
|
+
static description = 'Delete an S3 credential';
|
|
8
|
+
static examples = [
|
|
9
|
+
`<%= config.bin %> bucket delete-credential --bucket my-bucket --access-key AKIAIOSFODNN7EXAMPLE
|
|
10
|
+
Delete a specific credential
|
|
11
|
+
`,
|
|
12
|
+
`<%= config.bin %> bucket delete-credential --api-url https://bucket.example.com --access-key AKIAIOSFODNN7EXAMPLE
|
|
13
|
+
Delete credential using a direct API URL
|
|
14
|
+
`,
|
|
15
|
+
];
|
|
16
|
+
static flags = {
|
|
17
|
+
...BaseCommand.HIDDEN_FLAGS,
|
|
18
|
+
bucket: Flags.string({
|
|
19
|
+
char: 'b',
|
|
20
|
+
description: 'bucket name',
|
|
21
|
+
required: false,
|
|
22
|
+
exclusive: ['api-url'],
|
|
23
|
+
}),
|
|
24
|
+
'access-key': Flags.string({
|
|
25
|
+
description: 'access key of the credential to delete',
|
|
26
|
+
required: true,
|
|
27
|
+
}),
|
|
28
|
+
'api-url': Flags.string({
|
|
29
|
+
description: 'direct API URL (bypasses bucket discovery)',
|
|
30
|
+
required: false,
|
|
31
|
+
exclusive: ['bucket', 'application', 'version'],
|
|
32
|
+
}),
|
|
33
|
+
application: Flags.string({
|
|
34
|
+
char: 'a',
|
|
35
|
+
description: 'application name',
|
|
36
|
+
required: false,
|
|
37
|
+
exclusive: ['api-url'],
|
|
38
|
+
}),
|
|
39
|
+
version: Flags.string({
|
|
40
|
+
char: 'v',
|
|
41
|
+
description: 'application version',
|
|
42
|
+
required: false,
|
|
43
|
+
exclusive: ['api-url'],
|
|
44
|
+
}),
|
|
45
|
+
output: Flags.string({
|
|
46
|
+
char: 'o',
|
|
47
|
+
description: 'output format',
|
|
48
|
+
default: 'text',
|
|
49
|
+
options: ['text', 'json'],
|
|
50
|
+
}),
|
|
51
|
+
impersonate: Flags.string({
|
|
52
|
+
char: 'i',
|
|
53
|
+
description: 'impersonate organization',
|
|
54
|
+
required: false,
|
|
55
|
+
hidden: true,
|
|
56
|
+
}),
|
|
57
|
+
manifest: Flags.string({
|
|
58
|
+
char: 'M',
|
|
59
|
+
description: 'project manifest',
|
|
60
|
+
required: false,
|
|
61
|
+
default: 'raindrop.manifest',
|
|
62
|
+
hidden: true,
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
async run() {
|
|
66
|
+
const { flags } = await this.parse(DeleteCredential);
|
|
67
|
+
// Validate that we have either api-url or bucket
|
|
68
|
+
if (!flags['api-url'] && !flags.bucket) {
|
|
69
|
+
this.error('Either --api-url or --bucket must be specified');
|
|
70
|
+
}
|
|
71
|
+
let apiUrl;
|
|
72
|
+
let bucketName;
|
|
73
|
+
if (flags['api-url']) {
|
|
74
|
+
// Direct API URL provided, skip discovery
|
|
75
|
+
apiUrl = flags['api-url'];
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// Need to discover the bucket
|
|
79
|
+
bucketName = flags.bucket;
|
|
80
|
+
// Get application info from flags or config/manifest
|
|
81
|
+
let applicationName = flags.application;
|
|
82
|
+
let applicationVersionId = flags.version;
|
|
83
|
+
if (!applicationVersionId) {
|
|
84
|
+
const config = await this.loadConfig();
|
|
85
|
+
applicationVersionId = config.versionId;
|
|
86
|
+
}
|
|
87
|
+
if (!applicationName) {
|
|
88
|
+
const apps = await this.loadManifest();
|
|
89
|
+
const app = apps[0];
|
|
90
|
+
if (app === undefined) {
|
|
91
|
+
this.error('No application provided or found in manifest', { exit: 1 });
|
|
92
|
+
}
|
|
93
|
+
applicationName = valueOf(app.name);
|
|
94
|
+
}
|
|
95
|
+
// Query for the bucket module
|
|
96
|
+
const { client: catalogService, userId, organizationId: defaultOrganizationId } = await this.catalogService();
|
|
97
|
+
const organizationId = flags.impersonate ?? defaultOrganizationId;
|
|
98
|
+
const modulesResp = await catalogService.queryModules({
|
|
99
|
+
userId,
|
|
100
|
+
applicationName,
|
|
101
|
+
applicationVersionId,
|
|
102
|
+
organizationId,
|
|
103
|
+
moduleType: 'bucket',
|
|
104
|
+
});
|
|
105
|
+
// Find the specific bucket
|
|
106
|
+
const bucketModule = modulesResp.modules.find(m => m.name === bucketName && m.type === 'bucket');
|
|
107
|
+
if (!bucketModule) {
|
|
108
|
+
this.error(`Bucket '${bucketName}' not found in application ${applicationName}@${applicationVersionId}`);
|
|
109
|
+
}
|
|
110
|
+
// Extract the API URL from the bucket module
|
|
111
|
+
apiUrl = bucketModule.bucket?.s3?.apiUrl;
|
|
112
|
+
if (!apiUrl) {
|
|
113
|
+
this.error(`Bucket '${bucketName}' does not have an API URL configured`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Create the S3 credential service client
|
|
117
|
+
const { client: credentialService } = await this.bucketApiService(apiUrl);
|
|
118
|
+
try {
|
|
119
|
+
const response = await credentialService.deleteCredential({
|
|
120
|
+
accessKey: flags['access-key'],
|
|
121
|
+
});
|
|
122
|
+
// Output the result
|
|
123
|
+
if (flags.output === 'json') {
|
|
124
|
+
console.log(toJsonString(DeleteCredentialResponseSchema, response, { prettySpaces: 2 }));
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
if (response.deleted) {
|
|
128
|
+
console.log(`Successfully deleted credential '${flags['access-key']}'${bucketName ? ` from bucket '${bucketName}'` : ''}`);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.log(`Credential '${flags['access-key']}' not found${bucketName ? ` in bucket '${bucketName}'` : ''}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const err = error;
|
|
137
|
+
this.error(`Failed to delete credential: ${err.message}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class GetCredential extends BaseCommand<typeof GetCredential> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
bucket: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'access-key': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'api-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
application: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
version: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
impersonate: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
manifest: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
config: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
rainbowAuthService: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
raindropCatalogService: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
rainbowAuthToken: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
rainbowOrganizationId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
rainbowUserId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
sendVersionMetadata: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
};
|
|
22
|
+
run(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=get-credential.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-credential.d.ts","sourceRoot":"","sources":["../../../src/commands/bucket/get-credential.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW,CAAC,OAAO,aAAa,CAAC;IAC1E,MAAM,CAAC,WAAW,SAA6C;IAE/D,MAAM,CAAC,QAAQ,WAOb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;;;;;;;MAgDV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA+F3B"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { toJsonString } from '@bufbuild/protobuf';
|
|
2
|
+
import { timestampDate } from '@bufbuild/protobuf/wkt';
|
|
3
|
+
import { valueOf } from '@liquidmetal-ai/drizzle/appify/build';
|
|
4
|
+
import { GetCredentialResponseSchema } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/bucket_api_pb';
|
|
5
|
+
import { Flags } from '@oclif/core';
|
|
6
|
+
import { BaseCommand } from '../../base-command.js';
|
|
7
|
+
export default class GetCredential extends BaseCommand {
|
|
8
|
+
static description = 'Get details of a specific S3 credential';
|
|
9
|
+
static examples = [
|
|
10
|
+
`<%= config.bin %> bucket get-credential --bucket my-bucket --access-key AKIAIOSFODNN7EXAMPLE
|
|
11
|
+
Get details of a specific credential
|
|
12
|
+
`,
|
|
13
|
+
`<%= config.bin %> bucket get-credential --api-url https://bucket.example.com --access-key AKIAIOSFODNN7EXAMPLE
|
|
14
|
+
Get credential details using a direct API URL
|
|
15
|
+
`,
|
|
16
|
+
];
|
|
17
|
+
static flags = {
|
|
18
|
+
...BaseCommand.HIDDEN_FLAGS,
|
|
19
|
+
bucket: Flags.string({
|
|
20
|
+
char: 'b',
|
|
21
|
+
description: 'bucket name',
|
|
22
|
+
required: false,
|
|
23
|
+
exclusive: ['api-url'],
|
|
24
|
+
}),
|
|
25
|
+
'access-key': Flags.string({
|
|
26
|
+
description: 'access key of the credential to retrieve',
|
|
27
|
+
required: true,
|
|
28
|
+
}),
|
|
29
|
+
'api-url': Flags.string({
|
|
30
|
+
description: 'direct API URL (bypasses bucket discovery)',
|
|
31
|
+
required: false,
|
|
32
|
+
exclusive: ['bucket', 'application', 'version'],
|
|
33
|
+
}),
|
|
34
|
+
application: Flags.string({
|
|
35
|
+
char: 'a',
|
|
36
|
+
description: 'application name',
|
|
37
|
+
required: false,
|
|
38
|
+
exclusive: ['api-url'],
|
|
39
|
+
}),
|
|
40
|
+
version: Flags.string({
|
|
41
|
+
char: 'v',
|
|
42
|
+
description: 'application version',
|
|
43
|
+
required: false,
|
|
44
|
+
exclusive: ['api-url'],
|
|
45
|
+
}),
|
|
46
|
+
output: Flags.string({
|
|
47
|
+
char: 'o',
|
|
48
|
+
description: 'output format',
|
|
49
|
+
default: 'text',
|
|
50
|
+
options: ['text', 'json'],
|
|
51
|
+
}),
|
|
52
|
+
impersonate: Flags.string({
|
|
53
|
+
char: 'i',
|
|
54
|
+
description: 'impersonate organization',
|
|
55
|
+
required: false,
|
|
56
|
+
hidden: true,
|
|
57
|
+
}),
|
|
58
|
+
manifest: Flags.string({
|
|
59
|
+
char: 'M',
|
|
60
|
+
description: 'project manifest',
|
|
61
|
+
required: false,
|
|
62
|
+
default: 'raindrop.manifest',
|
|
63
|
+
hidden: true,
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
async run() {
|
|
67
|
+
const { flags } = await this.parse(GetCredential);
|
|
68
|
+
// Validate that we have either api-url or bucket
|
|
69
|
+
if (!flags['api-url'] && !flags.bucket) {
|
|
70
|
+
this.error('Either --api-url or --bucket must be specified');
|
|
71
|
+
}
|
|
72
|
+
let apiUrl;
|
|
73
|
+
let bucketName;
|
|
74
|
+
if (flags['api-url']) {
|
|
75
|
+
// Direct API URL provided, skip discovery
|
|
76
|
+
apiUrl = flags['api-url'];
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Need to discover the bucket
|
|
80
|
+
bucketName = flags.bucket;
|
|
81
|
+
// Get application info from flags or config/manifest
|
|
82
|
+
let applicationName = flags.application;
|
|
83
|
+
let applicationVersionId = flags.version;
|
|
84
|
+
if (!applicationVersionId) {
|
|
85
|
+
const config = await this.loadConfig();
|
|
86
|
+
applicationVersionId = config.versionId;
|
|
87
|
+
}
|
|
88
|
+
if (!applicationName) {
|
|
89
|
+
const apps = await this.loadManifest();
|
|
90
|
+
const app = apps[0];
|
|
91
|
+
if (app === undefined) {
|
|
92
|
+
this.error('No application provided or found in manifest', { exit: 1 });
|
|
93
|
+
}
|
|
94
|
+
applicationName = valueOf(app.name);
|
|
95
|
+
}
|
|
96
|
+
// Query for the bucket module
|
|
97
|
+
const { client: catalogService, userId, organizationId: defaultOrganizationId } = await this.catalogService();
|
|
98
|
+
const organizationId = flags.impersonate ?? defaultOrganizationId;
|
|
99
|
+
const modulesResp = await catalogService.queryModules({
|
|
100
|
+
userId,
|
|
101
|
+
applicationName,
|
|
102
|
+
applicationVersionId,
|
|
103
|
+
organizationId,
|
|
104
|
+
moduleType: 'bucket',
|
|
105
|
+
});
|
|
106
|
+
// Find the specific bucket
|
|
107
|
+
const bucketModule = modulesResp.modules.find(m => m.name === bucketName && m.type === 'bucket');
|
|
108
|
+
if (!bucketModule) {
|
|
109
|
+
this.error(`Bucket '${bucketName}' not found in application ${applicationName}@${applicationVersionId}`);
|
|
110
|
+
}
|
|
111
|
+
// Extract the API URL from the bucket module
|
|
112
|
+
apiUrl = bucketModule.bucket?.s3?.apiUrl;
|
|
113
|
+
if (!apiUrl) {
|
|
114
|
+
this.error(`Bucket '${bucketName}' does not have an API URL configured`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Create the S3 credential service client
|
|
118
|
+
const { client: credentialService } = await this.bucketApiService(apiUrl);
|
|
119
|
+
try {
|
|
120
|
+
const response = await credentialService.getCredential({
|
|
121
|
+
accessKey: flags['access-key'],
|
|
122
|
+
});
|
|
123
|
+
// Output the result
|
|
124
|
+
if (flags.output === 'json') {
|
|
125
|
+
console.log(toJsonString(GetCredentialResponseSchema, response, { prettySpaces: 2 }));
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
const cred = response.credential;
|
|
129
|
+
if (!cred) {
|
|
130
|
+
this.error('No credential returned from service');
|
|
131
|
+
}
|
|
132
|
+
console.log(`Credential details${bucketName ? ` for bucket '${bucketName}'` : ''}:\n`);
|
|
133
|
+
console.log(`Access Key: ${cred.accessKey}`);
|
|
134
|
+
console.log(`Name: ${cred.name}`);
|
|
135
|
+
if (cred.createdAt) {
|
|
136
|
+
console.log(`Created: ${timestampDate(cred.createdAt).toISOString()}`);
|
|
137
|
+
}
|
|
138
|
+
if (cred.expiresAt) {
|
|
139
|
+
console.log(`Expires: ${timestampDate(cred.expiresAt).toISOString()}`);
|
|
140
|
+
}
|
|
141
|
+
console.log('\nNote: Secret key is not displayed for security reasons');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
const err = error;
|
|
146
|
+
this.error(`Failed to get credential: ${err.message}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class ListCredentials extends BaseCommand<typeof ListCredentials> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
bucket: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'api-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
application: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
version: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
impersonate: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
manifest: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
config: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
rainbowAuthService: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
raindropCatalogService: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
rainbowAuthToken: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
rainbowOrganizationId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
rainbowUserId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
sendVersionMetadata: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
};
|
|
21
|
+
run(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=list-credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-credentials.d.ts","sourceRoot":"","sources":["../../../src/commands/bucket/list-credentials.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,WAAW,CAAC,OAAO,eAAe,CAAC;IAC9E,MAAM,CAAC,WAAW,SAAsC;IAExD,MAAM,CAAC,QAAQ,WAOb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;;;;;;MA4CV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAkG3B"}
|