@geekmidas/cloud 10.0.0-alpha.5 → 10.0.0-alpha.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +14 -6
  2. package/dist/index.cjs +3 -3
  3. package/dist/index.d.cts +1 -1
  4. package/dist/index.d.mts +1 -1
  5. package/dist/index.mjs +2 -3
  6. package/dist/utils/index.cjs +106 -5
  7. package/dist/utils/index.cjs.map +1 -0
  8. package/dist/utils/index.d.cts +62 -2
  9. package/dist/utils/index.d.cts.map +1 -0
  10. package/dist/utils/index.d.mts +62 -2
  11. package/dist/utils/index.d.mts.map +1 -0
  12. package/dist/utils/index.mjs +78 -2
  13. package/dist/utils/index.mjs.map +1 -0
  14. package/package.json +7 -7
  15. package/src/dokploy/Application.ts +52 -5
  16. package/src/dokploy/__tests__/Application.provider.spec.ts +206 -0
  17. package/src/sst/__tests__/api.spec.ts +185 -0
  18. package/src/sst/__tests__/encryption.spec.ts +90 -0
  19. package/src/sst/__tests__/fromManifest.integration.spec.ts +427 -0
  20. package/src/sst/__tests__/fromManifest.spec.ts +306 -5
  21. package/src/sst/__tests__/function.spec.ts +121 -0
  22. package/src/sst/__tests__/links.spec.ts +209 -0
  23. package/src/sst/__tests__/surfaces.spec.ts +17 -0
  24. package/src/sst/aws/Api.ts +16 -44
  25. package/src/sst/aws/Cache.ts +4 -4
  26. package/src/sst/aws/Credential.ts +42 -9
  27. package/src/sst/aws/Cron.ts +5 -45
  28. package/src/sst/aws/Database.ts +15 -1
  29. package/src/sst/aws/DatabaseBootstrap.ts +3 -0
  30. package/src/sst/aws/Encryption.ts +91 -0
  31. package/src/sst/aws/ExternalApi.ts +58 -0
  32. package/src/sst/aws/Function.ts +9 -38
  33. package/src/sst/aws/Queue.ts +34 -1
  34. package/src/sst/aws/RestApiSurface.ts +36 -14
  35. package/src/sst/aws/bootstrap/handler.ts +10 -1
  36. package/src/sst/fromManifest.ts +229 -20
  37. package/src/sst/index.ts +1 -0
  38. package/dist/index-B5CZ1xVf.d.cts +0 -64
  39. package/dist/index-B5CZ1xVf.d.cts.map +0 -1
  40. package/dist/index-DhHRjduZ.d.mts +0 -64
  41. package/dist/index-DhHRjduZ.d.mts.map +0 -1
  42. package/dist/utils-B1a2UuEO.cjs +0 -129
  43. package/dist/utils-B1a2UuEO.cjs.map +0 -1
  44. package/dist/utils-DMOXJ27j.mjs +0 -83
  45. package/dist/utils-DMOXJ27j.mjs.map +0 -1
  46. package/src/sst/__type-tests__/manifest.type-test.ts +0 -77
@@ -28,6 +28,11 @@ export interface BootstrapTenant {
28
28
  runtime: string;
29
29
  owner: string;
30
30
  reader?: string;
31
+ /**
32
+ * The database's own roles rather than a tenant's: its owner may create in
33
+ * the database, for trusted extensions.
34
+ */
35
+ ownsDatabase?: boolean;
31
36
  passwords: { runtime: string; owner: string; reader?: string };
32
37
  }
33
38
 
