@geekmidas/cloud 10.0.0-alpha.11 → 10.0.0-alpha.13

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,192 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { App } from '../App';
3
+ import { Cron } from '../aws/Cron';
4
+ import { Function } from '../aws/Function';
5
+ import { type GkmLinkable, ResourceType } from '../Linkable';
6
+
7
+ /**
8
+ * A Lambda and a schedule as data: the args each hands SST (a recording stub
9
+ * in `test/sst-globals.ts`), and the env validation that fails before deploy.
10
+ */
11
+
12
+ const app = new App({
13
+ name: 'shop',
14
+ stage: 'prod',
15
+ domain: 'shop.test',
16
+ hostedZoneId: 'Z1',
17
+ region: 'eu-west-1',
18
+ });
19
+ const stack = app.stack('jobs');
20
+ const db: GkmLinkable = { _id: 'db', _type: ResourceType.Postgres };
21
+
22
+ const argsOf = (component: unknown) =>
23
+ (component as { args: Record<string, unknown> }).args;
24
+
25
+ describe('Function', () => {
26
+ it('defaults the runtime and logging, and links only what its variables need', () => {
27
+ const fn = new Function(stack, 'Reports', {
28
+ handler: 'reports.handler',
29
+ links: [db],
30
+ envVars: ['DB_URL'],
31
+ environment: { FEATURE: 'on' },
32
+ });
33
+
34
+ expect(fn._type).toBe(ResourceType.Function);
35
+ expect(argsOf(fn)).toMatchObject({
36
+ handler: 'reports.handler',
37
+ runtime: 'nodejs24.x',
38
+ logging: { format: 'json' },
39
+ link: [db],
40
+ environment: expect.objectContaining({
41
+ SERVICE_NAME: 'Reports',
42
+ STAGE: 'prod',
43
+ FEATURE: 'on',
44
+ }),
45
+ });
46
+ expect(fn.validate().valid).toBe(true);
47
+ });
48
+
49
+ it('keeps a runtime and logging it was given', () => {
50
+ const fn = new Function(stack, 'Legacy', {
51
+ handler: 'legacy.handler',
52
+ runtime: 'nodejs20.x',
53
+ logging: { format: 'text' },
54
+ });
55
+
56
+ expect(argsOf(fn)).toMatchObject({
57
+ runtime: 'nodejs20.x',
58
+ logging: { format: 'text' },
59
+ link: [],
60
+ });
61
+ });
62
+
63
+ it('fails the synth on a variable no link provides, unless told not to check', () => {
64
+ expect(
65
+ () =>
66
+ new Function(stack, 'Mailer', {
67
+ handler: 'mailer.handler',
68
+ envVars: ['SMTP_URL'],
69
+ }),
70
+ ).toThrow(/SMTP_URL/);
71
+
72
+ const unchecked = new Function(stack, 'Mailer', {
73
+ handler: 'mailer.handler',
74
+ envVars: ['SMTP_URL'],
75
+ autoValidate: false,
76
+ });
77
+ expect(unchecked.validate()).toMatchObject({
78
+ valid: false,
79
+ invalidVars: ['SMTP_URL'],
80
+ });
81
+ });
82
+
83
+ it('builds one function per manifest entry, named for the stack', () => {
84
+ const functions = Function.fromManifest(
85
+ stack,
86
+ {
87
+ billing: [
88
+ {
89
+ name: 'Invoice',
90
+ handler: '.gkm/aws-lambda/functions/invoice.handler',
91
+ environment: ['DB_URL'],
92
+ timeout: 60,
93
+ memorySize: 512,
94
+ },
95
+ ],
96
+ ops: [
97
+ {
98
+ name: 'Ping',
99
+ handler: '.gkm/aws-lambda/functions/ping.handler',
100
+ environment: [],
101
+ },
102
+ ],
103
+ } as never,
104
+ { links: [db] },
105
+ );
106
+
107
+ expect(functions.map((f) => argsOf(f))).toEqual([
108
+ expect.objectContaining({
109
+ name: stack.logicalPrefixedName('Invoice'),
110
+ timeout: '60 seconds',
111
+ memory: '512 MB',
112
+ link: [db],
113
+ }),
114
+ expect.objectContaining({
115
+ name: stack.logicalPrefixedName('Ping'),
116
+ timeout: undefined,
117
+ memory: undefined,
118
+ link: [],
119
+ }),
120
+ ]);
121
+ });
122
+ });
123
+
124
+ describe('Cron', () => {
125
+ it('schedules the function it is given, by ARN', () => {
126
+ const processor = { arn: 'arn:aws:lambda:eu-west-1:1:function:nightly' };
127
+ const cron = new Cron(stack, 'Nightly', {
128
+ processor: processor as never,
129
+ schedule: 'rate(1 day)',
130
+ enabled: false,
131
+ });
132
+
133
+ expect(argsOf(cron)).toEqual({
134
+ enabled: false,
135
+ schedule: 'rate(1 day)',
136
+ function: processor.arn,
137
+ });
138
+ });
139
+
140
+ it('builds a validated function and a schedule per manifest cron', () => {
141
+ const crons = Cron.fromManifest(
142
+ stack,
143
+ [
144
+ {
145
+ name: 'Digest',
146
+ handler: '.gkm/aws-lambda/crons/digest.handler',
147
+ schedule: 'cron(0 8 * * ? *)',
148
+ environment: ['DB_URL'],
149
+ timeout: 120,
150
+ memorySize: 1024,
151
+ },
152
+ {
153
+ name: 'Sweep',
154
+ handler: '.gkm/aws-lambda/crons/sweep.handler',
155
+ schedule: 'rate(1 hour)',
156
+ environment: [],
157
+ },
158
+ ] as never,
159
+ { links: [db], enabled: true },
160
+ );
161
+
162
+ const [digest, sweep] = crons.map((c) => argsOf(c));
163
+ expect(digest).toMatchObject({
164
+ schedule: 'cron(0 8 * * ? *)',
165
+ enabled: true,
166
+ function: expect.stringContaining('DigestFunction'),
167
+ });
168
+ expect(sweep).toMatchObject({ schedule: 'rate(1 hour)' });
169
+ });
170
+ });
171
+
172
+ describe('App and Stack', () => {
173
+ it('pick a value for the stage, falling back to the default', () => {
174
+ expect(app.select({ prod: 'live', default: 'test' })).toBe('live');
175
+ expect(stack.select({ staging: 'test', default: 'dev' } as never)).toBe(
176
+ 'dev',
177
+ );
178
+ });
179
+
180
+ it('name subdomains and URLs under the root domain', () => {
181
+ expect(stack.domain).toBe('shop.test');
182
+ expect(stack.getSubdomain('api')).toBe('api.shop.test');
183
+ expect(stack.getURL('api')).toBe('https://api.shop.test');
184
+ expect(stack.getURL()).toBe('https://shop.test');
185
+ expect(app.getURL()).toBe('https://shop.test');
186
+ });
187
+
188
+ it('prefix physical names with the stage, app and stack', () => {
189
+ expect(app.logicalPrefixedName('Uploads')).toBe('prod-shop-uploads');
190
+ expect(stack.logicalPrefixedName('Uploads')).toBe('prod-shop-jobs-uploads');
191
+ });
192
+ });
@@ -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
+ });
@@ -206,7 +206,7 @@ export function withCacheTable(url: string, table: string): string {
206
206
  }
