stacktape 3.5.7 → 3.6.0-beta.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.
- package/.tsconfig.bun-build.json +1 -0
- package/ai-docs/cli-ref/aws-profile-create.md +22 -0
- package/ai-docs/cli-ref/aws-profile-delete.md +22 -0
- package/ai-docs/cli-ref/aws-profile-list.md +20 -0
- package/ai-docs/cli-ref/aws-profile-update.md +22 -0
- package/ai-docs/cli-ref/bastion-session.md +29 -0
- package/ai-docs/cli-ref/bastion-tunnel.md +30 -0
- package/ai-docs/cli-ref/bucket-sync.md +30 -0
- package/ai-docs/cli-ref/cf-module-update.md +26 -0
- package/ai-docs/cli-ref/cf-rollback.md +28 -0
- package/ai-docs/cli-ref/codebuild-deploy.md +34 -0
- package/ai-docs/cli-ref/compile-template.md +25 -0
- package/ai-docs/cli-ref/container-session.md +30 -0
- package/ai-docs/cli-ref/debug-alarms.md +28 -0
- package/ai-docs/cli-ref/debug-aws-sdk.md +33 -0
- package/ai-docs/cli-ref/debug-container-exec.md +36 -0
- package/ai-docs/cli-ref/debug-dynamodb.md +35 -0
- package/ai-docs/cli-ref/debug-logs.md +34 -0
- package/ai-docs/cli-ref/debug-metrics.md +33 -0
- package/ai-docs/cli-ref/debug-opensearch.md +35 -0
- package/ai-docs/cli-ref/debug-redis.md +36 -0
- package/ai-docs/cli-ref/debug-sql.md +35 -0
- package/ai-docs/cli-ref/defaults-configure.md +29 -0
- package/ai-docs/cli-ref/defaults-list.md +20 -0
- package/ai-docs/cli-ref/delete.md +24 -0
- package/ai-docs/cli-ref/deploy.md +25 -0
- package/ai-docs/cli-ref/deployment-script-run.md +28 -0
- package/ai-docs/cli-ref/dev-stop.md +26 -0
- package/ai-docs/cli-ref/dev.md +45 -0
- package/ai-docs/cli-ref/domain-add.md +26 -0
- package/ai-docs/cli-ref/help.md +18 -0
- package/ai-docs/cli-ref/info-operations.md +22 -0
- package/ai-docs/cli-ref/info-stack.md +30 -0
- package/ai-docs/cli-ref/info-stacks.md +26 -0
- package/ai-docs/cli-ref/info-whoami.md +22 -0
- package/ai-docs/cli-ref/init.md +30 -0
- package/ai-docs/cli-ref/login.md +20 -0
- package/ai-docs/cli-ref/logout.md +18 -0
- package/ai-docs/cli-ref/mcp-add.md +22 -0
- package/ai-docs/cli-ref/mcp.md +20 -0
- package/ai-docs/cli-ref/org-create.md +24 -0
- package/ai-docs/cli-ref/org-delete.md +24 -0
- package/ai-docs/cli-ref/org-list.md +22 -0
- package/ai-docs/cli-ref/package-workloads.md +25 -0
- package/ai-docs/cli-ref/param-get.md +26 -0
- package/ai-docs/cli-ref/preview-changes.md +23 -0
- package/ai-docs/cli-ref/project-create.md +22 -0
- package/ai-docs/cli-ref/projects-list.md +22 -0
- package/ai-docs/cli-ref/rollback.md +28 -0
- package/ai-docs/cli-ref/script-run.md +29 -0
- package/ai-docs/cli-ref/secret-create.md +28 -0
- package/ai-docs/cli-ref/secret-delete.md +26 -0
- package/ai-docs/cli-ref/secret-get.md +26 -0
- package/ai-docs/cli-ref/upgrade.md +20 -0
- package/ai-docs/cli-ref/version.md +18 -0
- package/ai-docs/concept/connecting-resources.md +369 -0
- package/ai-docs/concept/directives.md +371 -0
- package/ai-docs/concept/extending-cloudformation.md +315 -0
- package/ai-docs/concept/overrides-and-transforms.md +352 -0
- package/ai-docs/concept/stages-and-environments.md +347 -0
- package/ai-docs/concept/typescript-config.md +447 -0
- package/ai-docs/concept/yaml-config.md +338 -0
- package/ai-docs/config-ref/_root.md +142 -0
- package/ai-docs/config-ref/application-load-balancer.md +1109 -0
- package/ai-docs/config-ref/astro-web.md +115 -0
- package/ai-docs/config-ref/aws-cdk-construct.md +68 -0
- package/ai-docs/config-ref/bastion.md +93 -0
- package/ai-docs/config-ref/batch-job.md +179 -0
- package/ai-docs/config-ref/bucket.md +348 -0
- package/ai-docs/config-ref/cdn.md +496 -0
- package/ai-docs/config-ref/custom-resource.md +80 -0
- package/ai-docs/config-ref/deployment-script.md +79 -0
- package/ai-docs/config-ref/dynamo-db-table.md +202 -0
- package/ai-docs/config-ref/edge-lambda-function.md +87 -0
- package/ai-docs/config-ref/efs-filesystem.md +72 -0
- package/ai-docs/config-ref/event-bus.md +63 -0
- package/ai-docs/config-ref/function.md +409 -0
- package/ai-docs/config-ref/hosting-bucket.md +171 -0
- package/ai-docs/config-ref/http-api-gateway.md +149 -0
- package/ai-docs/config-ref/http-endpoint.md +92 -0
- package/ai-docs/config-ref/kinesis-stream.md +97 -0
- package/ai-docs/config-ref/mongo-db-atlas-cluster.md +254 -0
- package/ai-docs/config-ref/multi-container-workload.md +399 -0
- package/ai-docs/config-ref/network-load-balancer.md +118 -0
- package/ai-docs/config-ref/nextjs-web.md +147 -0
- package/ai-docs/config-ref/nuxt-web.md +81 -0
- package/ai-docs/config-ref/open-search.md +206 -0
- package/ai-docs/config-ref/private-service.md +75 -0
- package/ai-docs/config-ref/redis-cluster.md +223 -0
- package/ai-docs/config-ref/relational-database.md +525 -0
- package/ai-docs/config-ref/remix-web.md +74 -0
- package/ai-docs/config-ref/sns-topic.md +69 -0
- package/ai-docs/config-ref/solidstart-web.md +75 -0
- package/ai-docs/config-ref/sqs-queue-not-empty.md +405 -0
- package/ai-docs/config-ref/sqs-queue.md +232 -0
- package/ai-docs/config-ref/state-machine.md +235 -0
- package/ai-docs/config-ref/sveltekit-web.md +81 -0
- package/ai-docs/config-ref/tanstack-web.md +75 -0
- package/ai-docs/config-ref/upstash-redis.md +59 -0
- package/ai-docs/config-ref/user-auth-pool.md +876 -0
- package/ai-docs/config-ref/web-app-firewall.md +212 -0
- package/ai-docs/config-ref/web-service.md +178 -0
- package/ai-docs/config-ref/worker-service.md +41 -0
- package/ai-docs/getting-started/console.md +232 -0
- package/ai-docs/getting-started/deployment.md +434 -0
- package/ai-docs/getting-started/dev-mode.md +118 -0
- package/ai-docs/getting-started/how-it-works.md +119 -0
- package/ai-docs/getting-started/intro.md +157 -0
- package/ai-docs/getting-started/using-with-ai.md +228 -0
- package/ai-docs/getting-started/workflow.md +197 -0
- package/ai-docs/index.json +1514 -0
- package/ai-docs/recipe/background-jobs.md +183 -0
- package/ai-docs/recipe/database-migrations.md +240 -0
- package/ai-docs/recipe/graphql-api.md +211 -0
- package/ai-docs/recipe/monorepo-setup.md +183 -0
- package/ai-docs/recipe/nextjs-full-stack.md +188 -0
- package/ai-docs/recipe/rest-api-with-database.md +156 -0
- package/ai-docs/recipe/scheduled-tasks.md +186 -0
- package/ai-docs/recipe/static-website.md +241 -0
- package/ai-docs/troubleshooting/cloudformation-stack-states.md +189 -0
- package/bin/stacktape.js +206 -41
- package/package.json +1 -1
- package/plain.d.ts +309 -54
package/bin/stacktape.js
CHANGED
|
@@ -14,7 +14,11 @@ const {
|
|
|
14
14
|
accessSync,
|
|
15
15
|
constants,
|
|
16
16
|
unlinkSync,
|
|
17
|
-
readFileSync
|
|
17
|
+
readFileSync,
|
|
18
|
+
writeFileSync,
|
|
19
|
+
readdirSync,
|
|
20
|
+
rmSync,
|
|
21
|
+
statSync
|
|
18
22
|
} = require('node:fs');
|
|
19
23
|
const { get: httpsGet } = require('node:https');
|
|
20
24
|
const { platform, arch, homedir } = require('node:os');
|
|
@@ -33,6 +37,18 @@ const PLATFORM_MAP = {
|
|
|
33
37
|
'linux-x64-musl': { fileName: 'alpine.tar.gz', extract: extractTarGz }
|
|
34
38
|
};
|
|
35
39
|
|
|
40
|
+
const REQUIRED_HELPER_LAMBDA_PREFIXES = [
|
|
41
|
+
'stacktapeServiceLambda',
|
|
42
|
+
'cdnOriginRequestLambda',
|
|
43
|
+
'cdnOriginResponseLambda',
|
|
44
|
+
'batchJobTriggerLambda'
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const INSTALL_MARKER_FILE_NAME = '.stacktape-install.json';
|
|
48
|
+
const INSTALL_LOCK_DIR_SUFFIX = '.stacktape-install.lock';
|
|
49
|
+
const LOCK_WAIT_TIMEOUT_MS = 120000;
|
|
50
|
+
const STALE_LOCK_TIMEOUT_MS = 300000;
|
|
51
|
+
|
|
36
52
|
// ANSI color codes
|
|
37
53
|
const colors = {
|
|
38
54
|
reset: '\x1B[0m',
|
|
@@ -200,68 +216,208 @@ async function ensureBinary() {
|
|
|
200
216
|
|
|
201
217
|
const binaryName = platform() === 'win32' ? 'stacktape.exe' : 'stacktape';
|
|
202
218
|
|
|
219
|
+
const localCacheDir = join(__dirname, '..', 'bin');
|
|
220
|
+
|
|
203
221
|
let cacheDir;
|
|
204
222
|
try {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
cacheDir = localDir;
|
|
223
|
+
mkdirSync(localCacheDir, { recursive: true });
|
|
224
|
+
accessSync(localCacheDir, constants.W_OK);
|
|
225
|
+
cacheDir = localCacheDir;
|
|
209
226
|
} catch {
|
|
210
227
|
cacheDir = join(homedir(), '.stacktape', 'bin', version);
|
|
211
228
|
}
|
|
212
229
|
|
|
213
230
|
const binaryPath = join(cacheDir, binaryName);
|
|
231
|
+
const preserveLauncherScript = cacheDir === localCacheDir;
|
|
214
232
|
|
|
215
|
-
|
|
216
|
-
return binaryPath;
|
|
217
|
-
}
|
|
233
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
218
234
|
|
|
219
|
-
|
|
235
|
+
const lockDirPath = `${cacheDir}${INSTALL_LOCK_DIR_SUFFIX}`;
|
|
220
236
|
|
|
221
|
-
|
|
237
|
+
const isHelperLambdasCacheComplete = () => {
|
|
238
|
+
const helperLambdasDir = join(cacheDir, 'helper-lambdas');
|
|
239
|
+
if (!existsSync(helperLambdasDir)) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
222
242
|
|
|
223
|
-
|
|
224
|
-
|
|
243
|
+
try {
|
|
244
|
+
const files = readdirSync(helperLambdasDir);
|
|
245
|
+
return REQUIRED_HELPER_LAMBDA_PREFIXES.every((prefix) =>
|
|
246
|
+
files.some((fileName) => fileName.startsWith(`${prefix}-`) && fileName.endsWith('.zip'))
|
|
247
|
+
);
|
|
248
|
+
} catch {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
225
252
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
253
|
+
const isCacheValid = () => {
|
|
254
|
+
if (!existsSync(binaryPath)) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
229
257
|
|
|
230
|
-
|
|
231
|
-
|
|
258
|
+
if (!isHelperLambdasCacheComplete()) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
232
261
|
|
|
233
|
-
|
|
262
|
+
const markerPath = join(cacheDir, INSTALL_MARKER_FILE_NAME);
|
|
263
|
+
if (!existsSync(markerPath)) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
234
266
|
|
|
235
|
-
|
|
267
|
+
try {
|
|
268
|
+
const parsedMarker = JSON.parse(readFileSync(markerPath, 'utf8'));
|
|
269
|
+
return parsedMarker.version === version && parsedMarker.platformKey === platformKey;
|
|
270
|
+
} catch {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
};
|
|
236
274
|
|
|
237
|
-
|
|
238
|
-
|
|
275
|
+
const writeInstallMarker = () => {
|
|
276
|
+
const markerPath = join(cacheDir, INSTALL_MARKER_FILE_NAME);
|
|
277
|
+
writeFileSync(
|
|
278
|
+
markerPath,
|
|
279
|
+
JSON.stringify(
|
|
280
|
+
{
|
|
281
|
+
version,
|
|
282
|
+
platformKey,
|
|
283
|
+
helperLambdas: REQUIRED_HELPER_LAMBDA_PREFIXES,
|
|
284
|
+
installedAt: new Date().toISOString()
|
|
285
|
+
},
|
|
286
|
+
null,
|
|
287
|
+
2
|
|
288
|
+
)
|
|
289
|
+
);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const cleanupExtractedCache = () => {
|
|
293
|
+
if (!existsSync(cacheDir)) {
|
|
294
|
+
return;
|
|
239
295
|
}
|
|
240
296
|
|
|
241
|
-
|
|
297
|
+
try {
|
|
298
|
+
const entries = readdirSync(cacheDir);
|
|
299
|
+
for (const entry of entries) {
|
|
300
|
+
if (preserveLauncherScript && entry === 'stacktape.js') {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
rmSync(join(cacheDir, entry), { recursive: true, force: true });
|
|
304
|
+
}
|
|
305
|
+
} catch {
|
|
306
|
+
// Ignore cleanup errors and try reinstall anyway
|
|
307
|
+
}
|
|
308
|
+
};
|
|
242
309
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
310
|
+
const acquireInstallLock = async () => {
|
|
311
|
+
const start = Date.now();
|
|
312
|
+
while (true) {
|
|
313
|
+
try {
|
|
314
|
+
mkdirSync(lockDirPath);
|
|
315
|
+
return;
|
|
316
|
+
} catch (error) {
|
|
317
|
+
if (error.code !== 'EEXIST') {
|
|
318
|
+
throw error;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
const lockStats = statSync(lockDirPath);
|
|
323
|
+
const lockAge = Date.now() - lockStats.mtimeMs;
|
|
324
|
+
if (lockAge > STALE_LOCK_TIMEOUT_MS) {
|
|
325
|
+
rmSync(lockDirPath, { recursive: true, force: true });
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
} catch {
|
|
329
|
+
// Lock directory disappeared between checks
|
|
330
|
+
}
|
|
248
331
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
}
|
|
332
|
+
if (Date.now() - start > LOCK_WAIT_TIMEOUT_MS) {
|
|
333
|
+
throw new Error('Timed out waiting for Stacktape binary installation lock');
|
|
334
|
+
}
|
|
254
335
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
'linux-x64': 'curl -L https://installs.stacktape.com/linux.sh | sh',
|
|
259
|
-
'linux-arm64': 'curl -L https://installs.stacktape.com/linux-arm.sh | sh',
|
|
260
|
-
'linux-x64-musl': 'curl -L https://installs.stacktape.com/alpine.sh | sh',
|
|
261
|
-
'darwin-x64': 'curl -L https://installs.stacktape.com/macos.sh | sh',
|
|
262
|
-
'darwin-arm64': 'curl -L https://installs.stacktape.com/macos-arm.sh | sh'
|
|
336
|
+
await sleep(200);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
263
339
|
};
|
|
264
|
-
|
|
340
|
+
|
|
341
|
+
const releaseInstallLock = () => {
|
|
342
|
+
try {
|
|
343
|
+
rmSync(lockDirPath, { recursive: true, force: true });
|
|
344
|
+
} catch {
|
|
345
|
+
// Ignore release lock errors
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
const installBinary = async () => {
|
|
350
|
+
console.info(`${colors.dim}Installing Stacktape ${version} for ${platformKey}...${colors.reset}`);
|
|
351
|
+
|
|
352
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
353
|
+
|
|
354
|
+
const downloadUrl = `https://github.com/${GITHUB_REPO}/releases/download/${version}/${platformInfo.fileName}`;
|
|
355
|
+
const archivePath = join(cacheDir, `.download-${Date.now()}-${platformInfo.fileName}`);
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
console.info(`${colors.dim}Downloading from GitHub releases...${colors.reset}`);
|
|
359
|
+
await downloadFile(downloadUrl, archivePath);
|
|
360
|
+
|
|
361
|
+
console.info(`${colors.dim}Extracting...${colors.reset}`);
|
|
362
|
+
await platformInfo.extract(archivePath, cacheDir);
|
|
363
|
+
|
|
364
|
+
setExecutablePermissions(cacheDir);
|
|
365
|
+
|
|
366
|
+
unlinkSync(archivePath);
|
|
367
|
+
|
|
368
|
+
if (!existsSync(binaryPath)) {
|
|
369
|
+
throw new Error(`Binary not found after extraction: ${binaryPath}`);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (!isHelperLambdasCacheComplete()) {
|
|
373
|
+
throw new Error('Incomplete installation: helper lambdas were not extracted correctly');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
writeInstallMarker();
|
|
377
|
+
printLogo();
|
|
378
|
+
|
|
379
|
+
return binaryPath;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
try {
|
|
382
|
+
if (existsSync(archivePath)) {
|
|
383
|
+
unlinkSync(archivePath);
|
|
384
|
+
}
|
|
385
|
+
} catch {
|
|
386
|
+
// Ignore archive cleanup errors
|
|
387
|
+
}
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
if (isCacheValid()) {
|
|
393
|
+
return binaryPath;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
await acquireInstallLock();
|
|
397
|
+
|
|
398
|
+
try {
|
|
399
|
+
if (isCacheValid()) {
|
|
400
|
+
return binaryPath;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
let lastError;
|
|
404
|
+
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
405
|
+
try {
|
|
406
|
+
cleanupExtractedCache();
|
|
407
|
+
return await installBinary();
|
|
408
|
+
} catch (error) {
|
|
409
|
+
lastError = error;
|
|
410
|
+
cleanupExtractedCache();
|
|
411
|
+
if (attempt < 2) {
|
|
412
|
+
console.info(`\n${colors.dim}Retrying installation (${attempt + 1}/2)...${colors.reset}`);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
throw lastError;
|
|
418
|
+
} finally {
|
|
419
|
+
releaseInstallLock();
|
|
420
|
+
}
|
|
265
421
|
}
|
|
266
422
|
|
|
267
423
|
function getGlobalBinaryPathIfVersionMatches() {
|
|
@@ -269,6 +425,7 @@ function getGlobalBinaryPathIfVersionMatches() {
|
|
|
269
425
|
const globalDir = join(homedir(), '.stacktape', 'bin');
|
|
270
426
|
const globalBinaryPath = join(globalDir, binaryName);
|
|
271
427
|
const releaseDataPath = join(globalDir, 'release-data.json');
|
|
428
|
+
const globalHelperLambdasDir = join(globalDir, 'helper-lambdas');
|
|
272
429
|
|
|
273
430
|
if (!existsSync(globalBinaryPath) || !existsSync(releaseDataPath)) {
|
|
274
431
|
return null;
|
|
@@ -279,6 +436,14 @@ function getGlobalBinaryPathIfVersionMatches() {
|
|
|
279
436
|
if (version !== PACKAGE_VERSION) {
|
|
280
437
|
return null;
|
|
281
438
|
}
|
|
439
|
+
|
|
440
|
+
const files = readdirSync(globalHelperLambdasDir);
|
|
441
|
+
const hasAllHelperLambdas = REQUIRED_HELPER_LAMBDA_PREFIXES.every((prefix) =>
|
|
442
|
+
files.some((fileName) => fileName.startsWith(`${prefix}-`) && fileName.endsWith('.zip'))
|
|
443
|
+
);
|
|
444
|
+
if (!hasAllHelperLambdas) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
282
447
|
} catch {
|
|
283
448
|
return null;
|
|
284
449
|
}
|