@liquidmetal-ai/raindrop 0.1.5 → 0.2.2

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 (79) hide show
  1. package/README.md +261 -53
  2. package/dist/base-command.d.ts +13 -0
  3. package/dist/base-command.d.ts.map +1 -1
  4. package/dist/base-command.js +21 -1
  5. package/dist/build.d.ts +2 -3
  6. package/dist/build.d.ts.map +1 -1
  7. package/dist/build.js +1 -1
  8. package/dist/codegen.d.ts.map +1 -1
  9. package/dist/codegen.js +12 -0
  10. package/dist/commands/build/branch.d.ts +6 -3
  11. package/dist/commands/build/branch.d.ts.map +1 -1
  12. package/dist/commands/build/branch.js +107 -44
  13. package/dist/commands/build/checkout.d.ts +16 -0
  14. package/dist/commands/build/checkout.d.ts.map +1 -0
  15. package/dist/commands/build/checkout.js +66 -0
  16. package/dist/commands/build/delete.d.ts.map +1 -1
  17. package/dist/commands/build/delete.js +8 -7
  18. package/dist/commands/build/deploy.d.ts.map +1 -1
  19. package/dist/commands/build/deploy.js +84 -92
  20. package/dist/commands/build/env/get.d.ts.map +1 -1
  21. package/dist/commands/build/env/get.js +10 -9
  22. package/dist/commands/build/env/set.d.ts.map +1 -1
  23. package/dist/commands/build/env/set.js +10 -9
  24. package/dist/commands/build/find.d.ts.map +1 -1
  25. package/dist/commands/build/find.js +2 -7
  26. package/dist/commands/build/list.d.ts +15 -2
  27. package/dist/commands/build/list.d.ts.map +1 -1
  28. package/dist/commands/build/list.js +147 -35
  29. package/dist/commands/build/sandbox.d.ts.map +1 -1
  30. package/dist/commands/build/sandbox.js +12 -12
  31. package/dist/commands/build/start.d.ts.map +1 -1
  32. package/dist/commands/build/start.js +15 -17
  33. package/dist/commands/build/status.d.ts +2 -16
  34. package/dist/commands/build/status.d.ts.map +1 -1
  35. package/dist/commands/build/status.js +30 -64
  36. package/dist/commands/build/stop.d.ts.map +1 -1
  37. package/dist/commands/build/stop.js +17 -21
  38. package/dist/commands/build/unsandbox.d.ts.map +1 -1
  39. package/dist/commands/build/unsandbox.js +13 -13
  40. package/dist/commands/object/delete.d.ts +18 -0
  41. package/dist/commands/object/delete.d.ts.map +1 -0
  42. package/dist/commands/object/delete.js +66 -0
  43. package/dist/commands/object/get.d.ts +21 -0
  44. package/dist/commands/object/get.d.ts.map +1 -0
  45. package/dist/commands/object/get.js +95 -0
  46. package/dist/commands/object/list.d.ts +15 -0
  47. package/dist/commands/object/list.d.ts.map +1 -0
  48. package/dist/commands/object/list.js +79 -0
  49. package/dist/commands/object/put.d.ts +23 -0
  50. package/dist/commands/object/put.d.ts.map +1 -0
  51. package/dist/commands/object/put.js +99 -0
  52. package/dist/commands/query/chunk-search.d.ts +18 -0
  53. package/dist/commands/query/chunk-search.d.ts.map +1 -0
  54. package/dist/commands/query/chunk-search.js +79 -0
  55. package/dist/commands/query/register-retriever.d.ts +16 -0
  56. package/dist/commands/query/register-retriever.d.ts.map +1 -0
  57. package/dist/commands/query/register-retriever.js +56 -0
  58. package/dist/commands/query/search.d.ts +19 -0
  59. package/dist/commands/query/search.d.ts.map +1 -0
  60. package/dist/commands/query/search.js +124 -0
  61. package/dist/commands/tail.d.ts +1 -5
  62. package/dist/commands/tail.d.ts.map +1 -1
  63. package/dist/commands/tail.js +2 -50
  64. package/dist/config.d.ts +3 -3
  65. package/dist/config.js +2 -2
  66. package/dist/config.test.js +1 -1
  67. package/dist/index.d.ts +27 -5
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +36 -6
  70. package/dist/tsconfig.tsbuildinfo +1 -1
  71. package/oclif.manifest.json +755 -82
  72. package/package.json +2 -1
  73. package/templates/handlers/queue-consumer/index.ts.hbs +1 -1
  74. package/templates/handlers/r2-event-notification/index.ts.hbs +1 -1
  75. package/templates/handlers/task/index.test.ts +5 -0
  76. package/templates/handlers/task/index.ts.hbs +8 -0
  77. package/dist/commands/build/token.d.ts +0 -9
  78. package/dist/commands/build/token.d.ts.map +0 -1
  79. package/dist/commands/build/token.js +0 -42
