@geekmidas/cloud 1.1.1 → 10.0.0-alpha.0

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 (63) hide show
  1. package/dist/{index-ByEJy40r.d.cts → index-B5CZ1xVf.d.cts} +17 -9
  2. package/dist/index-B5CZ1xVf.d.cts.map +1 -0
  3. package/dist/{index-DZ0QrJQr.d.mts → index-DhHRjduZ.d.mts} +17 -9
  4. package/dist/index-DhHRjduZ.d.mts.map +1 -0
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.d.cts +1 -1
  7. package/dist/index.d.mts +1 -1
  8. package/dist/index.mjs +1 -1
  9. package/dist/utils/index.cjs +1 -1
  10. package/dist/utils/index.d.cts +1 -1
  11. package/dist/utils/index.d.mts +1 -1
  12. package/dist/utils/index.mjs +1 -1
  13. package/dist/{utils-CtMjuIMR.cjs → utils-B1a2UuEO.cjs} +5 -5
  14. package/dist/utils-B1a2UuEO.cjs.map +1 -0
  15. package/dist/{utils-BdKG20_m.mjs → utils-DMOXJ27j.mjs} +5 -5
  16. package/dist/utils-DMOXJ27j.mjs.map +1 -0
  17. package/package.json +44 -7
  18. package/src/dokploy/Application.ts +259 -0
  19. package/src/dokploy/__tests__/Application.spec.ts +69 -0
  20. package/src/dokploy/index.ts +18 -0
  21. package/src/sst/__tests__/LinkedEnvironment.spec.ts +4 -1
  22. package/src/sst/__tests__/backends.spec.ts +249 -0
  23. package/src/sst/__tests__/bootstrap.spec.ts +140 -0
  24. package/src/sst/__tests__/database.spec.ts +119 -0
  25. package/src/sst/__tests__/fromManifest.spec.ts +266 -0
  26. package/src/sst/__tests__/provides.spec.ts +107 -0
  27. package/src/sst/__tests__/ses.spec.ts +93 -0
  28. package/src/sst/__tests__/surfaces.spec.ts +132 -0
  29. package/src/sst/__type-tests__/authorizers.type-test.ts +2 -2
  30. package/src/sst/__type-tests__/manifest.type-test.ts +3 -3
  31. package/src/sst/__type-tests__/messaging.type-test.ts +3 -3
  32. package/src/sst/__type-tests__/storage.type-test.ts +2 -2
  33. package/src/sst/{Api.ts → aws/Api.ts} +3 -3
  34. package/src/sst/aws/Cache.ts +259 -0
  35. package/src/sst/aws/Credential.ts +28 -0
  36. package/src/sst/{Cron.ts → aws/Cron.ts} +2 -2
  37. package/src/sst/aws/Database.ts +190 -0
  38. package/src/sst/aws/DatabaseBootstrap.ts +309 -0
  39. package/src/sst/aws/DerivedDatabase.ts +117 -0
  40. package/src/sst/aws/Email.ts +181 -0
  41. package/src/sst/aws/FileServer.ts +82 -0
  42. package/src/sst/{Function.ts → aws/Function.ts} +3 -3
  43. package/src/sst/aws/ObjectStorage.ts +76 -0
  44. package/src/sst/aws/Queue.ts +116 -0
  45. package/src/sst/aws/RestApiSurface.ts +92 -0
  46. package/src/sst/aws/Secret.ts +76 -0
  47. package/src/sst/aws/StaticSite.ts +92 -0
  48. package/src/sst/{Storage.ts → aws/Storage.ts} +3 -3
  49. package/src/sst/aws/Topic.ts +68 -0
  50. package/src/sst/aws/bootstrap/handler.ts +110 -0
  51. package/src/sst/aws/ses.ts +132 -0
  52. package/src/sst/errors.ts +65 -0
  53. package/src/sst/fromManifest.ts +899 -0
  54. package/src/sst/index.ts +62 -7
  55. package/src/sst/naming.ts +37 -16
  56. package/src/sst/tsconfig.json +2 -2
  57. package/src/sst/upstash.d.ts +38 -0
  58. package/dist/index-ByEJy40r.d.cts.map +0 -1
  59. package/dist/index-DZ0QrJQr.d.mts.map +0 -1
  60. package/dist/utils-BdKG20_m.mjs.map +0 -1
  61. package/dist/utils-CtMjuIMR.cjs.map +0 -1
  62. package/src/sst/Queue.ts +0 -46
  63. package/src/sst/Topic.ts +0 -37
