@geekmidas/cloud 10.0.0-alpha.12 → 10.0.0-alpha.14

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.
@@ -0,0 +1,209 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { Cache, CacheNeedsProvider, CacheNeedsVpc } from '../aws/Cache';
3
+ import { Database } from '../aws/Database';
4
+ import { DatabaseReader, DatabaseSchema } from '../aws/DerivedDatabase';
5
+ import { Email } from '../aws/Email';
6
+ import { FileServer } from '../aws/FileServer';
7
+ import { Queue } from '../aws/Queue';
8
+ import { RestApiSurface } from '../aws/RestApiSurface';
9
+ import { Secret } from '../aws/Secret';
10
+ import { StaticSite } from '../aws/StaticSite';
11
+ import { Storage } from '../aws/Storage';
12
+ import { Topic } from '../aws/Topic';
13
+ import { ResourceType } from '../Linkable';
14
+
15
+ /**
16
+ * What a linked function receives from each component, and the type that
17
+ * decides which variables a link provides. `getSSTLink()` is the payload SST
18
+ * injects into every handler linked to the resource; `_type` is what
19
+ * `LinkedEnvironment` keys the variable names off.
20
+ */
21
+
22
+ const stack = {} as never;
23
+ const vpc = { subnets: ['subnet-1'], securityGroups: ['sg-1'] } as never;
24
+
25
+ /** Resolves `$util.output(promise)`, which the stub leaves as the promise. */
26
+ const settle = async (value: unknown) =>
27
+ (value as { apply: (fn: (v: unknown) => unknown) => unknown }).apply(
28
+ (v) => v,
29
+ );
30
+
31
+ describe('link payloads', () => {
32
+ it('a queue adds its ARN and connection string to SST’s own link', () => {
33
+ const queue = new Queue(stack, 'Emails');
34
+
35
+ expect(queue._type).toBe(ResourceType.Queue);
36
+ // The connection string itself is parsed back in provides.spec; here, the
37
+ // link carries exactly what `provides()` resolved.
38
+ expect(queue.getSSTLink().properties).toEqual({
39
+ name: 'Emails',
40
+ arn: queue.arn,
41
+ ...queue.provides(),
42
+ });
43
+ });
44
+
45
+ it('a topic carries its publisher connection string', () => {
46
+ const topic = new Topic(stack, 'Users');
47
+
48
+ expect(topic._type).toBe(ResourceType.SnsTopic);
49
+ expect(topic.getSSTLink().properties).toEqual({
50
+ name: 'Users',
51
+ ...topic.provides(),
52
+ });
53
+ });
54
+
55
+ it('a secret carries its value', () => {
56
+ const secret = new Secret(stack, 'AuthSecret');
57
+
58
+ expect(secret._type).toBe(ResourceType.SSTSecret);
59
+ expect(secret.getSSTLink().properties).toMatchObject(secret.provides());
60
+ });
61
+
62
+ it('a mailer carries its URL and sending identity, and nothing else', () => {
63
+ const email = new Email(stack, 'Mail', {
64
+ backend: 'smtp',
65
+ url: 'smtp://relay.test:587',
66
+ from: 'hello@shop.test',
67
+ } as never);
68
+
69
+ expect(email._type).toBe(ResourceType.Email);
70
+ expect(email.getSSTLink()).toEqual({
71
+ properties: { url: 'smtp://relay.test:587', from: 'hello@shop.test' },
72
+ });
73
+ });
74
+
75
+ it('a file server routes everything to its bucket, and links its URL', () => {
76
+ const origin = new Storage(stack, 'Uploads');
77
+ const server = new FileServer(stack, 'Files', { origin } as never);
78
+
79
+ expect(origin._type).toBe(ResourceType.ObjectStorage);
80
+ expect(origin._id).toBe('Uploads');
81
+ expect(server._type).toBe(ResourceType.FileServer);
82
+ expect((server as unknown as { routed: unknown[] }).routed).toEqual([
83
+ { pattern: '/*', bucket: origin },
84
+ ]);
85
+ expect(server.getSSTLink().properties).toMatchObject({
86
+ url: server.url,
87
+ });
88
+ });
89
+
90
+ it('a site is built the way its variant builds, and links its URL', () => {
91
+ const vite = new StaticSite(stack, 'Web');
92
+ const next = new StaticSite(stack, 'Admin', {
93
+ variant: 'next',
94
+ build: { command: 'pnpm build:custom', output: 'out' },
95
+ } as never);
96
+ const args = (site: unknown) => (site as { args: { build: unknown } }).args;
97
+
98
+ expect(vite._type).toBe(ResourceType.StaticSite);
99
+ expect(args(vite).build).toEqual(expect.objectContaining({}));
100
+ // A build the caller supplied wins over the variant's.
101
+ expect(args(next).build).toEqual({
102
+ command: 'pnpm build:custom',
103
+ output: 'out',
104
+ });
105
+ expect(vite.getSSTLink().properties).toMatchObject({ url: vite.url });
106
+ });
107
+
108
+ it('a surface links its address and, once resolved, who may call it', async () => {
109
+ const bare = new RestApiSurface(stack, 'Api');
110
+ const called = new RestApiSurface(stack, 'Api', {
111
+ callers: Promise.resolve({
112
+ trustedOrigins: 'https://web.shop.test',
113
+ cookieDomain: 'shop.test',
114
+ }),
115
+ });
116
+
117
+ expect(bare._type).toBe(ResourceType.ApiGatewayV2);
118
+ expect(await settle(bare.provides().trustedOrigins)).toBe('');
119
+ expect(await settle(bare.provides().cookieDomain)).toBe('');
120
+
121
+ const link = called.getSSTLink().properties as Record<string, unknown>;
122
+ expect(link.url).toBe(called.url);
123
+ expect(await settle(link.trustedOrigins)).toBe('https://web.shop.test');
124
+ expect(await settle(link.cookieDomain)).toBe('shop.test');
125
+ });
126
+
127
+ it('a database and the nodes derived from it each link only their own URL', () => {
128
+ const cluster = new Database(stack, 'Orders', { vpc, schema: 'app' });
129
+ const reader = new DatabaseReader('OrdersReader', cluster);
130
+ const tenant = new DatabaseSchema('AuthDb', cluster, 'authdb');
131
+
132
+ expect(cluster._type).toBe(ResourceType.SSTPostgres);
133
+ expect(reader._type).toBe(ResourceType.SSTPostgres);
134
+ expect(tenant._type).toBe(ResourceType.SSTPostgres);
135
+ expect(cluster.getSSTLink().properties).toMatchObject({
136
+ url: cluster.provides().url,
137
+ });
138
+ // Least privilege: the reader's link is its URL and not the writer's.
139
+ expect(reader.getSSTLink()).toEqual({
140
+ properties: { url: reader.provides().url },
141
+ });
142
+ expect(tenant.getSSTLink()).toEqual({
143
+ properties: { url: tenant.provides().url },
144
+ });
145
+ });
146
+
147
+ it('a cache given its URL links it as-is', () => {
148
+ const cache = new Cache(stack, 'Sessions', {
149
+ backend: 'db',
150
+ url: 'postgres://db.test/app',
151
+ });
152
+
153
+ expect(cache._type).toBe(ResourceType.Cache);
154
+ expect(cache.getSSTLink()).toEqual({
155
+ properties: { url: 'postgres://db.test/app' },
156
+ });
157
+ });
158
+ });
159
+
160
+ describe('Cache on Upstash', () => {
161
+ /** `sst add upstash` installs this global; here, a recording stand-in. */
162
+ const created: { name: string; args: Record<string, unknown> }[] = [];
163
+ class RedisDatabase {
164
+ readonly endpoint = 'eu1-cache.upstash.io';
165
+ readonly restToken = 'tok/en+1';
166
+ constructor(name: string, args: Record<string, unknown>) {
167
+ created.push({ name, args });
168
+ }
169
+ }
170
+
171
+ it('creates a TLS database and puts its token in the URL', () => {
172
+ (globalThis as Record<string, unknown>).upstash = { RedisDatabase };
173
+ try {
174
+ const defaulted = new Cache(stack, 'Sessions', { backend: 'upstash' });
175
+ new Cache(stack, 'Rates', { backend: 'upstash', region: 'us-east-1' });
176
+
177
+ expect(created).toEqual([
178
+ {
179
+ name: 'SessionsCache',
180
+ args: { databaseName: 'Sessions', region: 'eu-west-1', tls: true },
181
+ },
182
+ {
183
+ name: 'RatesCache',
184
+ args: { databaseName: 'Rates', region: 'us-east-1', tls: true },
185
+ },
186
+ ]);
187
+ // The address and the credential that opens it are one fact.
188
+ expect(defaulted.provides().url).toBe(
189
+ `https://:${encodeURIComponent('tok/en+1')}@eu1-cache.upstash.io`,
190
+ );
191
+ } finally {
192
+ delete (globalThis as Record<string, unknown>).upstash;
193
+ }
194
+ });
195
+ });
196
+
197
+ describe('Cache provisioning refusals', () => {
198
+ it('asks for the Upstash provider when it is not installed', () => {
199
+ expect(() => new Cache(stack, 'Sessions', { backend: 'upstash' })).toThrow(
200
+ CacheNeedsProvider,
201
+ );
202
+ });
203
+
204
+ it('asks for a VPC before creating an ElastiCache', () => {
205
+ expect(
206
+ () => new Cache(stack, 'Sessions', { backend: 'elasticache' }),
207
+ ).toThrow(CacheNeedsVpc);
208
+ });
209
+ });
@@ -153,7 +153,7 @@ export class Api<
153
153
  // Fail the whole synth if any route is misconfigured, with one actionable
