@anvil-cloud/sdk 0.0.4 → 0.0.5
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 +58 -26
- package/app.ts +285 -0
- package/bin/app.d.ts +110 -0
- package/bin/app.js +173 -0
- package/bin/app.js.map +1 -0
- package/bin/index.d.ts +1 -0
- package/bin/index.js +4 -1
- package/bin/index.js.map +1 -1
- package/bin/package.json +1 -1
- package/index.ts +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,58 +2,90 @@
|
|
|
2
2
|
|
|
3
3
|
**Cloud infrastructure that's secure by default — not by accident.**
|
|
4
4
|
|
|
5
|
-
Anvil wraps raw cloud resources into opinionated, production-ready components. No 200-line Terraform modules. No copy-pasting security configs
|
|
5
|
+
Anvil wraps raw cloud resources into opinionated, production-ready components. No 200-line Terraform modules. No copy-pasting security configs. Just declare what you need and Anvil handles the rest.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
import * as anvil from '@anvil-cloud/sdk';
|
|
7
|
+
## Install
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
});
|
|
9
|
+
```bash
|
|
10
|
+
npm install @anvil-cloud/sdk
|
|
13
11
|
```
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
## Quick start
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
Create `anvil.config.ts` at your project root:
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
```typescript
|
|
18
|
+
import { App } from '@anvil-cloud/sdk';
|
|
19
|
+
import * as anvil from '@anvil-cloud/sdk';
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
export default new App({
|
|
22
|
+
run(ctx) {
|
|
23
|
+
const bucket = new anvil.aws.Bucket('uploads', {
|
|
24
|
+
dataClassification: 'sensitive',
|
|
25
|
+
});
|
|
26
|
+
ctx.export('bucketName', bucket.bucketName);
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
```
|
|
22
30
|
|
|
23
|
-
|
|
31
|
+
Deploy:
|
|
24
32
|
|
|
25
33
|
```bash
|
|
26
|
-
|
|
34
|
+
anvil deploy
|
|
27
35
|
```
|
|
28
36
|
|
|
29
|
-
|
|
37
|
+
That S3 bucket ships with public access blocked, encryption enabled, and versioning on — because that's how every bucket should start. You opt _in_ to risk, not out of it.
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
npm install @anvil-cloud/sdk
|
|
33
|
-
```
|
|
39
|
+
## The App class
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
Every Anvil program starts with `new App()`. The `run` callback receives a `Context` with:
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
- `ctx.stage` — the current deployment stage (defaults to your OS username for dev isolation)
|
|
44
|
+
- `ctx.project` — the project name from `anvil.yaml`
|
|
45
|
+
- `ctx.export(name, value)` — export stack outputs
|
|
46
|
+
- `ctx.providers` — named cloud providers for multi-region / multi-account
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
## Multi-cloud
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
export default new App({
|
|
52
|
+
run(ctx) {
|
|
53
|
+
// AWS
|
|
54
|
+
const bucket = new anvil.aws.Bucket('data', {
|
|
55
|
+
dataClassification: 'sensitive',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// GCP
|
|
59
|
+
const gcsBucket = new anvil.gcp.StorageBucket('backup', {
|
|
60
|
+
dataClassification: 'internal',
|
|
61
|
+
location: 'US',
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
});
|
|
42
65
|
```
|
|
43
66
|
|
|
44
|
-
|
|
67
|
+
## Overrides
|
|
45
68
|
|
|
46
|
-
|
|
47
|
-
|
|
69
|
+
Every component accepts a `transform` argument to override the underlying resource config:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const bucket = new anvil.aws.Bucket('custom', {
|
|
73
|
+
dataClassification: 'non-sensitive',
|
|
74
|
+
transform: {
|
|
75
|
+
bucket: { forceDestroy: true, tags: { env: 'dev' } },
|
|
76
|
+
},
|
|
77
|
+
});
|
|
48
78
|
```
|
|
49
79
|
|
|
50
80
|
## How it works
|
|
51
81
|
|
|
52
|
-
Anvil is built on
|
|
82
|
+
Anvil is built on [Pulumi](https://www.pulumi.com/). Each component wraps one or more cloud resources with secure defaults. The `App` class handles config, providers, and exports so you write infrastructure — not boilerplate.
|
|
53
83
|
|
|
54
84
|
## Links
|
|
55
85
|
|
|
56
|
-
- [GitHub](https://github.com/
|
|
86
|
+
- [GitHub](https://github.com/DamienPace15/anvil)
|
|
87
|
+
- [Python SDK](https://pypi.org/project/anvil-cloud/)
|
|
88
|
+
- [Go SDK](https://pkg.go.dev/github.com/DamienPace15/anvil/sdk/go/anvil)
|
|
57
89
|
|
|
58
90
|
## License
|
|
59
91
|
|
package/app.ts
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import * as pulumi from '@pulumi/pulumi';
|
|
2
|
+
import * as aws from '@pulumi/aws';
|
|
3
|
+
import * as gcp from '@pulumi/gcp';
|
|
4
|
+
|
|
5
|
+
// ── Types ──────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Context passed to the App's run callback.
|
|
9
|
+
* This is the user's only interface to Anvil runtime information.
|
|
10
|
+
*/
|
|
11
|
+
export interface Context {
|
|
12
|
+
/** The current deployment stage (e.g. "dev", "staging", "prod", or OS username). */
|
|
13
|
+
readonly stage: string;
|
|
14
|
+
|
|
15
|
+
/** The project name from anvil.yaml. */
|
|
16
|
+
readonly project: string;
|
|
17
|
+
|
|
18
|
+
/** Named providers, keyed by their config name (e.g. "aws", "aws.us", "gcp.eu"). */
|
|
19
|
+
readonly providers: Record<string, pulumi.ProviderResource>;
|
|
20
|
+
|
|
21
|
+
/** Export a stack output value without importing Pulumi. */
|
|
22
|
+
export(name: string, value: pulumi.Input<any>): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** AWS provider configuration. */
|
|
26
|
+
export interface AwsProviderConfig {
|
|
27
|
+
region?: string;
|
|
28
|
+
profile?: string;
|
|
29
|
+
assumeRole?: {
|
|
30
|
+
roleArn: string;
|
|
31
|
+
sessionName?: string;
|
|
32
|
+
externalId?: string;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** GCP provider configuration. */
|
|
37
|
+
export interface GcpProviderConfig {
|
|
38
|
+
project?: string;
|
|
39
|
+
region?: string;
|
|
40
|
+
zone?: string;
|
|
41
|
+
credentials?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Default options applied to all resources. */
|
|
45
|
+
export interface DefaultsConfig {
|
|
46
|
+
/**
|
|
47
|
+
* Tags merged into every taggable resource via the cloud provider's
|
|
48
|
+
* native defaultTags (AWS) or defaultLabels (GCP).
|
|
49
|
+
*
|
|
50
|
+
* `stage` and `project` are auto-injected. User tags override auto-injected ones.
|
|
51
|
+
* Per-resource tags override default tags.
|
|
52
|
+
*/
|
|
53
|
+
tags?: Record<string, string>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Configuration for the App class.
|
|
58
|
+
*/
|
|
59
|
+
export interface AppConfig {
|
|
60
|
+
/** The infrastructure definition callback. Required. */
|
|
61
|
+
run: (ctx: Context) => void;
|
|
62
|
+
|
|
63
|
+
/** Default resource options applied to all resources. */
|
|
64
|
+
defaults?: DefaultsConfig;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Named provider configurations.
|
|
68
|
+
* Keys follow the pattern "cloud" or "cloud.name":
|
|
69
|
+
* "aws" → default AWS provider
|
|
70
|
+
* "aws.us" → named AWS provider for US region
|
|
71
|
+
* "gcp" → default GCP provider
|
|
72
|
+
* "gcp.eu" → named GCP provider for EU
|
|
73
|
+
*/
|
|
74
|
+
providers?: Record<string, AwsProviderConfig | GcpProviderConfig>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Called before the infrastructure program runs.
|
|
78
|
+
* @future Not yet implemented — reserved for forward compatibility.
|
|
79
|
+
*/
|
|
80
|
+
beforeDeploy?: (ctx: Context) => void;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Called after the infrastructure program completes successfully.
|
|
84
|
+
* @future CLI-side hook — not yet implemented.
|
|
85
|
+
*/
|
|
86
|
+
afterDeploy?: (ctx: Context) => void;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Called if the infrastructure program throws an error.
|
|
90
|
+
* @future CLI-side hook — not yet implemented.
|
|
91
|
+
*/
|
|
92
|
+
onError?: (ctx: Context, error: Error) => void;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── Helpers ────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Determine which cloud a provider key belongs to.
|
|
99
|
+
* "aws" → "aws", "aws.us" → "aws", "gcp.eu" → "gcp"
|
|
100
|
+
*/
|
|
101
|
+
function getCloud(key: string): string {
|
|
102
|
+
const dot = key.indexOf('.');
|
|
103
|
+
return dot === -1 ? key : key.substring(0, dot);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ── App ────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* App is the entry point for an Anvil infrastructure program.
|
|
110
|
+
*
|
|
111
|
+
* It wraps Pulumi's runtime so users never import `@pulumi/pulumi` directly.
|
|
112
|
+
* The constructor reads stage/project from Pulumi config, creates providers
|
|
113
|
+
* with default tags, and invokes the user's `run` callback with a Context.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* import { App } from "@anvil-cloud/sdk";
|
|
118
|
+
* import * as anvil from "@anvil-cloud/sdk";
|
|
119
|
+
*
|
|
120
|
+
* export default new App({
|
|
121
|
+
* defaults: {
|
|
122
|
+
* tags: { team: "platform" },
|
|
123
|
+
* },
|
|
124
|
+
* providers: {
|
|
125
|
+
* "aws": { region: "ap-southeast-2" },
|
|
126
|
+
* "aws.us": { region: "us-east-1" },
|
|
127
|
+
* },
|
|
128
|
+
* run(ctx) {
|
|
129
|
+
* const bucket = new anvil.aws.Bucket("my-data", {
|
|
130
|
+
* dataClassification: "sensitive",
|
|
131
|
+
* });
|
|
132
|
+
* ctx.export("bucketName", bucket.bucketName);
|
|
133
|
+
* },
|
|
134
|
+
* });
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export class App {
|
|
138
|
+
/** Stack outputs collected via ctx.export(). */
|
|
139
|
+
[key: string]: any;
|
|
140
|
+
|
|
141
|
+
constructor(config: AppConfig) {
|
|
142
|
+
// ── Read config from Pulumi ────────────────────────
|
|
143
|
+
const anvilConfig = new pulumi.Config('anvil');
|
|
144
|
+
const stage = anvilConfig.require('stage');
|
|
145
|
+
const project = pulumi.getProject();
|
|
146
|
+
|
|
147
|
+
// ── Build default tags ─────────────────────────────
|
|
148
|
+
const autoTags: Record<string, string> = { stage, project };
|
|
149
|
+
const userTags = config.defaults?.tags ?? {};
|
|
150
|
+
const mergedTags: Record<string, string> = { ...autoTags, ...userTags };
|
|
151
|
+
|
|
152
|
+
// ── Create providers ───────────────────────────────
|
|
153
|
+
const providers: Record<string, pulumi.ProviderResource> = {};
|
|
154
|
+
const defaultProviders: Record<string, pulumi.ProviderResource> = {};
|
|
155
|
+
|
|
156
|
+
if (config.providers) {
|
|
157
|
+
for (const [key, providerConfig] of Object.entries(config.providers)) {
|
|
158
|
+
const cloud = getCloud(key);
|
|
159
|
+
const isDefault = !key.includes('.');
|
|
160
|
+
const providerName = `anvil-provider-${key}`;
|
|
161
|
+
|
|
162
|
+
let provider: pulumi.ProviderResource;
|
|
163
|
+
|
|
164
|
+
switch (cloud) {
|
|
165
|
+
case 'aws': {
|
|
166
|
+
const awsConfig = providerConfig as AwsProviderConfig;
|
|
167
|
+
const awsArgs: Record<string, any> = {
|
|
168
|
+
defaultTags: { tags: mergedTags },
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
if (awsConfig.region) awsArgs.region = awsConfig.region;
|
|
172
|
+
if (awsConfig.profile) awsArgs.profile = awsConfig.profile;
|
|
173
|
+
if (awsConfig.assumeRole) {
|
|
174
|
+
awsArgs.assumeRoles = [
|
|
175
|
+
{
|
|
176
|
+
roleArn: awsConfig.assumeRole.roleArn,
|
|
177
|
+
sessionName: awsConfig.assumeRole.sessionName,
|
|
178
|
+
externalId: awsConfig.assumeRole.externalId,
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
provider = new aws.Provider(providerName, awsArgs);
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
case 'gcp': {
|
|
188
|
+
const gcpConfig = providerConfig as GcpProviderConfig;
|
|
189
|
+
const gcpArgs: Record<string, any> = {
|
|
190
|
+
defaultLabels: mergedTags,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
if (gcpConfig.project) gcpArgs.project = gcpConfig.project;
|
|
194
|
+
if (gcpConfig.region) gcpArgs.region = gcpConfig.region;
|
|
195
|
+
if (gcpConfig.zone) gcpArgs.zone = gcpConfig.zone;
|
|
196
|
+
if (gcpConfig.credentials)
|
|
197
|
+
gcpArgs.credentials = gcpConfig.credentials;
|
|
198
|
+
|
|
199
|
+
provider = new gcp.Provider(providerName, gcpArgs);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
default:
|
|
204
|
+
throw new Error(
|
|
205
|
+
`Unknown cloud provider "${cloud}" in providers config key "${key}".\n` +
|
|
206
|
+
` Supported prefixes: "aws", "gcp".`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
providers[key] = provider;
|
|
211
|
+
if (isDefault) {
|
|
212
|
+
defaultProviders[cloud] = provider;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// If no providers configured but defaults.tags is set,
|
|
218
|
+
// create implicit default providers to carry the tags.
|
|
219
|
+
if (!config.providers && config.defaults?.tags) {
|
|
220
|
+
const awsProvider = new aws.Provider('anvil-provider-aws', {
|
|
221
|
+
defaultTags: { tags: mergedTags },
|
|
222
|
+
});
|
|
223
|
+
providers['aws'] = awsProvider;
|
|
224
|
+
defaultProviders['aws'] = awsProvider;
|
|
225
|
+
|
|
226
|
+
const gcpProvider = new gcp.Provider('anvil-provider-gcp', {
|
|
227
|
+
defaultLabels: mergedTags,
|
|
228
|
+
});
|
|
229
|
+
providers['gcp'] = gcpProvider;
|
|
230
|
+
defaultProviders['gcp'] = gcpProvider;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ── Register default provider injection ────────────
|
|
234
|
+
if (Object.keys(defaultProviders).length > 0) {
|
|
235
|
+
pulumi.runtime.registerStackTransformation(
|
|
236
|
+
(
|
|
237
|
+
args: pulumi.ResourceTransformationArgs
|
|
238
|
+
): pulumi.ResourceTransformationResult | undefined => {
|
|
239
|
+
const typeParts = args.type.split(':');
|
|
240
|
+
let cloud: string | undefined;
|
|
241
|
+
|
|
242
|
+
if (typeParts[0] === 'anvil' && typeParts.length >= 3) {
|
|
243
|
+
cloud = typeParts[1];
|
|
244
|
+
} else if (typeParts.length >= 2) {
|
|
245
|
+
cloud = typeParts[0];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (cloud && defaultProviders[cloud] && !args.opts.provider) {
|
|
249
|
+
return {
|
|
250
|
+
props: args.props,
|
|
251
|
+
opts: pulumi.mergeOptions(args.opts, {
|
|
252
|
+
provider: defaultProviders[cloud],
|
|
253
|
+
}),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// ── Collect exports reference ──────────────────────
|
|
263
|
+
// We store exports on the App instance itself.
|
|
264
|
+
// Since the entry point does `export default new App(...)`,
|
|
265
|
+
// Pulumi picks up all enumerable properties as stack outputs.
|
|
266
|
+
const self = this;
|
|
267
|
+
|
|
268
|
+
// ── Create Context ─────────────────────────────────
|
|
269
|
+
const ctx: Context = {
|
|
270
|
+
stage,
|
|
271
|
+
project,
|
|
272
|
+
providers,
|
|
273
|
+
export(name: string, value: pulumi.Input<any>) {
|
|
274
|
+
self[name] = value;
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// ── Execute ────────────────────────────────────────
|
|
279
|
+
try {
|
|
280
|
+
config.run(ctx);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
throw error;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
package/bin/app.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as pulumi from '@pulumi/pulumi';
|
|
2
|
+
/**
|
|
3
|
+
* Context passed to the App's run callback.
|
|
4
|
+
* This is the user's only interface to Anvil runtime information.
|
|
5
|
+
*/
|
|
6
|
+
export interface Context {
|
|
7
|
+
/** The current deployment stage (e.g. "dev", "staging", "prod", or OS username). */
|
|
8
|
+
readonly stage: string;
|
|
9
|
+
/** The project name from anvil.yaml. */
|
|
10
|
+
readonly project: string;
|
|
11
|
+
/** Named providers, keyed by their config name (e.g. "aws", "aws.us", "gcp.eu"). */
|
|
12
|
+
readonly providers: Record<string, pulumi.ProviderResource>;
|
|
13
|
+
/** Export a stack output value without importing Pulumi. */
|
|
14
|
+
export(name: string, value: pulumi.Input<any>): void;
|
|
15
|
+
}
|
|
16
|
+
/** AWS provider configuration. */
|
|
17
|
+
export interface AwsProviderConfig {
|
|
18
|
+
region?: string;
|
|
19
|
+
profile?: string;
|
|
20
|
+
assumeRole?: {
|
|
21
|
+
roleArn: string;
|
|
22
|
+
sessionName?: string;
|
|
23
|
+
externalId?: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** GCP provider configuration. */
|
|
27
|
+
export interface GcpProviderConfig {
|
|
28
|
+
project?: string;
|
|
29
|
+
region?: string;
|
|
30
|
+
zone?: string;
|
|
31
|
+
credentials?: string;
|
|
32
|
+
}
|
|
33
|
+
/** Default options applied to all resources. */
|
|
34
|
+
export interface DefaultsConfig {
|
|
35
|
+
/**
|
|
36
|
+
* Tags merged into every taggable resource via the cloud provider's
|
|
37
|
+
* native defaultTags (AWS) or defaultLabels (GCP).
|
|
38
|
+
*
|
|
39
|
+
* `stage` and `project` are auto-injected. User tags override auto-injected ones.
|
|
40
|
+
* Per-resource tags override default tags.
|
|
41
|
+
*/
|
|
42
|
+
tags?: Record<string, string>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Configuration for the App class.
|
|
46
|
+
*/
|
|
47
|
+
export interface AppConfig {
|
|
48
|
+
/** The infrastructure definition callback. Required. */
|
|
49
|
+
run: (ctx: Context) => void;
|
|
50
|
+
/** Default resource options applied to all resources. */
|
|
51
|
+
defaults?: DefaultsConfig;
|
|
52
|
+
/**
|
|
53
|
+
* Named provider configurations.
|
|
54
|
+
* Keys follow the pattern "cloud" or "cloud.name":
|
|
55
|
+
* "aws" → default AWS provider
|
|
56
|
+
* "aws.us" → named AWS provider for US region
|
|
57
|
+
* "gcp" → default GCP provider
|
|
58
|
+
* "gcp.eu" → named GCP provider for EU
|
|
59
|
+
*/
|
|
60
|
+
providers?: Record<string, AwsProviderConfig | GcpProviderConfig>;
|
|
61
|
+
/**
|
|
62
|
+
* Called before the infrastructure program runs.
|
|
63
|
+
* @future Not yet implemented — reserved for forward compatibility.
|
|
64
|
+
*/
|
|
65
|
+
beforeDeploy?: (ctx: Context) => void;
|
|
66
|
+
/**
|
|
67
|
+
* Called after the infrastructure program completes successfully.
|
|
68
|
+
* @future CLI-side hook — not yet implemented.
|
|
69
|
+
*/
|
|
70
|
+
afterDeploy?: (ctx: Context) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Called if the infrastructure program throws an error.
|
|
73
|
+
* @future CLI-side hook — not yet implemented.
|
|
74
|
+
*/
|
|
75
|
+
onError?: (ctx: Context, error: Error) => void;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* App is the entry point for an Anvil infrastructure program.
|
|
79
|
+
*
|
|
80
|
+
* It wraps Pulumi's runtime so users never import `@pulumi/pulumi` directly.
|
|
81
|
+
* The constructor reads stage/project from Pulumi config, creates providers
|
|
82
|
+
* with default tags, and invokes the user's `run` callback with a Context.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* import { App } from "@anvil-cloud/sdk";
|
|
87
|
+
* import * as anvil from "@anvil-cloud/sdk";
|
|
88
|
+
*
|
|
89
|
+
* export default new App({
|
|
90
|
+
* defaults: {
|
|
91
|
+
* tags: { team: "platform" },
|
|
92
|
+
* },
|
|
93
|
+
* providers: {
|
|
94
|
+
* "aws": { region: "ap-southeast-2" },
|
|
95
|
+
* "aws.us": { region: "us-east-1" },
|
|
96
|
+
* },
|
|
97
|
+
* run(ctx) {
|
|
98
|
+
* const bucket = new anvil.aws.Bucket("my-data", {
|
|
99
|
+
* dataClassification: "sensitive",
|
|
100
|
+
* });
|
|
101
|
+
* ctx.export("bucketName", bucket.bucketName);
|
|
102
|
+
* },
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export declare class App {
|
|
107
|
+
/** Stack outputs collected via ctx.export(). */
|
|
108
|
+
[key: string]: any;
|
|
109
|
+
constructor(config: AppConfig);
|
|
110
|
+
}
|
package/bin/app.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.App = void 0;
|
|
4
|
+
const pulumi = require("@pulumi/pulumi");
|
|
5
|
+
const aws = require("@pulumi/aws");
|
|
6
|
+
const gcp = require("@pulumi/gcp");
|
|
7
|
+
// ── Helpers ────────────────────────────────────────────────
|
|
8
|
+
/**
|
|
9
|
+
* Determine which cloud a provider key belongs to.
|
|
10
|
+
* "aws" → "aws", "aws.us" → "aws", "gcp.eu" → "gcp"
|
|
11
|
+
*/
|
|
12
|
+
function getCloud(key) {
|
|
13
|
+
const dot = key.indexOf('.');
|
|
14
|
+
return dot === -1 ? key : key.substring(0, dot);
|
|
15
|
+
}
|
|
16
|
+
// ── App ────────────────────────────────────────────────────
|
|
17
|
+
/**
|
|
18
|
+
* App is the entry point for an Anvil infrastructure program.
|
|
19
|
+
*
|
|
20
|
+
* It wraps Pulumi's runtime so users never import `@pulumi/pulumi` directly.
|
|
21
|
+
* The constructor reads stage/project from Pulumi config, creates providers
|
|
22
|
+
* with default tags, and invokes the user's `run` callback with a Context.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { App } from "@anvil-cloud/sdk";
|
|
27
|
+
* import * as anvil from "@anvil-cloud/sdk";
|
|
28
|
+
*
|
|
29
|
+
* export default new App({
|
|
30
|
+
* defaults: {
|
|
31
|
+
* tags: { team: "platform" },
|
|
32
|
+
* },
|
|
33
|
+
* providers: {
|
|
34
|
+
* "aws": { region: "ap-southeast-2" },
|
|
35
|
+
* "aws.us": { region: "us-east-1" },
|
|
36
|
+
* },
|
|
37
|
+
* run(ctx) {
|
|
38
|
+
* const bucket = new anvil.aws.Bucket("my-data", {
|
|
39
|
+
* dataClassification: "sensitive",
|
|
40
|
+
* });
|
|
41
|
+
* ctx.export("bucketName", bucket.bucketName);
|
|
42
|
+
* },
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
class App {
|
|
47
|
+
constructor(config) {
|
|
48
|
+
// ── Read config from Pulumi ────────────────────────
|
|
49
|
+
const anvilConfig = new pulumi.Config('anvil');
|
|
50
|
+
const stage = anvilConfig.require('stage');
|
|
51
|
+
const project = pulumi.getProject();
|
|
52
|
+
// ── Build default tags ─────────────────────────────
|
|
53
|
+
const autoTags = { stage, project };
|
|
54
|
+
const userTags = config.defaults?.tags ?? {};
|
|
55
|
+
const mergedTags = { ...autoTags, ...userTags };
|
|
56
|
+
// ── Create providers ───────────────────────────────
|
|
57
|
+
const providers = {};
|
|
58
|
+
const defaultProviders = {};
|
|
59
|
+
if (config.providers) {
|
|
60
|
+
for (const [key, providerConfig] of Object.entries(config.providers)) {
|
|
61
|
+
const cloud = getCloud(key);
|
|
62
|
+
const isDefault = !key.includes('.');
|
|
63
|
+
const providerName = `anvil-provider-${key}`;
|
|
64
|
+
let provider;
|
|
65
|
+
switch (cloud) {
|
|
66
|
+
case 'aws': {
|
|
67
|
+
const awsConfig = providerConfig;
|
|
68
|
+
const awsArgs = {
|
|
69
|
+
defaultTags: { tags: mergedTags },
|
|
70
|
+
};
|
|
71
|
+
if (awsConfig.region)
|
|
72
|
+
awsArgs.region = awsConfig.region;
|
|
73
|
+
if (awsConfig.profile)
|
|
74
|
+
awsArgs.profile = awsConfig.profile;
|
|
75
|
+
if (awsConfig.assumeRole) {
|
|
76
|
+
awsArgs.assumeRoles = [
|
|
77
|
+
{
|
|
78
|
+
roleArn: awsConfig.assumeRole.roleArn,
|
|
79
|
+
sessionName: awsConfig.assumeRole.sessionName,
|
|
80
|
+
externalId: awsConfig.assumeRole.externalId,
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
provider = new aws.Provider(providerName, awsArgs);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case 'gcp': {
|
|
88
|
+
const gcpConfig = providerConfig;
|
|
89
|
+
const gcpArgs = {
|
|
90
|
+
defaultLabels: mergedTags,
|
|
91
|
+
};
|
|
92
|
+
if (gcpConfig.project)
|
|
93
|
+
gcpArgs.project = gcpConfig.project;
|
|
94
|
+
if (gcpConfig.region)
|
|
95
|
+
gcpArgs.region = gcpConfig.region;
|
|
96
|
+
if (gcpConfig.zone)
|
|
97
|
+
gcpArgs.zone = gcpConfig.zone;
|
|
98
|
+
if (gcpConfig.credentials)
|
|
99
|
+
gcpArgs.credentials = gcpConfig.credentials;
|
|
100
|
+
provider = new gcp.Provider(providerName, gcpArgs);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
default:
|
|
104
|
+
throw new Error(`Unknown cloud provider "${cloud}" in providers config key "${key}".\n` +
|
|
105
|
+
` Supported prefixes: "aws", "gcp".`);
|
|
106
|
+
}
|
|
107
|
+
providers[key] = provider;
|
|
108
|
+
if (isDefault) {
|
|
109
|
+
defaultProviders[cloud] = provider;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// If no providers configured but defaults.tags is set,
|
|
114
|
+
// create implicit default providers to carry the tags.
|
|
115
|
+
if (!config.providers && config.defaults?.tags) {
|
|
116
|
+
const awsProvider = new aws.Provider('anvil-provider-aws', {
|
|
117
|
+
defaultTags: { tags: mergedTags },
|
|
118
|
+
});
|
|
119
|
+
providers['aws'] = awsProvider;
|
|
120
|
+
defaultProviders['aws'] = awsProvider;
|
|
121
|
+
const gcpProvider = new gcp.Provider('anvil-provider-gcp', {
|
|
122
|
+
defaultLabels: mergedTags,
|
|
123
|
+
});
|
|
124
|
+
providers['gcp'] = gcpProvider;
|
|
125
|
+
defaultProviders['gcp'] = gcpProvider;
|
|
126
|
+
}
|
|
127
|
+
// ── Register default provider injection ────────────
|
|
128
|
+
if (Object.keys(defaultProviders).length > 0) {
|
|
129
|
+
pulumi.runtime.registerStackTransformation((args) => {
|
|
130
|
+
const typeParts = args.type.split(':');
|
|
131
|
+
let cloud;
|
|
132
|
+
if (typeParts[0] === 'anvil' && typeParts.length >= 3) {
|
|
133
|
+
cloud = typeParts[1];
|
|
134
|
+
}
|
|
135
|
+
else if (typeParts.length >= 2) {
|
|
136
|
+
cloud = typeParts[0];
|
|
137
|
+
}
|
|
138
|
+
if (cloud && defaultProviders[cloud] && !args.opts.provider) {
|
|
139
|
+
return {
|
|
140
|
+
props: args.props,
|
|
141
|
+
opts: pulumi.mergeOptions(args.opts, {
|
|
142
|
+
provider: defaultProviders[cloud],
|
|
143
|
+
}),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return undefined;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// ── Collect exports reference ──────────────────────
|
|
150
|
+
// We store exports on the App instance itself.
|
|
151
|
+
// Since the entry point does `export default new App(...)`,
|
|
152
|
+
// Pulumi picks up all enumerable properties as stack outputs.
|
|
153
|
+
const self = this;
|
|
154
|
+
// ── Create Context ─────────────────────────────────
|
|
155
|
+
const ctx = {
|
|
156
|
+
stage,
|
|
157
|
+
project,
|
|
158
|
+
providers,
|
|
159
|
+
export(name, value) {
|
|
160
|
+
self[name] = value;
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
// ── Execute ────────────────────────────────────────
|
|
164
|
+
try {
|
|
165
|
+
config.run(ctx);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.App = App;
|
|
173
|
+
//# sourceMappingURL=app.js.map
|
package/bin/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../app.ts"],"names":[],"mappings":"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"}
|
package/bin/index.d.ts
CHANGED
package/bin/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// *** WARNING: this file was generated by pulumi-language-nodejs. ***
|
|
3
3
|
// *** Do not edit by hand unless you're certain you know what you are doing! ***
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.types = exports.gcp = exports.aws = exports.Provider = void 0;
|
|
5
|
+
exports.App = exports.types = exports.gcp = exports.aws = exports.Provider = void 0;
|
|
6
6
|
const pulumi = require("@pulumi/pulumi");
|
|
7
7
|
const utilities = require("./utilities");
|
|
8
8
|
exports.Provider = null;
|
|
@@ -23,4 +23,7 @@ pulumi.runtime.registerResourcePackage("anvil", {
|
|
|
23
23
|
return new exports.Provider(name, undefined, { urn });
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
|
+
// Hand-written App class
|
|
27
|
+
var app_1 = require("./app");
|
|
28
|
+
Object.defineProperty(exports, "App", { enumerable: true, get: function () { return app_1.App; } });
|
|
26
29
|
//# sourceMappingURL=index.js.map
|
package/bin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,iFAAiF;;;AAEjF,yCAAyC;AACzC,yCAAyC;AAK5B,QAAA,QAAQ,GAAyC,IAAW,CAAC;AAC1E,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;AAGvE,sBAAsB;AACtB,6BAA6B;AAKzB,kBAAG;AAJP,6BAA6B;AAKzB,kBAAG;AAJP,iCAAiC;AAK7B,sBAAK;AAET,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,OAAO,EAAE;IAC5C,OAAO,EAAE,SAAS,CAAC,UAAU,EAAE;IAC/B,iBAAiB,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,GAAW,EAA2B,EAAE;QACpF,IAAI,IAAI,KAAK,wBAAwB,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;SACpD;QACD,OAAO,IAAI,gBAAQ,CAAC,IAAI,EAAO,SAAS,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACvD,CAAC;CACJ,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,iFAAiF;;;AAEjF,yCAAyC;AACzC,yCAAyC;AAK5B,QAAA,QAAQ,GAAyC,IAAW,CAAC;AAC1E,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;AAGvE,sBAAsB;AACtB,6BAA6B;AAKzB,kBAAG;AAJP,6BAA6B;AAKzB,kBAAG;AAJP,iCAAiC;AAK7B,sBAAK;AAET,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,OAAO,EAAE;IAC5C,OAAO,EAAE,SAAS,CAAC,UAAU,EAAE;IAC/B,iBAAiB,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,GAAW,EAA2B,EAAE;QACpF,IAAI,IAAI,KAAK,wBAAwB,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;SACpD;QACD,OAAO,IAAI,gBAAQ,CAAC,IAAI,EAAO,SAAS,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACvD,CAAC;CACJ,CAAC,CAAC;AAEH,yBAAyB;AACzB,6BAAsG;AAA7F,0FAAA,GAAG,OAAA"}
|
package/bin/package.json
CHANGED
package/index.ts
CHANGED