@@ -75,7 +80,11 @@ export async function handler(event: BootstrapEvent): Promise<BootstrapResult> {
75
80
 
76
81
  try {
77
82
  for (const tenant of event.tenants) {
78
- for (const statement of roleStatements(tenant)) {
83
+ const spec = {
84
+ ...tenant,
85
+ ...(tenant.ownsDatabase ? { database: event.master.database } : {}),
86
+ };
87
+ for (const statement of roleStatements(spec)) {
79
88
  if (statement.exists) {
80
89
  const { rows } = await client.query(
81
90
  statement.exists.sql,
@@ -26,10 +26,12 @@ import {
26
26
  cookieDomain,
27
27
  DEFAULT_POSTGRES_VERSION,
28
28
  dependentsOf,
29
+ mobileOrigins,
29
30
  PUBLIC,
30
31
  PUBLIC_PREFIX,
31
32
  providedKeyFor,
32
33
  provisionOrder,
34
+ schemeBase,
33
35
  } from '@geekmidas/manifest';
34
36
  import {
35
37
  Cache,
@@ -39,11 +41,15 @@ import {
39
41
  withCacheTable,
40
42
  } from './aws/Cache';
41
43
  import { Credential } from './aws/Credential';
42
- import { Database, DatabaseNeedsVpc } from './aws/Database';
44
+ import { Cron, type CronSchedule } from './aws/Cron';
45
+ import { Database, DatabaseNeedsVpc, type DatabaseProps } from './aws/Database';
43
46
  import { DatabaseBootstrap } from './aws/DatabaseBootstrap';
44
47
  import { DatabaseReader, DatabaseSchema } from './aws/DerivedDatabase';
45
48
  import { Email, EmailNeedsSender } from './aws/Email';
49
+ import { Encryption, type EncryptionProps } from './aws/Encryption';
50
+ import { ExternalApi, type ExternalApiProps } from './aws/ExternalApi';
46
51
  import { FileServer } from './aws/FileServer';
52
+ import { Function } from './aws/Function';
47
53
  import { ObjectStorage } from './aws/ObjectStorage';
48
54
  import { Queue } from './aws/Queue';
49
55
  import { RestApiSurface } from './aws/RestApiSurface';
@@ -98,8 +104,8 @@ export interface ProvisionContext {
98
104
  /**
99
105
  * Where a declared cache lives, and who delivers mail.
100
106
  *
101
- * Deployment choices rather than declarations, for the same reason
102
- * `services.events` is: the same application code caches into any of them and
107
+ * Deployment choices rather than declarations, for the same reason the
108
+ * event broker is: the same application code caches into any of them and
103
109
  * sends through any of them. They reach the provisioner here because it is
104
110
  * the only place that knows both the choice and the manifest.
105
111
  */
@@ -220,7 +226,11 @@ const PROVISIONERS: Partial<Record<DeclarationKind, Provisioner>> = {
220
226
  // rather than whatever Aurora defaults to that month. Local ran 18
221
227
  // while this ran 17.7, and neither was written down anywhere.
222
228
  version: String(d.version ?? DEFAULT_POSTGRES_VERSION),
223
- ...(props as unknown as sst.aws.PostgresArgs),
229
+ // `DatabaseProps`, not `sst.aws.PostgresArgs`: the database needs the
230
+ // `Vpc` component itself (its bootstrap function runs in the same VPC
231
+ // and needs the security groups too), where RDS would accept bare
232
+ // subnet ids. TS 7 checks the spread; 6 let the wider type through.
233
+ ...(props as unknown as Omit<DatabaseProps, 'schema'>),
224
234
  });
225
235
 
226
236
  // A database needs its own roles, not just its tenants'. Registering only
@@ -232,13 +242,21 @@ const PROVISIONERS: Partial<Record<DeclarationKind, Provisioner>> = {
232
242
  const bootstrap = bootstrapFor(cluster, d.id, context);
233
243
  const runtime = roleNameFor(d, context);
234
244
 
235
- bootstrap?.add({
245
+ const credentials = bootstrap?.add({
236
246
  id: d.id,
237
247
  schema: d.schema,
238
248
  runtime,
239
249
  owner: ownerRole(runtime),
250
+ ownsDatabase: true,
240
251
  ...(hasReader(d.id, context) ? { reader: readerRole(runtime) } : {}),
241
252
  });
253
+
254
+ // Registering the role was half of it: its handlers have to connect as
255
+ // it too, or the DDL creates a role nothing uses and every handler
256
+ // linked to the database still holds the master.
257
+ if (credentials) {
258
+ cluster.connectAs({ user: runtime, password: credentials.runtime });
259
+ }
242
260
  }
243
261
 
244
262
  return cluster;
@@ -363,17 +381,12 @@ const PROVISIONERS: Partial<Record<DeclarationKind, Provisioner>> = {
363
381
  },
364
382
 
365
383
  /**
366
- * The surface, without its routes.
367
- *
368
- * An API Gateway with no routes 404s everything, and that is the honest
369
- * state: the *surface* is what this kind declares, and mounting handlers on
370
- * it is the endpoint merge that has not landed — routes still reach the
371
- * deploy target through the separate `RouteInfo[]` pipeline.
384
+ * The surface, without its routes yet.
372
385
  *
373
- * Provisioning it anyway is not ceremony. Its address is what a site inlines
374
- * as `VITE_API_URL`, what an auth server puts on its trusted-origin list, and
375
- * what the cookie domain derives from — so everything downstream of the API
376
- * is blocked on the API *existing*, not on it answering.
386
+ * Its address is what a site inlines as `VITE_API_URL`, what an auth server
387
+ * puts on its trusted-origin list, and what the cookie domain derives from —
388
+ * so it is provisioned in order, and its endpoints are mounted by
389
+ * {@link mountRoutes} once everything they link to exists.
377
390
  */
378
391
  'rest-api': (stack, d, props, context) =>
379
392
  new RestApiSurface(stack, d.id, {
@@ -385,6 +398,30 @@ const PROVISIONERS: Partial<Record<DeclarationKind, Provisioner>> = {
385
398
 
386
399
  // The same storage as a secret, under a different role — see the component.
387
400
  credential: (stack, d, props) => new Credential(stack, d.id, props),
401
+
402
+ // In the stage's region, as mail is: a key in another region is a key
403
+ // every call crosses the world to reach.
404
+ encryption: (stack, d, props) =>
405
+ new Encryption(stack, d.id, {
406
+ ...(props as Partial<EncryptionProps>),
407
+ region:
408
+ (props as Partial<EncryptionProps>).region ??
409
+ $app.providers?.aws?.region ??
410
+ 'us-east-1',
411
+ }),
412
+
413
+ // Nothing to provision: the URL this stage calls, and the credentials kept
414
+ // as a secret.
415
+ 'external-api': (stack, d, props) => {
416
+ if (d.kind !== 'external-api') {
417
+ throw new UnknownDeclarationKind(d.kind, []);
418
+ }
419
+
420
+ return new ExternalApi(stack, d.id, {
421
+ ...(props as Partial<ExternalApiProps>),
422
+ url: d.url,
423
+ });
424
+ },
388
425
  };
389
426
 
390
427
  /**
@@ -565,9 +602,7 @@ function rootCluster(component: Provisioned): Database {
565
602
  * printed: one line per route, naming what it can reach.
566
603
  *
567
604
  * A surface with no routes says so rather than printing nothing, because "no
568
- * routes yet" and "this printed nothing" look identical otherwise — and for an
569
- * application's own API that is currently the true state, pending the endpoint
570
- * merge.
605
+ * routes" and "this printed nothing" look identical otherwise.
571
606
  *
572
607
  * Pure, so what gets printed can be asserted without a deploy.
573
608
  */
@@ -636,6 +671,8 @@ async function callersOf(
636
671
  id: string,
637
672
  manifest: ConstructManifest,
638
673
  provisioned: ProvisionedManifest,
674
+ /** The app's name — a mobile caller's scheme base when it gives none. */
675
+ project: string,
639
676
  ): Promise<{ trustedOrigins: string; cookieDomain?: string }> {
640
677
  // Every address here is a Pulumi output, not a string — a CloudFront domain
641
678
  // and an API Gateway endpoint are both known only after their resource
@@ -660,8 +697,17 @@ async function callersOf(
660
697
  const own = await resolved(provisioned[id]?.provides().url);
661
698
  const domain = cookieDomain([...(own ? [own] : []), ...origins]);
662
699
 
700
+ // A mobile caller is reached by its scheme — the bare one, deployed: what
701
+ // the store build registers.
702
+ const schemes = dependentsOf(manifest, id).flatMap((caller) => {
703
+ const app = manifest[caller];
704
+ return app?.kind === 'mobile-app'
705
+ ? mobileOrigins(schemeBase(project, app.scheme))
706
+ : [];
707
+ });
708
+
663
709
  return {
664
- trustedOrigins: origins.join(','),
710
+ trustedOrigins: [...origins, ...schemes].join(','),
665
711
  ...(domain ? { cookieDomain: domain } : {}),
666
712
  };
667
713
  }
@@ -711,6 +757,162 @@ export function isServed(id: string, manifest: ConstructManifest): boolean {
711
757
  );
712
758
  }
713
759
 
760
+ /**
761
+ * Kinds the in-order pass skips.
762
+ *
763
+ * - `mobile-app` ships through EAS and the stores. It is in the manifest for
764
+ * what it makes the surfaces trust, which `callersOf` reads off the graph.
765
+ * - `worker` is a process, not a resource: what it runs is provisioned as
766
+ * what it is — a queue's consumer by {@link subscribeConsumers}.
767
+ * - `cron` and `function` are Lambdas linked to what they depend on, so they
768
+ * are provisioned once all of it exists, by {@link provisionCompute}.
769
+ */
770
+ export const PROVISIONED_ELSEWHERE: ReadonlySet<DeclarationKind> =
771
+ new Set<DeclarationKind>(['mobile-app', 'worker', 'cron', 'function']);
772
+
773
+ /**
774
+ * Every function and cron: a Lambda running the handler the build wrote,
775
+ * linked to exactly what it depends on, in the database's network when it
776
+ * reaches one. A cron is that Lambda on its schedule; a function is reached
777
+ * at its URL, which only callers granted IAM access can invoke.
778
+ *
779
+ * After everything else is provisioned, because each links to things
780
+ * `provisionOrder` does not order before it.
781
+ */
782
+ export function provisionCompute(
783
+ stack: StackType,
784
+ manifest: ConstructManifest,
785
+ provisioned: ProvisionedManifest,
786
+ ): Cron[] {
787
+ const crons: Cron[] = [];
788
+
789
+ for (const [id, declaration] of Object.entries(manifest)) {
790
+ if (declaration?.kind !== 'function' && declaration?.kind !== 'cron') {
791
+ continue;
792
+ }
793
+
794
+ const { link } = resolveEdges(declaration.dependencies, provisioned);
795
+ const vpc = vpcFor(link);
796
+ const lambda = new Function(
797
+ stack,
798
+ declaration.kind === 'cron' ? `${id}Function` : id,
799
+ {
800
+ name: stack.logicalPrefixedName(id),
801
+ handler: declaration.handler,
802
+ link,
803
+ ...(vpc ? { vpc } : {}),
804
+ ...(declaration.kind === 'function'
805
+ ? { url: { authorization: 'iam' } }
806
+ : {}),
807
+ },
808
+ );
809
+
810
+ if (declaration.kind === 'cron') {
811
+ crons.push(
812
+ new Cron(stack, id, {
813
+ processor: lambda,
814
+ schedule: declaration.schedule as CronSchedule,
815
+ }),
816
+ );
817
+ continue;
818
+ }
819
+
820
+ assertProvides(
821
+ id,
822
+ declaration.provides,
823
+ Object.keys(lambda.provides()).map((role) =>
824
+ providedKeyFor(id, declaration.kind, role),
825
+ ),
826
+ );
827
+ provisioned[id] = lambda;
828
+ }
829
+
830
+ return crons;
831
+ }
832
+
833
+ /** A provisioned queue: what {@link subscribeConsumers} subscribes through. */
834
+ interface Consumable {
835
+ consume(consumer: {
836
+ handler: string;
837
+ link?: unknown[];
838
+ vpc?: sst.aws.Vpc;
839
+ }): unknown;
840
+ }
841
+
842
+ /**
843
+ * The network a function has to run in to reach what it links to.
844
+ *
845
+ * A database is private to its VPC, so a handler linked to one — or to a
846
+ * schema tenant or reader of one — runs inside it, or its connection times out.
847
+ */
848
+ export function vpcFor(link: readonly Provisioned[]): sst.aws.Vpc | undefined {
849
+ for (const component of link) {
850
+ const cluster = rootCluster(component);
851
+ if (cluster instanceof Database) return cluster.vpc;
852
+ }
853
+
854
+ return undefined;
855
+ }
856
+
857
+ /**
858
+ * Mount every surface's endpoints — the handlers the build wrote, each linked
859
+ * to exactly what that endpoint depends on.
860
+ *
861
+ * After every construct is provisioned, for the reason consumers are: an
862
+ * endpoint links to things `provisionOrder` does not order before its surface.
863
+ */
864
+ export function mountRoutes(
865
+ manifest: ConstructManifest,
866
+ provisioned: ProvisionedManifest,
867
+ ): void {
868
+ for (const [id, declaration] of Object.entries(manifest)) {
869
+ if (declaration?.kind !== 'rest-api') continue;
870
+
871
+ const surface = provisioned[id];
872
+ if (!(surface instanceof RestApiSurface)) continue;
873
+
874
+ for (const endpoint of declaration.endpoints) {
875
+ const { link } = resolveEdges(endpoint.dependencies, provisioned);
876
+ const vpc = vpcFor(link);
877
+ surface.mount({
878
+ method: endpoint.method,
879
+ path: endpoint.path,
880
+ handler: endpoint.handler,
881
+ link,
882
+ ...(vpc ? { vpc } : {}),
883
+ ...(endpoint.authorizer ? { authorizer: endpoint.authorizer } : {}),
884
+ });
885
+ }
886
+ }
887
+ }
888
+
889
+ /**
890
+ * Subscribe every queue's one consumer — the handler the build wrote for it,
891
+ * linked to what that consumer depends on.
892
+ *
893
+ * After every construct is provisioned, because a consumer links to things
894
+ * that `provisionOrder` does not order before the queue.
895
+ */
896
+ export function subscribeConsumers(
897
+ manifest: ConstructManifest,
898
+ provisioned: ProvisionedManifest,
899
+ ): void {
900
+ for (const [id, declaration] of Object.entries(manifest)) {
901
+ if (declaration?.kind !== 'queue') continue;
902
+
903
+ const queue = provisioned[id] as unknown as Consumable | undefined;
904
+ if (!queue) continue;
905
+
906
+ const { link } = resolveEdges(declaration.worker.dependencies, provisioned);
907
+ const vpc = vpcFor(link);
908
+ queue.consume({
909
+ handler: declaration.worker.handler,
910
+ link,
911
+ ...(vpc ? { vpc } : {}),
912
+ });
913
+ }
914
+ }
915
+
714
916
  /** The provisioner for a kind. Pure — the lookup is testable without Pulumi. */
715
917
  export function provisionerFor(kind: DeclarationKind): Provisioner {
716
918
  const provisioner = PROVISIONERS[kind];
@@ -799,6 +1001,7 @@ export function fromManifest(
799
1001
  for (const id of [...rest, ...sites]) {
800
1002
  const declaration = manifest[id];
801
1003
  if (!declaration) continue;
1004
+ if (PROVISIONED_ELSEWHERE.has(declaration.kind)) continue;
802
1005
 
803
1006
  const component = provisionerFor(declaration.kind)(
804
1007
  stack,
@@ -822,6 +1025,12 @@ export function fromManifest(
822
1025
  provisioned[id] = component;
823
1026
  }
824
1027
 
1028
+ // The functions and crons, each queue's one consumer and each surface's
1029
+ // endpoints, once everything they link to exists.
1030
+ provisionCompute(stack, manifest, provisioned);
1031
+ subscribeConsumers(manifest, provisioned);
1032
+ mountRoutes(manifest, provisioned);
1033
+
825
1034
  for (const line of describeRoutes(manifest)) console.log(line);
826
1035
 
827
1036
  // Now everything exists, so every surface's callers can be resolved — the
@@ -829,7 +1038,7 @@ export function fromManifest(
829
1038
  for (const [id, deferred] of callers) {
830
1039
  // Resolved with the promise itself: the addresses it needs are Pulumi
831
1040
  // outputs, so the answer arrives when they do.
832
- deferred.resolve(callersOf(id, manifest, provisioned));
1041
+ deferred.resolve(callersOf(id, manifest, provisioned, $app.name));
833
1042
  }
834
1043
 
835
1044
  // Last, and only now: the roles exist as passwords and secrets from the
package/src/sst/index.ts CHANGED
@@ -34,6 +34,7 @@ export {
34
34
  } from './aws/DatabaseBootstrap';
35
35
  export { DatabaseReader, DatabaseSchema } from './aws/DerivedDatabase';
36
36
  export { Email, EmailNeedsUrl, type EmailProps } from './aws/Email';
37
+ export { Encryption, type EncryptionProps } from './aws/Encryption';
37
38
  export { FileServer, type FileServerProps } from './aws/FileServer';
38
39
  export { Function, type FunctionProps } from './aws/Function';
39
40
  export {
@@ -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"}