@liquidmetal-ai/raindrop 0.0.0
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 +777 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +6 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/base-command.d.ts +27 -0
- package/dist/base-command.d.ts.map +1 -0
- package/dist/base-command.js +69 -0
- package/dist/build.d.ts +13 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +86 -0
- package/dist/build.test.d.ts +2 -0
- package/dist/build.test.d.ts.map +1 -0
- package/dist/build.test.js +41 -0
- package/dist/codegen.d.ts +32 -0
- package/dist/codegen.d.ts.map +1 -0
- package/dist/codegen.js +212 -0
- package/dist/codegen.test.d.ts +2 -0
- package/dist/codegen.test.d.ts.map +1 -0
- package/dist/codegen.test.js +97 -0
- package/dist/commands/auth/list.d.ts +10 -0
- package/dist/commands/auth/list.d.ts.map +1 -0
- package/dist/commands/auth/list.js +55 -0
- package/dist/commands/auth/login.d.ts +10 -0
- package/dist/commands/auth/login.d.ts.map +1 -0
- package/dist/commands/auth/login.js +69 -0
- package/dist/commands/auth/logout.d.ts +8 -0
- package/dist/commands/auth/logout.d.ts.map +1 -0
- package/dist/commands/auth/logout.js +15 -0
- package/dist/commands/auth/select.d.ts +10 -0
- package/dist/commands/auth/select.d.ts.map +1 -0
- package/dist/commands/auth/select.js +39 -0
- package/dist/commands/build/branch.d.ts +16 -0
- package/dist/commands/build/branch.d.ts.map +1 -0
- package/dist/commands/build/branch.js +81 -0
- package/dist/commands/build/delete.d.ts +19 -0
- package/dist/commands/build/delete.d.ts.map +1 -0
- package/dist/commands/build/delete.js +99 -0
- package/dist/commands/build/deploy.d.ts +18 -0
- package/dist/commands/build/deploy.d.ts.map +1 -0
- package/dist/commands/build/deploy.js +144 -0
- package/dist/commands/build/env/get.d.ts +19 -0
- package/dist/commands/build/env/get.d.ts.map +1 -0
- package/dist/commands/build/env/get.js +101 -0
- package/dist/commands/build/env/set.d.ts +20 -0
- package/dist/commands/build/env/set.d.ts.map +1 -0
- package/dist/commands/build/env/set.js +115 -0
- package/dist/commands/build/find.d.ts +24 -0
- package/dist/commands/build/find.d.ts.map +1 -0
- package/dist/commands/build/find.js +110 -0
- package/dist/commands/build/generate.d.ts +13 -0
- package/dist/commands/build/generate.d.ts.map +1 -0
- package/dist/commands/build/generate.js +38 -0
- package/dist/commands/build/init.d.ts +15 -0
- package/dist/commands/build/init.d.ts.map +1 -0
- package/dist/commands/build/init.js +57 -0
- package/dist/commands/build/list.d.ts +17 -0
- package/dist/commands/build/list.d.ts.map +1 -0
- package/dist/commands/build/list.js +100 -0
- package/dist/commands/build/start.d.ts +16 -0
- package/dist/commands/build/start.d.ts.map +1 -0
- package/dist/commands/build/start.js +71 -0
- package/dist/commands/build/stop.d.ts +15 -0
- package/dist/commands/build/stop.d.ts.map +1 -0
- package/dist/commands/build/stop.js +67 -0
- package/dist/commands/build/token.d.ts +9 -0
- package/dist/commands/build/token.d.ts.map +1 -0
- package/dist/commands/build/token.js +42 -0
- package/dist/commands/build/upload.d.ts +17 -0
- package/dist/commands/build/upload.d.ts.map +1 -0
- package/dist/commands/build/upload.js +75 -0
- package/dist/commands/build/validate.d.ts +13 -0
- package/dist/commands/build/validate.d.ts.map +1 -0
- package/dist/commands/build/validate.js +26 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +34 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +24 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +140 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/oclif.manifest.json +1208 -0
- package/package.json +107 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { valueOf } from '@liquidmetal-ai/drizzle/appify/build';
|
|
2
|
+
import { Flags } from '@oclif/core';
|
|
3
|
+
import { BaseCommand } from '../../base-command.js';
|
|
4
|
+
export default class Start extends BaseCommand {
|
|
5
|
+
static args = {};
|
|
6
|
+
static description = 'start a Raindrop application';
|
|
7
|
+
static examples = [
|
|
8
|
+
`<%= config.bin %> <%= command.id %> .
|
|
9
|
+
Start a Raindrop application.
|
|
10
|
+
`,
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
config: Flags.string({ char: 'c', description: 'config file', required: false, default: '.raindrop/config.json' }),
|
|
14
|
+
manifest: Flags.string({
|
|
15
|
+
char: 'm',
|
|
16
|
+
description: 'project manifest',
|
|
17
|
+
required: false,
|
|
18
|
+
default: 'raindrop.manifest',
|
|
19
|
+
}),
|
|
20
|
+
application: Flags.string({
|
|
21
|
+
char: 'a',
|
|
22
|
+
description: 'application to start',
|
|
23
|
+
required: false,
|
|
24
|
+
}),
|
|
25
|
+
version: Flags.string({
|
|
26
|
+
char: 'v',
|
|
27
|
+
description: 'application version to start',
|
|
28
|
+
required: false,
|
|
29
|
+
}),
|
|
30
|
+
impersonate: Flags.string({
|
|
31
|
+
char: 'i',
|
|
32
|
+
description: 'impersonate organization',
|
|
33
|
+
required: false,
|
|
34
|
+
hidden: true,
|
|
35
|
+
}),
|
|
36
|
+
rainbowAuthService: Flags.string({
|
|
37
|
+
default: 'https://liquidmetal.run/api/connect',
|
|
38
|
+
hidden: true,
|
|
39
|
+
env: 'LIQUIDMETAL_RAINBOW_AUTH_SERVICE',
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
async run() {
|
|
43
|
+
const { client: catalogService, userId, organizationId } = await this.catalogService();
|
|
44
|
+
const config = await this.loadConfig();
|
|
45
|
+
let appName = this.flags.application;
|
|
46
|
+
if (appName === undefined) {
|
|
47
|
+
const apps = await this.loadManifest();
|
|
48
|
+
const app = apps[0];
|
|
49
|
+
if (app === undefined) {
|
|
50
|
+
this.error('No application found in manifest', { exit: 1 });
|
|
51
|
+
}
|
|
52
|
+
appName = valueOf(app.name);
|
|
53
|
+
}
|
|
54
|
+
const resp = await catalogService.setApplicationActiveStates({
|
|
55
|
+
states: [
|
|
56
|
+
{
|
|
57
|
+
applicationName: this.flags.application || appName,
|
|
58
|
+
applicationVersionId: this.flags.version || config.versionId,
|
|
59
|
+
isActive: true,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
userId,
|
|
63
|
+
organizationId: this.flags.impersonate ?? organizationId,
|
|
64
|
+
});
|
|
65
|
+
if (resp.failure.length) {
|
|
66
|
+
this.error(`Failed to start applications: ${resp.failure.map((f) => `${f.name}@${f.versionId}`).join(', ')}`, {
|
|
67
|
+
exit: 1,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Stop extends BaseCommand<typeof Stop> {
|
|
3
|
+
static args: {};
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
application: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
version: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
impersonate: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
rainbowAuthService: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
config: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=stop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../../src/commands/build/stop.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,WAAW,CAAC,OAAO,IAAI,CAAC;IACxD,MAAM,CAAC,IAAI,KAAM;IAEjB,MAAM,CAAC,WAAW,SAAiC;IAEnD,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;MAuBV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAiC3B"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { valueOf } from '@liquidmetal-ai/drizzle/appify/build';
|
|
2
|
+
import { Flags } from '@oclif/core';
|
|
3
|
+
import { BaseCommand } from '../../base-command.js';
|
|
4
|
+
export default class Stop extends BaseCommand {
|
|
5
|
+
static args = {};
|
|
6
|
+
static description = 'stop a Raindrop application';
|
|
7
|
+
static examples = [
|
|
8
|
+
`<%= config.bin %> <%= command.id %> .
|
|
9
|
+
Stop a Raindrop application.
|
|
10
|
+
`,
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
application: Flags.string({
|
|
14
|
+
char: 'a',
|
|
15
|
+
description: 'application to stop',
|
|
16
|
+
required: false,
|
|
17
|
+
}),
|
|
18
|
+
version: Flags.string({
|
|
19
|
+
char: 'v',
|
|
20
|
+
description: 'application version to start',
|
|
21
|
+
required: false,
|
|
22
|
+
}),
|
|
23
|
+
impersonate: Flags.string({
|
|
24
|
+
char: 'i',
|
|
25
|
+
description: 'impersonate organization',
|
|
26
|
+
required: false,
|
|
27
|
+
hidden: true,
|
|
28
|
+
}),
|
|
29
|
+
rainbowAuthService: Flags.string({
|
|
30
|
+
default: 'https://liquidmetal.run/api/connect',
|
|
31
|
+
hidden: true,
|
|
32
|
+
env: 'LIQUIDMETAL_RAINBOW_AUTH_SERVICE',
|
|
33
|
+
}),
|
|
34
|
+
config: Flags.string({ default: '.raindrop/config.json', hidden: true }),
|
|
35
|
+
};
|
|
36
|
+
async run() {
|
|
37
|
+
const { client: catalogService, userId, organizationId } = await this.catalogService();
|
|
38
|
+
if (!this.flags.version) {
|
|
39
|
+
const config = await this.loadConfig();
|
|
40
|
+
this.flags.version = config.versionId;
|
|
41
|
+
}
|
|
42
|
+
if (!this.flags.application) {
|
|
43
|
+
const apps = await this.loadManifest();
|
|
44
|
+
const app = apps[0];
|
|
45
|
+
if (app === undefined) {
|
|
46
|
+
this.error('No application found in manifest', { exit: 1 });
|
|
47
|
+
}
|
|
48
|
+
this.flags.application = valueOf(app.name);
|
|
49
|
+
}
|
|
50
|
+
const resp = await catalogService.setApplicationActiveStates({
|
|
51
|
+
states: [
|
|
52
|
+
{
|
|
53
|
+
applicationName: this.flags.application,
|
|
54
|
+
applicationVersionId: this.flags.version,
|
|
55
|
+
isActive: false,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
userId,
|
|
59
|
+
organizationId: this.flags.impersonate ?? organizationId,
|
|
60
|
+
});
|
|
61
|
+
if (resp.failure.length) {
|
|
62
|
+
this.error(`Failed to stop applications: ${resp.failure.map((f) => `${f.name}@${f.versionId}`).join(', ')}`, {
|
|
63
|
+
exit: 1,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Token extends BaseCommand<typeof Token> {
|
|
3
|
+
static args: {};
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: never[];
|
|
6
|
+
static flags: {};
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../src/commands/build/token.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,WAAW,CAAC,OAAO,KAAK,CAAC;IAC1D,MAAM,CAAC,IAAI,KAAM;IAEjB,MAAM,CAAC,WAAW,SAAsD;IAExE,MAAM,CAAC,QAAQ,UAAM;IAErB,MAAM,CAAC,KAAK,KAAM;IAEZ,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAqC3B"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import open from 'open';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
3
|
+
export default class Token extends BaseCommand {
|
|
4
|
+
static args = {};
|
|
5
|
+
static description = 'generate a link to create a Cloudflare API token';
|
|
6
|
+
static examples = [];
|
|
7
|
+
static flags = {};
|
|
8
|
+
async run() {
|
|
9
|
+
const raindropPermissions = [
|
|
10
|
+
{ key: 'account_settings', type: 'read' },
|
|
11
|
+
{ key: 'd1', type: 'edit' },
|
|
12
|
+
{ key: 'memberships', type: 'read' },
|
|
13
|
+
{ key: 'page', type: 'edit' },
|
|
14
|
+
{ key: 'queues', type: 'edit' },
|
|
15
|
+
{ key: 'user_details', type: 'read' },
|
|
16
|
+
{ key: 'vectorize', type: 'edit' },
|
|
17
|
+
{ key: 'workers_kv_storage', type: 'edit' },
|
|
18
|
+
{ key: 'workers_r2', type: 'edit' },
|
|
19
|
+
{ key: 'workers_routes', type: 'edit' },
|
|
20
|
+
{ key: 'workers_scripts', type: 'edit' },
|
|
21
|
+
{ key: 'workers_tail', type: 'read' },
|
|
22
|
+
{ key: 'zone', type: 'read' },
|
|
23
|
+
];
|
|
24
|
+
const tokenUrl = `https://dash.cloudflare.com/profile/api-tokens?permissionGroupKeys=${encodeURIComponent(JSON.stringify(raindropPermissions))}&name=Raindrop%20CLI%20Token`;
|
|
25
|
+
this.log(`You need to generate a token to use this tool.`);
|
|
26
|
+
this.log(`The token should have the following permissions:`);
|
|
27
|
+
for (const claim of raindropPermissions) {
|
|
28
|
+
this.log(`- ${claim.type} ${claim.key}`);
|
|
29
|
+
}
|
|
30
|
+
this.log(``);
|
|
31
|
+
this.log(`After generating the token, you must add it to your environment along
|
|
32
|
+
with the account ID. The Account ID can be found in the Cloudflare
|
|
33
|
+
dashboard by navigating to a domain under your account and looking on
|
|
34
|
+
the lower right of the page.`);
|
|
35
|
+
this.log(``);
|
|
36
|
+
this.log(`export CLOUDFLARE_API_TOKEN=your_token`);
|
|
37
|
+
this.log(`export CLOUDFLARE_ACCOUNT_ID=your_account_id`);
|
|
38
|
+
this.log(``);
|
|
39
|
+
this.log(`Opening... ${tokenUrl}`);
|
|
40
|
+
await open(tokenUrl);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Upload extends BaseCommand<typeof Upload> {
|
|
3
|
+
static args: {};
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
root: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
manifest: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
config: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
versionId: 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
|
+
rainbowAuthService: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=upload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../src/commands/build/upload.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,WAAW,CAAC,OAAO,MAAM,CAAC;IAC5D,OAAgB,IAAI,KAAM;IAE1B,OAAgB,WAAW,SAAiD;IAE5E,OAAgB,QAAQ,WAA2C;IAEnE,OAAgB,KAAK;;;;;;;;MAsBnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAyClC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { valueOf } from '@liquidmetal-ai/drizzle/appify/build';
|
|
2
|
+
import { archive } from '@liquidmetal-ai/drizzle/codestore';
|
|
3
|
+
import { BundleArchiveType } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/catalog_pb';
|
|
4
|
+
import { FileSystemBundle } from '@liquidmetal-ai/drizzle/unsafe/codestore';
|
|
5
|
+
import { Flags } from '@oclif/core';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { BaseCommand } from '../../base-command.js';
|
|
8
|
+
import { buildHandlers } from '../../build.js';
|
|
9
|
+
export default class Upload extends BaseCommand {
|
|
10
|
+
static args = {};
|
|
11
|
+
static description = 'build and validate a LiquidMetal.AI project';
|
|
12
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
13
|
+
static flags = {
|
|
14
|
+
root: Flags.string({ char: 'r', description: 'root directory', required: false, default: process.cwd() }),
|
|
15
|
+
manifest: Flags.string({
|
|
16
|
+
char: 'm',
|
|
17
|
+
description: 'project manifest',
|
|
18
|
+
required: false,
|
|
19
|
+
default: 'raindrop.manifest',
|
|
20
|
+
}),
|
|
21
|
+
config: Flags.string({ char: 'c', description: 'config file', required: false, default: '.raindrop/config.json' }),
|
|
22
|
+
output: Flags.string({ char: 'o', description: 'output directory', required: false, default: 'dist' }),
|
|
23
|
+
versionId: Flags.string({ char: 'v', description: 'version ID', required: true }),
|
|
24
|
+
impersonate: Flags.string({
|
|
25
|
+
char: 'i',
|
|
26
|
+
description: 'impersonate organization',
|
|
27
|
+
required: false,
|
|
28
|
+
hidden: true,
|
|
29
|
+
}),
|
|
30
|
+
rainbowAuthService: Flags.string({
|
|
31
|
+
default: 'https://liquidmetal.run/api/connect',
|
|
32
|
+
hidden: true,
|
|
33
|
+
env: 'LIQUIDMETAL_RAINBOW_AUTH_SERVICE',
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
async run() {
|
|
37
|
+
const apps = await this.loadManifest();
|
|
38
|
+
const srcDir = path.join(this.flags.root, 'src');
|
|
39
|
+
const buildDir = path.isAbsolute(this.flags.output)
|
|
40
|
+
? this.flags.output
|
|
41
|
+
: path.join(this.flags.root, this.flags.output);
|
|
42
|
+
await buildHandlers(this, apps, buildDir, this.flags.root);
|
|
43
|
+
const { client: catalogService, organizationId: defaultOrganizationId, userId } = await this.catalogService();
|
|
44
|
+
const organizationId = this.flags.impersonate ?? defaultOrganizationId;
|
|
45
|
+
const config = await this.loadConfig();
|
|
46
|
+
const app = apps[0];
|
|
47
|
+
if (!app) {
|
|
48
|
+
this.error('No application found in manifest', { exit: 1 });
|
|
49
|
+
}
|
|
50
|
+
for (const handler of app.handlers()) {
|
|
51
|
+
const bundle = new FileSystemBundle(path.join(buildDir, valueOf(handler.name)));
|
|
52
|
+
await catalogService.uploadBundle({
|
|
53
|
+
userId,
|
|
54
|
+
organizationId,
|
|
55
|
+
applicationName: valueOf(app.name),
|
|
56
|
+
applicationVersionId: this.flags.versionId || config.versionId,
|
|
57
|
+
archiveType: BundleArchiveType.ZIP,
|
|
58
|
+
bundleName: valueOf(handler.name),
|
|
59
|
+
archive: Buffer.from(await archive(bundle)),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// Per above, each application gets the same db bundle, which is
|
|
63
|
+
// boneheaded. src/db is also pretty arbitrary.
|
|
64
|
+
const dbBundle = new FileSystemBundle(path.join(srcDir, 'db'));
|
|
65
|
+
await catalogService.uploadBundle({
|
|
66
|
+
userId,
|
|
67
|
+
organizationId,
|
|
68
|
+
applicationName: valueOf(app.name),
|
|
69
|
+
applicationVersionId: this.flags.versionId || config.versionId,
|
|
70
|
+
archiveType: BundleArchiveType.ZIP,
|
|
71
|
+
bundleName: 'db',
|
|
72
|
+
archive: Buffer.from(await archive(dbBundle)),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Build extends BaseCommand<typeof Build> {
|
|
3
|
+
static args: {};
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
root: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
manifest: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/commands/build/validate.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,WAAW,CAAC,OAAO,KAAK,CAAC;IAC1D,OAAgB,IAAI,KAAM;IAE1B,OAAgB,WAAW,SAAiD;IAE5E,OAAgB,QAAQ,WAA2C;IAEnE,OAAgB,KAAK;;;;MASnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAQlC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { BaseCommand } from '../../base-command.js';
|
|
4
|
+
import { buildHandlers } from '../../build.js';
|
|
5
|
+
export default class Build extends BaseCommand {
|
|
6
|
+
static args = {};
|
|
7
|
+
static description = 'build and validate a LiquidMetal.AI project';
|
|
8
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
9
|
+
static flags = {
|
|
10
|
+
root: Flags.string({ char: 'r', description: 'root directory', required: false, default: process.cwd() }),
|
|
11
|
+
manifest: Flags.string({
|
|
12
|
+
char: 'm',
|
|
13
|
+
description: 'project manifest',
|
|
14
|
+
required: false,
|
|
15
|
+
default: 'raindrop.manifest',
|
|
16
|
+
}),
|
|
17
|
+
output: Flags.string({ char: 'o', description: 'output directory', required: false, default: 'dist' }),
|
|
18
|
+
};
|
|
19
|
+
async run() {
|
|
20
|
+
const apps = await this.loadManifest();
|
|
21
|
+
const buildDir = path.isAbsolute(this.flags.output)
|
|
22
|
+
? this.flags.output
|
|
23
|
+
: path.join(this.flags.root, this.flags.output);
|
|
24
|
+
await buildHandlers(this, apps, buildDir, this.flags.root);
|
|
25
|
+
}
|
|
26
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const ConfigSchema: z.ZodObject<{
|
|
3
|
+
versionId: z.ZodString;
|
|
4
|
+
}, "strip", z.ZodTypeAny, {
|
|
5
|
+
versionId: string;
|
|
6
|
+
}, {
|
|
7
|
+
versionId: string;
|
|
8
|
+
}>;
|
|
9
|
+
export type Config = z.infer<typeof ConfigSchema>;
|
|
10
|
+
export declare const defaultConfig: Config;
|
|
11
|
+
export declare function loadConfig(configPath: string): Promise<Config>;
|
|
12
|
+
export declare function saveConfig(configPath: string, config: Config): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,YAAY;;;;;;EAEvB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,eAAO,MAAM,aAAa,EAAE,MAE3B,CAAC;AAKF,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUpE;AAGD,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlF"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { ensureDirectory } from './index.js';
|
|
5
|
+
export const ConfigSchema = z.object({
|
|
6
|
+
versionId: z.string(),
|
|
7
|
+
});
|
|
8
|
+
export const defaultConfig = {
|
|
9
|
+
versionId: '01j6jj6hs588hee9rzw9pqe9d4',
|
|
10
|
+
};
|
|
11
|
+
// loadConfig reads the configuration file at path and always returns
|
|
12
|
+
// an object that conforms to the ConfigSchema, even if it's empty. If
|
|
13
|
+
// the file exists, that just implies an empty config.
|
|
14
|
+
export async function loadConfig(configPath) {
|
|
15
|
+
let configFileContents;
|
|
16
|
+
try {
|
|
17
|
+
configFileContents = await readFile(configPath, {
|
|
18
|
+
encoding: 'utf-8',
|
|
19
|
+
});
|
|
20
|
+
return ConfigSchema.parse(JSON.parse(configFileContents));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return defaultConfig;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// saveConfig writes the given config object to the file at path.
|
|
27
|
+
export async function saveConfig(configPath, config) {
|
|
28
|
+
// Create the path to the file if it doesn't exist; make directories as needed.
|
|
29
|
+
await ensureDirectory(path.dirname(configPath));
|
|
30
|
+
const configJson = JSON.stringify(config, null, 2);
|
|
31
|
+
await writeFile(configPath, configJson, {
|
|
32
|
+
encoding: 'utf-8',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { expect, test } from 'vitest';
|
|
5
|
+
import { loadConfig, saveConfig } from './config.js';
|
|
6
|
+
test('loading missing config returns default/base config', async () => {
|
|
7
|
+
const configPath = '/tmp/this-never-exists-config.json';
|
|
8
|
+
const config = await loadConfig(configPath);
|
|
9
|
+
expect(config).toEqual({
|
|
10
|
+
versionId: '01j6jj6hs588hee9rzw9pqe9d4',
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
test('save/load config', async () => {
|
|
14
|
+
// Make a temp directory and write a config file to it.
|
|
15
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'config-test'));
|
|
16
|
+
const configPath = path.join(tempDir, 'config.json');
|
|
17
|
+
await saveConfig(configPath, {
|
|
18
|
+
versionId: 'test-version-id',
|
|
19
|
+
});
|
|
20
|
+
const config = await loadConfig(configPath);
|
|
21
|
+
expect(config).toEqual({
|
|
22
|
+
versionId: 'test-version-id',
|
|
23
|
+
});
|
|
24
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ServiceType } from '@bufbuild/protobuf';
|
|
2
|
+
import { PromiseClient } from '@connectrpc/connect';
|
|
3
|
+
import { Application } from '@liquidmetal-ai/drizzle/appify/build';
|
|
4
|
+
import { RainbowAuthService } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/rainbow_auth_connect';
|
|
5
|
+
import { RaindropState } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/raindrop_pb';
|
|
6
|
+
export { run } from '@oclif/core';
|
|
7
|
+
export declare function configFromAppFile(appFile: string): Promise<Application[]>;
|
|
8
|
+
export declare function joinPath(...parts: string[]): string;
|
|
9
|
+
export declare function useClient<T extends ServiceType>(service: T, baseUrl: string): PromiseClient<T>;
|
|
10
|
+
export declare function createAuthenticatingClient<T extends ServiceType>(service: T, configDir: string, rainbowAuth: PromiseClient<typeof RainbowAuthService>): Promise<{
|
|
11
|
+
client: PromiseClient<T>;
|
|
12
|
+
userId: string;
|
|
13
|
+
organizationId: string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function readState(configDir: string): Promise<RaindropState>;
|
|
16
|
+
export declare function replaceState(configDir: string, state: RaindropState): Promise<void>;
|
|
17
|
+
export declare function ensureDirectory(dir: string): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAoC,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEtF,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAEnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mEAAmE,CAAC;AAEvG,OAAO,EAAE,aAAa,EAAE,MAAM,0DAA0D,CAAC;AAKzF,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAG/E;AAGD,wBAAgB,QAAQ,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAEnD;AAGD,wBAAgB,SAAS,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,CAM9F;AA8FD,wBAAsB,0BAA0B,CAAC,CAAC,SAAS,WAAW,EACpE,OAAO,EAAE,CAAC,EACV,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,aAAa,CAAC,OAAO,kBAAkB,CAAC,GACpD,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,CAkB/E;AAID,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAUzE;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CASzF;AAGD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { createPromiseClient } from '@connectrpc/connect';
|
|
2
|
+
import { createConnectTransport } from '@connectrpc/connect-web';
|
|
3
|
+
import { mustManifestFromString } from '@liquidmetal-ai/drizzle/appify/index';
|
|
4
|
+
import { RaindropState } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/raindrop_pb';
|
|
5
|
+
import { Mutex } from 'async-mutex';
|
|
6
|
+
import * as fs from 'node:fs/promises';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
export { run } from '@oclif/core';
|
|
9
|
+
export async function configFromAppFile(appFile) {
|
|
10
|
+
const contents = await fs.readFile(appFile, 'utf8');
|
|
11
|
+
return mustManifestFromString(contents);
|
|
12
|
+
}
|
|
13
|
+
// joinPath joins path parts and removes any duplicate slashes.
|
|
14
|
+
export function joinPath(...parts) {
|
|
15
|
+
return parts.join('/').replace(/\/+/g, '/');
|
|
16
|
+
}
|
|
17
|
+
// useClient returns a promise client for the given service at baseUrl.
|
|
18
|
+
export function useClient(service, baseUrl) {
|
|
19
|
+
const transport = createConnectTransport({
|
|
20
|
+
baseUrl,
|
|
21
|
+
});
|
|
22
|
+
return createPromiseClient(service, transport);
|
|
23
|
+
}
|
|
24
|
+
const accessTokenAndRefreshMutex = new Mutex();
|
|
25
|
+
// bearerTokenAndRefresh returns an access token for the currently selected
|
|
26
|
+
// organization based on the raindrop state found in the config directory. If
|
|
27
|
+
// the access token is expired, the refresh token is used to generate a new
|
|
28
|
+
// bearer token.
|
|
29
|
+
async function bearerTokenAndRefresh(configDir, rainbowAuth) {
|
|
30
|
+
// utilize a mutex to probe if the refresh token is expired and to execute
|
|
31
|
+
// refreshing as invoking refresh multiple times with the same refresh token
|
|
32
|
+
// will invalidate the token.
|
|
33
|
+
return await accessTokenAndRefreshMutex.runExclusive(async () => {
|
|
34
|
+
const state = await readState(configDir);
|
|
35
|
+
if (!state.currentOrganizationId) {
|
|
36
|
+
throw new Error('not logged in');
|
|
37
|
+
}
|
|
38
|
+
const token = state.organizationIdToBearerToken[state.currentOrganizationId];
|
|
39
|
+
if (!token) {
|
|
40
|
+
throw new Error('no credentials set for current organization');
|
|
41
|
+
}
|
|
42
|
+
if (!token.accessTokenExpiresAt) {
|
|
43
|
+
throw new Error('accessTokenExpiresAt at not set');
|
|
44
|
+
}
|
|
45
|
+
const expiresAtBuffered = new Date(token.accessTokenExpiresAt.toDate().getTime() - 1000);
|
|
46
|
+
if (expiresAtBuffered.getTime() < Date.now()) {
|
|
47
|
+
const next = await rainbowAuth.refreshAccessToken({
|
|
48
|
+
...token,
|
|
49
|
+
});
|
|
50
|
+
if (!next.bearerToken) {
|
|
51
|
+
throw new Error('unable to refresh login');
|
|
52
|
+
}
|
|
53
|
+
state.organizationIdToBearerToken[state.currentOrganizationId] = next.bearerToken;
|
|
54
|
+
await replaceState(configDir, state);
|
|
55
|
+
return next.bearerToken;
|
|
56
|
+
}
|
|
57
|
+
return token;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// createAuthenticateInterceptor returns a connect rpc interceptor which ensures
|
|
61
|
+
// that the user is logged in with an active access token and automatically
|
|
62
|
+
// refreshes the access tokens when making requests.
|
|
63
|
+
async function createAuthenticateInterceptor(service, configDir, rainbowAuth) {
|
|
64
|
+
const { userId, organizationId, catalogServiceBaseUrl } = await bearerTokenAndRefresh(configDir, rainbowAuth);
|
|
65
|
+
const interceptor = (next) => async (req) => {
|
|
66
|
+
const { accessToken } = await bearerTokenAndRefresh(configDir, rainbowAuth);
|
|
67
|
+
req.header.set('Authorization', `Bearer ${accessToken}`);
|
|
68
|
+
return await next(req);
|
|
69
|
+
};
|
|
70
|
+
let baseUrl = '';
|
|
71
|
+
switch (service.typeName) {
|
|
72
|
+
case 'liquidmetal.v1alpha1.CatalogService':
|
|
73
|
+
baseUrl = catalogServiceBaseUrl;
|
|
74
|
+
if (process.env.RAINDROP_CATALOG_API_BASE_URL) {
|
|
75
|
+
baseUrl = process.env.RAINDROP_CATALOG_API_BASE_URL;
|
|
76
|
+
// Prepend missing protocol if missing
|
|
77
|
+
if (!baseUrl.match(/^http(s):\/\//)) {
|
|
78
|
+
baseUrl = `https://${baseUrl}`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
default:
|
|
83
|
+
throw new Error(`unable to determine baseUrl for service=${service.typeName}`);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
interceptor,
|
|
87
|
+
userId,
|
|
88
|
+
organizationId,
|
|
89
|
+
baseUrl,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
// createAuthenticatingClient should be used for instantiating any connect rpc
|
|
93
|
+
// client that needs to authenticate the requests.
|
|
94
|
+
export async function createAuthenticatingClient(service, configDir, rainbowAuth) {
|
|
95
|
+
const { interceptor: authenticate, baseUrl, userId, organizationId, } = await createAuthenticateInterceptor(service, configDir, rainbowAuth);
|
|
96
|
+
const transport = createConnectTransport({
|
|
97
|
+
baseUrl,
|
|
98
|
+
interceptors: [authenticate],
|
|
99
|
+
});
|
|
100
|
+
return {
|
|
101
|
+
client: createPromiseClient(service, transport),
|
|
102
|
+
userId,
|
|
103
|
+
organizationId,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const configBasename = 'raindrop.json';
|
|
107
|
+
export async function readState(configDir) {
|
|
108
|
+
const filename = path.join(configDir, configBasename);
|
|
109
|
+
try {
|
|
110
|
+
await fs.access(filename, fs.constants.F_OK);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
await replaceState(configDir, new RaindropState({}));
|
|
114
|
+
}
|
|
115
|
+
const data = await fs.readFile(filename, { encoding: 'utf8' });
|
|
116
|
+
return RaindropState.fromJsonString(data);
|
|
117
|
+
}
|
|
118
|
+
export async function replaceState(configDir, state) {
|
|
119
|
+
const filename = path.join(configDir, configBasename);
|
|
120
|
+
const data = state.toJsonString({
|
|
121
|
+
prettySpaces: 2,
|
|
122
|
+
});
|
|
123
|
+
// Ensure config directory exists as well
|
|
124
|
+
await ensureDirectory(configDir);
|
|
125
|
+
await fs.writeFile(filename, data, 'utf8');
|
|
126
|
+
}
|
|
127
|
+
// ensureDirectory ensures that the directory exists at the given path
|
|
128
|
+
export async function ensureDirectory(dir) {
|
|
129
|
+
try {
|
|
130
|
+
await fs.stat(dir);
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
if (e instanceof Error && e.message.indexOf('ENOENT') > -1) {
|
|
134
|
+
await fs.mkdir(dir, { recursive: true });
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
throw e;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["../src/base-command.ts","../src/build.test.ts","../src/build.ts","../src/codegen.test.ts","../src/codegen.ts","../src/config.test.ts","../src/config.ts","../src/index.test.ts","../src/index.ts","../src/commands/auth/list.ts","../src/commands/auth/login.ts","../src/commands/auth/logout.ts","../src/commands/auth/select.ts","../src/commands/build/branch.ts","../src/commands/build/delete.ts","../src/commands/build/deploy.ts","../src/commands/build/find.ts","../src/commands/build/generate.ts","../src/commands/build/init.ts","../src/commands/build/list.ts","../src/commands/build/start.ts","../src/commands/build/stop.ts","../src/commands/build/token.ts","../src/commands/build/upload.ts","../src/commands/build/validate.ts","../src/commands/build/env/get.ts","../src/commands/build/env/set.ts"],"version":"5.6.2"}
|