package/dist/codegen.js CHANGED
@@ -13,6 +13,7 @@ const TEMPLATE_R2_EVENT_NOTIFICATION = path.join('handlers', 'r2-event-notificat
13
13
  const TEMPLATE_QUEUE_CONSUMER = path.join('handlers', 'queue-consumer');
14
14
  const TEMPLATE_HTTP_SERVICE = path.join('handlers', 'http-service');
15
15
  const TEMPLATE_ACTOR = path.join('handlers', 'actor');
16
+ const TEMPLATE_TASK = path.join('handlers', 'task');
16
17
  const TEMPLATE_EXTENSION = '.hbs';
17
18
  const SCAFFOLDING_PREFIX = '__';
18
19
  const HANDLEBARS_RENDER_OPTS = {
@@ -116,6 +117,13 @@ export function codegenPlan(apps) {
116
117
  context: { actorClassName: kebabCaseToUpperCamelCase(valueOf(actor.name)) },
117
118
  });
118
119
  }
120
+ for (const task of app.task) {
121
+ plan.push({
122
+ templateName: path.join(TEMPLATES_DIR, TEMPLATE_TASK),
123
+ outPath: path.join(HANDLERS_DIR, valueOf(task.name)),
124
+ context: { taskClassName: kebabCaseToUpperCamelCase(valueOf(task.name)) },
125
+ });
126
+ }
119
127
  }
120
128
  return plan;
121
129
  }
@@ -179,6 +187,10 @@ export function gatherEnvForHandler(handler, app) {
179
187
  bindings[kebabCaseToConstantCase(valueOf(appVectorizeIndex.name))] = 'VectorIndex';
180
188
  types.add('VectorIndex');
181
189
  }
190
+ for (const appKvStore of app.kvStore) {
191
+ bindings[kebabCaseToConstantCase(valueOf(appKvStore.name))] = 'KvStore';
192
+ types.add('KvStore');
193
+ }
182
194
  for (const env of app.env) {
183
195
  bindings[kebabCaseToConstantCase(valueOf(env.name))] = 'string';
184
196
  }
@@ -1,14 +1,17 @@
1
1
  import { BaseCommand } from '../../base-command.js';
