@gershy/lilac 0.0.14 → 0.0.16

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.
@@ -4,13 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.regions = exports.capitalKeys = void 0;
7
- const clearing_1 = require("@gershy/clearing");
7
+ require("@gershy/clearing");
8
8
  const util_phrasing_1 = __importDefault(require("@gershy/util-phrasing"));
9
9
  const capitalKeys = (v) => {
10
- if ((0, clearing_1.isCls)(v, Array))
11
- return v[map](v => (0, exports.capitalKeys)(v));
12
- if ((0, clearing_1.isCls)(v, Object))
13
- return v[mapk]((val, key) => [(0, util_phrasing_1.default)(key, 'camel', 'kamel'), (0, exports.capitalKeys)(val)]);
10
+ if (cl.isCls(v, Array))
11
+ return v[cl.map](v => (0, exports.capitalKeys)(v));
12
+ if (cl.isCls(v, Object))
13
+ return v[cl.mapk]((val, key) => [(0, util_phrasing_1.default)('camel->kamel', key), (0, exports.capitalKeys)(val)]);
14
14
  return v;
15
15
  };
16
16
  exports.capitalKeys = capitalKeys;
@@ -54,7 +54,7 @@ exports.regions = [
54
54
  // Ignoring these for now...
55
55
  // 'us-gov-east-1',
56
56
  // 'us-gov-west-1',
57
- ][map](region => {
57
+ ][cl.map](region => {
58
58
  const [c, z, num] = region.split('-');
59
59
  const [dir0, dir1 = dir0] = z.match(/central|north|south|east|west/g);
60
60
  return {
@@ -1,2 +1,3 @@
1
+ import '@gershy/clearing';
1
2
  declare const normalize: (val: any, seen?: Set<any>) => any;
2
3
  export default normalize;
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const clearing_1 = require("@gershy/clearing");
3
+ require("@gershy/clearing");
4
+ const { isCls, getClsName } = clearing;
4
5
  const normalize = (val, seen = new Set()) => {
5
6
  // Derives a json-stringifiable value from *any* value
6
7
  // E.g. to hash *anything*: hash(JSON.stringify(normalized(anything)));
7
8
  // Handles terminations
8
- if ((0, clearing_1.isCls)(val, String))
9
+ if (isCls(val, String))
9
10
  return val;
10
- if ((0, clearing_1.isCls)(val, Number))
11
+ if (isCls(val, Number))
11
12
  return val;
12
13
  if (val === null)
13
14
  return null;
@@ -16,10 +17,10 @@ const normalize = (val, seen = new Set()) => {
16
17
  if (seen.has(val))
17
18
  return '<<!circ!>>';
18
19
  seen.add(val);
19
- if ((0, clearing_1.isCls)(val, Array))
20
- return val[map](v => normalize(v, seen));
21
- if ((0, clearing_1.isCls)(val, Object))
20
+ if (isCls(val, Array))
21
+ return val[cl.map](v => normalize(v, seen));
22
+ if (isCls(val, Object))
22
23
  return normalize(Object.entries(val).sort((e0, e1) => e0[0] < e1[0] ? -1 : 1), seen);
23
- return normalize({ $form: (0, clearing_1.getClsName)(val), ...val }, seen);
24
+ return normalize({ $form: getClsName(val), ...val }, seen);
24
25
  };
25
26
  exports.default = normalize;
@@ -1,6 +1,8 @@
1
1
  import type { Fact } from '@gershy/disk';
2
2
  import { ProcOpts } from '@gershy/nodejs-proc';
3
- export type ProcTerraformArgs = ProcOpts & {};
3
+ export type ProcTerraformArgs = ProcOpts & {
4
+ config?: string;
5
+ };
4
6
  declare const _default: (fact: Fact, cmd: string, opts?: ProcTerraformArgs) => Promise<{
5
7
  logDb: Fact;
6
8
  output: string;
@@ -17,14 +17,19 @@ exports.default = (fact, cmd, opts = {}) => {
17
17
  timeoutMs: 0,
18
18
  ...opts,
19
19
  cwd: fact,
20
- env: { TF_DATA_DIR: '' }
20
+ env: {
21
+ ...process.env,
22
+ TF_DATA_DIR: '',
23
+ TF_CLI_CONFIG_FILE: '',
24
+ ...opts.env
25
+ }
21
26
  });
22
27
  return Object.assign(prm.then(async (result) => {
23
28
  const logDb = await writeLog(result.output);
24
29
  return { logDb, output: result.output.split('\n').slice(-numTailingTfLogLines).join('\n') };
25
30
  }, async (err) => {
26
- const logDb = await writeLog(err.output ?? err[limn]());
27
- throw Error(`terraform failed (${err.message})`)[mod]({
31
+ const logDb = await writeLog(err.output ?? err[cl.limn]());
32
+ throw Error(`terraform failed (${err.message})`)[cl.mod]({
28
33
  logDb,
29
34
  ...(err.output ? { output: err.output.split('\n').slice(-numTailingTfLogLines).join('\n') } : { cause: err })
30
35
  });
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = (str, escapeChars) => {
4
- if (!escapeChars[has]('\\'))
4
+ if (!escapeChars[cl.has]('\\'))
5
5
  escapeChars += '\\';
6
6
  // The regex to construct must have "\" and "]" escaped:
7
7
  const escChars = escapeChars.replace(/([\\\]])/g, '\\$1');
@@ -6,7 +6,7 @@ const embed = (v) => '${' + v + '}';
6
6
  exports.embed = embed;
7
7
  const json = (v) => [
8
8
  '| <<EOF',
9
- JSON.stringify(v, null, 2)[indent](2),
9
+ JSON.stringify(v, null, 2)[cl.indent](2),
10
10
  'EOF'
11
11
  ].join('\n');
12
12
  exports.json = json;
package/cmp/mjs/main.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import '../sideEffects.js';
2
2
  import { PetalTerraform } from './petal/terraform/terraform.ts';
3
3
  import type Logger from '@gershy/logger';
4
- import type { Fact } from '@gershy/disk';
4
+ import { type Fact } from '@gershy/disk';
5
+ import '@gershy/clearing';
5
6
  import { Soil } from './soil/soil.ts';
6
7
  import { SuperIterable } from './util/superIterable.ts';
7
8
  export type Context = {
@@ -9,6 +10,7 @@ export type Context = {
9
10
  logger: Logger;
10
11
  fact: Fact;
11
12
  patioFact: Fact;
13
+ shedFact: Fact;
12
14
  maturity: string;
13
15
  debug: boolean;
14
16
  pfx: string;
@@ -18,6 +20,7 @@ export declare class Flower {
18
20
  constructor();
19
21
  getDependencies(): Generator<Flower>;
20
22
  getPetals(ctx: Context): SuperIterable<PetalTerraform.Base>;
23
+ cultivate(): Promise<void>;
21
24
  }
22
25
  type RegistryFlowers<R extends Registry<any>, M extends 'real' | 'test'> = R extends Registry<infer Flowers> ? {
23
26
  [K in keyof Flowers]: Flowers[K][M];
@@ -39,13 +42,14 @@ export declare class Garden<Reg extends Registry<any>> {
39
42
  private ctx;
40
43
  private reg;
41
44
  private def;
45
+ private tfProcArgs;
42
46
  constructor(args: {
43
47
  context: Context;
44
48
  registry: Reg;
45
49
  define: Garden<Reg>['def'];
46
50
  });
47
51
  private getPetals;
48
- genTerraform(deployTarget: Soil.Base): Promise<Obj<Fact>>;
52
+ genTerraform(soil: Soil.Base): Promise<Obj<Fact>>;
49
53
  private terraformInit;
50
54
  private terraformPlan;
51
55
  private terraformApply;
package/cmp/mjs/main.js CHANGED
@@ -2,15 +2,24 @@
2
2
  // A more generic (beyond just tf) provider is very hard to support due to the multiplicity of
3
3
  // provider/petal combos - e.g. "api" flower would need to support ,api.getCloudformationPetals,
4
4
  // api.getTerraformPetals, etc... supporting just terraform for now
5
- // Watch out when working lilac into an npm dependency, need to allow the user a way to declare
6
- // their absolute repo path (so "<repo>/..." filenames work in any setup!)
7
- // Can region be dealt with any better??
8
5
  // Support test-mode (Flowers need to be able to do setup, share config, write to volumes, etc)
9
6
  import { PetalTerraform } from "./petal/terraform/terraform.js";
10
- import { isCls, skip } from '@gershy/clearing';
11
- import procTerraform from "./util/procTerraform.js";
7
+ import { tempFact } from '@gershy/disk';
8
+ import '@gershy/clearing';
12
9
  import tryWithHealing from '@gershy/util-try-with-healing';
13
10
  import phrasing from '@gershy/util-phrasing';
11
+ import proc from '@gershy/nodejs-proc';
12
+ const { isCls, skip } = cl;
13
+ const toArr = cl.toArr;
14
+ const allObj = cl.allObj;
15
+ const allArr = cl.allArr;
16
+ const has = cl.has;
17
+ const map = cl.map;
18
+ const mod = cl.mod;
19
+ const walk = cl.walk;
20
+ const merge = cl.merge;
21
+ const upper = cl.upper;
22
+ const baseline = cl.baseline;
14
23
  export class Flower {
15
24
  // TODO: The downside of having this static is that different instances may use different
16
25
  // services - e.g. api gateway instance may have "useEdge: true", in which case we'd like to
@@ -27,6 +36,11 @@ export class Flower {
27
36
  getPetals(ctx) {
28
37
  throw Error('not implemented');
29
38
  }
39
+ async cultivate() {
40
+ // This function is called once all Flowers for a given Garden have been constructed. The main
41
+ // purpose of this phase is to allow Flowers which reference each other via functions to run
42
+ // such functions without running into uninitialized values.
43
+ }
30
44
  }
31
45
  ;
32
46
  export class Registry {
@@ -40,7 +54,7 @@ export class Registry {
40
54
  }
41
55
  getAwsServices() {
42
56
  const services = new Set();
43
- for (const [k, { real }] of this.flowers)
57
+ for (const [k, { real }] of this.flowers[walk]())
44
58
  for (const awsService of real.getAwsServices())
45
59
  services.add(awsService);
46
60
  return services[toArr](v => v);
@@ -58,11 +72,21 @@ export class Garden {
58
72
  ctx;
59
73
  reg;
60
74
  def;
75
+ tfProcArgs;
61
76
  constructor(args) {
62
77
  const { define, registry, context } = args;
63
78
  this.ctx = context;
64
79
  this.reg = registry;
65
80
  this.def = define;
81
+ this.tfProcArgs = {
82
+ timeoutMs: 0,
83
+ env: {
84
+ ...process.env,
85
+ TF_LOG: 'DEBUG',
86
+ TF_DATA_DIR: '',
87
+ TF_CLI_CONFIG_FILE: ''
88
+ }
89
+ };
66
90
  }
67
91
  async *getPetals() {
68
92
  // TODO: We always use the "real" flowers from the registry - this is part of the shift to
@@ -72,21 +96,22 @@ export class Garden {
72
96
  // conditionally calling `this.registry.get('fake')`...
73
97
  const seenFlowers = new Set();
74
98
  const seenPetals = new Set();
75
- for await (const topLevelFlower of await this.def(this.ctx, this.reg.get('real'))) {
76
- for (const flower of topLevelFlower.getDependencies()) {
77
- if (seenFlowers.has(flower))
78
- continue;
99
+ for await (const topLevelFlower of await this.def(this.ctx, this.reg.get('real')))
100
+ for (const flower of topLevelFlower.getDependencies())
79
101
  seenFlowers.add(flower);
80
- for await (const petal of await flower.getPetals(this.ctx)) {
81
- if (seenPetals.has(petal))
82
- continue;
83
- yield petal;
84
- }
102
+ // Now we've exhaustively referenced all Flowers - we can cultivate them
103
+ await Promise.all(seenFlowers[toArr](f => f.cultivate()));
104
+ for (const flower of seenFlowers) {
105
+ for await (const petal of await flower.getPetals(this.ctx)) {
106
+ if (seenPetals.has(petal))
107
+ continue;
108
+ seenPetals.add(petal);
109
+ yield petal;
85
110
  }
86
111
  }
87
112
  }
88
- async genTerraform(deployTarget) {
89
- const soilTfPetalsPrm = deployTarget.getTerraformPetals(this.ctx);
113
+ async genTerraform(soil) {
114
+ const soilTfPetalsPrm = soil.getTerraformPetals(this.ctx);
90
115
  return this.ctx.logger.scope('garden.genTerraform', {}, async (logger) => {
91
116
  const setupTfProj = async (args) => args.logger.scope('tf', { proj: this.ctx.name, tf: args.term }, async (logger) => {
92
117
  // Allows a terraform project to be defined in terms of a function which writes to main.tf,
@@ -108,8 +133,7 @@ export class Garden {
108
133
  const stream = await args.fact.kid(['main.tf']).getDataHeadStream();
109
134
  await args.setup(args.fact, stream, async (petal) => {
110
135
  // Include a utility function the caller can use to easily write petals
111
- const { tf, files = {} } = await petal.getResult()
112
- .then(tf => isCls(tf, String) ? { tf } : tf);
136
+ const { tf, files = {} } = await petal.getResult().then(tf => isCls(tf, String) ? { tf } : tf);
113
137
  if (tf)
114
138
  await stream.write(`${tf}\n`);
115
139
  await Promise.all(files[toArr]((data, kfp) => args.fact.kid(kfp.split('/')).setData(data)));
@@ -154,7 +178,7 @@ export class Garden {
154
178
  // Create ddb tf state locking table
155
179
  await writePetalTfAndFiles(new PetalTerraform.Resource('awsDynamodbTable', 'tfState', {
156
180
  name: ddbName,
157
- billingMode: phrasing('payPerRequest', 'camel', 'snake')[upper](),
181
+ billingMode: phrasing('camel->snake', 'payPerRequest')[upper](),
158
182
  hashKey: 'LockID',
159
183
  $attribute: { name: 'LockID', type: 'S' }
160
184
  }));
@@ -181,31 +205,55 @@ export class Garden {
181
205
  });
182
206
  });
183
207
  }
184
- terraformInit(fact, args) {
208
+ // TODO: Write terraform output to logs??
209
+ async terraformInit(fact) {
210
+ // Consider if we ever want to pass "-reconfigure" and "-migrate-state" options; these are
211
+ // useful if we are moving backends (e.g. one aws account to another), and want to move our
212
+ // full iac definition too
213
+ // Ensure the mirror directory exists in the shed
214
+ const mirrorFact = this.ctx.shedFact.kid(['lilacTerraformMirror']);
215
+ await mirrorFact.kid(['note.txt']).setData(`Root of terraform mirror for @gershy/lilac`);
185
216
  return this.ctx.logger.scope('execTf.init', { fact: fact.fsp() }, async (logger) => {
186
- // Consider if we ever want to pass "-reconfigure" and "-migrate-state" options; these are
187
- // useful if we are moving backends (e.g. one aws account to another), and want to move our
188
- // full iac definition too
189
- // TODO: Some terraform commands fail when offline - can this be covered up? Possibly by
190
- // checking terraform binaries into the repo? (Cross-platform nightmare though...)
191
- const result = await procTerraform(fact, `terraform init -input=false`, {
192
- onData: async (mode, data) => logger.log({ $$: 'notice', mode, data }) ?? null
217
+ const { output: result } = await tryWithHealing({
218
+ fn: () => logger.scope('attempt', {}, async (logger) => {
219
+ const configFact = tempFact.kid([`${Math.random().toString(36).slice(2)}.terraform.rc`]);
220
+ await configFact.setData(String[baseline](`
221
+ | provider_installation {
222
+ | filesystem_mirror {
223
+ | path = "${mirrorFact.fsp().replaceAll('\\', '/')}"
224
+ | }
225
+ | }
226
+ `));
227
+ return proc(`terraform init -input=false`, {}[merge](this.tfProcArgs)[merge]({
228
+ cwd: fact,
229
+ env: { TF_CLI_CONFIG_FILE: configFact.fsp() }
230
+ })).finally(() => configFact.rem());
231
+ }),
232
+ canHeal: err => (err?.output ?? '')[has]('Could not retrieve the list of available versions for provider'),
233
+ heal: () => logger.scope('mirror', { fsp: mirrorFact.fsp() }, async (logger) => {
234
+ const { output: result } = await proc(`terraform providers mirror "${mirrorFact.fsp().replaceAll('\\', '/')}"`, { cwd: fact, timeoutMs: 0 });
235
+ logger.log({ $$: 'result', result });
236
+ })
193
237
  });
194
- logger.log({ $$: 'result', logFp: result.logDb.toString(), msg: result.output });
238
+ logger.log({ $$: 'result', result });
195
239
  return result;
196
240
  });
197
241
  }
198
242
  terraformPlan(fact, args) {
199
243
  return this.ctx.logger.scope('execTf.plan', { fact: fact.fsp() }, async (logger) => {
200
- const result = await procTerraform(fact, `terraform plan -input=false`);
201
- logger.log({ $$: 'result', logFp: result.logDb.toString(), msg: result.output });
244
+ const { output: result } = await proc(`terraform plan -input=false`, {}[merge](this.tfProcArgs)[merge]({
245
+ cwd: fact,
246
+ }));
247
+ logger.log({ $$: 'result', result });
202
248
  return result;
203
249
  });
204
250
  }
205
251
  terraformApply(fact, args) {
206
252
  return this.ctx.logger.scope('execTf.apply', { fact: fact.fsp() }, async (logger) => {
207
- const result = await procTerraform(fact, `terraform apply -input=false -auto-approve`);
208
- logger.log({ $$: 'result', logFp: result.logDb.toString(), msg: result.output });
253
+ const { output: result } = await proc(`terraform apply -input=false -auto-approve`, {}[merge](this.tfProcArgs)[merge]({
254
+ cwd: fact
255
+ }));
256
+ logger.log({ $$: 'result', result });
209
257
  return result;
210
258
  });
211
259
  }
@@ -1,3 +1,4 @@
1
+ import '@gershy/clearing';
1
2
  import Petal from '../petal.ts';
2
3
  export declare namespace PetalTerraform {
3
4
  class Base extends Petal {
@@ -1,7 +1,15 @@
1
- import { getClsName, isCls } from '@gershy/clearing';
1
+ import '@gershy/clearing';
2
2
  import slashEscape from "../../util/slashEscape.js";
3
3
  import Petal from "../petal.js";
4
4
  import ph from '@gershy/util-phrasing';
5
+ const { getClsName, isCls } = cl;
6
+ const hasHead = cl.hasHead;
7
+ const map = cl.map;
8
+ const hasTail = cl.hasTail;
9
+ const indent = cl.indent;
10
+ const mod = cl.mod;
11
+ const toArr = cl.toArr;
12
+ const has = cl.has;
5
13
  export var PetalTerraform;
6
14
  (function (PetalTerraform) {
7
15
  class Base extends Petal {
@@ -49,13 +57,13 @@ export var PetalTerraform;
49
57
  throw Error('tf key of this form must correspond to object value')[mod]({ k, v });
50
58
  // Resolve to raw string?
51
59
  if (special && isCls(v, String))
52
- return [ph(pcs[0], 'camel', 'snake'), ' = ', this.terraformEncode(v[hasHead]('| ') ? v : `| ${v}`)];
60
+ return [ph('camel->snake', pcs[0]), ' = ', this.terraformEncode(v[hasHead]('| ') ? v : `| ${v}`)];
53
61
  // Resolve to nested block?
54
62
  if (special && isCls(v, Object))
55
- return [[ph(pcs[0], 'camel', 'snake'), ...pcs.slice(1)[map](pc => ph(pc, 'camel', 'snake'))].join(' '), ' ', this.terraformEncode(v)];
63
+ return [[ph('camel->snake', pcs[0]), ...pcs.slice(1)[map](pc => ph('camel->snake', pc))].join(' '), ' ', this.terraformEncode(v)];
56
64
  // Resolve anything else to typical property - use the key exactly as provided (to support,
57
65
  // e.g., aws format for keys in policies, any other specific format, etc.)
58
- return [ph(pcs[0], 'camel', 'snake'), ' = ', this.terraformEncode(v)];
66
+ return [ph('camel->snake', pcs[0]), ' = ', this.terraformEncode(v)];
59
67
  });
60
68
  const len = entryItems.length;
61
69
  if (len === 0)
@@ -76,9 +84,9 @@ export var PetalTerraform;
76
84
  refStr(props = []) {
77
85
  if (!isCls(props, Array))
78
86
  props = [props];
79
- const base = `${ph(this.getType(), 'camel', 'snake')}.${ph(this.getHandle(), 'camel', 'snake')}`;
87
+ const base = `${ph('camel->snake', this.getType())}.${ph('camel->snake', this.getHandle())}`;
80
88
  return props.length
81
- ? `${base}.${props[map](v => ph(v, 'camel', 'snake')).join('.')}`
89
+ ? `${base}.${props[map](v => ph('camel->snake', v)).join('.')}`
82
90
  : base;
83
91
  }
84
92
  ref(props = []) {
@@ -124,7 +132,7 @@ export var PetalTerraform;
124
132
  getHandle() { return this.handle; }
125
133
  getProps() { return this.props; }
126
134
  async getResultHeader() {
127
- return `resource "${ph(this.type, 'camel', 'snake')}" "${ph(this.handle, 'camel', 'snake')}"`;
135
+ return `resource "${ph('camel->snake', this.type)}" "${ph('camel->snake', this.handle)}"`;
128
136
  }
129
137
  }
130
138
  PetalTerraform.Resource = Resource;
@@ -139,7 +147,7 @@ export var PetalTerraform;
139
147
  }
140
148
  getProps() { return this.props; }
141
149
  async getResultHeader() {
142
- return `provider "${ph(this.name, 'camel', 'snake')}"`;
150
+ return `provider "${ph('camel->snake', this.name)}"`;
143
151
  }
144
152
  }
145
153
  PetalTerraform.Provider = Provider;
@@ -158,7 +166,7 @@ export var PetalTerraform;
158
166
  getHandle() { return this.handle; }
159
167
  getProps() { return this.props; }
160
168
  async getResultHeader() {
161
- return `data "${ph(this.type, 'camel', 'snake')}" "${ph(this.handle, 'camel', 'snake')}"`;
169
+ return `data "${ph('camel->snake', this.type)}" "${ph('camel->snake', this.handle)}"`;
162
170
  }
163
171
  refStr(props = []) {
164
172
  return `data.${super.refStr(props)}`;
@@ -1,8 +1,10 @@
1
1
  import { Context, PetalTerraform, Registry } from '../main.ts';
2
2
  import { RegionTerm } from '../util/aws.ts';
3
+ import '@gershy/clearing';
3
4
  import { NetProc } from '@gershy/util-http';
4
5
  import { SuperIterable } from '../util/superIterable.ts';
5
6
  import type Logger from '@gershy/logger';
7
+ import { RestApi } from '@aws-sdk/client-api-gateway';
6
8
  export declare namespace Soil {
7
9
  type PetalProjArgs = {
8
10
  s3Name: string;
@@ -13,11 +15,14 @@ export declare namespace Soil {
13
15
  };
14
16
  type LocalStackAwsService = never | 'acm' | 'apigateway' | 'cloudformation' | 'cloudwatch' | 'config' | 'dynamodb' | 'dynamodbstreams' | 'ec2' | 'es' | 'events' | 'firehose' | 'iam' | 'kinesis' | 'kms' | 'lambda' | 'logs' | 'opensearch' | 'redshift' | 'resource' | 'resourcegroupstaggingapi' | 'route53' | 'route53resolver' | 's3' | 's3control' | 'scheduler' | 'secretsmanager' | 'ses' | 'sns' | 'sqs' | 'ssm' | 'stepfunctions' | 'sts' | 'support' | 'swf' | 'transcribe';
15
17
  type BaseArgs = {
18
+ logger: Logger;
16
19
  registry: Registry<any>;
17
20
  };
18
21
  class Base {
22
+ protected logger: Logger;
19
23
  protected registry: Registry<any>;
20
24
  constructor(args: BaseArgs);
25
+ getRegion(): string;
21
26
  getTerraformPetals(ctx: Context): Promise<PetalProjResult>;
22
27
  }
23
28
  type LocalStackArgs = BaseArgs & {
@@ -34,19 +39,22 @@ export declare namespace Soil {
34
39
  private static localStackInternalPort;
35
40
  private aws;
36
41
  private localStackDocker;
37
- private procArgs;
38
42
  constructor(args: LocalStackArgs);
43
+ getRegion(): "ca-central-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2";
39
44
  private getAwsServices;
40
45
  private getDockerContainers;
41
- run(args: {
42
- logger: Logger;
43
- }): Promise<{
46
+ run(): Promise<{
44
47
  aws: {
45
48
  services: LocalStackAwsService[];
46
49
  region: "ca-central-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2";
47
50
  };
48
51
  netProc: NetProc;
49
- url: string;
52
+ getApis: () => Promise<{
53
+ [x: string]: RestApi & {
54
+ id: string;
55
+ name: string;
56
+ };
57
+ }>;
50
58
  }>;
51
59
  end(args?: {
52
60
  containers?: Awaited<ReturnType<Soil.LocalStack['getDockerContainers']>>;
@@ -71,6 +79,7 @@ export declare namespace Soil {
71
79
  class AwsCloud extends Base {
72
80
  private aws;
73
81
  constructor(args: AwsCloudArgs);
82
+ getRegion(): "ca-central-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2";
74
83
  getTerraformPetals(ctx: Context): Promise<{
75
84
  boot: () => Generator<PetalTerraform.Terraform | PetalTerraform.Provider | PetalTerraform.File, void, unknown>;
76
85
  main: (args: any) => Generator<PetalTerraform.Terraform | PetalTerraform.Provider | PetalTerraform.File, void, unknown>;