154
154
  // message per offending route.
155
155
  if (failures.length) {
156
- throw new Error(failures.map((f) => f.message).join('\n\n'));
156
+ throw new RoutesMissingEnvironment(id, failures);
157
157
  }
158
158
  }
159
159
 
@@ -307,3 +307,18 @@ export interface ApiProps<TAuthorizers extends Record<string, unknown> = {}>
307
307
  * may override it. */
308
308
  runtime?: sst.aws.FunctionArgs['runtime'];
309
309
  }
310
+
311
+ /**
312
+ * Routes that read variables nothing links or whitelists. Collected across
313
+ * every route so one synth reports all of them, each with its own suggestions,
314
+ * rather than stopping at the first.
315
+ */
316
+ export class RoutesMissingEnvironment extends Error {
317
+ constructor(
318
+ readonly api: string,
319
+ readonly failures: readonly EnvValidationError[],
320
+ ) {
321
+ super(failures.map((f) => f.message).join('\n\n'));
322
+ this.name = 'RoutesMissingEnvironment';
323
+ }
324
+ }
@@ -84,7 +84,21 @@ export class Database<
84
84
  * produces a database that looks empty.
85
85
  */
86
86
  provides(): Record<string, $util.Input<string>> {
87
- return { url: this.urlFor({}) };
87
+ return { url: this.urlFor(this.role ? { as: this.role } : {}) };
88
+ }
89
+
90
+ /**
91
+ * The runtime role this database's own handlers connect as.
92
+ *
93
+ * Set by the adapter once the bootstrap has registered the role — the
94
+ * cluster exists before any role does, so it cannot be a constructor
95
+ * argument. Until it is set (and under `roles: false`, where it never is),
96
+ * the URL is the master's.
97
+ */
98
+ private role: { user: string; password: $util.Input<string> } | undefined;
99
+
100
+ connectAs(role: { user: string; password: $util.Input<string> }): void {
101
+ this.role = role;
88
102
  }
89
103
 