2
2
  export default class Branch extends BaseCommand<typeof Branch> {
3
- static args: {};
3
+ static args: {
4
+ branch: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
4
6
  static description: string;
5
7
  static examples: string[];
6
8
  static flags: {
7
9
  root: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
10
  manifest: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
11
  config: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
- previousVersionId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
- select: 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
+ versionId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ start: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
15
  impersonate: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
16
  rainbowAuthService: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
17
  raindropCatalogService: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -1 +1 @@
1
- {"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../../src/commands/build/branch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,WAAW,CAAC,OAAO,MAAM,CAAC;IAC5D,MAAM,CAAC,IAAI,KAAM;IAEjB,MAAM,CAAC,WAAW,SAAiD;IAEnE,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;MA6CV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAmD3B"}
1
+ {"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../../src/commands/build/branch.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,WAAW,CAAC,OAAO,MAAM,CAAC;IAC5D,MAAM,CAAC,IAAI;;MAET;IAEF,MAAM,CAAC,WAAW,SAAiD;IAEnE,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;;MA4CV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAqH3B"}
@@ -1,8 +1,16 @@
1
1
  import { valueOf } from '@liquidmetal-ai/drizzle/appify/build';
2
- import { Flags } from '@oclif/core';
2
+ import { archive } from '@liquidmetal-ai/drizzle/codestore';
3
+ import { BundleArchiveType, ReleaseRequest_Lock } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/catalog_pb';
4
+ import { FileSystemBundle } from '@liquidmetal-ai/drizzle/unsafe/codestore';
5
+ import { Args, Flags } from '@oclif/core';
6
+ import fs from 'node:fs/promises';
7
+ import * as path from 'node:path';
3
8
  import { BaseCommand } from '../../base-command.js';
9
+ import { buildHandlers } from '../../build.js';
4
10
  export default class Branch extends BaseCommand {
5
- static args = {};
11
+ static args = {
12
+ branch: Args.string({ description: 'branch name', required: true }),
13
+ };
6
14
  static description = 'create a new branch in the Raindrop catalog';
7
15
  static examples = [
8
16
  `<%= config.bin %> <%= command.id %> .
@@ -24,18 +32,17 @@ Created new branch 1234
24
32
  hidden: true,
25
33
  default: '.raindrop/config.json',
26
34
  }),
27
- previousVersionId: Flags.string({
35
+ output: Flags.string({ char: 'o', description: 'output directory', required: false, default: 'dist' }),
36
+ versionId: Flags.string({
28
37
  char: 'p',
29
- aliases: ['prev'],
30
- description: 'previous version ID',
38
+ aliases: ['version'],
39
+ description: 'Branch from this version',
31
40
  required: false,
32
- exclusive: ['select'],
33
41
  }),
34
- select: Flags.string({
35
- char: 's',
36
- description: 'select a specific version ID',
42
+ start: Flags.boolean({
43
+ description: 'Start the application',
44
+ default: false,
37
45
  required: false,
38
- exclusive: ['previousVersionId'],
39
46
  }),
40
47
  impersonate: Flags.string({
41
48
  char: 'i',
@@ -56,49 +63,105 @@ Created new branch 1234
56
63
  show: Flags.boolean({ description: 'show the current branch', required: false }),
57
64
  };
58
65
  async run() {
59
- const { client: catalogService, userId, organizationId: defaultOrganizationId } = await this.catalogService();
60
- const organizationId = this.flags.impersonate ?? defaultOrganizationId;
61
66
  const config = await this.loadConfig();
62
67
  // Allow the user to see the currently selected version
63
68
  if (this.flags.show) {
64
- this.log(`Current branch: ${config.versionId}`);
69
+ this.log(`Current versionId: ${config.versionId}`);
65
70
  return;
66
71
  }
67
- // If we're selecting a version, just update config.
68
- if (this.flags.select) {
69
- // Check if this is a valid version.
70
- const resp = await catalogService.versions({ userId, organizationId });
71
- const validVersion = resp.versions.some((app) => {
72
- if (app.versionId === this.flags.select) {
73
- return true;
74
- }
72
+ // Build then deploy
73
+ const manifestPath = path.isAbsolute(this.flags.manifest)
74
+ ? this.flags.manifest
75
+ : path.join(this.flags.root, this.flags.manifest);
76
+ // Do this first to check for errors.
77
+ const apps = await this.loadManifest();
78
+ // We should really just work with a single app at the moment.
79
+ if (apps[0] === undefined) {
80
+ this.error('There are no applications in the manifest');
81
+ }
82
+ const app = apps[0];
83
+ const manifestContents = await fs.readFile(manifestPath, 'utf8');
84
+ const buildDir = path.isAbsolute(this.flags.output)
85
+ ? this.flags.output
86
+ : path.join(this.flags.root, this.flags.output);
87
+ // It's weird that it takes an array of apps.
88
+ await buildHandlers(this, apps, buildDir, this.flags.root);
89
+ const versionId = this.flags.versionId || config.versionId;
90
+ const runtimeVersion = await this.raindropFrameworkVersion();
91
+ const { client: catalogService, userId, organizationId: defaultOrganizationId } = await this.catalogService();
92
+ const organizationId = this.flags.impersonate ?? defaultOrganizationId;
93
+ const deployResp = await catalogService.deploy({
94
+ userId: userId,
95
+ organizationId: organizationId,
96
+ applications: [
97
+ {
98
+ application: valueOf(app.name),
99
+ previousVersionId: versionId,
100
+ branch: this.args.branch,
101
+ amend: false,
102
+ metadata: {
103
+ runtimeVersion,
104
+ },
105
+ manifest: manifestContents,
106
+ },
107
+ ],
108
+ });
109
+ if (deployResp.applications[0] === undefined) {
110
+ this.error('Failed to deploy application');
111
+ }
112
+ // If we deployed, we have to actually retrieve the
113
+ // currentVersionId from the response.
114
+ const currentVersionId = deployResp.applications[0].currentVersionId;
115
+ // And save it asap.
116
+ config.versionId = currentVersionId;
117
+ await this.saveConfig(config);
118
+ // Upload bundle to this version's store.
119
+ for (const handler of app.handlers()) {
120
+ const bundle = new FileSystemBundle(path.join(buildDir, valueOf(handler.name)));
121
+ await catalogService.uploadBundle({
122
+ userId,
123
+ organizationId,
124
+ applicationName: valueOf(app.name),
125
+ applicationVersionId: currentVersionId,
126
+ archiveType: BundleArchiveType.ZIP,
127
+ bundleName: valueOf(handler.name),
128
+ archive: Buffer.from(await archive(bundle)),
75
129
  });
76
- if (!validVersion) {
77
- this.error(`Version ${this.flags.select} does not exist`, { exit: 1 });
78
- }
79
- // We have a valid version, check to see if it exists against
80
- // this application or none.
81
- const apps = await this.loadManifest();
82
- const app = apps[0];
83
- if (app === undefined) {
84
- this.error('No application found in manifest', { exit: 1 });
85
- }
86
- const applicationResp = await catalogService.applications({ userId, organizationId });
87
- if (applicationResp.applications.some((a) => a.name !== valueOf(app.name) && a.versionId === this.flags.select)) {
88
- this.error(`Cannot select version ${this.flags.select} belonging to another application`, { exit: 1 });
89
- }
90
- config.versionId = this.flags.select;
91
- await this.saveConfig(config);
92
- return;
130
+ this.log(`Uploaded bundle "${valueOf(handler.name)}"`);
131
+ }
132
+ // Upload DB bundle if it exists.
133
+ const dbDir = path.join(this.flags.root, 'db');
134
+ let dbExists = false;
135
+ try {
136
+ const stat = await fs.lstat(dbDir);
137
+ dbExists = stat.isDirectory();
138
+ }
139
+ catch (_e) {
140
+ // Nothing to do
93
141
  }
94
- const previousVersionId = this.flags.previousVersionId || config.versionId;
95
- const resp = await catalogService.createVersion({
142
+ if (dbExists) {
143
+ const dbBundle = new FileSystemBundle(path.join(this.flags.root, 'db'));
144
+ await catalogService.uploadBundle({
145
+ userId,
146
+ organizationId,
147
+ applicationName: valueOf(app.name),
148
+ applicationVersionId: currentVersionId,
149
+ archiveType: BundleArchiveType.ZIP,
150
+ bundleName: 'db',
151
+ archive: Buffer.from(await archive(dbBundle)),
152
+ });
153
+ this.log(`Uploaded bundle "db"`);
154
+ }
155
+ // Release locks.
156
+ await catalogService.release({
96
157
  userId,
97
158
  organizationId,
98
- previousVersionId,
159
+ locks: deployResp.applications.map((a) => new ReleaseRequest_Lock({
160
+ applicationName: a.applicationName,
161
+ currentVersionId: a.currentVersionId,
162
+ lock: a.lock,
163
+ })),
99
164
  });
100
- config.versionId = resp.versionId;
101
- await this.saveConfig(config);
102
- console.log(`Created new branch ${config.versionId}`);
165
+ // TODO [ian] Call watch and subscribe to events.
103
166
  }
104
167
  }
@@ -0,0 +1,16 @@
1
+ import { BaseCommand } from '../../base-command.js';
2
+ export default class Branch extends BaseCommand<typeof Branch> {
3
+ static args: {
4
+ version: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
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
+ rainbowAuthService: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
12
+ raindropCatalogService: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ };
14
+ run(): Promise<void>;
15
+ }
16
+ //# sourceMappingURL=checkout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../../src/commands/build/checkout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,WAAW,CAAC,OAAO,MAAM,CAAC;IAC5D,MAAM,CAAC,IAAI;;MAET;IAEF,MAAM,CAAC,WAAW,SAAsD;IAExE,MAAM,CAAC,QAAQ,WAOb;IAEF,MAAM,CAAC,KAAK;;;;;MAmBV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA+B3B"}
@@ -0,0 +1,66 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { BaseCommand } from '../../base-command.js';
3
+ export default class Branch extends BaseCommand {
4
+ static args = {
5
+ version: Args.string({ description: 'version id', required: false }),
6
+ };
7
+ static description = 'switch the current context to a specific version';
8
+ static examples = [
9
+ `<%= config.bin %> <%= command.id %>
10
+ Currently on version: 01jac6p20m4gahn1kaa2mhm2js
11
+
12
+ <%= config.bin %> <%= command.id %> 01jux6z20m4gbhn5kaa4mcm2jr
13
+ Switched to version: 01jux6z20m4gbhn5kaa4mcm2jr
14
+ `,
15
+ ];
16
+ static flags = {
17
+ config: Flags.string({
18
+ char: 'c',
19
+ description: 'config file',
20
+ required: false,
21
+ hidden: true,
22
+ default: '.raindrop/config.json',
23
+ }),
24
+ output: Flags.string({ char: 'o', description: 'output format', required: false, default: 'text' }),
25
+ rainbowAuthService: Flags.string({
26
+ default: 'https://liquidmetal.run/api/connect',
27
+ hidden: true,
28
+ env: 'LIQUIDMETAL_RAINBOW_AUTH_SERVICE',
29
+ }),
30
+ raindropCatalogService: Flags.string({
31
+ env: 'RAINDROP_CATALOG_SERVICE',
32
+ description: 'URL of the catalog service',
33
+ hidden: true,
34
+ }),
35
+ };
36
+ async run() {
37
+ if (['text', 'json'].indexOf(this.flags.output) === -1) {
38
+ this.error(`unsupported output format: ${this.flags.output}`, { exit: 1 });
39
+ }
40
+ const config = await this.loadConfig();
41
+ // No args: just show the current version
42
+ if (!this.args.version) {
43
+ if (this.flags.output === 'json') {
44
+ console.log(JSON.stringify({ versionId: config.versionId }, null, 2));
45
+ }
46
+ else {
47
+ if (!config.versionId) {
48
+ console.log('No version set');
49
+ }
50
+ else {
51
+ console.log(`Currently on version ${config.versionId}`);
52
+ }
53
+ }
54
+ return;
55
+ }
56
+ // Switch to a different version
57
+ config.versionId = this.args.version;
58
+ await this.saveConfig(config);
59
+ if (this.flags.output === 'json') {
60
+ console.log(JSON.stringify({ versionId: config.versionId }, null, 2));
61
+ }
62
+ else {
63
+ console.log(`Switched to version ${config.versionId}`);
64
+ }
65
+ }
66
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/build/delete.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,WAAW,CAAC,OAAO,MAAM,CAAC;IAC5D,MAAM,CAAC,IAAI;;MAET;IAEF,MAAM,CAAC,WAAW,SAAkC;IAEpD,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;MAiDV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAqD3B"}
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/build/delete.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,WAAW,CAAC,OAAO,MAAM,CAAC;IAC5D,MAAM,CAAC,IAAI;;MAET;IAEF,MAAM,CAAC,WAAW,SAAkC;IAEpD,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;MAiDV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAsD3B"}
@@ -88,17 +88,18 @@ Deleted (application) at version (version)
88
88
  this.args.application = valueOf(app.name);
89
89
  }
90
90
  try {
91
- const resp = await catalogService.deleteApplications({
91
+ await catalogService.delete({
92
92
  userId,
93
93
  organizationId: this.flags.impersonate ?? organizationId,
94
94
  // Omitting versionId will delete all versions of the application
95
- applications: [{ name: this.args.application, versionId }],
95
+ applications: [{ applicationName: this.args.application, currentVersionId: versionId }],
96
96
  });
97
- if (resp.failure.length) {
98
- this.error(`Failed to delete applications: ${resp.failure.map((f) => `${f.name}@${f.versionId}`).join(', ')}`, {
99
- exit: 1,
100
- });
101
- }
97
+ // TODO [ian] Failures?
98
+ // if (resp.failure.length) {
99
+ // this.error(`Failed to delete applications: ${resp.failure.map((f) => `${f.name}@${f.versionId}`).join(', ')}`, {
100
+ // exit: 1,
101
+ // });
102
+ // }
102
103
  }
103
104
  catch (e) {
104
105
  if (e instanceof Error) {
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/commands/build/deploy.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,WAAW,CAAC,OAAO,MAAM,CAAC;IAC5D,MAAM,CAAC,IAAI,KAAM;IAEjB,MAAM,CAAC,WAAW,SAAmC;IAErD,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;;MA6CV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAiI3B"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/commands/build/deploy.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,WAAW,CAAC,OAAO,MAAM,CAAC;IAC5D,MAAM,CAAC,IAAI,KAAM;IAEjB,MAAM,CAAC,WAAW,SAAmC;IAErD,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;;MA6CV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA4H3B"}
@@ -1,14 +1,12 @@
1
1
  import { valueOf } from '@liquidmetal-ai/drizzle/appify/build';
2
- import { JSONTranslator, Parser, Tokenizer } from '@liquidmetal-ai/drizzle/appify/parse';
3
2
  import { archive } from '@liquidmetal-ai/drizzle/codestore';
4
- import { BundleArchiveType, } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/catalog_pb';
3
+ import { BundleArchiveType, ReleaseRequest_Lock } from '@liquidmetal-ai/drizzle/liquidmetal/v1alpha1/catalog_pb';
5
4
  import { FileSystemBundle } from '@liquidmetal-ai/drizzle/unsafe/codestore';
6
5
  import { Flags } from '@oclif/core';
7
6
  import fs from 'node:fs/promises';
8
7
  import * as path from 'node:path';
9
8
  import { BaseCommand } from '../../base-command.js';
10
9
  import { buildHandlers } from '../../build.js';
11
- import { defaultConfig } from '../../config.js';
12
10
  export default class Deploy extends BaseCommand {
13
11
  static args = {};
14
12
  static description = 'deploy a Raindrop application';
@@ -70,112 +68,106 @@ Deploy a Raindrop application.
70
68
  : path.join(this.flags.root, this.flags.manifest);
71
69
  // Do this first to check for errors.
72
70
  const apps = await this.loadManifest();
71
+ // We should really just work with a single app at the moment.
72
+ if (apps[0] === undefined) {
73
+ this.error('There are no applications in the manifest');
74
+ }
75
+ const app = apps[0];
73
76
  const manifestContents = await fs.readFile(manifestPath, 'utf8');
74
- // Now do a translate to get the JSON version of the manifest.
75
- const tokenizer = new Tokenizer(await fs.readFile(manifestPath, 'utf8'));
76
- const parser = new Parser(tokenizer);
77
- const manifestJson = new JSONTranslator().translate(parser.parse());
78
77
  const buildDir = path.isAbsolute(this.flags.output)
79
78
  ? this.flags.output
80
79
  : path.join(this.flags.root, this.flags.output);
80
+ // It's weird that it takes an array of apps.
81
81
  await buildHandlers(this, apps, buildDir, this.flags.root);
82
82
  const config = await this.loadConfig();
83
- const versionId = this.flags.versionId || config.versionId;
84
- if (versionId === defaultConfig.versionId) {
85
- this.error('You must create a new version with `raindrop build branch` before deploying your first application', {
86
- exit: 1,
87
- });
88
- }
83
+ const versionId = this.flags.versionId ?? config.versionId;
84
+ const runtimeVersion = await this.raindropFrameworkVersion();
89
85
  const { client: catalogService, userId, organizationId: defaultOrganizationId } = await this.catalogService();
90
86
  const organizationId = this.flags.impersonate ?? defaultOrganizationId;
91
- // The raindrop-framework version is pinned to the raindrop-runtime version
92
- const runtimeVersion = await this.raindropFrameworkVersion();
93
- let changed = [];
94
- if (this.flags.amend) {
95
- const manifests = apps.map((app) => ({
96
- name: valueOf(app.name),
97
- versionId,
98
- manifest: manifestContents,
99
- metadata: {
100
- runtimeVersion,
87
+ const deployResp = await catalogService.deploy({
88
+ userId: userId,
89
+ organizationId: organizationId,
90
+ applications: [
91
+ {
92
+ application: valueOf(app.name),
93
+ currentVersionId: this.flags.amend ? versionId : undefined,
94
+ previousVersionId: this.flags.amend ? undefined : versionId,
95
+ amend: this.flags.amend,
96
+ metadata: {
97
+ runtimeVersion,
98
+ },
99
+ manifest: manifestContents,
101
100
  },
102
- }));
103
- const appsResp = await catalogService.setApplicationManifests({
104
- manifests,
101
+ ],
102
+ });
103
+ if (deployResp.applications[0] === undefined) {
104
+ this.error('Failed to deploy application');
105
+ }
106
+ // If we deployed, we have to actually retrieve the
107
+ // currentVersionId from the response.
108
+ const currentVersionId = deployResp.applications[0].currentVersionId;
109
+ // And save it asap.
110
+ config.versionId = currentVersionId;
111
+ await this.saveConfig(config);
112
+ // Upload bundle to this version's store.
113
+ for (const handler of app.handlers()) {
114
+ const bundle = new FileSystemBundle(path.join(buildDir, valueOf(handler.name)));
115
+ await catalogService.uploadBundle({
105
116
  userId,
106
117
  organizationId,
118
+ applicationName: valueOf(app.name),
119
+ applicationVersionId: currentVersionId,
120
+ archiveType: BundleArchiveType.ZIP,
121
+ bundleName: valueOf(handler.name),
122
+ archive: Buffer.from(await archive(bundle)),
107
123
  });
108
- changed = appsResp.success;
109
- if (appsResp.failure.length > 0) {
110
- this.error(`Failed to amend applications: ${appsResp.failure.map((a) => `${a.name}@${a.versionId}`).join(', ')}. Make sure the application exists and the version is sandboxed.`, { exit: 1 });
111
- }
124
+ this.log(`Uploaded bundle "${valueOf(handler.name)}"`);
112
125
  }
113
- else {
114
- const applications = apps.map((app) => ({
115
- name: valueOf(app.name),
116
- manifest: manifestContents,
117
- manifestJson: JSON.stringify(manifestJson),
118
- version: {
119
- case: 'versionId',
120
- value: versionId,
121
- },
122
- isActive: this.flags.start,
123
- metadata: { runtimeVersion },
124
- }));
125
- const appsResp = await catalogService.createApplications({
126
- applications,
126
+ // Upload DB bundle if it exists.
127
+ const dbDir = path.join(this.flags.root, 'db');
128
+ let dbExists = false;
129
+ try {
130
+ const stat = await fs.lstat(dbDir);
131
+ dbExists = stat.isDirectory();
132
+ }
133
+ catch (_e) {
134
+ // Nothing to do
135
+ }
136
+ if (dbExists) {
137
+ const dbBundle = new FileSystemBundle(path.join(this.flags.root, 'db'));
138
+ await catalogService.uploadBundle({
127
139
  userId,
128
140
  organizationId,
129
- suite: undefined, // TODO [bosgood] Provide suite name once available
141
+ applicationName: valueOf(app.name),
142
+ applicationVersionId: currentVersionId,
143
+ archiveType: BundleArchiveType.ZIP,
144
+ bundleName: 'db',
145
+ archive: Buffer.from(await archive(dbBundle)),
130
146
  });
131
- changed = appsResp.applications;
147
+ this.log(`Uploaded bundle "db"`);
132
148
  }
133
- // Upload bundle to this version's store.
134
- for (const [i, app] of apps.entries()) {
135
- const appResp = changed[i];
136
- if (!appResp) {
137
- this.error(`Failed to create application ${valueOf(app.name)}, not uploading code bundle`, { exit: false });
138
- continue;
139
- }
140
- const versionId = appResp.versionId;
141
- this.log(`${this.flags.amend ? 'Updated' : 'Created'} application "${valueOf(app.name)}" with version ID "${versionId}"`);
142
- for (const handler of app.handlers()) {
143
- const bundle = new FileSystemBundle(path.join(buildDir, valueOf(handler.name)));
144
- await catalogService.uploadBundle({
145
- userId,
146
- organizationId,
147
- applicationName: valueOf(app.name),
148
- applicationVersionId: versionId,
149
- archiveType: BundleArchiveType.ZIP,
150
- bundleName: valueOf(handler.name),
151
- archive: Buffer.from(await archive(bundle)),
152
- });
153
- this.log(`Uploaded bundle "${valueOf(handler.name)}"`);
154
- }
155
- // Per above, each application gets the same db bundle, which is
156
- // boneheaded. src/db is pretty arbitrary.
157
- const dbDir = path.join(this.flags.root, 'db');
158
- let dbExists = false;
159
- try {
160
- const stat = await fs.lstat(dbDir);
161
- dbExists = stat.isDirectory();
162
- }
163
- catch (_e) {
164
- // Nothing to do
165
- }
166
- if (dbExists) {
167
- const dbBundle = new FileSystemBundle(path.join(this.flags.root, 'db'));
168
- await catalogService.uploadBundle({
169
- userId,
170
- organizationId,
171
- applicationName: valueOf(app.name),
172
- applicationVersionId: versionId,
173
- archiveType: BundleArchiveType.ZIP,
174
- bundleName: 'db',
175
- archive: Buffer.from(await archive(dbBundle)),
176
- });
177
- this.log(`Uploaded bundle "db"`);
178
- }
149
+ // Set to start?
150
+ if (this.flags.start) {
151
+ await catalogService.setActive({
152
+ userId,
153
+ organizationId,
154
+ applications: deployResp.applications.map((a) => ({
155
+ applicationName: a.applicationName,
156
+ currentVersionId: a.currentVersionId,
157
+ isActive: this.flags.start,
158
+ })),
159
+ });
179
160
  }
161
+ // Release locks.
162
+ await catalogService.release({
163
+ userId,
164
+ organizationId,
165
+ locks: deployResp.applications.map((a) => new ReleaseRequest_Lock({
166
+ applicationName: a.applicationName,
167
+ currentVersionId: a.currentVersionId,
168
+ lock: a.lock,
169
+ })),
170
+ });
171
+ // TODO [ian] Call watch and subscribe to events.
180
172
  }
181
173
  }
@@ -1 +1 @@
1
- {"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../../src/commands/build/env/get.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,WAAW,CAAC,OAAO,GAAG,CAAC;IACtD,MAAM,CAAC,IAAI;;MAET;IAEF,MAAM,CAAC,WAAW,SAA2B;IAE7C,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;MA0CV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA0D3B"}
1
+ {"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../../src/commands/build/env/get.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,WAAW,CAAC,OAAO,GAAG,CAAC;IACtD,MAAM,CAAC,IAAI;;MAET;IAEF,MAAM,CAAC,WAAW,SAA2B;IAE7C,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;MA0CV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA2D3B"}
@@ -64,9 +64,6 @@ sets an env var/secret.
64
64
  let isSecret = false;
65
65
  // Split up the variable path.
66
66
  const path = this.args.var.split(':');
67
- if (path.shift() !== valueOf(app.name)) {
68
- this.error(`variable does not belong to application ${valueOf(app.name)}`, { exit: 1 });
69
- }
70
67
  const envVarName = path.pop();
71
68
  if (envVarName === undefined) {
72
69
  this.error('variable name not specified', { exit: 1 });
@@ -98,18 +95,22 @@ sets an env var/secret.
98
95
  }
99
96
  const config = await this.loadConfig();
100
97
  const { client: catalogService, userId, organizationId } = await this.catalogService();
101
- const resp = await catalogService.getEnv({
98
+ const resp = await catalogService.getEnvs({
102
99
  userId,
103
100
  organizationId: this.flags.impersonate ?? organizationId,
104
- applicationName: valueOf(app.name),
105
- applicationVersionId: this.flags.versionId || config.versionId,
106
- key: this.args.var,
101
+ envs: [
102
+ {
103
+ applicationName: valueOf(app.name),
104
+ currentVersionId: this.flags.versionId || config.versionId,
105
+ key: this.args.var,
106
+ },
107
+ ],
107
108
  });
108
109
  if (isSecret) {
109
- console.log(`${this.args.var}=[hash: ${resp.value}]`);
110
+ console.log(`${this.args.var}=[hash: ${resp.envs[0]?.value}]`);
110
111
  }
111
112
  else {
112
- console.log(`${this.args.var}=${resp.value}`);
113
+ console.log(`${this.args.var}=${resp.envs[0]?.value}`);
113
114
  }
114
115
  }
115
116
  }
@@ -1 +1 @@
1
- {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../../../src/commands/build/env/set.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,WAAW,CAAC,OAAO,GAAG,CAAC;IACtD,MAAM,CAAC,IAAI;;;MAGT;IAEF,MAAM,CAAC,WAAW,SAA2B;IAE7C,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;MA2CV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAqE3B"}
1
+ {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../../../src/commands/build/env/set.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,WAAW,CAAC,OAAO,GAAG,CAAC;IACtD,MAAM,CAAC,IAAI;;;MAGT;IAEF,MAAM,CAAC,WAAW,SAA2B;IAE7C,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;MA2CV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAsE3B"}