@@ -0,0 +1,132 @@
1
+ import { createHmac } from 'node:crypto';
2
+
3
+ /**
4
+ * An SES SMTP password, derived from an IAM secret access key.
5
+ *
6
+ * SES does not hand you an SMTP password. It hands you IAM credentials, and the
7
+ * SMTP password is a *signature* computed from the secret access key with a
8
+ * fixed, documented recipe — so provisioning SMTP access means creating a user,
9
+ * creating an access key, and then doing this arithmetic. That is why `email` is
10
+ * the only kind whose provisioner is a chain rather than a component.
11
+ *
12
+ * The recipe is AWS's, verbatim: a SigV4 signing key over the constant date
13
+ * `11111111`, the region, the service `ses`, the terminator `aws4_request`, and
14
+ * the message `SendRawEmail` — then a one-byte version prefix, base64-encoded.
15
+ *
16
+ * Pure, which is the only way this gets checked at all: AWS documents the
17
+ * recipe but publishes no worked example, so there is no golden value to assert
18
+ * against. What the tests do instead is check the properties the recipe implies
19
+ * — the version byte survives, the output is deterministic, and it changes with
20
+ * both the key and the region. A wrong password fails at the first send, long
21
+ * after the stack reported success, so it is worth saying plainly that this has
22
+ * been verified against the documented algorithm and not against SES.
23
+ *
24
+ * @see https://docs.aws.amazon.com/ses/latest/dg/smtp-credentials.html
25
+ */
26
+ export function smtpPassword(secretAccessKey: string, region: string): string {
27
+ // Not every region has an SMTP endpoint, and deriving a password for one
28
+ // that does not produces a credential that can never work — a failure that
29
+ // surfaces at the first send rather than at deploy.
30
+ if (!SMTP_REGIONS.includes(region)) throw new NoSmtpEndpoint(region);
31
+
32
+ // The date is a constant, not today's: this is a signing key that never
33
+ // rotates on a schedule, so AWS fixed the date rather than leaving a
34
+ // credential that silently expires.
35
+ const date = sign(`AWS4${secretAccessKey}`, '11111111');
36
+ const regional = sign(date, region);
37
+ const service = sign(regional, 'ses');
38
+ const terminated = sign(service, 'aws4_request');
39
+ const signature = sign(terminated, 'SendRawEmail');
40
+
41
+ // The version prefix tells SES which derivation produced the rest. Without
42
+ // it the password is the right bytes and still rejected.
43
+ return Buffer.concat([Buffer.from([VERSION]), signature]).toString('base64');
44
+ }
45
+
46
+ /** The only version AWS has ever published. */
47
+ const VERSION = 0x04;
48
+
49
+ /**
50
+ * The regions with an SES SMTP endpoint.
51
+ *
52
+ * Shorter than the list of regions SES runs in, and shorter still than the list
53
+ * of AWS regions — which is exactly why it is worth checking. AWS's own script
54
+ * raises on a region outside this set rather than returning a password that
55
+ * looks fine.
56
+ */
57
+ export const SMTP_REGIONS: readonly string[] = [
58
+ 'us-east-2',
59
+ 'us-east-1',
60
+ 'us-west-2',
61
+ 'ap-south-1',
62
+ 'ap-northeast-2',
63
+ 'ap-southeast-1',
64
+ 'ap-southeast-2',
65
+ 'ap-northeast-1',
66
+ 'ca-central-1',
67
+ 'eu-central-1',
68
+ 'eu-west-1',
69
+ 'eu-west-2',
70
+ 'eu-south-1',
71
+ 'eu-north-1',
72
+ 'sa-east-1',
73
+ 'us-gov-west-1',
74
+ 'us-gov-east-1',
75
+ ];
76
+
77
+ /** SES has no SMTP endpoint in the region an email construct resolved to. */
78
+ export class NoSmtpEndpoint extends Error {
79
+ constructor(readonly region: string) {
80
+ super(
81
+ `SES has no SMTP endpoint in ${region}, so no SMTP password derived ` +
82
+ `for it can work. Send from one of: ${SMTP_REGIONS.join(', ')}.`,
83
+ );
84
+ this.name = 'NoSmtpEndpoint';
85
+ }
86
+ }
87
+
88
+ function sign(key: string | Buffer, message: string): Buffer {
89
+ return createHmac('sha256', key).update(message, 'utf8').digest();
90
+ }
91
+
92
+ /**
93
+ * Where SES accepts SMTP in a region.
94
+ *
95
+ * Read off the region rather than configured, for the same reason every other
96
+ * address in this package is: a host somebody types is a host that can be typed
97
+ * wrongly, and this one is derivable.
98
+ */
99
+ export function smtpEndpoint(region: string): string {
100
+ return `email-smtp.${region}.amazonaws.com`;
101
+ }
102
+
103
+ /**
104
+ * The submission port.
105
+ *
106
+ * 587 with STARTTLS rather than 465 with implicit TLS: both work, and 587 is the
107
+ * one that is not blocked by default on most networks — including, historically,
108
+ * on EC2.
109
+ */
110
+ export const SMTP_PORT = 587;
111
+
112
+ /**
113
+ * An `smtp://` URL for a set of SES credentials.
114
+ *
115
+ * The same shape Mailpit gets locally and the same shape Resend gets deployed,
116
+ * which is the whole reason the declaration promises `smtp://` and names no
117
+ * provider: what changes between them is a host and a credential, and nothing a
118
+ * client can see.
119
+ */
120
+ export function sesSmtpUrl(options: {
121
+ accessKeyId: string;
122
+ secretAccessKey: string;
123
+ region: string;
124
+ }): string {
125
+ const password = smtpPassword(options.secretAccessKey, options.region);
126
+
127
+ // Encoded, because a base64 password can contain `+` and `/` — both of which
128
+ // mean something else in a URL's authority section.
129
+ return `smtp://${encodeURIComponent(options.accessKeyId)}:${encodeURIComponent(
130
+ password,
131
+ )}@${smtpEndpoint(options.region)}:${SMTP_PORT}`;
132
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Adapter errors.
3
+ *
4
+ * Messages state the rule, which is constant; the specifics are fields. An
5
+ * interpolated message cannot be matched on, reads differently every time it is
6
+ * thrown, and carries values into every log line that touches it.
7
+ */
8
+
9
+ /** A manifest declared a kind this adapter cannot provision. */
10
+ export class UnknownDeclarationKind extends Error {
11
+ /** The kind that had no provisioner. */
12
+ readonly kind: string;
13
+ /** What this adapter can provision — the actionable half of the failure. */
14
+ readonly supported: readonly string[];
15
+
16
+ constructor(kind: string, supported: readonly string[]) {
17
+ super('No provisioner for this declaration kind');
18
+ this.name = 'UnknownDeclarationKind';
19
+ this.kind = kind;
20
+ this.supported = supported;
21
+ }
22
+ }
23
+
24
+ /**
25
+ * What the app declared a construct provides and what the component actually
26
+ * supplies have diverged.
27
+ *
28
+ * Caught at synth rather than as a missing environment variable at runtime,
29
+ * which is the failure it replaces.
30
+ */
31
+ export class ProvidesMismatch extends Error {
32
+ /** The construct whose contract was broken. */
33
+ readonly id: string;
34
+ /** Declared by the app, not supplied by infra. */
35
+ readonly missing: readonly string[];
36
+ /** Supplied by infra, not declared by the app. */
37
+ readonly extra: readonly string[];
38
+
39
+ constructor(
40
+ id: string,
41
+ missing: readonly string[],
42
+ extra: readonly string[],
43
+ ) {
44
+ super('Declared and supplied env keys do not match');
45
+ this.name = 'ProvidesMismatch';
46
+ this.id = id;
47
+ this.missing = missing;
48
+ this.extra = extra;
49
+ }
50
+ }
51
+
52
+ /** A dependency edge pointed at a construct the manifest does not contain. */
53
+ export class UnresolvedDependency extends Error {
54
+ /** The id the edge named. */
55
+ readonly target: string;
56
+ /** What the manifest does contain, so a typo is obvious. */
57
+ readonly available: readonly string[];
58
+
59
+ constructor(target: string, available: readonly string[]) {
60
+ super('Dependency target is not in the manifest');
61
+ this.name = 'UnresolvedDependency';
62
+ this.target = target;
63
+ this.available = available;
64
+ }
65
+ }