90
104
  /**
@@ -232,13 +232,20 @@ const PROVISIONERS: Partial<Record<DeclarationKind, Provisioner>> = {
232
232
  const bootstrap = bootstrapFor(cluster, d.id, context);
233
233
  const runtime = roleNameFor(d, context);
234
234
 
235
- bootstrap?.add({
235
+ const credentials = bootstrap?.add({
236
236
  id: d.id,
237
237
  schema: d.schema,
238
238
  runtime,
239
239
  owner: ownerRole(runtime),
240
240
  ...(hasReader(d.id, context) ? { reader: readerRole(runtime) } : {}),
241
241
  });
242
+
243
+ // Registering the role was half of it: its handlers have to connect as
244
+ // it too, or the DDL creates a role nothing uses and every handler
245
+ // linked to the database still holds the master.
246
+ if (credentials) {
247
+ cluster.connectAs({ user: runtime, password: credentials.runtime });
248
+ }
242
249
  }
243
250
 
244
251
  return cluster;
@@ -1,64 +0,0 @@
1
- //#region src/utils/index.d.ts
2
- declare function getLocalIpAddress(): string | null;
3
- declare function environmentCase(name: string): string;
4
- declare enum ResourceType {
5
- ApiGatewayV2 = "sst.aws.ApiGatewayV2",
6
- Postgres = "sst.aws.Postgres",
7
- Function = "sst.aws.Function",
8
- ObjectStorage = "sst.aws.Bucket",
9
- Vpc = "sst.aws.Vpc",
10
- Secret = "sst.sst.Secret",
11
- SSTSecret = "sst:sst:Secret",
12
- SSTFunction = "sst:sst:Function",
13
- SSTApiGatewayV2 = "sst:aws:ApiGatewayV2",
14
- SSTPostgres = "sst:aws:Postgres",
15
- SSTObjectStorage = "sst:aws:Bucket",
16
- SnsTopic = "sst:aws:SnsTopic",
17
- }
18
- declare function buildResourceEnv(record: Record<string, Resource | string>): Record<string, string>;
19
- /**
20
- * SST links a resource under one of two spellings — `sst.aws.Bucket` when it
21
- * comes from the state file, `sst:aws:Bucket` when it comes from the runtime —
22
- * and `processors` has always handled both. Only the dotted half was admitted
23
- * here, so the colon half could not be passed to `buildResourceEnv` without a
24
- * cast, and `SnsTopic` was missing from `Resource` altogether despite being the
25
- * only thing that produces `*_ARN`.
26
- */
27
- type ApiGatewayV2 = {
28
- type: ResourceType.ApiGatewayV2 | ResourceType.SSTApiGatewayV2;
29
- url: string;
30
- };
31
- type Postgres = {
32
- database: string;
33
- host: string;
34
- password: string;
35
- port: number;
36
- type: ResourceType.Postgres | ResourceType.SSTPostgres;
37
- username: string;
38
- };
39
- type Function = {
40
- name: string;
41
- type: ResourceType.Function | ResourceType.SSTFunction;
42
- };
43
- type Bucket = {
44
- name: string;
45
- type: ResourceType.ObjectStorage | ResourceType.SSTObjectStorage;
46
- };
47
- type SnsTopic = {
48
- arn: string;
49
- type: ResourceType.SnsTopic;
50
- };
51
- type Vpc = {
52
- bastion: string;
53
- type: ResourceType.Vpc;
54
- };
55
- type Secret = {
56
- type: ResourceType.Secret | ResourceType.SSTSecret;
57
- value: string;
58
- };
59
- type Resource = ApiGatewayV2 | Postgres | Function | Bucket | SnsTopic | Vpc | Secret;
60
- type ResourceProcessor<K extends Resource> = (name: string, value: K) => Record<string, string | number>;
61
- //# sourceMappingURL=index.d.ts.map
62
- //#endregion
63
- export { ApiGatewayV2, Bucket, Function, Postgres, Resource, ResourceProcessor, ResourceType, Secret, SnsTopic, Vpc, buildResourceEnv, environmentCase, getLocalIpAddress };
64
- //# sourceMappingURL=index-B5CZ1xVf.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-B5CZ1xVf.d.cts","names":[],"sources":["../src/utils/index.ts"],"sourcesContent":[],"mappings":";iBAGgB,iBAAA,CAAA;AAAA,iBAcA,eAAA,CAdiB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAcjB,aAOJ,YAAA;EAAA,YAAA,GAAY,sBAAA;EA+DR,QAAA,GAAA,kBAAgB;EAAA,QAAA,GAAA,kBAAA;EAAA,aACR,GAAA,gBAAA;EAAQ,GAAvB,GAAA,aAAA;EAAM,MACZ,GAAA,gBAAA;EAAM,SAAA,GAAA,gBAAA;EA0BG,WAAA,GAAA,kBAAY;EAAA,eAAA,GAAA,sBAAA;EAAA,WACjB,GAAA,kBAAa;EAAY,gBAAgB,GAAA,gBAAA;EAAe,QAAA,GAAA,kBAAA;AAI/D;AAAoB,iBAjCJ,gBAAA,CAiCI,MAAA,EAhCX,MAgCW,CAAA,MAAA,EAhCI,QAgCJ,GAAA,MAAA,CAAA,CAAA,EA/BjB,MA+BiB,CAAA,MAAA,EAAA,MAAA,CAAA;;;AAKmC;AAIvD;;;;AAEuD;AAG3C,KAnBA,YAAA,GAmBM;EAAA,IAAA,EAlBX,YAAA,CAAa,YAkBF,GAlBiB,YAAA,CAAa,eAkB9B;EAAA,GAEX,EAAA,MAAA;CAA0B;AAAgC,KAhBrD,QAAA,GAgBqD;EAGrD,QAAA,EAAA,MAAQ;EAKR,IAAA,EAAG,MAAA;EAKH,QAAA,EAAM,MAAA;EAAA,IAAA,EAAA,MAAA;EAAA,IACX,EAzBA,YAAA,CAAa,QAyBA,GAzBW,YAAA,CAAa,WAyBxB;EAAM,QAAG,EAAA,MAAa;AAAS,CAAA;AAIvC,KAzBA,QAAA,GAyBQ;EAAA,IAAA,EAAA,MAAA;EAAA,IACjB,EAxBI,YAAA,CAAa,QAwBjB,GAxB4B,YAAA,CAAa,WAwBzC;CAAY;AAEZ,KAvBS,MAAA,GAuBT;EAAQ,IACR,EAAA,MAAA;EAAM,IACN,EAvBI,YAAA,CAAa,aAuBjB,GAvBiC,YAAA,CAAa,gBAuB9C;CAAQ;AAER,KAtBS,QAAA,GAsBT;EAAM,GAAA,EAAA,MAAA;EAEG,IAAA,EAtBL,YAAA,CAAa,QAsBS;CAAA;AAAW,KAnB5B,GAAA,GAmB4B;EAAQ,OAExC,EAAA,MAAA;EAAC,IACJ,EApBE,YAAA,CAAa,GAoBf;AAAM,CAAA;KAjBC,MAAA;QACL,YAAA,CAAa,SAAS,YAAA,CAAa;;;KAI9B,QAAA,GACT,eACA,WACA,WACA,SACA,WACA,MACA;KAES,4BAA4B,kCAEhC,MACH"}
@@ -1,64 +0,0 @@
1
- //#region src/utils/index.d.ts
2
- declare function getLocalIpAddress(): string | null;
3
- declare function environmentCase(name: string): string;
4
- declare enum ResourceType {
5
- ApiGatewayV2 = "sst.aws.ApiGatewayV2",
6
- Postgres = "sst.aws.Postgres",
7
- Function = "sst.aws.Function",
8
- ObjectStorage = "sst.aws.Bucket",
9
- Vpc = "sst.aws.Vpc",
10
- Secret = "sst.sst.Secret",
11
- SSTSecret = "sst:sst:Secret",
12
- SSTFunction = "sst:sst:Function",
13
- SSTApiGatewayV2 = "sst:aws:ApiGatewayV2",
14
- SSTPostgres = "sst:aws:Postgres",
15
- SSTObjectStorage = "sst:aws:Bucket",
16
- SnsTopic = "sst:aws:SnsTopic",
17
- }
18
- declare function buildResourceEnv(record: Record<string, Resource | string>): Record<string, string>;
19
- /**
20
- * SST links a resource under one of two spellings — `sst.aws.Bucket` when it
21
- * comes from the state file, `sst:aws:Bucket` when it comes from the runtime —
22
- * and `processors` has always handled both. Only the dotted half was admitted
23
- * here, so the colon half could not be passed to `buildResourceEnv` without a
24
- * cast, and `SnsTopic` was missing from `Resource` altogether despite being the
25
- * only thing that produces `*_ARN`.
26
- */
27
- type ApiGatewayV2 = {
28
- type: ResourceType.ApiGatewayV2 | ResourceType.SSTApiGatewayV2;
29
- url: string;
30
- };
31
- type Postgres = {
32
- database: string;
33
- host: string;
34
- password: string;
35
- port: number;
36
- type: ResourceType.Postgres | ResourceType.SSTPostgres;
37
- username: string;
38
- };
39
- type Function = {
40
- name: string;
41
- type: ResourceType.Function | ResourceType.SSTFunction;
42
- };
43
- type Bucket = {
44
- name: string;
45
- type: ResourceType.ObjectStorage | ResourceType.SSTObjectStorage;
46
- };
47
- type SnsTopic = {
48
- arn: string;
49
- type: ResourceType.SnsTopic;
50
- };
51
- type Vpc = {
52
- bastion: string;
53
- type: ResourceType.Vpc;
54
- };
55
- type Secret = {
56
- type: ResourceType.Secret | ResourceType.SSTSecret;
57
- value: string;
58
- };
59
- type Resource = ApiGatewayV2 | Postgres | Function | Bucket | SnsTopic | Vpc | Secret;
60
- type ResourceProcessor<K extends Resource> = (name: string, value: K) => Record<string, string | number>;
61
- //# sourceMappingURL=index.d.ts.map
62
- //#endregion
63
- export { ApiGatewayV2, Bucket, Function, Postgres, Resource, ResourceProcessor, ResourceType, Secret, SnsTopic, Vpc, buildResourceEnv, environmentCase, getLocalIpAddress };
64
- //# sourceMappingURL=index-DhHRjduZ.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-DhHRjduZ.d.mts","names":[],"sources":["../src/utils/index.ts"],"sourcesContent":[],"mappings":";iBAGgB,iBAAA,CAAA;AAAA,iBAcA,eAAA,CAdiB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAcjB,aAOJ,YAAA;EAAA,YAAA,GAAY,sBAAA;EA+DR,QAAA,GAAA,kBAAgB;EAAA,QAAA,GAAA,kBAAA;EAAA,aACR,GAAA,gBAAA;EAAQ,GAAvB,GAAA,aAAA;EAAM,MACZ,GAAA,gBAAA;EAAM,SAAA,GAAA,gBAAA;EA0BG,WAAA,GAAA,kBAAY;EAAA,eAAA,GAAA,sBAAA;EAAA,WACjB,GAAA,kBAAa;EAAY,gBAAgB,GAAA,gBAAA;EAAe,QAAA,GAAA,kBAAA;AAI/D;AAAoB,iBAjCJ,gBAAA,CAiCI,MAAA,EAhCX,MAgCW,CAAA,MAAA,EAhCI,QAgCJ,GAAA,MAAA,CAAA,CAAA,EA/BjB,MA+BiB,CAAA,MAAA,EAAA,MAAA,CAAA;;;AAKmC;AAIvD;;;;AAEuD;AAG3C,KAnBA,YAAA,GAmBM;EAAA,IAAA,EAlBX,YAAA,CAAa,YAkBF,GAlBiB,YAAA,CAAa,eAkB9B;EAAA,GAEX,EAAA,MAAA;CAA0B;AAAgC,KAhBrD,QAAA,GAgBqD;EAGrD,QAAA,EAAA,MAAQ;EAKR,IAAA,EAAG,MAAA;EAKH,QAAA,EAAM,MAAA;EAAA,IAAA,EAAA,MAAA;EAAA,IACX,EAzBA,YAAA,CAAa,QAyBA,GAzBW,YAAA,CAAa,WAyBxB;EAAM,QAAG,EAAA,MAAa;AAAS,CAAA;AAIvC,KAzBA,QAAA,GAyBQ;EAAA,IAAA,EAAA,MAAA;EAAA,IACjB,EAxBI,YAAA,CAAa,QAwBjB,GAxB4B,YAAA,CAAa,WAwBzC;CAAY;AAEZ,KAvBS,MAAA,GAuBT;EAAQ,IACR,EAAA,MAAA;EAAM,IACN,EAvBI,YAAA,CAAa,aAuBjB,GAvBiC,YAAA,CAAa,gBAuB9C;CAAQ;AAER,KAtBS,QAAA,GAsBT;EAAM,GAAA,EAAA,MAAA;EAEG,IAAA,EAtBL,YAAA,CAAa,QAsBS;CAAA;AAAW,KAnB5B,GAAA,GAmB4B;EAAQ,OAExC,EAAA,MAAA;EAAC,IACJ,EApBE,YAAA,CAAa,GAoBf;AAAM,CAAA;KAjBC,MAAA;QACL,YAAA,CAAa,SAAS,YAAA,CAAa;;;KAI9B,QAAA,GACT,eACA,WACA,WACA,SACA,WACA,MACA;KAES,4BAA4B,kCAEhC,MACH"}
@@ -1,129 +0,0 @@
1
- //#region rolldown:runtime
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
- key = keys[i];
11
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
- get: ((k) => from[k]).bind(null, key),
13
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
- });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
- value: mod,
20
- enumerable: true
21
- }) : target, mod));
22
-
23
- //#endregion
24
- const node_os = __toESM(require("node:os"));
25
- const lodash_snakecase = __toESM(require("lodash.snakecase"));
26
-
27
- //#region src/utils/index.ts
28
- function getLocalIpAddress() {
29
- const networkInterfaces = node_os.default.networkInterfaces();
30
- for (const interfaceName in networkInterfaces) {
31
- const addresses = networkInterfaces[interfaceName] || [];
32
- for (const addressInfo of addresses) if (addressInfo.family === "IPv4" && !addressInfo.internal) return addressInfo.address;
33
- }
34
- return null;
35
- }
36
- function environmentCase(name) {
37
- return (0, lodash_snakecase.default)(name).toUpperCase().replace(/_\d+/g, (r) => {
38
- return r.replace("_", "");
39
- });
40
- }
41
- let ResourceType = /* @__PURE__ */ function(ResourceType$1) {
42
- ResourceType$1["ApiGatewayV2"] = "sst.aws.ApiGatewayV2";
43
- ResourceType$1["Postgres"] = "sst.aws.Postgres";
44
- ResourceType$1["Function"] = "sst.aws.Function";
45
- ResourceType$1["ObjectStorage"] = "sst.aws.Bucket";
46
- ResourceType$1["Vpc"] = "sst.aws.Vpc";
47
- ResourceType$1["Secret"] = "sst.sst.Secret";
48
- ResourceType$1["SSTSecret"] = "sst:sst:Secret";
49
- ResourceType$1["SSTFunction"] = "sst:sst:Function";
50
- ResourceType$1["SSTApiGatewayV2"] = "sst:aws:ApiGatewayV2";
51
- ResourceType$1["SSTPostgres"] = "sst:aws:Postgres";
52
- ResourceType$1["SSTObjectStorage"] = "sst:aws:Bucket";
53
- ResourceType$1["SnsTopic"] = "sst:aws:SnsTopic";
54
- return ResourceType$1;
55
- }({});
56
- const secret = (name, value) => ({ [environmentCase(name)]: value.value });
57
- const postgres = (key, value) => {
58
- const prefix = `${environmentCase(key)}`;
59
- return {
60
- [`${prefix}_NAME`]: value.database,
61
- [`${prefix}_HOST`]: value.host,
62
- [`${prefix}_PASSWORD`]: value.password,
63
- [`${prefix}_PORT`]: value.port,
64
- [`${prefix}_USERNAME`]: value.username
65
- };
66
- };
67
- const bucket = (name, value) => {
68
- const prefix = `${environmentCase(name)}`;
69
- return { [`${prefix}_NAME`]: value.name };
70
- };
71
- const topic = (name, value) => {
72
- const prefix = `${environmentCase(name)}`;
73
- const key = `${prefix}_ARN`;
74
- return { [key]: value.arn };
75
- };
76
- const noop = (_name, _value) => ({});
77
- const processors = {
78
- [ResourceType.ApiGatewayV2]: noop,
79
- [ResourceType.Function]: noop,
80
- [ResourceType.Vpc]: noop,
81
- [ResourceType.Secret]: secret,
82
- [ResourceType.Postgres]: postgres,
83
- [ResourceType.ObjectStorage]: bucket,
84
- [ResourceType.SSTSecret]: secret,
85
- [ResourceType.SSTObjectStorage]: bucket,
86
- [ResourceType.SSTFunction]: noop,
87
- [ResourceType.SSTPostgres]: postgres,
88
- [ResourceType.SSTApiGatewayV2]: noop,
89
- [ResourceType.SnsTopic]: topic
90
- };
91
- function buildResourceEnv(record) {
92
- const env = {};
93
- for (const [k, value] of Object.entries(record)) {
94
- if (typeof value === "string") {
95
- env[environmentCase(k)] = value;
96
- continue;
97
- }
98
- const processor = processors[value.type];
99
- if (processor) Object.assign(env, processor(k, value));
100
- }
101
- return env;
102
- }
103
-
104
- //#endregion
105
- Object.defineProperty(exports, 'ResourceType', {
106
- enumerable: true,
107
- get: function () {
108
- return ResourceType;
109
- }
110
- });
111
- Object.defineProperty(exports, 'buildResourceEnv', {
112
- enumerable: true,
113
- get: function () {
114
- return buildResourceEnv;
115
- }
116
- });
117
- Object.defineProperty(exports, 'environmentCase', {
118
- enumerable: true,
119
- get: function () {
120
- return environmentCase;
121
- }
122
- });
123
- Object.defineProperty(exports, 'getLocalIpAddress', {
124
- enumerable: true,
125
- get: function () {
126
- return getLocalIpAddress;
127
- }
128
- });
129
- //# sourceMappingURL=utils-B1a2UuEO.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils-B1a2UuEO.cjs","names":["name: string","value: Secret","key: string","value: Postgres","value: Bucket","value: SnsTopic","_name: string","_value: any","processors: Record<ResourceType, ResourceProcessor<any>>","record: Record<string, Resource | string>","env: Record<string, string>"],"sources":["../src/utils/index.ts"],"sourcesContent":["import os from 'node:os';\nimport snakecase from 'lodash.snakecase';\n\nexport function getLocalIpAddress() {\n\tconst networkInterfaces = os.networkInterfaces();\n\tfor (const interfaceName in networkInterfaces) {\n\t\tconst addresses = networkInterfaces[interfaceName] || [];\n\t\tfor (const addressInfo of addresses) {\n\t\t\t// Look for an IPv4 address that is not internal (loopback)\n\t\t\tif (addressInfo.family === 'IPv4' && !addressInfo.internal) {\n\t\t\t\treturn addressInfo.address;\n\t\t\t}\n\t\t}\n\t}\n\treturn null; // No suitable IP address found\n}\n\nexport function environmentCase(name: string) {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => {\n\t\t\treturn r.replace('_', '');\n\t\t});\n}\nexport enum ResourceType {\n\tApiGatewayV2 = 'sst.aws.ApiGatewayV2',\n\tPostgres = 'sst.aws.Postgres',\n\tFunction = 'sst.aws.Function',\n\tObjectStorage = 'sst.aws.Bucket',\n\tVpc = 'sst.aws.Vpc',\n\tSecret = 'sst.sst.Secret',\n\tSSTSecret = 'sst:sst:Secret',\n\tSSTFunction = 'sst:sst:Function',\n\tSSTApiGatewayV2 = 'sst:aws:ApiGatewayV2',\n\tSSTPostgres = 'sst:aws:Postgres',\n\tSSTObjectStorage = 'sst:aws:Bucket',\n\tSnsTopic = 'sst:aws:SnsTopic',\n}\n\nconst secret = (name: string, value: Secret) => ({\n\t[environmentCase(name)]: value.value,\n});\nconst postgres = (key: string, value: Postgres) => {\n\tconst prefix = `${environmentCase(key)}`;\n\treturn {\n\t\t[`${prefix}_NAME`]: value.database,\n\t\t[`${prefix}_HOST`]: value.host,\n\t\t[`${prefix}_PASSWORD`]: value.password,\n\t\t[`${prefix}_PORT`]: value.port,\n\t\t[`${prefix}_USERNAME`]: value.username,\n\t};\n};\n\nconst bucket = (name: string, value: Bucket) => {\n\tconst prefix = `${environmentCase(name)}`;\n\treturn {\n\t\t[`${prefix}_NAME`]: value.name,\n\t};\n};\n\nconst topic = (name: string, value: SnsTopic) => {\n\tconst prefix = `${environmentCase(name)}`;\n\tconst key = `${prefix}_ARN`;\n\n\treturn {\n\t\t[key]: value.arn,\n\t};\n};\n\nconst noop = (_name: string, _value: any) => ({});\n\nconst processors: Record<ResourceType, ResourceProcessor<any>> = {\n\t[ResourceType.ApiGatewayV2]: noop,\n\t[ResourceType.Function]: noop,\n\t[ResourceType.Vpc]: noop,\n\t[ResourceType.Secret]: secret,\n\t[ResourceType.Postgres]: postgres,\n\t[ResourceType.ObjectStorage]: bucket,\n\n\t[ResourceType.SSTSecret]: secret,\n\t[ResourceType.SSTObjectStorage]: bucket,\n\t[ResourceType.SSTFunction]: noop,\n\t[ResourceType.SSTPostgres]: postgres,\n\t[ResourceType.SSTApiGatewayV2]: noop,\n\t[ResourceType.SnsTopic]: topic,\n};\n\nexport function buildResourceEnv(\n\trecord: Record<string, Resource | string>,\n): Record<string, string> {\n\tconst env: Record<string, string> = {};\n\tfor (const [k, value] of Object.entries(record)) {\n\t\tif (typeof value === 'string') {\n\t\t\tenv[environmentCase(k)] = value;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst processor = processors[value.type];\n\t\tif (processor) {\n\t\t\tObject.assign(env, processor(k, value));\n\t\t} else {\n\t\t}\n\t}\n\n\treturn env;\n}\n\n/**\n * SST links a resource under one of two spellings — `sst.aws.Bucket` when it\n * comes from the state file, `sst:aws:Bucket` when it comes from the runtime —\n * and `processors` has always handled both. Only the dotted half was admitted\n * here, so the colon half could not be passed to `buildResourceEnv` without a\n * cast, and `SnsTopic` was missing from `Resource` altogether despite being the\n * only thing that produces `*_ARN`.\n */\nexport type ApiGatewayV2 = {\n\ttype: ResourceType.ApiGatewayV2 | ResourceType.SSTApiGatewayV2;\n\turl: string;\n};\n\nexport type Postgres = {\n\tdatabase: string;\n\thost: string;\n\tpassword: string;\n\tport: number;\n\ttype: ResourceType.Postgres | ResourceType.SSTPostgres;\n\tusername: string;\n};\n\nexport type Function = {\n\tname: string;\n\ttype: ResourceType.Function | ResourceType.SSTFunction;\n};\n\nexport type Bucket = {\n\tname: string;\n\ttype: ResourceType.ObjectStorage | ResourceType.SSTObjectStorage;\n};\n\nexport type SnsTopic = {\n\tarn: string;\n\ttype: ResourceType.SnsTopic;\n};\n\nexport type Vpc = {\n\tbastion: string;\n\ttype: ResourceType.Vpc;\n};\n\nexport type Secret = {\n\ttype: ResourceType.Secret | ResourceType.SSTSecret;\n\tvalue: string;\n};\n\nexport type Resource =\n\t| ApiGatewayV2\n\t| Postgres\n\t| Function\n\t| Bucket\n\t| SnsTopic\n\t| Vpc\n\t| Secret;\n\nexport type ResourceProcessor<K extends Resource> = (\n\tname: string,\n\tvalue: K,\n) => Record<string, string | number>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,SAAgB,oBAAoB;CACnC,MAAM,oBAAoB,gBAAG,mBAAmB;AAChD,MAAK,MAAM,iBAAiB,mBAAmB;EAC9C,MAAM,YAAY,kBAAkB,kBAAkB,CAAE;AACxD,OAAK,MAAM,eAAe,UAEzB,KAAI,YAAY,WAAW,WAAW,YAAY,SACjD,QAAO,YAAY;CAGrB;AACD,QAAO;AACP;AAED,SAAgB,gBAAgBA,MAAc;AAC7C,QAAO,8BAAU,KAAK,CACpB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACxB,SAAO,EAAE,QAAQ,KAAK,GAAG;CACzB,EAAC;AACH;AACD,IAAY,wDAAL;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA;AAED,MAAM,SAAS,CAACA,MAAcC,WAAmB,GAC/C,gBAAgB,KAAK,GAAG,MAAM,MAC/B;AACD,MAAM,WAAW,CAACC,KAAaC,UAAoB;CAClD,MAAM,UAAU,EAAE,gBAAgB,IAAI,CAAC;AACvC,QAAO;IACJ,EAAE,OAAO,SAAS,MAAM;IACxB,EAAE,OAAO,SAAS,MAAM;IACxB,EAAE,OAAO,aAAa,MAAM;IAC5B,EAAE,OAAO,SAAS,MAAM;IACxB,EAAE,OAAO,aAAa,MAAM;CAC9B;AACD;AAED,MAAM,SAAS,CAACH,MAAcI,UAAkB;CAC/C,MAAM,UAAU,EAAE,gBAAgB,KAAK,CAAC;AACxC,QAAO,IACJ,EAAE,OAAO,SAAS,MAAM,KAC1B;AACD;AAED,MAAM,QAAQ,CAACJ,MAAcK,UAAoB;CAChD,MAAM,UAAU,EAAE,gBAAgB,KAAK,CAAC;CACxC,MAAM,OAAO,EAAE,OAAO;AAEtB,QAAO,GACL,MAAM,MAAM,IACb;AACD;AAED,MAAM,OAAO,CAACC,OAAeC,YAAiB,CAAE;AAEhD,MAAMC,aAA2D;EAC/D,aAAa,eAAe;EAC5B,aAAa,WAAW;EACxB,aAAa,MAAM;EACnB,aAAa,SAAS;EACtB,aAAa,WAAW;EACxB,aAAa,gBAAgB;EAE7B,aAAa,YAAY;EACzB,aAAa,mBAAmB;EAChC,aAAa,cAAc;EAC3B,aAAa,cAAc;EAC3B,aAAa,kBAAkB;EAC/B,aAAa,WAAW;AACzB;AAED,SAAgB,iBACfC,QACyB;CACzB,MAAMC,MAA8B,CAAE;AACtC,MAAK,MAAM,CAAC,GAAG,MAAM,IAAI,OAAO,QAAQ,OAAO,EAAE;AAChD,aAAW,UAAU,UAAU;AAC9B,OAAI,gBAAgB,EAAE,IAAI;AAC1B;EACA;EAED,MAAM,YAAY,WAAW,MAAM;AACnC,MAAI,UACH,QAAO,OAAO,KAAK,UAAU,GAAG,MAAM,CAAC;CAGxC;AAED,QAAO;AACP"}
@@ -1,83 +0,0 @@
1
- import os from "node:os";
2
- import snakecase from "lodash.snakecase";
3
-
4
- //#region src/utils/index.ts
5
- function getLocalIpAddress() {
6
- const networkInterfaces = os.networkInterfaces();
7
- for (const interfaceName in networkInterfaces) {
8
- const addresses = networkInterfaces[interfaceName] || [];
9
- for (const addressInfo of addresses) if (addressInfo.family === "IPv4" && !addressInfo.internal) return addressInfo.address;
10
- }
11
- return null;
12
- }
13
- function environmentCase(name) {
14
- return snakecase(name).toUpperCase().replace(/_\d+/g, (r) => {
15
- return r.replace("_", "");
16
- });
17
- }
18
- let ResourceType = /* @__PURE__ */ function(ResourceType$1) {
19
- ResourceType$1["ApiGatewayV2"] = "sst.aws.ApiGatewayV2";
20
- ResourceType$1["Postgres"] = "sst.aws.Postgres";
21
- ResourceType$1["Function"] = "sst.aws.Function";
22
- ResourceType$1["ObjectStorage"] = "sst.aws.Bucket";
23
- ResourceType$1["Vpc"] = "sst.aws.Vpc";
24
- ResourceType$1["Secret"] = "sst.sst.Secret";
25
- ResourceType$1["SSTSecret"] = "sst:sst:Secret";
26
- ResourceType$1["SSTFunction"] = "sst:sst:Function";
27
- ResourceType$1["SSTApiGatewayV2"] = "sst:aws:ApiGatewayV2";
28
- ResourceType$1["SSTPostgres"] = "sst:aws:Postgres";
29
- ResourceType$1["SSTObjectStorage"] = "sst:aws:Bucket";
30
- ResourceType$1["SnsTopic"] = "sst:aws:SnsTopic";
31
- return ResourceType$1;
32
- }({});
33
- const secret = (name, value) => ({ [environmentCase(name)]: value.value });
34
- const postgres = (key, value) => {
35
- const prefix = `${environmentCase(key)}`;
36
- return {
37
- [`${prefix}_NAME`]: value.database,
38
- [`${prefix}_HOST`]: value.host,
39
- [`${prefix}_PASSWORD`]: value.password,
40
- [`${prefix}_PORT`]: value.port,
41
- [`${prefix}_USERNAME`]: value.username
42
- };
43
- };
44
- const bucket = (name, value) => {
45
- const prefix = `${environmentCase(name)}`;
46
- return { [`${prefix}_NAME`]: value.name };
47
- };
48
- const topic = (name, value) => {
49
- const prefix = `${environmentCase(name)}`;
50
- const key = `${prefix}_ARN`;
51
- return { [key]: value.arn };
52
- };
53
- const noop = (_name, _value) => ({});
54
- const processors = {
55
- [ResourceType.ApiGatewayV2]: noop,
56
- [ResourceType.Function]: noop,
57
- [ResourceType.Vpc]: noop,
58
- [ResourceType.Secret]: secret,
59
- [ResourceType.Postgres]: postgres,
60
- [ResourceType.ObjectStorage]: bucket,
61
- [ResourceType.SSTSecret]: secret,
62
- [ResourceType.SSTObjectStorage]: bucket,
63
- [ResourceType.SSTFunction]: noop,
64
- [ResourceType.SSTPostgres]: postgres,
65
- [ResourceType.SSTApiGatewayV2]: noop,
66
- [ResourceType.SnsTopic]: topic
67
- };
68
- function buildResourceEnv(record) {
69
- const env = {};
70
- for (const [k, value] of Object.entries(record)) {
71
- if (typeof value === "string") {
72
- env[environmentCase(k)] = value;
73
- continue;
74
- }
75
- const processor = processors[value.type];
76
- if (processor) Object.assign(env, processor(k, value));
77
- }
78
- return env;
79
- }
80
-
81
- //#endregion
82
- export { ResourceType, buildResourceEnv, environmentCase, getLocalIpAddress };
83
- //# sourceMappingURL=utils-DMOXJ27j.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils-DMOXJ27j.mjs","names":["name: string","value: Secret","key: string","value: Postgres","value: Bucket","value: SnsTopic","_name: string","_value: any","processors: Record<ResourceType, ResourceProcessor<any>>","record: Record<string, Resource | string>","env: Record<string, string>"],"sources":["../src/utils/index.ts"],"sourcesContent":["import os from 'node:os';\nimport snakecase from 'lodash.snakecase';\n\nexport function getLocalIpAddress() {\n\tconst networkInterfaces = os.networkInterfaces();\n\tfor (const interfaceName in networkInterfaces) {\n\t\tconst addresses = networkInterfaces[interfaceName] || [];\n\t\tfor (const addressInfo of addresses) {\n\t\t\t// Look for an IPv4 address that is not internal (loopback)\n\t\t\tif (addressInfo.family === 'IPv4' && !addressInfo.internal) {\n\t\t\t\treturn addressInfo.address;\n\t\t\t}\n\t\t}\n\t}\n\treturn null; // No suitable IP address found\n}\n\nexport function environmentCase(name: string) {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => {\n\t\t\treturn r.replace('_', '');\n\t\t});\n}\nexport enum ResourceType {\n\tApiGatewayV2 = 'sst.aws.ApiGatewayV2',\n\tPostgres = 'sst.aws.Postgres',\n\tFunction = 'sst.aws.Function',\n\tObjectStorage = 'sst.aws.Bucket',\n\tVpc = 'sst.aws.Vpc',\n\tSecret = 'sst.sst.Secret',\n\tSSTSecret = 'sst:sst:Secret',\n\tSSTFunction = 'sst:sst:Function',\n\tSSTApiGatewayV2 = 'sst:aws:ApiGatewayV2',\n\tSSTPostgres = 'sst:aws:Postgres',\n\tSSTObjectStorage = 'sst:aws:Bucket',\n\tSnsTopic = 'sst:aws:SnsTopic',\n}\n\nconst secret = (name: string, value: Secret) => ({\n\t[environmentCase(name)]: value.value,\n});\nconst postgres = (key: string, value: Postgres) => {\n\tconst prefix = `${environmentCase(key)}`;\n\treturn {\n\t\t[`${prefix}_NAME`]: value.database,\n\t\t[`${prefix}_HOST`]: value.host,\n\t\t[`${prefix}_PASSWORD`]: value.password,\n\t\t[`${prefix}_PORT`]: value.port,\n\t\t[`${prefix}_USERNAME`]: value.username,\n\t};\n};\n\nconst bucket = (name: string, value: Bucket) => {\n\tconst prefix = `${environmentCase(name)}`;\n\treturn {\n\t\t[`${prefix}_NAME`]: value.name,\n\t};\n};\n\nconst topic = (name: string, value: SnsTopic) => {\n\tconst prefix = `${environmentCase(name)}`;\n\tconst key = `${prefix}_ARN`;\n\n\treturn {\n\t\t[key]: value.arn,\n\t};\n};\n\nconst noop = (_name: string, _value: any) => ({});\n\nconst processors: Record<ResourceType, ResourceProcessor<any>> = {\n\t[ResourceType.ApiGatewayV2]: noop,\n\t[ResourceType.Function]: noop,\n\t[ResourceType.Vpc]: noop,\n\t[ResourceType.Secret]: secret,\n\t[ResourceType.Postgres]: postgres,\n\t[ResourceType.ObjectStorage]: bucket,\n\n\t[ResourceType.SSTSecret]: secret,\n\t[ResourceType.SSTObjectStorage]: bucket,\n\t[ResourceType.SSTFunction]: noop,\n\t[ResourceType.SSTPostgres]: postgres,\n\t[ResourceType.SSTApiGatewayV2]: noop,\n\t[ResourceType.SnsTopic]: topic,\n};\n\nexport function buildResourceEnv(\n\trecord: Record<string, Resource | string>,\n): Record<string, string> {\n\tconst env: Record<string, string> = {};\n\tfor (const [k, value] of Object.entries(record)) {\n\t\tif (typeof value === 'string') {\n\t\t\tenv[environmentCase(k)] = value;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst processor = processors[value.type];\n\t\tif (processor) {\n\t\t\tObject.assign(env, processor(k, value));\n\t\t} else {\n\t\t}\n\t}\n\n\treturn env;\n}\n\n/**\n * SST links a resource under one of two spellings — `sst.aws.Bucket` when it\n * comes from the state file, `sst:aws:Bucket` when it comes from the runtime —\n * and `processors` has always handled both. Only the dotted half was admitted\n * here, so the colon half could not be passed to `buildResourceEnv` without a\n * cast, and `SnsTopic` was missing from `Resource` altogether despite being the\n * only thing that produces `*_ARN`.\n */\nexport type ApiGatewayV2 = {\n\ttype: ResourceType.ApiGatewayV2 | ResourceType.SSTApiGatewayV2;\n\turl: string;\n};\n\nexport type Postgres = {\n\tdatabase: string;\n\thost: string;\n\tpassword: string;\n\tport: number;\n\ttype: ResourceType.Postgres | ResourceType.SSTPostgres;\n\tusername: string;\n};\n\nexport type Function = {\n\tname: string;\n\ttype: ResourceType.Function | ResourceType.SSTFunction;\n};\n\nexport type Bucket = {\n\tname: string;\n\ttype: ResourceType.ObjectStorage | ResourceType.SSTObjectStorage;\n};\n\nexport type SnsTopic = {\n\tarn: string;\n\ttype: ResourceType.SnsTopic;\n};\n\nexport type Vpc = {\n\tbastion: string;\n\ttype: ResourceType.Vpc;\n};\n\nexport type Secret = {\n\ttype: ResourceType.Secret | ResourceType.SSTSecret;\n\tvalue: string;\n};\n\nexport type Resource =\n\t| ApiGatewayV2\n\t| Postgres\n\t| Function\n\t| Bucket\n\t| SnsTopic\n\t| Vpc\n\t| Secret;\n\nexport type ResourceProcessor<K extends Resource> = (\n\tname: string,\n\tvalue: K,\n) => Record<string, string | number>;\n"],"mappings":";;;;AAGA,SAAgB,oBAAoB;CACnC,MAAM,oBAAoB,GAAG,mBAAmB;AAChD,MAAK,MAAM,iBAAiB,mBAAmB;EAC9C,MAAM,YAAY,kBAAkB,kBAAkB,CAAE;AACxD,OAAK,MAAM,eAAe,UAEzB,KAAI,YAAY,WAAW,WAAW,YAAY,SACjD,QAAO,YAAY;CAGrB;AACD,QAAO;AACP;AAED,SAAgB,gBAAgBA,MAAc;AAC7C,QAAO,UAAU,KAAK,CACpB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACxB,SAAO,EAAE,QAAQ,KAAK,GAAG;CACzB,EAAC;AACH;AACD,IAAY,wDAAL;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA;AAED,MAAM,SAAS,CAACA,MAAcC,WAAmB,GAC/C,gBAAgB,KAAK,GAAG,MAAM,MAC/B;AACD,MAAM,WAAW,CAACC,KAAaC,UAAoB;CAClD,MAAM,UAAU,EAAE,gBAAgB,IAAI,CAAC;AACvC,QAAO;IACJ,EAAE,OAAO,SAAS,MAAM;IACxB,EAAE,OAAO,SAAS,MAAM;IACxB,EAAE,OAAO,aAAa,MAAM;IAC5B,EAAE,OAAO,SAAS,MAAM;IACxB,EAAE,OAAO,aAAa,MAAM;CAC9B;AACD;AAED,MAAM,SAAS,CAACH,MAAcI,UAAkB;CAC/C,MAAM,UAAU,EAAE,gBAAgB,KAAK,CAAC;AACxC,QAAO,IACJ,EAAE,OAAO,SAAS,MAAM,KAC1B;AACD;AAED,MAAM,QAAQ,CAACJ,MAAcK,UAAoB;CAChD,MAAM,UAAU,EAAE,gBAAgB,KAAK,CAAC;CACxC,MAAM,OAAO,EAAE,OAAO;AAEtB,QAAO,GACL,MAAM,MAAM,IACb;AACD;AAED,MAAM,OAAO,CAACC,OAAeC,YAAiB,CAAE;AAEhD,MAAMC,aAA2D;EAC/D,aAAa,eAAe;EAC5B,aAAa,WAAW;EACxB,aAAa,MAAM;EACnB,aAAa,SAAS;EACtB,aAAa,WAAW;EACxB,aAAa,gBAAgB;EAE7B,aAAa,YAAY;EACzB,aAAa,mBAAmB;EAChC,aAAa,cAAc;EAC3B,aAAa,cAAc;EAC3B,aAAa,kBAAkB;EAC/B,aAAa,WAAW;AACzB;AAED,SAAgB,iBACfC,QACyB;CACzB,MAAMC,MAA8B,CAAE;AACtC,MAAK,MAAM,CAAC,GAAG,MAAM,IAAI,OAAO,QAAQ,OAAO,EAAE;AAChD,aAAW,UAAU,UAAU;AAC9B,OAAI,gBAAgB,EAAE,IAAI;AAC1B;EACA;EAED,MAAM,YAAY,WAAW,MAAM;AACnC,MAAI,UACH,QAAO,OAAO,KAAK,UAAU,GAAG,MAAM,CAAC;CAGxC;AAED,QAAO;AACP"}