207
207
 
208
208
  /**
209
- * `services.cache: 'db'` in an app that declares more than one database.
209
+ * A `'db'` cache in an app that declares more than one database.
210
210
  *
211
211
  * Picking one would put the cache somewhere nobody chose, and the symptom —
212
212
  * entries that are never found — appears long after the deploy reported
@@ -222,7 +222,7 @@ export class CacheIsAmbiguous extends Error {
222
222
  `'${id}' is a cache backed by the database, and this app declares ` +
223
223
  `${databases.length}: ${databases.join(', ')}. Declare the cache from ` +
224
224
  `its database — e.g. ${databases[0]}.cache('${id}') — rather than ` +
225
- `with services.cache.`,
225
+ `as a bare new Cache().`,
226
226
  );
227
227
  this.name = 'CacheIsAmbiguous';
228
228
  }
@@ -232,8 +232,8 @@ export class CacheNeedsDatabase extends Error {
232
232
  constructor(readonly id: string) {
233
233
  super(
234
234
  `'${id}' is a cache backed by the database, and this app declares no ` +
235
- `database for it to live in. Declare one, or set services.cache to ` +
236
- `'upstash' or 'elasticache'.`,
235
+ `database for it to live in. Declare one, or declare the cache from ` +
236
+ `the database it belongs to.`,
237
237
  );
238
238
  this.name = 'CacheNeedsDatabase';
239
239
  }
@@ -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
  /**
@@ -98,8 +98,8 @@ export interface ProvisionContext {
98
98
  /**
99
99
  * Where a declared cache lives, and who delivers mail.
100
100
  *
101
- * Deployment choices rather than declarations, for the same reason
102
- * `services.events` is: the same application code caches into any of them and
101
+ * Deployment choices rather than declarations, for the same reason the
102
+ * event broker is: the same application code caches into any of them and
103
103
  * sends through any of them. They reach the provisioner here because it is
104
104
  * the only place that knows both the choice and the manifest.
105
105
  */
@@ -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"}