@actuallyjamez/elysian 0.5.1 → 0.7.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.
@@ -0,0 +1,168 @@
1
+ /**
2
+ * LocalStack detection and tflocal execution utilities
3
+ */
4
+ import { existsSync } from "fs";
5
+ import { join } from "path";
6
+ /**
7
+ * Check if LocalStack is running by hitting the health endpoint
8
+ */
9
+ export async function isLocalStackRunning(endpoint = "http://localhost:4566") {
10
+ try {
11
+ const controller = new AbortController();
12
+ const timeout = setTimeout(() => controller.abort(), 2000);
13
+ const response = await fetch(`${endpoint}/_localstack/health`, {
14
+ signal: controller.signal,
15
+ });
16
+ clearTimeout(timeout);
17
+ return response.ok;
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ }
23
+ /**
24
+ * Check if tflocal CLI is installed
25
+ */
26
+ export async function isTfLocalInstalled() {
27
+ try {
28
+ const proc = Bun.spawn(["tflocal", "--version"], {
29
+ stdout: "pipe",
30
+ stderr: "pipe",
31
+ });
32
+ const exitCode = await proc.exited;
33
+ return exitCode === 0;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ /**
40
+ * Check if terraform has been initialized in the given directory
41
+ */
42
+ export function isTerraformInitialized(terraformDir) {
43
+ return existsSync(join(terraformDir, ".terraform"));
44
+ }
45
+ /**
46
+ * Run tflocal init
47
+ */
48
+ export async function runTfLocalInit(terraformDir) {
49
+ try {
50
+ const proc = Bun.spawn(["tflocal", "init", "-input=false"], {
51
+ cwd: terraformDir,
52
+ stdout: "pipe",
53
+ stderr: "pipe",
54
+ });
55
+ const exitCode = await proc.exited;
56
+ if (exitCode !== 0) {
57
+ const stderr = await new Response(proc.stderr).text();
58
+ return { success: false, error: stderr };
59
+ }
60
+ return { success: true };
61
+ }
62
+ catch (error) {
63
+ return {
64
+ success: false,
65
+ error: error instanceof Error ? error.message : String(error),
66
+ };
67
+ }
68
+ }
69
+ /**
70
+ * Run tflocal apply with auto-approve
71
+ */
72
+ export async function runTfLocalApply(terraformDir) {
73
+ try {
74
+ const proc = Bun.spawn(["tflocal", "apply", "-auto-approve", "-input=false"], {
75
+ cwd: terraformDir,
76
+ stdout: "pipe",
77
+ stderr: "pipe",
78
+ });
79
+ const exitCode = await proc.exited;
80
+ if (exitCode !== 0) {
81
+ const stderr = await new Response(proc.stderr).text();
82
+ const stdout = await new Response(proc.stdout).text();
83
+ // Terraform often outputs errors to stdout
84
+ return { success: false, error: stderr || stdout };
85
+ }
86
+ return { success: true };
87
+ }
88
+ catch (error) {
89
+ return {
90
+ success: false,
91
+ error: error instanceof Error ? error.message : String(error),
92
+ };
93
+ }
94
+ }
95
+ /**
96
+ * Transform AWS URLs to LocalStack URLs
97
+ * Converts URLs like:
98
+ * https://abc123.execute-api.eu-west-2.amazonaws.com/
99
+ * To:
100
+ * http://abc123.execute-api.localhost.localstack.cloud:4566/
101
+ */
102
+ export function transformToLocalStackUrl(value) {
103
+ if (typeof value !== "string") {
104
+ return value;
105
+ }
106
+ // Match API Gateway URLs: https://{api-id}.execute-api.{region}.amazonaws.com
107
+ const apiGatewayPattern = /https:\/\/([a-z0-9]+)\.execute-api\.([a-z0-9-]+)\.amazonaws\.com(\/.*)?/gi;
108
+ return value.replace(apiGatewayPattern, (match, apiId, region, path) => {
109
+ const pathSuffix = path || "";
110
+ return `http://${apiId}.execute-api.localhost.localstack.cloud:4566${pathSuffix}`;
111
+ });
112
+ }
113
+ /**
114
+ * Transform all URLs in terraform outputs to LocalStack format
115
+ */
116
+ export function transformOutputsForLocalStack(outputs) {
117
+ const result = {};
118
+ for (const [key, value] of Object.entries(outputs)) {
119
+ result[key] = transformToLocalStackUrl(value);
120
+ }
121
+ return result;
122
+ }
123
+ /**
124
+ * Get terraform outputs as JSON
125
+ */
126
+ export async function getTerraformOutputs(terraformDir, transformForLocalStack = true) {
127
+ try {
128
+ const proc = Bun.spawn(["tflocal", "output", "-json"], {
129
+ cwd: terraformDir,
130
+ stdout: "pipe",
131
+ stderr: "pipe",
132
+ });
133
+ const exitCode = await proc.exited;
134
+ if (exitCode !== 0) {
135
+ return null;
136
+ }
137
+ const stdout = await new Response(proc.stdout).text();
138
+ const outputs = JSON.parse(stdout);
139
+ // Extract just the values from the output structure
140
+ const result = {};
141
+ for (const [key, output] of Object.entries(outputs)) {
142
+ result[key] = output.value;
143
+ }
144
+ // Transform URLs to LocalStack format if requested
145
+ if (transformForLocalStack) {
146
+ return transformOutputsForLocalStack(result);
147
+ }
148
+ return result;
149
+ }
150
+ catch {
151
+ return null;
152
+ }
153
+ }
154
+ /**
155
+ * Detect LocalStack availability
156
+ * Returns an object with detection results and reasons
157
+ */
158
+ export async function detectLocalStack() {
159
+ const [localstackRunning, tfLocalInstalled] = await Promise.all([
160
+ isLocalStackRunning(),
161
+ isTfLocalInstalled(),
162
+ ]);
163
+ return {
164
+ available: localstackRunning && tfLocalInstalled,
165
+ localstackRunning,
166
+ tfLocalInstalled,
167
+ };
168
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuallyjamez/elysian",
3
- "version": "0.5.1",
3
+ "version": "0.7.0",
4
4
  "description": "Automatic Lambda bundler for Elysia with API Gateway and Terraform integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,8 @@
20
20
  },
21
21
  "files": [
22
22
  "dist",
23
- "templates"
23
+ "templates",
24
+ "README.md"
24
25
  ],
25
26
  "repository": {
26
27
  "type": "git",