@stacksjs/ts-cloud 0.7.47 → 0.7.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 (36) hide show
  1. package/dist/bin/cli.js +299 -299
  2. package/dist/{chunk-2mw2566h.js → chunk-a4q0231r.js} +4 -4
  3. package/dist/{chunk-tskj9fay.js → chunk-f29w04w5.js} +1 -1
  4. package/dist/{chunk-stt1z5cx.js → chunk-r16e02bc.js} +189 -2
  5. package/dist/{chunk-3c46eypc.js → chunk-rrn8njr2.js} +37 -4
  6. package/dist/{chunk-ebx9gjnn.js → chunk-z58fqnjm.js} +2 -2
  7. package/dist/deploy/index.js +4 -4
  8. package/dist/drivers/hetzner/driver.d.ts +8 -0
  9. package/dist/drivers/index.js +2 -2
  10. package/dist/drivers/shared/cloudfront-origin.d.ts +4 -0
  11. package/dist/index.js +29 -5
  12. package/dist/ui/index.html +3 -3
  13. package/dist/ui/server/actions.html +3 -3
  14. package/dist/ui/server/backups.html +3 -3
  15. package/dist/ui/server/database.html +3 -3
  16. package/dist/ui/server/deployments.html +3 -3
  17. package/dist/ui/server/firewall.html +3 -3
  18. package/dist/ui/server/logs.html +3 -3
  19. package/dist/ui/server/services.html +3 -3
  20. package/dist/ui/server/sites.html +3 -3
  21. package/dist/ui/server/ssh-keys.html +3 -3
  22. package/dist/ui/server/team.html +3 -3
  23. package/dist/ui/server/terminal.html +3 -3
  24. package/dist/ui/server/workers.html +3 -3
  25. package/dist/ui/serverless/alarms.html +3 -3
  26. package/dist/ui/serverless/assets.html +3 -3
  27. package/dist/ui/serverless/data.html +3 -3
  28. package/dist/ui/serverless/deployments.html +3 -3
  29. package/dist/ui/serverless/functions.html +3 -3
  30. package/dist/ui/serverless/logs.html +3 -3
  31. package/dist/ui/serverless/queues.html +3 -3
  32. package/dist/ui/serverless/scheduler.html +3 -3
  33. package/dist/ui/serverless/secrets.html +3 -3
  34. package/dist/ui/serverless/traces.html +3 -3
  35. package/dist/ui/serverless.html +3 -3
  36. package/package.json +3 -3
@@ -6,7 +6,7 @@ import {
6
6
  step,
7
7
  success,
8
8
  warn
9
- } from "./chunk-tskj9fay.js";
9
+ } from "./chunk-f29w04w5.js";
10
10
  import {
11
11
  CloudWatchLogsClient,
12
12
  CostExplorerClient,
@@ -29,7 +29,7 @@ import {
29
29
  resolveSiteKind,
30
30
  resolveUiSource,
31
31
  siteInstallBase
32
- } from "./chunk-3c46eypc.js";
32
+ } from "./chunk-rrn8njr2.js";
33
33
  import {
34
34
  artifactKey,
35
35
  composeServerlessAppTemplate,
@@ -44,7 +44,7 @@ import {
44
44
  resolveServerlessArtifactBucketName,
45
45
  resolveServerlessAssetBucketName,
46
46
  resolveServerlessRuntime
47
- } from "./chunk-stt1z5cx.js";
47
+ } from "./chunk-r16e02bc.js";
48
48
  import {
49
49
  deployStaticSiteWithExternalDnsFull
50
50
  } from "./chunk-jp2a8yad.js";
@@ -388,7 +388,7 @@ async function deployServerlessApp(config, environment, opts = {}) {
388
388
  }
389
389
  if (imageMode) {
390
390
  step("Building + pushing container image");
391
- const { buildAndPushServerlessImage } = await import("./chunk-ebx9gjnn.js");
391
+ const { buildAndPushServerlessImage } = await import("./chunk-z58fqnjm.js");
392
392
  const built = await buildAndPushServerlessImage({
393
393
  app,
394
394
  projectRoot,
@@ -8,7 +8,7 @@ import {
8
8
  phpRuntimeLayerAssets,
9
9
  runPhpBuildHooks,
10
10
  sha256
11
- } from "./chunk-stt1z5cx.js";
11
+ } from "./chunk-r16e02bc.js";
12
12
 
13
13
  // src/deploy/serverless-image.ts
14
14
  import { execFileSync } from "node:child_process";
@@ -10449,6 +10449,135 @@ class SMS {
10449
10449
  return { resources, outputs };
10450
10450
  }
10451
10451
  }
10452
+ function logicalPart(value) {
10453
+ const clean = value.replace(/[^a-zA-Z0-9]/g, " ").trim();
10454
+ const part = clean.split(/\s+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
10455
+ return part || "User";
10456
+ }
10457
+ function normalizeHomeDirectory(value, username) {
10458
+ const path = (value || username).replace(/^\/+|\/+$/g, "");
10459
+ if (!path || path.split("/").includes(".."))
10460
+ throw new Error(`sftp: invalid homeDirectory for user ${username}`);
10461
+ return path;
10462
+ }
10463
+
10464
+ class Sftp {
10465
+ static create(options) {
10466
+ if (!options.bucket.trim())
10467
+ throw new Error("sftp: bucket is required");
10468
+ const endpointType = options.endpointType ?? "PUBLIC";
10469
+ if (endpointType === "VPC" && (!options.endpointDetails?.vpcId || !options.endpointDetails.subnetIds.length))
10470
+ throw new Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");
10471
+ const prefix = `${logicalPart(options.slug)}${logicalPart(options.environment)}Sftp`;
10472
+ const serverLogicalId = `${prefix}Server`;
10473
+ const resources = {};
10474
+ let loggingRoleArn;
10475
+ if (options.logging !== false) {
10476
+ const loggingRoleLogicalId = `${prefix}LoggingRole`;
10477
+ resources[loggingRoleLogicalId] = {
10478
+ Type: "AWS::IAM::Role",
10479
+ Properties: {
10480
+ AssumeRolePolicyDocument: {
10481
+ Version: "2012-10-17",
10482
+ Statement: [{ Effect: "Allow", Principal: { Service: "transfer.amazonaws.com" }, Action: "sts:AssumeRole" }]
10483
+ },
10484
+ Policies: [{
10485
+ PolicyName: "TransferLogging",
10486
+ PolicyDocument: {
10487
+ Version: "2012-10-17",
10488
+ Statement: [{
10489
+ Effect: "Allow",
10490
+ Action: ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:DescribeLogStreams", "logs:PutLogEvents"],
10491
+ Resource: "arn:aws:logs:*:*:log-group:/aws/transfer/*"
10492
+ }]
10493
+ }
10494
+ }]
10495
+ }
10496
+ };
10497
+ loggingRoleArn = { "Fn::GetAtt": [loggingRoleLogicalId, "Arn"] };
10498
+ }
10499
+ resources[serverLogicalId] = {
10500
+ Type: "AWS::Transfer::Server",
10501
+ Properties: {
10502
+ Domain: "S3",
10503
+ EndpointType: endpointType,
10504
+ IdentityProviderType: "SERVICE_MANAGED",
10505
+ Protocols: ["SFTP"],
10506
+ ...endpointType === "VPC" ? {
10507
+ EndpointDetails: {
10508
+ VpcId: options.endpointDetails.vpcId,
10509
+ SubnetIds: options.endpointDetails.subnetIds,
10510
+ ...options.endpointDetails.securityGroupIds?.length ? { SecurityGroupIds: options.endpointDetails.securityGroupIds } : {},
10511
+ ...options.endpointDetails.addressAllocationIds?.length ? { AddressAllocationIds: options.endpointDetails.addressAllocationIds } : {}
10512
+ }
10513
+ } : {},
10514
+ ...options.securityPolicyName ? { SecurityPolicyName: options.securityPolicyName } : {},
10515
+ ...loggingRoleArn ? { LoggingRole: loggingRoleArn } : {},
10516
+ Tags: [
10517
+ { Key: "Project", Value: options.slug },
10518
+ { Key: "Environment", Value: options.environment },
10519
+ { Key: "ManagedBy", Value: "ts-cloud" }
10520
+ ]
10521
+ }
10522
+ };
10523
+ for (const [username, user] of Object.entries(options.users)) {
10524
+ if (!/^[a-zA-Z0-9_.@-]{3,100}$/.test(username))
10525
+ throw new Error(`sftp: invalid username ${username}`);
10526
+ if (!user.sshPublicKeys.length)
10527
+ throw new Error(`sftp: user ${username} requires at least one SSH public key`);
10528
+ const userPart = logicalPart(username);
10529
+ const home = normalizeHomeDirectory(user.homeDirectory, username);
10530
+ const userLogicalId = `${prefix}${userPart}User`;
10531
+ let roleArn = user.roleArn;
10532
+ if (!roleArn) {
10533
+ const roleLogicalId = `${prefix}${userPart}Role`;
10534
+ const bucketArn = `arn:aws:s3:::${options.bucket}`;
10535
+ resources[roleLogicalId] = {
10536
+ Type: "AWS::IAM::Role",
10537
+ Properties: {
10538
+ AssumeRolePolicyDocument: {
10539
+ Version: "2012-10-17",
10540
+ Statement: [{ Effect: "Allow", Principal: { Service: "transfer.amazonaws.com" }, Action: "sts:AssumeRole" }]
10541
+ },
10542
+ Policies: [{
10543
+ PolicyName: "SftpHomeDirectory",
10544
+ PolicyDocument: {
10545
+ Version: "2012-10-17",
10546
+ Statement: [
10547
+ {
10548
+ Effect: "Allow",
10549
+ Action: ["s3:ListBucket", "s3:GetBucketLocation"],
10550
+ Resource: bucketArn,
10551
+ Condition: { StringLike: { "s3:prefix": [home, `${home}/*`] } }
10552
+ },
10553
+ {
10554
+ Effect: "Allow",
10555
+ Action: ["s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:GetObjectVersion"],
10556
+ Resource: `${bucketArn}/${home}/*`
10557
+ }
10558
+ ]
10559
+ }
10560
+ }]
10561
+ }
10562
+ };
10563
+ roleArn = { "Fn::GetAtt": [roleLogicalId, "Arn"] };
10564
+ }
10565
+ resources[userLogicalId] = {
10566
+ Type: "AWS::Transfer::User",
10567
+ DependsOn: [serverLogicalId],
10568
+ Properties: {
10569
+ ServerId: { Ref: serverLogicalId },
10570
+ UserName: username,
10571
+ Role: roleArn,
10572
+ HomeDirectoryType: "PATH",
10573
+ HomeDirectory: `/${options.bucket}/${home}`,
10574
+ SshPublicKeys: user.sshPublicKeys
10575
+ }
10576
+ };
10577
+ }
10578
+ return { resources, serverLogicalId };
10579
+ }
10580
+ }
10452
10581
 
10453
10582
  class AI {
10454
10583
  static createBedrockRole(servicePrincipal, options) {
@@ -24325,6 +24454,9 @@ var cloud_config_schema_default = {
24325
24454
  cdn: {
24326
24455
  $ref: "#/definitions/cdn"
24327
24456
  },
24457
+ sftp: {
24458
+ $ref: "#/definitions/sftp"
24459
+ },
24328
24460
  functions: {
24329
24461
  type: "object",
24330
24462
  description: "Lambda functions configuration",
@@ -24375,6 +24507,14 @@ var cloud_config_schema_default = {
24375
24507
  timeout: { type: "number", description: "HTTP request timeout in seconds" },
24376
24508
  gatewayVersion: { type: "number", enum: [1, 2], description: "API Gateway version (2 = HTTP API, 1 = REST)" },
24377
24509
  warm: { type: "number", description: "Keep-warm / provisioned concurrency count" },
24510
+ lambdaInsights: {
24511
+ type: "object",
24512
+ description: "CloudWatch Lambda Insights extension configuration for zip deployments",
24513
+ required: ["layerArn"],
24514
+ properties: {
24515
+ layerArn: { type: "string", description: "Region- and architecture-specific Lambda Insights extension layer ARN" }
24516
+ }
24517
+ },
24378
24518
  queues: { description: "Queue names (true = single default queue, false = disabled)" },
24379
24519
  scheduler: { type: "string", enum: ["off", "on", "sub-minute"], description: "Task scheduler mode" },
24380
24520
  build: { type: "array", items: { type: "string" }, description: "Commands run locally before packaging" },
@@ -24648,6 +24788,15 @@ var cloud_config_schema_default = {
24648
24788
  type: "boolean",
24649
24789
  default: true
24650
24790
  },
24791
+ originShield: {
24792
+ type: "boolean",
24793
+ description: "Enable CloudFront Origin Shield",
24794
+ default: false
24795
+ },
24796
+ originShieldRegion: {
24797
+ type: "string",
24798
+ description: "AWS region used by CloudFront Origin Shield"
24799
+ },
24651
24800
  compress: {
24652
24801
  type: "boolean",
24653
24802
  description: "Enable automatic compression",
@@ -24688,6 +24837,38 @@ var cloud_config_schema_default = {
24688
24837
  }
24689
24838
  }
24690
24839
  },
24840
+ sftp: {
24841
+ type: "object",
24842
+ required: ["bucket", "users"],
24843
+ properties: {
24844
+ bucket: { type: "string", description: "S3 bucket backing the SFTP server" },
24845
+ endpointType: { type: "string", enum: ["PUBLIC", "VPC"], default: "PUBLIC" },
24846
+ endpointDetails: {
24847
+ type: "object",
24848
+ required: ["vpcId", "subnetIds"],
24849
+ properties: {
24850
+ vpcId: { type: "string" },
24851
+ subnetIds: { type: "array", items: { type: "string" }, minItems: 1 },
24852
+ securityGroupIds: { type: "array", items: { type: "string" } },
24853
+ addressAllocationIds: { type: "array", items: { type: "string" } }
24854
+ }
24855
+ },
24856
+ securityPolicyName: { type: "string" },
24857
+ logging: { type: "boolean", default: true },
24858
+ users: {
24859
+ type: "object",
24860
+ additionalProperties: {
24861
+ type: "object",
24862
+ required: ["sshPublicKeys"],
24863
+ properties: {
24864
+ sshPublicKeys: { type: "array", items: { type: "string" }, minItems: 1 },
24865
+ homeDirectory: { type: "string" },
24866
+ roleArn: { type: "string" }
24867
+ }
24868
+ }
24869
+ }
24870
+ }
24871
+ },
24691
24872
  function: {
24692
24873
  type: "object",
24693
24874
  required: ["name", "runtime"],
@@ -44564,6 +44745,9 @@ function composeServerlessAppTemplate(opts) {
44564
44745
  const hasQueue = queueNames.length > 0;
44565
44746
  const logRetention = app.logRetention ?? 14;
44566
44747
  const imageMode = app.packaging === "image";
44748
+ if (imageMode && app.lambdaInsights) {
44749
+ throw new Error("serverless app: `lambdaInsights` layer attachment is only supported for zip packaging. Container images must install the Lambda Insights extension in the image.");
44750
+ }
44567
44751
  const schedulerEnabled = (app.scheduler ?? "on") !== "off";
44568
44752
  const cacheEnabled = (app.cache?.driver ?? "dynamodb") === "dynamodb";
44569
44753
  const assetsEnabled = Boolean(app.assets);
@@ -44625,6 +44809,8 @@ function composeServerlessAppTemplate(opts) {
44625
44809
  const managedPolicies = ["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];
44626
44810
  if (app.vpc?.subnets?.length)
44627
44811
  managedPolicies.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");
44812
+ if (app.lambdaInsights)
44813
+ managedPolicies.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");
44628
44814
  resources.AppRole = {
44629
44815
  Type: "AWS::IAM::Role",
44630
44816
  Properties: {
@@ -44680,6 +44866,7 @@ function composeServerlessAppTemplate(opts) {
44680
44866
  Type: "AWS::Logs::LogGroup",
44681
44867
  Properties: { LogGroupName: `/aws/lambda/${name}`, RetentionInDays: logRetention }
44682
44868
  };
44869
+ const layers = [...opts.runtimeLayers ?? [], ...app.lambdaInsights ? [app.lambdaInsights.layerArn] : []];
44683
44870
  const codeProps = imageMode ? {
44684
44871
  PackageType: "Image",
44685
44872
  Code: { ImageUri: Fn2.ref("ImageUri") },
@@ -44688,7 +44875,7 @@ function composeServerlessAppTemplate(opts) {
44688
44875
  Runtime: runtime,
44689
44876
  Handler: handler8,
44690
44877
  Code: { S3Bucket: Fn2.ref("ArtifactBucket"), S3Key: Fn2.ref("ArtifactKey") },
44691
- ...opts.runtimeLayers?.length ? { Layers: opts.runtimeLayers } : {}
44878
+ ...layers.length ? { Layers: [...new Set(layers)] } : {}
44692
44879
  };
44693
44880
  resources[logicalId] = {
44694
44881
  Type: "AWS::Lambda::Function",
@@ -46184,4 +46371,4 @@ class ResourceManagementManager {
46184
46371
  }
46185
46372
  var resourceManagementManager = new ResourceManagementManager;
46186
46373
 
46187
- export { detectServiceRegion, signRequest, signRequestAsync, createPresignedUrl, createPresignedUrlAsync, makeAWSRequest, makeAWSRequestOnce, makeAWSRequestAsync, parseXMLResponse, parseJSONResponse, clearSigningKeyCache, getSigningKeyCacheSize, isNodeCryptoAvailable, isWebCryptoAvailable, QueuePresets, RealtimePresets, detectDeploymentTargets, resolveDeploymentMode, deploymentCoexistenceError, resolveAppDatabase, resolveCloudProvider, TemplateBuilder, Pseudo, generateResourceName, generateLogicalId, getTimestamp, sanitizeName, resolveProjectStackName, resolveSiteStackName, resolveSiteResourceName, resolveSiteBucketName, resolveStorageBucketName, resolveDeployBucketName, resolveServerlessAppStackName, resolveServerlessArtifactBucketName, resolveServerlessAssetBucketName, DependencyGraph, analyzeStackDiff, formatDiff, Storage, Registry, CDN, DNS, Security, Compute, Network, FileSystem, Email, exports_incoming_call, Phone, Queue, JobLoader, StacksIntegration, exports_send, SMS, AI, Database, Cache, Permissions, ApiGateway, Messaging, Workflow, Monitoring, Auth, Deployment, AssetHasher, Secrets, ParameterStore, Search, Redirects, Communication, Fn2, Arn, AWS_PSEUDO_PARAMETERS, CloudFormationBuilder, buildCloudFormationTemplate, createStaticSitePreset, createNodeJsServerPreset, createNodeJsServerlessPreset, createServerlessNodePreset, createFullStackAppPreset, createApiBackendPreset, createWordPressPreset, createJamstackPreset, createMicroservicesPreset, createRealtimeAppPreset, createDataPipelinePreset, createMLApiPreset, createTraditionalWebAppPreset, createLaravelPreset, createServerlessLaravelPreset, createDashboardSite, DASHBOARD_STATE_DIR, DASHBOARD_ENTRY, DASHBOARD_PORT_BASE, DASHBOARD_PORT_SPAN, deriveManagementDashboardPort, resolveDashboardDomain, resolveDashboardDomains, hasManagementDashboardSite, MANAGEMENT_DASHBOARD_SITE_PREFIX, managementDashboardSiteName, isManagementDashboardSiteName, resolveManagementDashboardSites, resolveManagementDashboardSite, extendPreset, composePresets, createPreset, mergeInfrastructure, withMonitoring, withSecurity, withDatabase, withCache, withCDN, withQueue, fromEnvironment, fromSharedCredentials, fromEC2Metadata, fromECSMetadata, fromWebIdentity, getCredentials, createCredentialProvider, resolveCredentials, resolveRegion, getAccountId, S3Error, createS3Client, CloudError, ConfigurationError, CredentialError, DeploymentError, ValidationError, AWSAPIError, ErrorCodes, getErrorDetails, createError, DebugLogger, validateConfiguration, detectMisconfigurations, validateCredentials, checkIAMPermissions, getRequiredPermissions, suggestIAMPolicy, DEFAULT_SERVICE_LIMITS, checkServiceQuotas, getQuotaUsageSummary, suggestQuotaIncrease, FileCache, TemplateCache, templateCache, hashFile, hashString, hashBuffer, hashDirectory, hashManifest, quickHash, findChangedFiles, HashCache, parallel, batch, parallelMap, parallelWithRetry, sequence, withTimeout, RateLimiter, chunk, processInChunks, diffTemplates, getDiffSummary, requiresReplacement, categorizeChanges, getDeploymentStrategy, getDiffStats, cloud_config_schema_default, validateAgainstSchema, defaultLocalConfig, getLocalConfig, isLocalDevelopment, getLocalEndpoint, getLocalCredentials, getLocalEnvVars, MockCloudFormation, MockS3, MockDynamoDB, createMockAWS, PreviewEnvironmentManager, previewManager, generatePreviewWorkflow, generateCleanupWorkflow, generateCostReportWorkflow, PreviewNotificationService, previewNotifications, formatTable, formatTree, formatProgressBar, formatBytes, formatDuration, formatList, formatKeyValue, ProgressBar, MultiStepProgress, Spinner, TaskList, suggestCommand, formatSuggestion, isLikelyTypo, getContextualHelp, searchCommands, autocomplete, suggestFlags, formatFlagSuggestions, getCommandUsage, validateCommand, REPL, REPLContext, REPLCommandBuilder, CommandHistory, formatHistory, formatHistoryStats, MultiRegionManager, multiRegionManager, CrossRegionReferenceManager, GlobalResourceManager, RegionPairManager, StackDependencyManager, crossRegionReferenceManager, globalResourceManager, regionPairManager, stackDependencyManager, AWS_REGIONS, getRegion, getAllRegions, getRegionsByLocation, getRegionsByCompliance, getRegionsByPricingTier, isValidRegion, getClosestRegion, suggestRegions, suggestRegionPairs, formatRegion, formatRegionList, getRegionStats, MultiAccountManager, OrganizationManager, multiAccountManager, organizationManager, RECOMMENDED_ACCOUNT_STRUCTURES, RECOMMENDED_SCPS, COMMON_CROSS_ACCOUNT_ROLES, getRecommendedStructure, generateCrossAccountRoleCF, validateAccountStructure, formatAccountStructure, generateDeploymentWorkflow, generateMultiEnvWorkflow, generatePRPreviewWorkflow, generateScheduledWorkflow, generateMatrixWorkflow, generateDeploymentPipeline, generateMultiEnvPipeline, generatePreviewPipeline, generateScheduledPipeline, generateManualPipeline, generateDeploymentConfig, generateMultiEnvConfig, generateScheduledConfig, generateApprovalConfig, generateParallelConfig, BackupManager, backupManager, DisasterRecoveryManager, drManager, AWSConfigManager, awsConfigManager, CloudTrailManager, cloudTrailManager, GuardDutyManager, guardDutyManager, SecurityHubManager, securityHubManager, BlueGreenManager, blueGreenManager, CanaryManager, canaryManager, ABTestManager, abTestManager, ProgressiveDeploymentManager, progressiveDeploymentManager, XRayManager, xrayManager, MetricsManager, metricsManager, LogsManager, logsManager, SyntheticsManager, syntheticsManager, MigrationManager, migrationManager, ReplicaManager, replicaManager, PerformanceManager, performanceManager, DatabaseUserManager, databaseUserManager, SecretsRotationManager, secretsRotationManager, SecretsManager, secretsManager, CertificateManager, certificateManager, SecurityScanningManager, securityScanningManager, ImageScanningManager, imageScanningManager, BuildOptimizationManager, buildOptimizationManager, ContainerRegistryManager, containerRegistryManager, ServiceMeshManager, serviceMeshManager, LambdaLayersManager, lambdaLayersManager, LambdaVersionsManager, lambdaVersionsManager, LambdaConcurrencyManager, lambdaConcurrencyManager, LambdaDestinationsManager, lambdaDestinationsManager, LambdaVPCManager, lambdaVPCManager, LambdaDLQManager, lambdaDLQManager, Route53RoutingManager, route53RoutingManager, DNSSECManager, dnssecManager, Route53ResolverManager, route53ResolverManager, BounceComplaintHandler, bounceComplaintHandler, EmailAnalyticsManager, emailAnalyticsManager, SenderReputationManager, senderReputationManager, EmailTemplateManager, emailTemplateManager, exports_advanced, exports_inbound, exports_advanced2, exports_advanced3, FIFOQueueManager, fifoQueueManager, DLQMonitoringManager, dlqMonitoringManager, BatchProcessingManager, batchProcessingManager, QueueManagementManager, queueManagementManager, createZip, generateBootstrap, runBuildHooks, sha256, artifactKey, packageServerlessApp, MANAGED_NODE_VERSIONS, resolveServerlessRuntime, resolveQueues, resolveQueueNames, composeServerlessAppTemplate, PHP_LAYER_EXTENSIONS, phpLayerPackages, phpLayerBuildStage, generatePhpLayerDockerfile, generateAppImageDockerfile, sharedRuntimeLoop, buildNodeRuntimeLayerZip, buildBunRuntimeLayerZip, resolveApp, eventToRequest, responseToResult, createHttpHandler, createQueueHandler, createCliHandler, createHandlers, generatePhpFpmConfig, phpRuntimeLayerAssets, laravelServerlessEnvDefaults, LARAVEL_SERVERLESS_BUILD_STEPS, buildPhpRuntimeLayerZip, PHP_DEFAULT_EXCLUDES, runPhpBuildHooks, collectPhpAppEntries, packagePhpApp, StaticSiteManager, staticSiteManager, StorageAdvancedManager, storageAdvancedManager, HealthCheckManager, healthCheckManager, NetworkSecurityManager, networkSecurityManager, ResourceManagementManager, resourceManagementManager };
46374
+ export { detectServiceRegion, signRequest, signRequestAsync, createPresignedUrl, createPresignedUrlAsync, makeAWSRequest, makeAWSRequestOnce, makeAWSRequestAsync, parseXMLResponse, parseJSONResponse, clearSigningKeyCache, getSigningKeyCacheSize, isNodeCryptoAvailable, isWebCryptoAvailable, QueuePresets, RealtimePresets, detectDeploymentTargets, resolveDeploymentMode, deploymentCoexistenceError, resolveAppDatabase, resolveCloudProvider, TemplateBuilder, Pseudo, generateResourceName, generateLogicalId, getTimestamp, sanitizeName, resolveProjectStackName, resolveSiteStackName, resolveSiteResourceName, resolveSiteBucketName, resolveStorageBucketName, resolveDeployBucketName, resolveServerlessAppStackName, resolveServerlessArtifactBucketName, resolveServerlessAssetBucketName, DependencyGraph, analyzeStackDiff, formatDiff, Storage, Registry, CDN, DNS, Security, Compute, Network, FileSystem, Email, exports_incoming_call, Phone, Queue, JobLoader, StacksIntegration, exports_send, SMS, Sftp, AI, Database, Cache, Permissions, ApiGateway, Messaging, Workflow, Monitoring, Auth, Deployment, AssetHasher, Secrets, ParameterStore, Search, Redirects, Communication, Fn2, Arn, AWS_PSEUDO_PARAMETERS, CloudFormationBuilder, buildCloudFormationTemplate, createStaticSitePreset, createNodeJsServerPreset, createNodeJsServerlessPreset, createServerlessNodePreset, createFullStackAppPreset, createApiBackendPreset, createWordPressPreset, createJamstackPreset, createMicroservicesPreset, createRealtimeAppPreset, createDataPipelinePreset, createMLApiPreset, createTraditionalWebAppPreset, createLaravelPreset, createServerlessLaravelPreset, createDashboardSite, DASHBOARD_STATE_DIR, DASHBOARD_ENTRY, DASHBOARD_PORT_BASE, DASHBOARD_PORT_SPAN, deriveManagementDashboardPort, resolveDashboardDomain, resolveDashboardDomains, hasManagementDashboardSite, MANAGEMENT_DASHBOARD_SITE_PREFIX, managementDashboardSiteName, isManagementDashboardSiteName, resolveManagementDashboardSites, resolveManagementDashboardSite, extendPreset, composePresets, createPreset, mergeInfrastructure, withMonitoring, withSecurity, withDatabase, withCache, withCDN, withQueue, fromEnvironment, fromSharedCredentials, fromEC2Metadata, fromECSMetadata, fromWebIdentity, getCredentials, createCredentialProvider, resolveCredentials, resolveRegion, getAccountId, S3Error, createS3Client, CloudError, ConfigurationError, CredentialError, DeploymentError, ValidationError, AWSAPIError, ErrorCodes, getErrorDetails, createError, DebugLogger, validateConfiguration, detectMisconfigurations, validateCredentials, checkIAMPermissions, getRequiredPermissions, suggestIAMPolicy, DEFAULT_SERVICE_LIMITS, checkServiceQuotas, getQuotaUsageSummary, suggestQuotaIncrease, FileCache, TemplateCache, templateCache, hashFile, hashString, hashBuffer, hashDirectory, hashManifest, quickHash, findChangedFiles, HashCache, parallel, batch, parallelMap, parallelWithRetry, sequence, withTimeout, RateLimiter, chunk, processInChunks, diffTemplates, getDiffSummary, requiresReplacement, categorizeChanges, getDeploymentStrategy, getDiffStats, cloud_config_schema_default, validateAgainstSchema, defaultLocalConfig, getLocalConfig, isLocalDevelopment, getLocalEndpoint, getLocalCredentials, getLocalEnvVars, MockCloudFormation, MockS3, MockDynamoDB, createMockAWS, PreviewEnvironmentManager, previewManager, generatePreviewWorkflow, generateCleanupWorkflow, generateCostReportWorkflow, PreviewNotificationService, previewNotifications, formatTable, formatTree, formatProgressBar, formatBytes, formatDuration, formatList, formatKeyValue, ProgressBar, MultiStepProgress, Spinner, TaskList, suggestCommand, formatSuggestion, isLikelyTypo, getContextualHelp, searchCommands, autocomplete, suggestFlags, formatFlagSuggestions, getCommandUsage, validateCommand, REPL, REPLContext, REPLCommandBuilder, CommandHistory, formatHistory, formatHistoryStats, MultiRegionManager, multiRegionManager, CrossRegionReferenceManager, GlobalResourceManager, RegionPairManager, StackDependencyManager, crossRegionReferenceManager, globalResourceManager, regionPairManager, stackDependencyManager, AWS_REGIONS, getRegion, getAllRegions, getRegionsByLocation, getRegionsByCompliance, getRegionsByPricingTier, isValidRegion, getClosestRegion, suggestRegions, suggestRegionPairs, formatRegion, formatRegionList, getRegionStats, MultiAccountManager, OrganizationManager, multiAccountManager, organizationManager, RECOMMENDED_ACCOUNT_STRUCTURES, RECOMMENDED_SCPS, COMMON_CROSS_ACCOUNT_ROLES, getRecommendedStructure, generateCrossAccountRoleCF, validateAccountStructure, formatAccountStructure, generateDeploymentWorkflow, generateMultiEnvWorkflow, generatePRPreviewWorkflow, generateScheduledWorkflow, generateMatrixWorkflow, generateDeploymentPipeline, generateMultiEnvPipeline, generatePreviewPipeline, generateScheduledPipeline, generateManualPipeline, generateDeploymentConfig, generateMultiEnvConfig, generateScheduledConfig, generateApprovalConfig, generateParallelConfig, BackupManager, backupManager, DisasterRecoveryManager, drManager, AWSConfigManager, awsConfigManager, CloudTrailManager, cloudTrailManager, GuardDutyManager, guardDutyManager, SecurityHubManager, securityHubManager, BlueGreenManager, blueGreenManager, CanaryManager, canaryManager, ABTestManager, abTestManager, ProgressiveDeploymentManager, progressiveDeploymentManager, XRayManager, xrayManager, MetricsManager, metricsManager, LogsManager, logsManager, SyntheticsManager, syntheticsManager, MigrationManager, migrationManager, ReplicaManager, replicaManager, PerformanceManager, performanceManager, DatabaseUserManager, databaseUserManager, SecretsRotationManager, secretsRotationManager, SecretsManager, secretsManager, CertificateManager, certificateManager, SecurityScanningManager, securityScanningManager, ImageScanningManager, imageScanningManager, BuildOptimizationManager, buildOptimizationManager, ContainerRegistryManager, containerRegistryManager, ServiceMeshManager, serviceMeshManager, LambdaLayersManager, lambdaLayersManager, LambdaVersionsManager, lambdaVersionsManager, LambdaConcurrencyManager, lambdaConcurrencyManager, LambdaDestinationsManager, lambdaDestinationsManager, LambdaVPCManager, lambdaVPCManager, LambdaDLQManager, lambdaDLQManager, Route53RoutingManager, route53RoutingManager, DNSSECManager, dnssecManager, Route53ResolverManager, route53ResolverManager, BounceComplaintHandler, bounceComplaintHandler, EmailAnalyticsManager, emailAnalyticsManager, SenderReputationManager, senderReputationManager, EmailTemplateManager, emailTemplateManager, exports_advanced, exports_inbound, exports_advanced2, exports_advanced3, FIFOQueueManager, fifoQueueManager, DLQMonitoringManager, dlqMonitoringManager, BatchProcessingManager, batchProcessingManager, QueueManagementManager, queueManagementManager, createZip, generateBootstrap, runBuildHooks, sha256, artifactKey, packageServerlessApp, MANAGED_NODE_VERSIONS, resolveServerlessRuntime, resolveQueues, resolveQueueNames, composeServerlessAppTemplate, PHP_LAYER_EXTENSIONS, phpLayerPackages, phpLayerBuildStage, generatePhpLayerDockerfile, generateAppImageDockerfile, sharedRuntimeLoop, buildNodeRuntimeLayerZip, buildBunRuntimeLayerZip, resolveApp, eventToRequest, responseToResult, createHttpHandler, createQueueHandler, createCliHandler, createHandlers, generatePhpFpmConfig, phpRuntimeLayerAssets, laravelServerlessEnvDefaults, LARAVEL_SERVERLESS_BUILD_STEPS, buildPhpRuntimeLayerZip, PHP_DEFAULT_EXCLUDES, runPhpBuildHooks, collectPhpAppEntries, packagePhpApp, StaticSiteManager, staticSiteManager, StorageAdvancedManager, storageAdvancedManager, HealthCheckManager, healthCheckManager, NetworkSecurityManager, networkSecurityManager, ResourceManagementManager, resourceManagementManager };
@@ -6,7 +6,7 @@ import {
6
6
  resolveCloudProvider,
7
7
  resolveManagementDashboardSites,
8
8
  resolveProjectStackName
9
- } from "./chunk-stt1z5cx.js";
9
+ } from "./chunk-r16e02bc.js";
10
10
  import {
11
11
  EC2Client,
12
12
  SSMClient
@@ -2447,6 +2447,9 @@ class HetznerDriver {
2447
2447
  if (!compute) {
2448
2448
  throw new Error("infrastructure.compute is required to provision Hetzner compute");
2449
2449
  }
2450
+ if (config.cloud?.attachTo) {
2451
+ return this.attachToComputeInfrastructure(config.cloud.attachTo, config, environment);
2452
+ }
2450
2453
  const stackName = resolveProjectStackName(config, environment);
2451
2454
  const serverName = `${slug}-${environment}-app`;
2452
2455
  const phpBox = compute.runtime === "php" || !!compute.php;
@@ -3022,9 +3025,9 @@ class HetznerDriver {
3022
3025
  const exact = servers.filter((server) => matchesTsCloudLabels(server.labels, options.slug, options.environment, role));
3023
3026
  if (exact.length > 0)
3024
3027
  return exact.map(toTarget);
3025
- if (role === "app") {
3028
+ if (role === "app" || role === "lb" || role === "services") {
3026
3029
  const state = await readDriverState(options.stackName ?? `${options.slug}-${options.environment}`);
3027
- const pinnedIds = [state?.serverId, ...state?.appServerIds ?? []].filter((id) => typeof id === "number");
3030
+ const pinnedIds = [...new Set(role === "app" ? [state?.serverId, ...state?.appServerIds ?? []] : role === "lb" ? [state?.lbServerId] : [state?.servicesServerId])].filter((id) => typeof id === "number");
3028
3031
  if (pinnedIds.length > 0) {
3029
3032
  const pinned = [];
3030
3033
  for (const id of pinnedIds) {
@@ -3043,6 +3046,34 @@ class HetznerDriver {
3043
3046
  }
3044
3047
  return [];
3045
3048
  }
3049
+ async attachToComputeInfrastructure(ownerSlug, config, environment) {
3050
+ const servers = await this.client.listServers();
3051
+ const running = (role) => servers.filter((server) => server.status !== "off" && matchesTsCloudLabels(server.labels, ownerSlug, environment, role));
3052
+ const appServers = running("app");
3053
+ if (appServers.length === 0) {
3054
+ throw new Error(`Cannot attach '${config.project.slug}' to '${ownerSlug}': no running Hetzner app server is labeled for ${ownerSlug}/${environment}. Deploy the owner project first.`);
3055
+ }
3056
+ const lbServer = running("lb")[0];
3057
+ const servicesServer = running("services")[0];
3058
+ const primaryApp = appServers[0];
3059
+ const publicGateway = lbServer ?? primaryApp;
3060
+ const stackName = resolveProjectStackName(config, environment);
3061
+ const state = {
3062
+ provider: "hetzner",
3063
+ stackName,
3064
+ serverId: primaryApp.id,
3065
+ serverName: primaryApp.name,
3066
+ appServerIds: appServers.map((server) => server.id),
3067
+ lbServerId: lbServer?.id,
3068
+ servicesServerId: servicesServer?.id,
3069
+ servicesPrivateIp: servicesServer?.private_net?.[0]?.ip,
3070
+ publicIp: publicGateway.public_net.ipv4?.ip,
3071
+ deployStoragePath: "/var/ts-cloud/staging",
3072
+ sshUser: this.sshUser
3073
+ };
3074
+ await writeDriverState(stackName, state);
3075
+ return this.outputsFromState(state);
3076
+ }
3046
3077
  async runRemoteDeploy(options) {
3047
3078
  if (options.targets.length === 0) {
3048
3079
  return { success: false, instanceCount: 0, perInstance: [], error: "No targets provided" };
@@ -5120,6 +5151,8 @@ function buildCloudFrontOriginConfig(options) {
5120
5151
  throw new Error("buildCloudFrontOriginConfig: at least one alias is required");
5121
5152
  if (aliases.includes(options.originDomain))
5122
5153
  throw new Error(`buildCloudFrontOriginConfig: originDomain ${options.originDomain} must not be one of the aliases (it would loop)`);
5154
+ if (options.originShield && !options.originShieldRegion)
5155
+ throw new Error("buildCloudFrontOriginConfig: originShieldRegion is required when originShield is enabled");
5123
5156
  const header = options.originSecretHeader ?? "X-Origin-Verify";
5124
5157
  const customHeaders = options.originSecret ? { Quantity: 1, Items: [{ HeaderName: header, HeaderValue: options.originSecret }] } : { Quantity: 0 };
5125
5158
  const behaviors = [...options.behaviors ?? []].sort((a, b) => b.pathPattern.length - a.pathPattern.length);
@@ -5146,7 +5179,7 @@ function buildCloudFrontOriginConfig(options) {
5146
5179
  },
5147
5180
  ConnectionAttempts: 3,
5148
5181
  ConnectionTimeout: 10,
5149
- OriginShield: { Enabled: false },
5182
+ OriginShield: options.originShield ? { Enabled: true, OriginShieldRegion: options.originShieldRegion } : { Enabled: false },
5150
5183
  OriginAccessControlId: ""
5151
5184
  }]
5152
5185
  },
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  buildAndPushServerlessImage
3
- } from "./chunk-tskj9fay.js";
3
+ } from "./chunk-f29w04w5.js";
4
4
  import"./chunk-hsk6fe6x.js";
5
- import"./chunk-stt1z5cx.js";
5
+ import"./chunk-r16e02bc.js";
6
6
  import"./chunk-arsh1g5h.js";
7
7
  import"./chunk-v0bahtg2.js";
8
8
  export {
@@ -14,10 +14,10 @@ import {
14
14
  sanitizeCloudConfig,
15
15
  setMaintenance,
16
16
  startLocalDashboardServer
17
- } from "../chunk-2mw2566h.js";
17
+ } from "../chunk-a4q0231r.js";
18
18
  import {
19
19
  buildAndPushServerlessImage
20
- } from "../chunk-tskj9fay.js";
20
+ } from "../chunk-f29w04w5.js";
21
21
  import"../chunk-b82pbxyp.js";
22
22
  import"../chunk-hsk6fe6x.js";
23
23
  import {
@@ -32,8 +32,8 @@ import {
32
32
  resolveUiSource,
33
33
  siteInstallBase,
34
34
  validateDeploymentConfig
35
- } from "../chunk-3c46eypc.js";
36
- import"../chunk-stt1z5cx.js";
35
+ } from "../chunk-rrn8njr2.js";
36
+ import"../chunk-r16e02bc.js";
37
37
  import"../chunk-93hjhs78.js";
38
38
  import {
39
39
  deleteStaticSite,
@@ -83,6 +83,14 @@ export declare class HetznerDriver implements CloudDriver {
83
83
  getComputeOutputs(options: ProvisionComputeOptions): Promise<ComputeStackOutputs>;
84
84
  uploadRelease(options: UploadReleaseOptions): Promise<UploadReleaseResult>;
85
85
  findComputeTargets(options: FindComputeTargetsOptions): Promise<ComputeTarget[]>;
86
+ /**
87
+ * Attach this project to compute owned by another ts-cloud project.
88
+ *
89
+ * The owner's Hetzner labels are the source of truth. We write a tenant-local
90
+ * state pin so all later deploy operations resolve the same app/LB targets,
91
+ * even when several unrelated managed boxes exist in the Hetzner project.
92
+ */
93
+ private attachToComputeInfrastructure;
86
94
  runRemoteDeploy(options: RunRemoteDeployOptions): Promise<RemoteDeployResult>;
87
95
  /**
88
96
  * Ensure the local SSH public key is registered in the Hetzner project and
@@ -51,8 +51,8 @@ import {
51
51
  waitForCloudInit,
52
52
  waitForSsh,
53
53
  wrapCloudInitUserData
54
- } from "../chunk-3c46eypc.js";
55
- import"../chunk-stt1z5cx.js";
54
+ } from "../chunk-rrn8njr2.js";
55
+ import"../chunk-r16e02bc.js";
56
56
  import"../chunk-93hjhs78.js";
57
57
  import"../chunk-qpj3edwz.js";
58
58
  import"../chunk-vd87cpvn.js";
@@ -53,6 +53,10 @@ export interface BuildCloudFrontOriginOptions {
53
53
  comment?: string;
54
54
  /** `PriceClass_All` | `PriceClass_200` | `PriceClass_100`. @default 'PriceClass_All' */
55
55
  priceClass?: string;
56
+ /** Enable CloudFront Origin Shield for the custom origin. @default false */
57
+ originShield?: boolean;
58
+ /** AWS region used by Origin Shield. Required when {@link originShield} is enabled. */
59
+ originShieldRegion?: string;
56
60
  }
57
61
  /**
58
62
  * Build a complete CloudFront `DistributionConfig` for a self-hosted origin.
package/dist/index.js CHANGED
@@ -57,10 +57,10 @@ import {
57
57
  sanitizeCloudConfig,
58
58
  setMaintenance,
59
59
  startLocalDashboardServer
60
- } from "./chunk-2mw2566h.js";
60
+ } from "./chunk-a4q0231r.js";
61
61
  import {
62
62
  buildAndPushServerlessImage
63
- } from "./chunk-tskj9fay.js";
63
+ } from "./chunk-f29w04w5.js";
64
64
  import {
65
65
  CloudWatchLogsClient,
66
66
  EFSClient,
@@ -108,7 +108,7 @@ import {
108
108
  waitForCloudInit,
109
109
  waitForSsh,
110
110
  wrapCloudInitUserData
111
- } from "./chunk-3c46eypc.js";
111
+ } from "./chunk-rrn8njr2.js";
112
112
  import {
113
113
  ABTestManager,
114
114
  AI,
@@ -231,6 +231,7 @@ import {
231
231
  SecurityScanningManager,
232
232
  SenderReputationManager,
233
233
  ServiceMeshManager,
234
+ Sftp,
234
235
  Spinner,
235
236
  StackDependencyManager,
236
237
  StacksIntegration,
@@ -513,7 +514,7 @@ import {
513
514
  withSecurity,
514
515
  withTimeout,
515
516
  xrayManager
516
- } from "./chunk-stt1z5cx.js";
517
+ } from "./chunk-r16e02bc.js";
517
518
  import {
518
519
  EC2Client,
519
520
  SSMClient
@@ -592,6 +593,7 @@ class InfrastructureGenerator {
592
593
  servers: { ...this.config.infrastructure?.servers, ...envInfra.servers },
593
594
  databases: { ...this.config.infrastructure?.databases, ...envInfra.databases },
594
595
  cdn: { ...this.config.infrastructure?.cdn, ...envInfra.cdn },
596
+ sftp: envInfra.sftp ?? this.config.infrastructure?.sftp,
595
597
  queues: { ...this.config.infrastructure?.queues, ...envInfra.queues },
596
598
  redirects: { ...this.config.infrastructure?.redirects, ...envInfra.redirects },
597
599
  realtime: { ...this.config.infrastructure?.realtime, ...envInfra.realtime },
@@ -1921,6 +1923,23 @@ else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`
1921
1923
  }
1922
1924
  }
1923
1925
  }
1926
+ if (this.mergedConfig.infrastructure?.sftp) {
1927
+ const result = Sftp.create({
1928
+ ...this.mergedConfig.infrastructure.sftp,
1929
+ slug,
1930
+ environment: env
1931
+ });
1932
+ for (const [logicalId, resource] of Object.entries(result.resources))
1933
+ this.builder.addResource(logicalId, resource);
1934
+ this.builder.addOutput("SftpServerId", {
1935
+ Value: { Ref: result.serverLogicalId },
1936
+ Description: "AWS Transfer Family SFTP server ID"
1937
+ });
1938
+ this.builder.addOutput("SftpEndpoint", {
1939
+ Value: { "Fn::Sub": `\${${result.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com` },
1940
+ Description: "AWS Transfer Family SFTP endpoint"
1941
+ });
1942
+ }
1924
1943
  if (hostedZoneId && websiteBucketDistributions.length > 0) {
1925
1944
  for (const { name, distLogicalId, aliases } of websiteBucketDistributions) {
1926
1945
  for (const alias of aliases) {
@@ -2008,7 +2027,11 @@ else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`
2008
2027
  OriginPath: "",
2009
2028
  S3OriginConfig: {
2010
2029
  OriginAccessIdentity: ""
2011
- }
2030
+ },
2031
+ OriginShield: cdnConfig.originShield ? {
2032
+ Enabled: true,
2033
+ OriginShieldRegion: cdnConfig.originShieldRegion || this.mergedConfig.environments[env]?.region || this.mergedConfig.project.region || "us-east-1"
2034
+ } : { Enabled: false }
2012
2035
  }];
2013
2036
  const cacheBehaviors = [];
2014
2037
  const extraDependsOn = [];
@@ -5006,6 +5029,7 @@ export {
5006
5029
  exports_send as SmsHandlers,
5007
5030
  SmsClient,
5008
5031
  exports_advanced3 as SmsAdvanced,
5032
+ Sftp,
5009
5033
  ServiceMeshManager,
5010
5034
  SenderReputationManager,
5011
5035
  SecurityScanningManager,