@infoxchange/make-it-so 3.0.0 → 3.1.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/README.md CHANGED
@@ -2,7 +2,15 @@
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/%40infoxchange%2Fmake-it-so)](https://www.npmjs.com/package/@infoxchange/make-it-so)
4
4
 
5
- A helpful little library that allows you to deploy apps on Infoxchange's (IX) infrastructure without having to specify all the implementation details that are specific to IX's deployment environment. You tell it what you want and it will worry about making it happen. Most of the heavily lifting is done by [SST](https://sst.dev) which is extending to take care the IX related specifics.
5
+ A helpful little library that allows you to deploy apps on Infoxchange's (IX) infrastructure without having to specify
6
+ all the implementation details that are specific to IX's deployment environment. You tell it what you want and it will
7
+ worry about making it happen. Most of the heavily lifting is done by [SST](https://sst.dev) which is extending to take
8
+ care the IX related specifics.
9
+
10
+ > [!WARNING]
11
+ > If the app is using SST v2 then you should use the
12
+ > [@infoxchange/make-it-so-sst-v2 npm package](https://www.npmjs.com/package/@infoxchange/make-it-so-sst-v2) which is
13
+ > built from the [sst-v2 branch](https://github.com/infoxchange/make-it-so/tree/sst-v2).
6
14
 
7
15
  ## Installation
8
16
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/ix/index.ts", "../../node_modules/sst3/platform/src/components/naming.ts", "../../src/components/ix/dns.ts", "../../node_modules/sst3/platform/src/components/component.ts", "../../node_modules/sst3/platform/src/components/error.ts", "../../node_modules/sst3/platform/src/components/aws/helpers/provider.ts", "../../node_modules/sst3/platform/src/util/lazy.ts", "../../src/components/ix/InternalNetwork.ts", "../../src/components/setup-components.ts"],
4
- "sourcesContent": ["export * from \"./dns.js\";\nexport * from \"./InternalNetwork.js\";\n", "import crypto from \"crypto\";\nexport function logicalName(name: string) {\n name = name.replace(/[^a-zA-Z0-9]/g, \"\");\n return name.charAt(0).toUpperCase() + name.slice(1);\n}\nexport function physicalName(max: number, name: string, suffix: string = \"\") {\n // This function does the following:\n // - Removes all non-alphanumeric characters\n // - Prefixes the name with the app name and stage\n // - Truncates the name if it's too long\n // - Adds a random suffix\n // - Adds a suffix if provided\n const main = prefixName(max - 9 - suffix.length, name);\n const random = hashStringToPrettyString(crypto.randomBytes(8).toString(\"hex\"), 8);\n return `${main}-${random}${suffix}`;\n}\nexport function prefixName(max: number, name: string) {\n // This function does the following:\n // - Removes all non-alphanumeric characters\n // - Prefixes the name with the app name and stage\n // - Truncates the name if it's too long\n // ie. foo => app-stage-foo\n name = name.replace(/[^a-zA-Z0-9]/g, \"\");\n const stageLen = $app.stage.length;\n const nameLen = name.length;\n const strategy = nameLen + 1 >= max\n ? (\"name\" as const)\n : nameLen + stageLen + 2 >= max\n ? (\"stage+name\" as const)\n : (\"app+stage+name\" as const);\n if (strategy === \"name\")\n return `${name.substring(0, max)}`;\n if (strategy === \"stage+name\")\n return `${$app.stage.substring(0, max - nameLen - 1)}-${name}`;\n return `${$app.name.substring(0, max - stageLen - nameLen - 2)}-${$app.stage}-${name}`;\n}\nexport function hashNumberToPrettyString(number: number, length: number) {\n const charLength = PRETTY_CHARS.length;\n let hash = \"\";\n while (number > 0) {\n hash = PRETTY_CHARS[number % charLength] + hash;\n number = Math.floor(number / charLength);\n }\n // Padding with 's'\n hash = hash.slice(0, length);\n while (hash.length < length) {\n hash = \"s\" + hash;\n }\n return hash;\n}\nexport function hashStringToPrettyString(str: string, length: number) {\n const hash = crypto.createHash(\"sha256\");\n hash.update(str);\n const num = Number(\"0x\" + hash.digest(\"hex\").substring(0, 16));\n return hashNumberToPrettyString(num, length);\n}\nexport const PRETTY_CHARS = \"abcdefhkmnorstuvwxz\";\n", "// Based on https://github.com/anomalyco/sst/blob/3407c32b2cf97b85ea96a92361c6f4a0a8d55200/platform/src/components/aws/dns.ts\n/**\n * The AWS DNS Adapter is used to create DNS records to manage domains hosted on\n * [Route 53](https://aws.amazon.com/route53/).\n *\n * This adapter is passed in as `domain.dns` when setting a custom domain.\n *\n * @example\n *\n * ```ts\n * {\n * domain: {\n * name: \"example.com\",\n * dns: sst.aws.dns()\n * }\n * }\n * ```\n *\n * You can also specify a hosted zone ID if you have multiple hosted zones with the same domain.\n *\n * ```ts\n * {\n * domain: {\n * name: \"example.com\",\n * dns: sst.aws.dns({\n * zone: \"Z2FDTNDATAQYW2\"\n * })\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\nimport { AliasRecord, Dns, Record as DnsRecord, } from \"sst3/platform/src/components/dns\";\nimport { logicalName } from \"sst3/platform/src/components/naming\";\nimport { ComponentResourceOptions, output } from \"@pulumi/pulumi\";\nimport { Transform, transform } from \"sst3/platform/src/components/component\";\nimport { Input } from \"sst3/platform/src/components/input\";\nimport { useProvider } from \"sst3/platform/src/components/aws/helpers/provider\";\nimport { route53 } from \"@pulumi/aws\";\nimport { VisibleError } from \"sst3/platform/src/components/error\";\nimport * as awsSdk from \"@pulumi/aws\";\nexport interface DnsArgs {\n /**\n * Set the hosted zone ID if you have multiple hosted zones that have the same\n * domain in Route 53.\n *\n * The 14 letter ID of the [Route 53 hosted zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/hosted-zones-working-with.html) that contains the `domainName`. You can find the hosted zone ID in the Route 53 part of the AWS Console.\n *\n * @example\n * ```js\n * {\n * zone: \"Z2FDTNDATAQYW2\"\n * }\n * ```\n */\n zone?: Input<string>;\n /**\n * Set to `true` if you want to let the new DNS records replace the existing ones.\n *\n * :::tip\n * Use this to migrate over your domain without any downtime.\n * :::\n *\n * This is useful if your domain is currently used by another app and you want to switch it\n * to your current app. Without setting this, you'll first have to remove the existing DNS\n * records and then add the new one. This can cause downtime.\n *\n * You can avoid this by setting this to `true` and the existing DNS records will be replaced\n * without any downtime. Just make sure that when you remove your old app, you don't remove\n * the DNS records.\n *\n * @default `false`\n * @example\n * ```js\n * {\n * override: true\n * }\n * ```\n */\n override?: Input<boolean>;\n /**\n * [Transform](/docs/components#transform) how this component creates its underlying\n * resources.\n */\n transform?: {\n /**\n * Transform the AWS Route 53 record resource.\n */\n record?: Transform<route53.RecordArgs & {\n aliasIpType?: \"IPv4\" | \"IPv6\";\n // Can be used to override the raw input to the IX DNS lambda\n lambdaInput?: Record<string, unknown>;\n }>;\n };\n}\nexport function dns(args: DnsArgs = {}) {\n return {\n provider: \"aws\",\n createAlias,\n createCaa,\n createRecord,\n } satisfies Dns;\n /**\n * Creates alias records in the hosted zone.\n *\n * @param namePrefix The prefix to use for the resource names.\n * @param record The alias record to create.\n * @param opts The component resource options.\n */\n function createAlias(namePrefix: string, record: AliasRecord, opts: ComponentResourceOptions) {\n return [\"A\", \"AAAA\"].map((type) => _createRecord(namePrefix, {\n type,\n name: record.name,\n aliases: [\n {\n name: record.aliasName,\n zoneId: record.aliasZone,\n evaluateTargetHealth: true,\n },\n ],\n }, opts));\n }\n function createCaa(\n /* eslint-disable @typescript-eslint/no-unused-vars -- Kept for typing even though it's not used for this\n implementation of Dns */\n namePrefix: string, recordName: string, opts: ComponentResourceOptions) {\n // placeholder\n return undefined;\n }\n /**\n * Creates a DNS record in the hosted zone.\n *\n * @param namePrefix The prefix to use for the resource names.\n * @param record The DNS record to create.\n * @param opts The component resource options.\n */\n function createRecord(namePrefix: string, record: DnsRecord, opts: ComponentResourceOptions) {\n return _createRecord(namePrefix, {\n type: record.type,\n name: record.name,\n ttl: 60,\n records: [record.value],\n }, opts);\n }\n function _createRecord(namePrefix: string, partial: Omit<route53.RecordArgs, \"zoneId\">, opts: ComponentResourceOptions) {\n return output(partial).apply((partial) => {\n const nameSuffix = logicalName(partial.name);\n const zoneId = \"\"; // The IX dns lambda will determine the zone ID based on the domain name\n const dnsRecord = createRecord();\n return dnsRecord;\n function createRecord() {\n const [name, mergedArgs, mergedOpts] = transform(args.transform?.record, `${namePrefix}${partial.type}Record${nameSuffix}`, {\n zoneId,\n allowOverwrite: args.override,\n ...partial,\n }, opts);\n const lambdaInput = output(mergedArgs).apply((mergedArgs) => {\n const { aliases } = mergedArgs;\n let { aliasIpType } = mergedArgs;\n if (aliases && aliases.length > 1) {\n throw new VisibleError(\"Aliases with multiple targets are not supported\");\n }\n const [alias] = aliases || [];\n if (alias) {\n if (mergedArgs.type === \"A\") {\n aliasIpType = \"IPv4\";\n }\n else if (mergedArgs.type === \"AAAA\") {\n aliasIpType = \"IPv6\";\n }\n else {\n throw new VisibleError(\"Alias records can only be created for A or AAAA record types\");\n }\n }\n return {\n RecordType: mergedArgs.type,\n // Even though a trailing dot is valid a bug in the IX dns lambda means that an error occurs\n // when trying to find the hosted zone if there is a trailing dot.\n RecordFQDN: mergedArgs.name.replace(/\\.$/, \"\"),\n // If giving the IX dns lambda multiple values we need to wrap in 'Value' objects\n // unlike for single values where the lambda does it for us\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L133\n RecordValue: mergedArgs.records?.map((value) => ({ Value: value })),\n ...(mergedArgs.zoneId ? { HostedZoneId: mergedArgs.zoneId } : {}),\n ...(mergedArgs.ttl ? { RecordTTL: mergedArgs.ttl } : {}),\n ...(alias\n ? {\n RecordType: \"ALIAS\",\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L145\n RecordValue: alias.name,\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L144\n AliasZoneId: alias.zoneId,\n // alias.evaluateTargetHealth can't be set by the lambda\n IpAddressType: aliasIpType?.toLowerCase(),\n }\n : {}),\n ...mergedArgs.lambdaInput,\n };\n });\n // output([mergedArgs, lambdaInput]).apply(([mergedArgs, lambdaInput]) => console.log('________ BEFORE', mergedArgs, '___________ AFTER', lambdaInput));\n return new awsSdk.lambda.Invocation(name, {\n input: output(lambdaInput).apply((lambdaInput) => JSON.stringify({\n RequestType: \"Create\",\n ResourceProperties: lambdaInput,\n // We need some value so that the lambda doesn't throw an error but we don't want the lambda to actually\n // send a response to this url (the response is for CloudFormation which we're not using). Setting an\n // invalid domain will cause it to log an error but not throw so the lambda is considered successful.\n ResponseURL: \"invalid://make-it-so-dns\",\n StackId: \"\",\n RequestId: \"\",\n LogicalResourceId: \"\",\n })),\n functionName: awsSdk.ssm\n .getParameter({\n name: \"/shared-services/route53/lambdaArn\",\n })\n .then((param) => param.value),\n }, {\n ...mergedOpts,\n // Function can only be invoked from within the same region it is deployed\n provider: useProvider(\"ap-southeast-2\"),\n });\n }\n });\n }\n}\n", "import { ComponentResource, ComponentResourceOptions, Inputs, runtime, output, asset as pulumiAsset, Input, all, Output, } from \"@pulumi/pulumi\";\nimport { prefixName, physicalName } from \"./naming.js\";\nimport { VisibleError } from \"./error.js\";\nimport path from \"path\";\nimport { statSync } from \"fs\";\n// Previously, `this.api.id` was used as the ID. `this.api.id` was of type Output<string>\n// the value evaluates to the mistake id.\n// In the future version, we will release a breaking change to fix this.\nexport const outputId = \"Calling [toString] on an [Output<T>] is not supported.\\n\\nTo get the value of an Output<T> as an Output<string> consider either:\\n1: o.apply(v => `prefix${v}suffix`)\\n2: pulumi.interpolate `prefix${v}suffix`\\n\\nSee https://www.pulumi.com/docs/concepts/inputs-outputs for more details.\\nThis function may throw in a future version of @pulumi/pulumi.\";\n/**\n * Helper type to inline nested types\n */\nexport type Prettify<T> = {\n [K in keyof T]: T[K];\n} & {};\nexport type Transform<T> = Partial<T> | ((args: T, opts: $util.CustomResourceOptions, name: string) => undefined);\nexport function transform<T extends object>(transform: Transform<T> | undefined, name: string, args: T, opts: $util.CustomResourceOptions) {\n // Case: transform is a function\n if (typeof transform === \"function\") {\n transform(args, opts, name);\n return [name, args, opts] as const;\n }\n // Case: no transform\n // Case: transform is an argument\n return [name, { ...args, ...transform }, opts] as const;\n}\nexport class Component extends ComponentResource {\n private componentType: string;\n private componentName: string;\n constructor(type: string, name: string, args?: Inputs, opts?: ComponentResourceOptions) {\n const transforms = ComponentTransforms.get(type) ?? [];\n for (const transform of transforms) {\n transform({ name, props: args, opts });\n }\n super(type, name, args, {\n transformations: [\n // Ensure logical and physical names are prefixed\n (args) => {\n // Ensure component names do not contain spaces\n if (name.includes(\" \"))\n throw new Error(`Invalid component name \"${name}\" (${args.type}). Component names cannot contain spaces.`);\n // Ensure names are prefixed with parent's name\n if (args.type !== type &&\n // @ts-expect-error\n !args.name.startsWith(args.opts.parent!.__name)) {\n throw new Error(`In \"${name}\" component, the logical name of \"${args.name}\" (${args.type}) is not prefixed with parent's name ${\n // @ts-expect-error\n args.opts.parent!.__name}`);\n }\n // Ensure physical names are prefixed with app/stage\n // note: We are setting the default names here instead of inline when creating\n // the resource is b/c the physical name is inferred from the logical name.\n // And it's convenient to access the logical name here.\n if (args.type.startsWith(\"sst:\"))\n return;\n if ([\n // resources manually named\n \"aws:cloudwatch/logGroup:LogGroup\",\n \"aws:ecs/service:Service\",\n \"aws:ecs/taskDefinition:TaskDefinition\",\n \"aws:lb/targetGroup:TargetGroup\",\n \"aws:servicediscovery/privateDnsNamespace:PrivateDnsNamespace\",\n \"aws:servicediscovery/service:Service\",\n // resources not prefixed\n \"pulumi-nodejs:dynamic:Resource\",\n \"random:index/randomId:RandomId\",\n \"random:index/randomPassword:RandomPassword\",\n \"command:local:Command\",\n \"tls:index/privateKey:PrivateKey\",\n \"aws:acm/certificate:Certificate\",\n \"aws:acm/certificateValidation:CertificateValidation\",\n \"aws:apigateway/basePathMapping:BasePathMapping\",\n \"aws:apigateway/deployment:Deployment\",\n \"aws:apigateway/domainName:DomainName\",\n \"aws:apigateway/integration:Integration\",\n \"aws:apigateway/integrationResponse:IntegrationResponse\",\n \"aws:apigateway/method:Method\",\n \"aws:apigateway/methodResponse:MethodResponse\",\n \"aws:apigateway/resource:Resource\",\n \"aws:apigateway/response:Response\",\n \"aws:apigateway/stage:Stage\",\n \"aws:apigateway/usagePlanKey:UsagePlanKey\",\n \"aws:apigatewayv2/apiMapping:ApiMapping\",\n \"aws:apigatewayv2/domainName:DomainName\",\n \"aws:apigatewayv2/integration:Integration\",\n \"aws:apigatewayv2/route:Route\",\n \"aws:apigatewayv2/stage:Stage\",\n \"aws:appautoscaling/target:Target\",\n \"aws:appsync/dataSource:DataSource\",\n \"aws:appsync/domainName:DomainName\",\n \"aws:appsync/domainNameApiAssociation:DomainNameApiAssociation\",\n \"aws:appsync/function:Function\",\n \"aws:appsync/resolver:Resolver\",\n \"aws:ec2/routeTableAssociation:RouteTableAssociation\",\n \"aws:ec2/eipAssociation:EipAssociation\",\n \"aws:ecs/clusterCapacityProviders:ClusterCapacityProviders\",\n \"aws:efs/fileSystem:FileSystem\",\n \"aws:efs/mountTarget:MountTarget\",\n \"aws:efs/accessPoint:AccessPoint\",\n \"aws:iam/accessKey:AccessKey\",\n \"aws:iam/instanceProfile:InstanceProfile\",\n \"aws:iam/policy:Policy\",\n \"aws:iam/userPolicy:UserPolicy\",\n \"aws:cloudfront/cachePolicy:CachePolicy\",\n \"aws:cloudfront/distribution:Distribution\",\n \"aws:cognito/identityPoolRoleAttachment:IdentityPoolRoleAttachment\",\n \"aws:cognito/identityProvider:IdentityProvider\",\n \"aws:cognito/userPoolClient:UserPoolClient\",\n \"aws:lambda/eventSourceMapping:EventSourceMapping\",\n \"aws:lambda/functionEventInvokeConfig:FunctionEventInvokeConfig\",\n \"aws:lambda/functionUrl:FunctionUrl\",\n \"aws:lambda/invocation:Invocation\",\n \"aws:lambda/permission:Permission\",\n \"aws:lambda/provisionedConcurrencyConfig:ProvisionedConcurrencyConfig\",\n \"aws:lb/listener:Listener\",\n \"aws:lb/listenerRule:ListenerRule\",\n \"aws:opensearch/domainPolicy:DomainPolicy\",\n \"aws:rds/proxyDefaultTargetGroup:ProxyDefaultTargetGroup\",\n \"aws:rds/proxyTarget:ProxyTarget\",\n \"aws:route53/record:Record\",\n \"aws:s3/bucketCorsConfigurationV2:BucketCorsConfigurationV2\",\n \"aws:s3/bucketNotification:BucketNotification\",\n \"aws:s3/bucketObject:BucketObject\",\n \"aws:s3/bucketObjectv2:BucketObjectv2\",\n \"aws:s3/bucketPolicy:BucketPolicy\",\n \"aws:s3/bucketPublicAccessBlock:BucketPublicAccessBlock\",\n \"aws:s3/bucketVersioningV2:BucketVersioningV2\",\n \"aws:s3/bucketLifecycleConfigurationV2:BucketLifecycleConfigurationV2\",\n \"aws:s3/bucketWebsiteConfigurationV2:BucketWebsiteConfigurationV2\",\n \"aws:secretsmanager/secretVersion:SecretVersion\",\n \"aws:ses/domainIdentityVerification:DomainIdentityVerification\",\n \"aws:sesv2/configurationSetEventDestination:ConfigurationSetEventDestination\",\n \"aws:sesv2/emailIdentity:EmailIdentity\",\n \"aws:sns/topicPolicy:TopicPolicy\",\n \"aws:sns/topicSubscription:TopicSubscription\",\n \"aws:sqs/queuePolicy:QueuePolicy\",\n \"aws:ssm/parameter:Parameter\",\n \"cloudflare:index/dnsRecord:DnsRecord\",\n \"cloudflare:index/workersCronTrigger:WorkersCronTrigger\",\n \"cloudflare:index/workersCustomDomain:WorkersCustomDomain\",\n \"docker-build:index:Image\",\n \"vercel:index/dnsRecord:DnsRecord\",\n ].includes(args.type))\n return;\n const namingRules: Record<string, [\n string,\n number,\n {\n lower?: boolean;\n replace?: (name: string) => string;\n suffix?: () => Output<string>;\n }?\n ]> = {\n \"aws:apigateway/apiKey:ApiKey\": [\"name\", 1024],\n \"aws:apigateway/authorizer:Authorizer\": [\"name\", 128],\n \"aws:apigateway/restApi:RestApi\": [\"name\", 128],\n \"aws:apigateway/usagePlan:UsagePlan\": [\"name\", 65536], // no length limit\n \"aws:apigatewayv2/api:Api\": [\"name\", 128],\n \"aws:apigatewayv2/authorizer:Authorizer\": [\"name\", 128],\n \"aws:apigatewayv2/vpcLink:VpcLink\": [\"name\", 128],\n \"aws:appautoscaling/policy:Policy\": [\"name\", 255],\n \"aws:appsync/graphQLApi:GraphQLApi\": [\"name\", 65536],\n \"aws:cloudwatch/eventBus:EventBus\": [\"name\", 256],\n \"aws:cloudwatch/eventTarget:EventTarget\": [\"targetId\", 64],\n \"aws:cloudwatch/eventRule:EventRule\": [\"name\", 64],\n \"aws:cloudfront/function:Function\": [\"name\", 64],\n \"aws:cloudfront/keyValueStore:KeyValueStore\": [\"name\", 64],\n \"aws:cognito/identityPool:IdentityPool\": [\"identityPoolName\", 128],\n \"aws:cognito/userPool:UserPool\": [\"name\", 128],\n \"aws:dynamodb/table:Table\": [\"name\", 255],\n \"aws:ec2/keyPair:KeyPair\": [\"keyName\", 255],\n \"aws:ec2/eip:Eip\": [\"tags\", 255],\n \"aws:ec2/instance:Instance\": [\"tags\", 255],\n \"aws:ec2/internetGateway:InternetGateway\": [\"tags\", 255],\n \"aws:ec2/natGateway:NatGateway\": [\"tags\", 255],\n \"aws:ec2/routeTable:RouteTable\": [\"tags\", 255],\n \"aws:ec2/securityGroup:SecurityGroup\": [\"tags\", 255],\n \"aws:ec2/defaultSecurityGroup:DefaultSecurityGroup\": [\"tags\", 255],\n \"aws:ec2/subnet:Subnet\": [\"tags\", 255],\n \"aws:ec2/vpc:Vpc\": [\"tags\", 255],\n \"aws:ecs/cluster:Cluster\": [\"name\", 255],\n \"aws:elasticache/parameterGroup:ParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:elasticache/replicationGroup:ReplicationGroup\": [\n \"replicationGroupId\",\n 40,\n { lower: true, replace: (name) => name.replaceAll(/-+/g, \"-\") },\n ],\n \"aws:elasticache/subnetGroup:SubnetGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:iam/role:Role\": [\"name\", 64],\n \"aws:iam/user:User\": [\"name\", 64],\n \"aws:iot/authorizer:Authorizer\": [\"name\", 128],\n \"aws:iot/topicRule:TopicRule\": [\n \"name\",\n 128,\n { replace: (name) => name.replaceAll(\"-\", \"_\") },\n ],\n \"aws:kinesis/stream:Stream\": [\"name\", 255],\n // AWS Load Balancer name allows 32 chars, but an 8 char suffix\n // ie. \"-1234567\" is automatically added\n \"aws:lb/loadBalancer:LoadBalancer\": [\"name\", 24],\n \"aws:lambda/function:Function\": [\"name\", 64],\n \"aws:opensearch/domain:Domain\": [\"domainName\", 28, { lower: true }],\n \"aws:rds/cluster:Cluster\": [\n \"clusterIdentifier\",\n 63,\n { lower: true },\n ],\n \"aws:rds/clusterInstance:ClusterInstance\": [\n \"identifier\",\n 63,\n { lower: true },\n ],\n \"aws:rds/instance:Instance\": [\"identifier\", 63, { lower: true }],\n \"aws:rds/proxy:Proxy\": [\"name\", 60, { lower: true }],\n \"aws:rds/clusterParameterGroup:ClusterParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:rds/parameterGroup:ParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:rds/subnetGroup:SubnetGroup\": [\"name\", 255, { lower: true }],\n \"aws:s3/bucketV2:BucketV2\": [\"bucket\", 63, { lower: true }],\n \"aws:secretsmanager/secret:Secret\": [\"name\", 512],\n \"aws:sesv2/configurationSet:ConfigurationSet\": [\n \"configurationSetName\",\n 64,\n { lower: true },\n ],\n \"aws:sfn/stateMachine:StateMachine\": [\"name\", 80],\n \"aws:sns/topic:Topic\": [\n \"name\",\n 256,\n {\n suffix: () => output(args.props.fifoTopic).apply((fifo) => fifo ? \".fifo\" : \"\"),\n },\n ],\n \"aws:sqs/queue:Queue\": [\n \"name\",\n 80,\n {\n suffix: () => output(args.props.fifoQueue).apply((fifo) => fifo ? \".fifo\" : \"\"),\n },\n ],\n \"cloudflare:index/d1Database:D1Database\": [\n \"name\",\n 64,\n { lower: true },\n ],\n \"cloudflare:index/r2Bucket:R2Bucket\": [\"name\", 64, { lower: true }],\n \"cloudflare:index/workersScript:WorkersScript\": [\n \"scriptName\",\n 64,\n { lower: true },\n ],\n \"cloudflare:index/queue:Queue\": [\"queueName\", 64, { lower: true }],\n \"cloudflare:index/workersKvNamespace:WorkersKvNamespace\": [\n \"title\",\n 64,\n { lower: true },\n ],\n };\n const rule = namingRules[args.type];\n if (!rule)\n throw new VisibleError(`In \"${name}\" component, the physical name of \"${args.name}\" (${args.type}) is not prefixed`);\n // name is already set\n const nameField = rule[0];\n const length = rule[1];\n const options = rule[2];\n if (args.props[nameField] && args.props[nameField] !== \"\")\n return;\n // Handle prefix field is tags\n if (nameField === \"tags\") {\n return {\n props: {\n ...args.props,\n tags: {\n // @ts-expect-error\n ...args.tags,\n Name: prefixName(length, args.name),\n },\n },\n opts: args.opts,\n };\n }\n // Handle prefix field is name\n const suffix = options?.suffix ? options.suffix() : output(\"\");\n return {\n props: {\n ...args.props,\n [nameField]: suffix.apply((suffix) => {\n let v = options?.lower\n ? physicalName(length, args.name, suffix).toLowerCase()\n : physicalName(length, args.name, suffix);\n if (options?.replace)\n v = options.replace(v);\n return v;\n }),\n },\n opts: {\n ...args.opts,\n ignoreChanges: [...(args.opts.ignoreChanges ?? []), nameField],\n },\n };\n },\n // Set child resources `retainOnDelete` if set on component\n (args) => ({\n props: args.props,\n opts: {\n ...args.opts,\n retainOnDelete: args.opts.retainOnDelete ?? opts?.retainOnDelete,\n },\n }),\n ...(opts?.transformations ?? []),\n ],\n ...opts,\n });\n this.componentType = type;\n this.componentName = name;\n }\n /** @internal */\n protected registerVersion(input: {\n new: number;\n old?: number;\n message?: string;\n forceUpgrade?: `v${number}`;\n }) {\n // Check component version\n const oldVersion = input.old;\n const newVersion = input.new ?? 1;\n if (oldVersion) {\n const className = this.componentType.replaceAll(\":\", \".\");\n // Invalid forceUpgrade value\n if (input.forceUpgrade && input.forceUpgrade !== `v${newVersion}`) {\n throw new VisibleError([\n `The value of \"forceUpgrade\" does not match the version of \"${className}\" component.`,\n `Set \"forceUpgrade\" to \"v${newVersion}\" to upgrade to the new version.`,\n ].join(\"\\n\"));\n }\n // Version upgraded without forceUpgrade\n if (oldVersion < newVersion && !input.forceUpgrade) {\n throw new VisibleError(input.message ?? \"\");\n }\n // Version downgraded\n if (oldVersion > newVersion) {\n throw new VisibleError([\n `It seems you are trying to use an older version of \"${className}\".`,\n `You need to recreate this component to rollback - https://sst.dev/docs/components/#versioning`,\n ].join(\"\\n\"));\n }\n }\n // Set version\n if (newVersion > 1) {\n new Version(this.componentName, newVersion, { parent: this });\n }\n }\n}\nconst ComponentTransforms = new Map<string, any[]>();\nexport function $transform<T, Args, Options>(resource: {\n new (name: string, args: Args, opts?: Options): T;\n}, cb: (args: Args, opts: Options, name: string) => void) {\n // @ts-expect-error\n const type = resource.__pulumiType;\n if (type.startsWith(\"sst:\")) {\n let transforms = ComponentTransforms.get(type);\n if (!transforms) {\n transforms = [];\n ComponentTransforms.set(type, transforms);\n }\n transforms.push((input: any) => {\n cb(input.props, input.opts, input.name);\n return input;\n });\n return;\n }\n runtime.registerStackTransformation((input) => {\n if (input.type !== type)\n return;\n cb(input.props as any, input.opts as any, input.name);\n return input;\n });\n}\nexport function $asset(assetPath: string) {\n const fullPath = path.isAbsolute(assetPath)\n ? assetPath\n : path.join($cli.paths.root, assetPath);\n try {\n return statSync(fullPath).isDirectory()\n ? new pulumiAsset.FileArchive(fullPath)\n : new pulumiAsset.FileAsset(fullPath);\n }\n catch (e) {\n throw new VisibleError(`Asset not found: ${fullPath}`);\n }\n}\nexport function $lazy<T>(fn: () => T) {\n return output(undefined)\n .apply(async () => output(fn()))\n .apply((x) => x);\n}\nexport function $print(...msg: Input<any>[]) {\n return all(msg).apply((msg) => console.log(...msg));\n}\nexport class Version extends ComponentResource {\n constructor(target: string, version: number, opts: ComponentResourceOptions) {\n super(\"sst:sst:Version\", target + \"Version\", {}, opts);\n this.registerOutputs({ target, version });\n }\n}\nexport type ComponentVersion = {\n major: number;\n minor: number;\n};\nexport function parseComponentVersion(version: string): ComponentVersion {\n const [major, minor] = version.split(\".\");\n return { major: parseInt(major), minor: parseInt(minor) };\n}\n", "export class VisibleError extends Error {\n constructor(...message: string[]) {\n super(message.join(\"\\n\"));\n }\n}\n", "import { runtime } from \"@pulumi/pulumi\";\nimport { Provider, Region } from \"@pulumi/aws\";\nimport { lazy } from \"../../../util/lazy\";\nconst useProviderCache = lazy(() => new Map<string, Provider>());\nexport const useProvider = (region: Region) => {\n const cache = useProviderCache();\n const existing = cache.get(region);\n if (existing)\n return existing;\n const config = runtime.allConfig();\n for (const key in config) {\n const value = config[key];\n delete config[key];\n const [prefix, real] = key.split(\":\");\n if (prefix !== \"aws\")\n continue;\n // Array and Object values are JSON encoded, ie.\n // {\n // allowedAccountIds: '[\"112245769880\"]',\n // defaultTags: '{\"tags\":{\"sst:app\":\"playground\",\"sst:stage\":\"frank\"}}',\n // region: 'us-east-1'\n // }\n try {\n config[real] = JSON.parse(value);\n }\n catch (e) {\n config[real] = value;\n }\n }\n const provider = new Provider(`AwsProvider.sst.${region}`, {\n ...config,\n region,\n });\n cache.set(region, provider);\n return provider;\n};\n", "export function lazy<T>(callback: () => T) {\n let loaded = false;\n let result: T;\n return () => {\n if (!loaded) {\n loaded = true;\n result = callback();\n }\n return result;\n };\n}\n", "import * as pulumi from \"@pulumi/pulumi\";\nimport * as awsSdk from \"@pulumi/aws\";\nimport { deployConfig } from \"@infoxchange/make-it-so\";\nimport { Transform, transform } from \"sst3/platform/src/components/component\";\nexport interface InternalNetworkArgs {\n name?: string;\n transform?: {\n securityGroup?: Transform<aws.ec2.SecurityGroupArgs>;\n };\n}\nexport class InternalNetwork extends pulumi.ComponentResource {\n public readonly vpc: pulumi.Output<aws.ec2.GetVpcResult>;\n public readonly subnetIds: pulumi.Output<string[]>;\n public readonly securityGroup: pulumi.Output<aws.ec2.SecurityGroup>;\n constructor(name: string, args: InternalNetworkArgs = {}, opts?: pulumi.ComponentResourceOptions) {\n super(\"ix:aws:InternalNetwork\", name, args, opts);\n // Get VPC ID from SSM parameter\n const vpcIdParam = awsSdk.ssm.getParameterOutput({\n name: \"/vpc/id\",\n }, { parent: this });\n const vpcId = vpcIdParam.value;\n // Get VPC details\n this.vpc = vpcId.apply(async (vpcId) => await awsSdk.ec2.getVpc({ id: vpcId }));\n // Get subnet IDs\n this.subnetIds = InternalNetwork.getVpcSubnetIds();\n this.securityGroup = this.vpc.apply((vpc) => this.createSecurityGroup({\n parentName: name,\n vpc: vpc,\n args: args.transform?.securityGroup,\n opts: { parent: this },\n }));\n this.registerOutputs({\n vpc: this.vpc,\n subnetIds: this.subnetIds,\n });\n }\n public get securityGroupIds(): pulumi.Output<pulumi.Output<string>[]> {\n return pulumi.output(this.securityGroup).apply((sg) => [sg.id]);\n }\n static getVpcSubnetIds(): pulumi.Output<string[]> {\n const { workloadGroup, appName } = deployConfig;\n let suffix = \"\";\n if (workloadGroup === \"ds\") {\n const possibleSuffixes = [\"\", \"-2\"];\n // Randomly select a suffix to spread workload's IP usage across both sets of subnets. Use the app name as a seed\n // to ensure consistent selection on redeploys.\n const hash = appName\n .split(\"\")\n .reduce((acc, char) => acc + char.charCodeAt(0), 0);\n suffix = possibleSuffixes[hash % possibleSuffixes.length];\n }\n const subnetOutputs = [1, 2, 3].map((subnetNum) => awsSdk.ssm.getParameterOutput({\n name: `/vpc/subnet/private-${workloadGroup}${suffix}/${subnetNum}/id`,\n }).value);\n return pulumi.all(subnetOutputs);\n }\n // Based on https://github.com/anomalyco/sst/blob/3407c32b2cf97b85ea96a92361c6f4a0a8d55200/platform/src/components/aws/vpc.ts#L840\n createSecurityGroup({ parentName, vpc, args, opts, }: {\n parentName: string;\n vpc: aws.ec2.GetVpcResult;\n args?: Transform<aws.ec2.SecurityGroupArgs>;\n opts: pulumi.ComponentResourceOptions;\n }) {\n return new awsSdk.ec2.SecurityGroup(...transform(args, `${parentName}SecurityGroup`, {\n description: \"Managed by make-it-so\",\n vpcId: vpc.id,\n egress: [\n {\n fromPort: 0,\n toPort: 0,\n protocol: \"-1\",\n cidrBlocks: [\"0.0.0.0/0\"],\n },\n ],\n ingress: [\n {\n fromPort: 0,\n toPort: 0,\n protocol: \"-1\",\n // Restricts inbound traffic to only within the VPC\n cidrBlocks: [vpc.cidrBlock],\n },\n ],\n }, opts));\n }\n}\n", "import { ix } from \"./index.js\";\nimport { ComponentResourceOptions, output } from \"@pulumi/pulumi\";\nimport { getDeployConfig } from \"@infoxchange/make-it-so\";\nexport function setup() {\n const siteConstructs = [\n sst.aws.StaticSite,\n sst.aws.Nextjs,\n sst.aws.Nuxt,\n sst.aws.Remix,\n sst.aws.React,\n sst.aws.TanStackStart,\n sst.aws.Astro,\n sst.aws.SvelteKit,\n sst.aws.SolidStart,\n sst.aws.Analog,\n ];\n type SiteArgs = ConstructorParameters<(typeof siteConstructs)[number]>[1];\n type Site = {\n new (name: string, args: SiteArgs, opts?: ComponentResourceOptions): unknown;\n };\n for (const construct of siteConstructs) {\n $transform(construct as Site, (args, opts, name) => {\n addDefaultDomain(args, name);\n });\n }\n function addDefaultDomain(args: SiteArgs | undefined, name: string) {\n if (!args) {\n throw new Error(`No args provided to ${name}`);\n }\n const domainArgs = {\n name: getDeployConfig().siteDomains[0],\n dns: ix.dns(),\n };\n if (!(\"domain\" in args)) {\n args.domain = domainArgs;\n }\n else if (args.domain) {\n args.domain = output(args.domain).apply((domain) => {\n if (typeof domain === \"string\") {\n return {\n name: domain,\n dns: domainArgs.dns,\n };\n }\n else if (!(\"dns\" in domain)) {\n domain.dns = domainArgs.dns;\n }\n return domain;\n });\n }\n }\n}\n"],
4
+ "sourcesContent": ["export * from \"./dns.js\";\nexport * from \"./InternalNetwork.js\";\n", "import crypto from \"crypto\";\nexport function logicalName(name: string) {\n name = name.replace(/[^a-zA-Z0-9]/g, \"\");\n return name.charAt(0).toUpperCase() + name.slice(1);\n}\nexport function physicalName(max: number, name: string, suffix: string = \"\") {\n // This function does the following:\n // - Removes all non-alphanumeric characters\n // - Prefixes the name with the app name and stage\n // - Truncates the name if it's too long\n // - Adds a random suffix\n // - Adds a suffix if provided\n const main = prefixName(max - 9 - suffix.length, name);\n const random = hashStringToPrettyString(crypto.randomBytes(8).toString(\"hex\"), 8);\n return `${main}-${random}${suffix}`;\n}\nexport function prefixName(max: number, name: string) {\n // This function does the following:\n // - Removes all non-alphanumeric characters\n // - Prefixes the name with the app name and stage\n // - Truncates the name if it's too long\n // ie. foo => app-stage-foo\n name = name.replace(/[^a-zA-Z0-9]/g, \"\");\n const stageLen = $app.stage.length;\n const nameLen = name.length;\n const strategy = nameLen + 1 >= max\n ? (\"name\" as const)\n : nameLen + stageLen + 2 >= max\n ? (\"stage+name\" as const)\n : (\"app+stage+name\" as const);\n if (strategy === \"name\")\n return `${name.substring(0, max)}`;\n if (strategy === \"stage+name\")\n return `${$app.stage.substring(0, max - nameLen - 1)}-${name}`;\n return `${$app.name.substring(0, max - stageLen - nameLen - 2)}-${$app.stage}-${name}`;\n}\nexport function hashNumberToPrettyString(number: number, length: number) {\n const charLength = PRETTY_CHARS.length;\n let hash = \"\";\n while (number > 0) {\n hash = PRETTY_CHARS[number % charLength] + hash;\n number = Math.floor(number / charLength);\n }\n // Padding with 's'\n hash = hash.slice(0, length);\n while (hash.length < length) {\n hash = \"s\" + hash;\n }\n return hash;\n}\nexport function hashStringToPrettyString(str: string, length: number) {\n const hash = crypto.createHash(\"sha256\");\n hash.update(str);\n const num = Number(\"0x\" + hash.digest(\"hex\").substring(0, 16));\n return hashNumberToPrettyString(num, length);\n}\nexport const PRETTY_CHARS = \"abcdefhkmnorstuvwxz\";\n", "// Based on https://github.com/anomalyco/sst/blob/3407c32b2cf97b85ea96a92361c6f4a0a8d55200/platform/src/components/aws/dns.ts\n/**\n * The AWS DNS Adapter is used to create DNS records to manage domains hosted on\n * [Route 53](https://aws.amazon.com/route53/).\n *\n * This adapter is passed in as `domain.dns` when setting a custom domain.\n *\n * @example\n *\n * ```ts\n * {\n * domain: {\n * name: \"example.com\",\n * dns: sst.aws.dns()\n * }\n * }\n * ```\n *\n * You can also specify a hosted zone ID if you have multiple hosted zones with the same domain.\n *\n * ```ts\n * {\n * domain: {\n * name: \"example.com\",\n * dns: sst.aws.dns({\n * zone: \"Z2FDTNDATAQYW2\"\n * })\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\nimport { AliasRecord, Dns, Record as DnsRecord, } from \"sst3/platform/src/components/dns\";\nimport { logicalName } from \"sst3/platform/src/components/naming\";\nimport { ComponentResourceOptions, output } from \"@pulumi/pulumi\";\nimport { Transform, transform } from \"sst3/platform/src/components/component\";\nimport { Input } from \"sst3/platform/src/components/input\";\nimport { useProvider } from \"sst3/platform/src/components/aws/helpers/provider\";\nimport { route53 } from \"@pulumi/aws\";\nimport { VisibleError } from \"sst3/platform/src/components/error\";\nimport * as awsSdk from \"@pulumi/aws\";\nexport interface DnsArgs {\n /**\n * Set the hosted zone ID if you have multiple hosted zones that have the same\n * domain in Route 53.\n *\n * The 14 letter ID of the [Route 53 hosted zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/hosted-zones-working-with.html) that contains the `domainName`. You can find the hosted zone ID in the Route 53 part of the AWS Console.\n *\n * @example\n * ```js\n * {\n * zone: \"Z2FDTNDATAQYW2\"\n * }\n * ```\n */\n zone?: Input<string>;\n /**\n * Set to `true` if you want to let the new DNS records replace the existing ones.\n *\n * :::tip\n * Use this to migrate over your domain without any downtime.\n * :::\n *\n * This is useful if your domain is currently used by another app and you want to switch it\n * to your current app. Without setting this, you'll first have to remove the existing DNS\n * records and then add the new one. This can cause downtime.\n *\n * You can avoid this by setting this to `true` and the existing DNS records will be replaced\n * without any downtime. Just make sure that when you remove your old app, you don't remove\n * the DNS records.\n *\n * @default `false`\n * @example\n * ```js\n * {\n * override: true\n * }\n * ```\n */\n override?: Input<boolean>;\n /**\n * [Transform](/docs/components#transform) how this component creates its underlying\n * resources.\n */\n transform?: {\n /**\n * Transform the AWS Route 53 record resource.\n */\n record?: Transform<route53.RecordArgs & {\n aliasIpType?: \"IPv4\" | \"IPv6\";\n // Can be used to override the raw input to the IX DNS lambda\n lambdaInput?: Record<string, unknown>;\n }>;\n };\n}\nexport function dns(args: DnsArgs = {}) {\n return {\n provider: \"aws\",\n createAlias,\n createCaa,\n createRecord,\n } satisfies Dns;\n /**\n * Creates alias records in the hosted zone.\n *\n * @param namePrefix The prefix to use for the resource names.\n * @param record The alias record to create.\n * @param opts The component resource options.\n */\n function createAlias(namePrefix: string, record: AliasRecord, opts: ComponentResourceOptions) {\n return [\"A\", \"AAAA\"].map((type) => _createRecord(namePrefix, {\n type,\n name: record.name,\n aliases: [\n {\n name: record.aliasName,\n zoneId: record.aliasZone,\n evaluateTargetHealth: true,\n },\n ],\n }, opts));\n }\n function createCaa(\n /* eslint-disable @typescript-eslint/no-unused-vars -- Kept for typing even though it's not used for this\n implementation of Dns */\n namePrefix: string, recordName: string, opts: ComponentResourceOptions) {\n // placeholder\n return undefined;\n }\n /**\n * Creates a DNS record in the hosted zone.\n *\n * @param namePrefix The prefix to use for the resource names.\n * @param record The DNS record to create.\n * @param opts The component resource options.\n */\n function createRecord(namePrefix: string, record: DnsRecord, opts: ComponentResourceOptions) {\n return _createRecord(namePrefix, {\n type: record.type,\n name: record.name,\n ttl: 60,\n records: [record.value],\n }, opts);\n }\n function _createRecord(namePrefix: string, partial: Omit<route53.RecordArgs, \"zoneId\">, opts: ComponentResourceOptions) {\n return output(partial).apply((partial) => {\n const nameSuffix = logicalName(partial.name);\n const zoneId = \"\"; // The IX dns lambda will determine the zone ID based on the domain name\n const dnsRecord = createRecord();\n return dnsRecord;\n function createRecord() {\n const [name, mergedArgs, mergedOpts] = transform(args.transform?.record, `${namePrefix}${partial.type}Record${nameSuffix}`, {\n zoneId,\n allowOverwrite: args.override,\n ...partial,\n }, opts);\n const lambdaInput = output(mergedArgs).apply((mergedArgs) => {\n const { aliases } = mergedArgs;\n let { aliasIpType } = mergedArgs;\n if (aliases && aliases.length > 1) {\n throw new VisibleError(\"Aliases with multiple targets are not supported\");\n }\n const [alias] = aliases || [];\n if (alias) {\n if (mergedArgs.type === \"A\") {\n aliasIpType = \"IPv4\";\n }\n else if (mergedArgs.type === \"AAAA\") {\n aliasIpType = \"IPv6\";\n }\n else {\n throw new VisibleError(\"Alias records can only be created for A or AAAA record types\");\n }\n }\n return {\n RecordType: mergedArgs.type,\n // Even though a trailing dot is valid a bug in the IX dns lambda means that an error occurs\n // when trying to find the hosted zone if there is a trailing dot.\n RecordFQDN: mergedArgs.name.replace(/\\.$/, \"\"),\n // If giving the IX dns lambda multiple values we need to wrap in 'Value' objects\n // unlike for single values where the lambda does it for us\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L133\n RecordValue: mergedArgs.records?.map((value) => ({ Value: value })),\n ...(mergedArgs.zoneId ? { HostedZoneId: mergedArgs.zoneId } : {}),\n ...(mergedArgs.ttl ? { RecordTTL: mergedArgs.ttl } : {}),\n ...(alias\n ? {\n RecordType: \"ALIAS\",\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L145\n RecordValue: alias.name,\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L144\n AliasZoneId: alias.zoneId,\n // alias.evaluateTargetHealth can't be set by the lambda\n IpAddressType: aliasIpType?.toLowerCase(),\n }\n : {}),\n ...mergedArgs.lambdaInput,\n };\n });\n // output([mergedArgs, lambdaInput]).apply(([mergedArgs, lambdaInput]) => console.log('________ BEFORE', mergedArgs, '___________ AFTER', lambdaInput));\n return new awsSdk.lambda.Invocation(name, {\n input: output(lambdaInput).apply((lambdaInput) => JSON.stringify({\n RequestType: \"Create\",\n ResourceProperties: lambdaInput,\n // We need some value so that the lambda doesn't throw an error but we don't want the lambda to actually\n // send a response to this url (the response is for CloudFormation which we're not using). Setting an\n // invalid domain will cause it to log an error but not throw so the lambda is considered successful.\n ResponseURL: \"invalid://make-it-so-dns\",\n StackId: \"\",\n RequestId: \"\",\n LogicalResourceId: \"\",\n })),\n functionName: awsSdk.ssm\n .getParameter({\n name: \"/shared-services/route53/lambdaArn\",\n })\n .then((param) => param.value),\n }, {\n ...mergedOpts,\n // Function can only be invoked from within the same region it is deployed\n provider: useProvider(\"ap-southeast-2\"),\n });\n }\n });\n }\n}\n", "import { ComponentResource, ComponentResourceOptions, Inputs, runtime, output, asset as pulumiAsset, Input, all, Output, } from \"@pulumi/pulumi\";\nimport { prefixName, physicalName } from \"./naming.js\";\nimport { VisibleError } from \"./error.js\";\nimport path from \"path\";\nimport { statSync } from \"fs\";\n// Previously, `this.api.id` was used as the ID. `this.api.id` was of type Output<string>\n// the value evaluates to the mistake id.\n// In the future version, we will release a breaking change to fix this.\nexport const outputId = \"Calling [toString] on an [Output<T>] is not supported.\\n\\nTo get the value of an Output<T> as an Output<string> consider either:\\n1: o.apply(v => `prefix${v}suffix`)\\n2: pulumi.interpolate `prefix${v}suffix`\\n\\nSee https://www.pulumi.com/docs/concepts/inputs-outputs for more details.\\nThis function may throw in a future version of @pulumi/pulumi.\";\n/**\n * Helper type to inline nested types\n */\nexport type Prettify<T> = {\n [K in keyof T]: T[K];\n} & {};\nexport type Transform<T> = Partial<T> | ((args: T, opts: $util.CustomResourceOptions, name: string) => undefined);\nexport function transform<T extends object>(transform: Transform<T> | undefined, name: string, args: T, opts: $util.CustomResourceOptions) {\n // Case: transform is a function\n if (typeof transform === \"function\") {\n transform(args, opts, name);\n return [name, args, opts] as const;\n }\n // Case: no transform\n // Case: transform is an argument\n return [name, { ...args, ...transform }, opts] as const;\n}\nexport class Component extends ComponentResource {\n private componentType: string;\n private componentName: string;\n constructor(type: string, name: string, args?: Inputs, opts?: ComponentResourceOptions) {\n const transforms = ComponentTransforms.get(type) ?? [];\n for (const transform of transforms) {\n transform({ name, props: args, opts });\n }\n super(type, name, {}, {\n transformations: [\n // Ensure logical and physical names are prefixed\n (args) => {\n // Ensure component names do not contain spaces\n if (name.includes(\" \"))\n throw new Error(`Invalid component name \"${name}\" (${args.type}). Component names cannot contain spaces.`);\n // Ensure names are prefixed with parent's name\n if (args.type !== type &&\n // @ts-expect-error\n !args.name.startsWith(args.opts.parent!.__name)) {\n throw new Error(`In \"${name}\" component, the logical name of \"${args.name}\" (${args.type}) is not prefixed with parent's name ${\n // @ts-expect-error\n args.opts.parent!.__name}`);\n }\n // Ensure physical names are prefixed with app/stage\n // note: We are setting the default names here instead of inline when creating\n // the resource is b/c the physical name is inferred from the logical name.\n // And it's convenient to access the logical name here.\n if (args.type.startsWith(\"sst:\"))\n return;\n if ([\n // resources manually named\n \"aws:cloudwatch/logGroup:LogGroup\",\n \"aws:ecs/service:Service\",\n \"aws:ecs/taskDefinition:TaskDefinition\",\n \"aws:lb/targetGroup:TargetGroup\",\n \"aws:servicediscovery/privateDnsNamespace:PrivateDnsNamespace\",\n \"aws:servicediscovery/service:Service\",\n // resources not prefixed\n \"pulumi-nodejs:dynamic:Resource\",\n \"random:index/randomId:RandomId\",\n \"random:index/randomPassword:RandomPassword\",\n \"command:local:Command\",\n \"tls:index/privateKey:PrivateKey\",\n \"aws:acm/certificate:Certificate\",\n \"aws:acm/certificateValidation:CertificateValidation\",\n \"aws:apigateway/basePathMapping:BasePathMapping\",\n \"aws:apigateway/deployment:Deployment\",\n \"aws:apigateway/domainName:DomainName\",\n \"aws:apigateway/integration:Integration\",\n \"aws:apigateway/integrationResponse:IntegrationResponse\",\n \"aws:apigateway/method:Method\",\n \"aws:apigateway/methodResponse:MethodResponse\",\n \"aws:apigateway/resource:Resource\",\n \"aws:apigateway/response:Response\",\n \"aws:apigateway/stage:Stage\",\n \"aws:apigateway/usagePlanKey:UsagePlanKey\",\n \"aws:apigatewayv2/apiMapping:ApiMapping\",\n \"aws:apigatewayv2/domainName:DomainName\",\n \"aws:apigatewayv2/integration:Integration\",\n \"aws:apigatewayv2/route:Route\",\n \"aws:apigatewayv2/stage:Stage\",\n \"aws:appautoscaling/target:Target\",\n \"aws:appsync/dataSource:DataSource\",\n \"aws:appsync/domainName:DomainName\",\n \"aws:appsync/domainNameApiAssociation:DomainNameApiAssociation\",\n \"aws:appsync/function:Function\",\n \"aws:appsync/resolver:Resolver\",\n \"aws:ec2/routeTableAssociation:RouteTableAssociation\",\n \"aws:ec2/eipAssociation:EipAssociation\",\n \"aws:ecs/clusterCapacityProviders:ClusterCapacityProviders\",\n \"aws:efs/fileSystem:FileSystem\",\n \"aws:efs/mountTarget:MountTarget\",\n \"aws:efs/accessPoint:AccessPoint\",\n \"aws:iam/accessKey:AccessKey\",\n \"aws:iam/instanceProfile:InstanceProfile\",\n \"aws:iam/policy:Policy\",\n \"aws:iam/userPolicy:UserPolicy\",\n \"aws:cloudfront/cachePolicy:CachePolicy\",\n \"aws:cloudfront/distribution:Distribution\",\n \"aws:cognito/identityPoolRoleAttachment:IdentityPoolRoleAttachment\",\n \"aws:cognito/identityProvider:IdentityProvider\",\n \"aws:cognito/userPoolClient:UserPoolClient\",\n \"aws:lambda/eventSourceMapping:EventSourceMapping\",\n \"aws:lambda/functionEventInvokeConfig:FunctionEventInvokeConfig\",\n \"aws:lambda/functionUrl:FunctionUrl\",\n \"aws:lambda/invocation:Invocation\",\n \"aws:lambda/permission:Permission\",\n \"aws:lambda/provisionedConcurrencyConfig:ProvisionedConcurrencyConfig\",\n \"aws:lb/listener:Listener\",\n \"aws:lb/listenerRule:ListenerRule\",\n \"aws:opensearch/domainPolicy:DomainPolicy\",\n \"aws:rds/proxyDefaultTargetGroup:ProxyDefaultTargetGroup\",\n \"aws:rds/proxyTarget:ProxyTarget\",\n \"aws:route53/record:Record\",\n \"aws:s3/bucketCorsConfigurationV2:BucketCorsConfigurationV2\",\n \"aws:s3/bucketNotification:BucketNotification\",\n \"aws:s3/bucketObject:BucketObject\",\n \"aws:s3/bucketObjectv2:BucketObjectv2\",\n \"aws:s3/bucketPolicy:BucketPolicy\",\n \"aws:s3/bucketPublicAccessBlock:BucketPublicAccessBlock\",\n \"aws:s3/bucketVersioningV2:BucketVersioningV2\",\n \"aws:s3/bucketLifecycleConfigurationV2:BucketLifecycleConfigurationV2\",\n \"aws:s3/bucketWebsiteConfigurationV2:BucketWebsiteConfigurationV2\",\n \"aws:secretsmanager/secretVersion:SecretVersion\",\n \"aws:ses/domainIdentityVerification:DomainIdentityVerification\",\n \"aws:sesv2/configurationSetEventDestination:ConfigurationSetEventDestination\",\n \"aws:sesv2/emailIdentity:EmailIdentity\",\n \"aws:sns/topicPolicy:TopicPolicy\",\n \"aws:sns/topicSubscription:TopicSubscription\",\n \"aws:sqs/queuePolicy:QueuePolicy\",\n \"aws:ssm/parameter:Parameter\",\n \"cloudflare:index/dnsRecord:DnsRecord\",\n \"cloudflare:index/workersCronTrigger:WorkersCronTrigger\",\n \"cloudflare:index/workersCustomDomain:WorkersCustomDomain\",\n \"docker-build:index:Image\",\n \"vercel:index/dnsRecord:DnsRecord\",\n ].includes(args.type))\n return;\n const namingRules: Record<string, [\n string,\n number,\n {\n lower?: boolean;\n replace?: (name: string) => string;\n suffix?: () => Output<string>;\n }?\n ]> = {\n \"aws:apigateway/apiKey:ApiKey\": [\"name\", 1024],\n \"aws:apigateway/authorizer:Authorizer\": [\"name\", 128],\n \"aws:apigateway/restApi:RestApi\": [\"name\", 128],\n \"aws:apigateway/usagePlan:UsagePlan\": [\"name\", 65536], // no length limit\n \"aws:apigatewayv2/api:Api\": [\"name\", 128],\n \"aws:apigatewayv2/authorizer:Authorizer\": [\"name\", 128],\n \"aws:apigatewayv2/vpcLink:VpcLink\": [\"name\", 128],\n \"aws:appautoscaling/policy:Policy\": [\"name\", 255],\n \"aws:appsync/graphQLApi:GraphQLApi\": [\"name\", 65536],\n \"aws:cloudwatch/eventBus:EventBus\": [\"name\", 256],\n \"aws:cloudwatch/eventTarget:EventTarget\": [\"targetId\", 64],\n \"aws:cloudwatch/eventRule:EventRule\": [\"name\", 64],\n \"aws:cloudfront/function:Function\": [\"name\", 64],\n \"aws:cloudfront/keyValueStore:KeyValueStore\": [\"name\", 64],\n \"aws:cognito/identityPool:IdentityPool\": [\"identityPoolName\", 128],\n \"aws:cognito/userPool:UserPool\": [\"name\", 128],\n \"aws:dynamodb/table:Table\": [\"name\", 255],\n \"aws:ec2/keyPair:KeyPair\": [\"keyName\", 255],\n \"aws:ec2/eip:Eip\": [\"tags\", 255],\n \"aws:ec2/instance:Instance\": [\"tags\", 255],\n \"aws:ec2/internetGateway:InternetGateway\": [\"tags\", 255],\n \"aws:ec2/natGateway:NatGateway\": [\"tags\", 255],\n \"aws:ec2/routeTable:RouteTable\": [\"tags\", 255],\n \"aws:ec2/securityGroup:SecurityGroup\": [\"tags\", 255],\n \"aws:ec2/defaultSecurityGroup:DefaultSecurityGroup\": [\"tags\", 255],\n \"aws:ec2/subnet:Subnet\": [\"tags\", 255],\n \"aws:ec2/vpc:Vpc\": [\"tags\", 255],\n \"aws:ecs/cluster:Cluster\": [\"name\", 255],\n \"aws:elasticache/parameterGroup:ParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:elasticache/replicationGroup:ReplicationGroup\": [\n \"replicationGroupId\",\n 40,\n { lower: true, replace: (name) => name.replaceAll(/-+/g, \"-\") },\n ],\n \"aws:elasticache/subnetGroup:SubnetGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:iam/role:Role\": [\"name\", 64],\n \"aws:iam/user:User\": [\"name\", 64],\n \"aws:iot/authorizer:Authorizer\": [\"name\", 128],\n \"aws:iot/topicRule:TopicRule\": [\n \"name\",\n 128,\n { replace: (name) => name.replaceAll(\"-\", \"_\") },\n ],\n \"aws:kinesis/stream:Stream\": [\"name\", 255],\n // AWS Load Balancer name allows 32 chars, but an 8 char suffix\n // ie. \"-1234567\" is automatically added\n \"aws:lb/loadBalancer:LoadBalancer\": [\"name\", 24],\n \"aws:lambda/function:Function\": [\"name\", 64],\n \"aws:opensearch/domain:Domain\": [\"domainName\", 28, { lower: true }],\n \"aws:rds/cluster:Cluster\": [\n \"clusterIdentifier\",\n 63,\n { lower: true },\n ],\n \"aws:rds/clusterInstance:ClusterInstance\": [\n \"identifier\",\n 63,\n { lower: true },\n ],\n \"aws:rds/instance:Instance\": [\"identifier\", 63, { lower: true }],\n \"aws:rds/proxy:Proxy\": [\"name\", 60, { lower: true }],\n \"aws:rds/clusterParameterGroup:ClusterParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:rds/parameterGroup:ParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:rds/subnetGroup:SubnetGroup\": [\"name\", 255, { lower: true }],\n \"aws:s3/bucketV2:BucketV2\": [\"bucket\", 63, { lower: true }],\n \"aws:secretsmanager/secret:Secret\": [\"name\", 512],\n \"aws:sesv2/configurationSet:ConfigurationSet\": [\n \"configurationSetName\",\n 64,\n { lower: true },\n ],\n \"aws:sfn/stateMachine:StateMachine\": [\"name\", 80],\n \"aws:sns/topic:Topic\": [\n \"name\",\n 256,\n {\n suffix: () => output(args.props.fifoTopic).apply((fifo) => fifo ? \".fifo\" : \"\"),\n },\n ],\n \"aws:sqs/queue:Queue\": [\n \"name\",\n 80,\n {\n suffix: () => output(args.props.fifoQueue).apply((fifo) => fifo ? \".fifo\" : \"\"),\n },\n ],\n \"cloudflare:index/d1Database:D1Database\": [\n \"name\",\n 64,\n { lower: true },\n ],\n \"cloudflare:index/r2Bucket:R2Bucket\": [\"name\", 64, { lower: true }],\n \"cloudflare:index/workersScript:WorkersScript\": [\n \"scriptName\",\n 64,\n { lower: true },\n ],\n \"cloudflare:index/queue:Queue\": [\"queueName\", 64, { lower: true }],\n \"cloudflare:index/workersKvNamespace:WorkersKvNamespace\": [\n \"title\",\n 64,\n { lower: true },\n ],\n };\n const rule = namingRules[args.type];\n if (!rule)\n throw new VisibleError(`In \"${name}\" component, the physical name of \"${args.name}\" (${args.type}) is not prefixed`);\n // name is already set\n const nameField = rule[0];\n const length = rule[1];\n const options = rule[2];\n if (args.props[nameField] && args.props[nameField] !== \"\")\n return;\n // Handle prefix field is tags\n if (nameField === \"tags\") {\n return {\n props: {\n ...args.props,\n tags: {\n // @ts-expect-error\n ...args.tags,\n Name: prefixName(length, args.name),\n },\n },\n opts: args.opts,\n };\n }\n // Handle prefix field is name\n const suffix = options?.suffix ? options.suffix() : output(\"\");\n return {\n props: {\n ...args.props,\n [nameField]: suffix.apply((suffix) => {\n let v = options?.lower\n ? physicalName(length, args.name, suffix).toLowerCase()\n : physicalName(length, args.name, suffix);\n if (options?.replace)\n v = options.replace(v);\n return v;\n }),\n },\n opts: {\n ...args.opts,\n ignoreChanges: [...(args.opts.ignoreChanges ?? []), nameField],\n },\n };\n },\n // Set child resources `retainOnDelete` if set on component\n (args) => ({\n props: args.props,\n opts: {\n ...args.opts,\n retainOnDelete: args.opts.retainOnDelete ?? opts?.retainOnDelete,\n },\n }),\n ...(opts?.transformations ?? []),\n ],\n ...opts,\n });\n this.componentType = type;\n this.componentName = name;\n }\n /** @internal */\n protected registerVersion(input: {\n new: number;\n old?: number;\n message?: string;\n forceUpgrade?: `v${number}`;\n }) {\n // Check component version\n const oldVersion = input.old;\n const newVersion = input.new ?? 1;\n if (oldVersion) {\n const className = this.componentType.replaceAll(\":\", \".\");\n // Invalid forceUpgrade value\n if (input.forceUpgrade && input.forceUpgrade !== `v${newVersion}`) {\n throw new VisibleError([\n `The value of \"forceUpgrade\" does not match the version of \"${className}\" component.`,\n `Set \"forceUpgrade\" to \"v${newVersion}\" to upgrade to the new version.`,\n ].join(\"\\n\"));\n }\n // Version upgraded without forceUpgrade\n if (oldVersion < newVersion && !input.forceUpgrade) {\n throw new VisibleError(input.message ?? \"\");\n }\n // Version downgraded\n if (oldVersion > newVersion) {\n throw new VisibleError([\n `It seems you are trying to use an older version of \"${className}\".`,\n `You need to recreate this component to rollback - https://sst.dev/docs/components/#versioning`,\n ].join(\"\\n\"));\n }\n }\n // Set version\n if (newVersion > 1) {\n new Version(this.componentName, newVersion, { parent: this });\n }\n }\n}\nconst ComponentTransforms = new Map<string, any[]>();\nexport function $transform<T, Args, Options>(resource: {\n new (name: string, args: Args, opts?: Options): T;\n}, cb: (args: Args, opts: Options, name: string) => void) {\n // @ts-expect-error\n const type = resource.__pulumiType;\n if (type.startsWith(\"sst:\")) {\n let transforms = ComponentTransforms.get(type);\n if (!transforms) {\n transforms = [];\n ComponentTransforms.set(type, transforms);\n }\n transforms.push((input: any) => {\n cb(input.props, input.opts, input.name);\n return input;\n });\n return;\n }\n runtime.registerStackTransformation((input) => {\n if (input.type !== type)\n return;\n cb(input.props as any, input.opts as any, input.name);\n return input;\n });\n}\nexport function $asset(assetPath: string) {\n const fullPath = path.isAbsolute(assetPath)\n ? assetPath\n : path.join($cli.paths.root, assetPath);\n try {\n return statSync(fullPath).isDirectory()\n ? new pulumiAsset.FileArchive(fullPath)\n : new pulumiAsset.FileAsset(fullPath);\n }\n catch (e) {\n throw new VisibleError(`Asset not found: ${fullPath}`);\n }\n}\nexport function $lazy<T>(fn: () => T) {\n return output(undefined)\n .apply(async () => output(fn()))\n .apply((x) => x);\n}\nexport function $print(...msg: Input<any>[]) {\n return all(msg).apply((msg) => console.log(...msg));\n}\nexport class Version extends ComponentResource {\n constructor(target: string, version: number, opts: ComponentResourceOptions) {\n super(\"sst:sst:Version\", target + \"Version\", {}, opts);\n this.registerOutputs({ target, version });\n }\n}\nexport type ComponentVersion = {\n major: number;\n minor: number;\n};\nexport function parseComponentVersion(version: string): ComponentVersion {\n const [major, minor] = version.split(\".\");\n return { major: parseInt(major), minor: parseInt(minor) };\n}\n", "export class VisibleError extends Error {\n constructor(...message: string[]) {\n super(message.join(\"\\n\"));\n }\n}\n", "import { runtime } from \"@pulumi/pulumi\";\nimport { Provider, Region } from \"@pulumi/aws\";\nimport { lazy } from \"../../../util/lazy\";\nconst useProviderCache = lazy(() => new Map<string, Provider>());\nexport const useProvider = (region: Region) => {\n const cache = useProviderCache();\n const existing = cache.get(region);\n if (existing)\n return existing;\n const config = runtime.allConfig();\n for (const key in config) {\n const value = config[key];\n delete config[key];\n const [prefix, real] = key.split(\":\");\n if (prefix !== \"aws\")\n continue;\n // Array and Object values are JSON encoded, ie.\n // {\n // allowedAccountIds: '[\"112245769880\"]',\n // defaultTags: '{\"tags\":{\"sst:app\":\"playground\",\"sst:stage\":\"frank\"}}',\n // region: 'us-east-1'\n // }\n try {\n config[real] = JSON.parse(value);\n }\n catch (e) {\n config[real] = value;\n }\n }\n const provider = new Provider(`AwsProvider.sst.${region}`, {\n ...config,\n region,\n });\n cache.set(region, provider);\n return provider;\n};\n", "export function lazy<T>(callback: () => T) {\n let loaded = false;\n let result: T;\n return () => {\n if (!loaded) {\n loaded = true;\n result = callback();\n }\n return result;\n };\n}\n", "import * as pulumi from \"@pulumi/pulumi\";\nimport * as awsSdk from \"@pulumi/aws\";\nimport { deployConfig } from \"@infoxchange/make-it-so\";\nimport { Transform, transform } from \"sst3/platform/src/components/component\";\nexport interface InternalNetworkArgs {\n name?: string;\n transform?: {\n securityGroup?: Transform<aws.ec2.SecurityGroupArgs>;\n };\n}\nexport class InternalNetwork extends pulumi.ComponentResource {\n public readonly vpc: pulumi.Output<aws.ec2.GetVpcResult>;\n public readonly subnetIds: pulumi.Output<string[]>;\n public readonly securityGroup: pulumi.Output<aws.ec2.SecurityGroup>;\n constructor(name: string, args: InternalNetworkArgs = {}, opts?: pulumi.ComponentResourceOptions) {\n super(\"ix:aws:InternalNetwork\", name, args, opts);\n // Get VPC ID from SSM parameter\n const vpcIdParam = awsSdk.ssm.getParameterOutput({\n name: \"/vpc/id\",\n }, { parent: this });\n const vpcId = vpcIdParam.value;\n // Get VPC details\n this.vpc = vpcId.apply(async (vpcId) => await awsSdk.ec2.getVpc({ id: vpcId }));\n // Get subnet IDs\n this.subnetIds = InternalNetwork.getVpcSubnetIds();\n this.securityGroup = this.vpc.apply((vpc) => this.createSecurityGroup({\n parentName: name,\n vpc: vpc,\n args: args.transform?.securityGroup,\n opts: { parent: this },\n }));\n this.registerOutputs({\n vpc: this.vpc,\n subnetIds: this.subnetIds,\n });\n }\n public get securityGroupIds(): pulumi.Output<pulumi.Output<string>[]> {\n return pulumi.output(this.securityGroup).apply((sg) => [sg.id]);\n }\n static getVpcSubnetIds(): pulumi.Output<string[]> {\n const { workloadGroup, appName } = deployConfig;\n let suffix = \"\";\n if (workloadGroup === \"ds\") {\n const possibleSuffixes = [\"\", \"-2\"];\n // Randomly select a suffix to spread workload's IP usage across both sets of subnets. Use the app name as a seed\n // to ensure consistent selection on redeploys.\n const hash = appName\n .split(\"\")\n .reduce((acc, char) => acc + char.charCodeAt(0), 0);\n suffix = possibleSuffixes[hash % possibleSuffixes.length];\n }\n const subnetOutputs = [1, 2, 3].map((subnetNum) => awsSdk.ssm.getParameterOutput({\n name: `/vpc/subnet/private-${workloadGroup}${suffix}/${subnetNum}/id`,\n }).value);\n return pulumi.all(subnetOutputs);\n }\n // Based on https://github.com/anomalyco/sst/blob/3407c32b2cf97b85ea96a92361c6f4a0a8d55200/platform/src/components/aws/vpc.ts#L840\n createSecurityGroup({ parentName, vpc, args, opts, }: {\n parentName: string;\n vpc: aws.ec2.GetVpcResult;\n args?: Transform<aws.ec2.SecurityGroupArgs>;\n opts: pulumi.ComponentResourceOptions;\n }) {\n return new awsSdk.ec2.SecurityGroup(...transform(args, `${parentName}SecurityGroup`, {\n description: \"Managed by make-it-so\",\n vpcId: vpc.id,\n egress: [\n {\n fromPort: 0,\n toPort: 0,\n protocol: \"-1\",\n cidrBlocks: [\"0.0.0.0/0\"],\n },\n ],\n ingress: [\n {\n fromPort: 0,\n toPort: 0,\n protocol: \"-1\",\n // Restricts inbound traffic to only within the VPC\n cidrBlocks: [vpc.cidrBlock],\n },\n ],\n }, opts));\n }\n}\n", "import { ix } from \"./index.js\";\nimport { ComponentResourceOptions, output } from \"@pulumi/pulumi\";\nimport { getDeployConfig } from \"@infoxchange/make-it-so\";\nexport function setup() {\n const siteConstructs = [\n sst.aws.StaticSite,\n sst.aws.Nextjs,\n sst.aws.Nuxt,\n sst.aws.Remix,\n sst.aws.React,\n sst.aws.TanStackStart,\n sst.aws.Astro,\n sst.aws.SvelteKit,\n sst.aws.SolidStart,\n sst.aws.Analog,\n ];\n type SiteArgs = ConstructorParameters<(typeof siteConstructs)[number]>[1];\n type Site = {\n new (name: string, args: SiteArgs, opts?: ComponentResourceOptions): unknown;\n };\n for (const construct of siteConstructs) {\n $transform(construct as Site, (args, opts, name) => {\n addDefaultDomain(args, name);\n });\n }\n function addDefaultDomain(args: SiteArgs | undefined, name: string) {\n if (!args) {\n throw new Error(`No args provided to ${name}`);\n }\n const domainArgs = {\n name: getDeployConfig().siteDomains[0],\n dns: ix.dns(),\n };\n if (!(\"domain\" in args)) {\n args.domain = domainArgs;\n }\n else if (args.domain) {\n args.domain = output(args.domain).apply((domain) => {\n if (typeof domain === \"string\") {\n return {\n name: domain,\n dns: domainArgs.dns,\n };\n }\n else if (!(\"dns\" in domain)) {\n domain.dns = domainArgs.dns;\n }\n return domain;\n });\n }\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": ["output", "transform", "runtime", "runtime", "output", "partial", "createRecord", "mergedArgs", "lambdaInput", "awsSdk", "vpcId", "output"]
7
7
  }
@@ -15,6 +15,7 @@ export declare const deployConfig: {
15
15
  smtpPort: number;
16
16
  clamAVUrl: string;
17
17
  vpcHttpProxy: string;
18
+ alarmSnsTopic: string;
18
19
  } | {
19
20
  isIxDeploy: false;
20
21
  appName: string;
@@ -30,6 +31,7 @@ export declare const deployConfig: {
30
31
  smtpHost: string;
31
32
  clamAVUrl: string;
32
33
  vpcHttpProxy: string;
34
+ alarmSnsTopic: string;
33
35
  isInternalApp?: boolean | undefined;
34
36
  smtpPort?: number | undefined;
35
37
  };
@@ -50,6 +52,7 @@ export declare const getDeployConfig: () => {
50
52
  smtpPort: number;
51
53
  clamAVUrl: string;
52
54
  vpcHttpProxy: string;
55
+ alarmSnsTopic: string;
53
56
  } | {
54
57
  isIxDeploy: false;
55
58
  appName: string;
@@ -65,6 +68,7 @@ export declare const getDeployConfig: () => {
65
68
  smtpHost: string;
66
69
  clamAVUrl: string;
67
70
  vpcHttpProxy: string;
71
+ alarmSnsTopic: string;
68
72
  isInternalApp?: boolean | undefined;
69
73
  smtpPort?: number | undefined;
70
74
  };
@@ -1 +1 @@
1
- {"version":3,"file":"deployConfig.d.ts","sourceRoot":"","sources":["../src/deployConfig.ts"],"names":[],"mappings":"AAyFA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAA6B,CAAC;AAGvD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAmC,CAAC"}
1
+ {"version":3,"file":"deployConfig.d.ts","sourceRoot":"","sources":["../src/deployConfig.ts"],"names":[],"mappings":"AA4FA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAA6B,CAAC;AAGvD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAmC,CAAC"}
package/dist/index.js CHANGED
@@ -23,7 +23,8 @@ var getEnvVars = () => ({
23
23
  smtpHost: process.env.SMTP_HOST ?? "",
24
24
  smtpPort: process.env.SMTP_PORT ?? "",
25
25
  clamAVUrl: process.env.CLAMAV_URL ?? "",
26
- vpcHttpProxy: process.env.VPC_HTTP_PROXY ?? ""
26
+ vpcHttpProxy: process.env.VPC_HTTP_PROXY ?? "",
27
+ alarmSnsTopic: process.env.IX_ALARM_SNS_TOPIC ?? ""
27
28
  });
28
29
  var ixDeployConfigSchema = z.object({
29
30
  isIxDeploy: z.literal(true),
@@ -41,7 +42,8 @@ var ixDeployConfigSchema = z.object({
41
42
  smtpHost: z.string().min(1),
42
43
  smtpPort: z.coerce.number().int(),
43
44
  clamAVUrl: z.string().url(),
44
- vpcHttpProxy: z.string().url()
45
+ vpcHttpProxy: z.string().url(),
46
+ alarmSnsTopic: z.string().min(1)
45
47
  }).strip();
46
48
  var nonIxDeployConfigSchema = z.object({
47
49
  isIxDeploy: z.literal(false),
@@ -59,7 +61,8 @@ var nonIxDeployConfigSchema = z.object({
59
61
  smtpHost: z.string(),
60
62
  smtpPort: z.string().transform((val) => isNaN(parseInt(val, 10)) ? void 0 : parseInt(val, 10)),
61
63
  clamAVUrl: z.string(),
62
- vpcHttpProxy: z.string()
64
+ vpcHttpProxy: z.string(),
65
+ alarmSnsTopic: z.string()
63
66
  }).strip();
64
67
  var schema = z.discriminatedUnion("isIxDeploy", [
65
68
  ixDeployConfigSchema,
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/deployConfig.ts", "../src/components/ix/index.ts", "../node_modules/sst3/platform/src/components/naming.ts", "../src/components/ix/dns.ts", "../node_modules/sst3/platform/src/components/component.ts", "../node_modules/sst3/platform/src/components/error.ts", "../node_modules/sst3/platform/src/components/aws/helpers/provider.ts", "../node_modules/sst3/platform/src/util/lazy.ts", "../src/components/ix/InternalNetwork.ts", "../src/components/setup-components.ts", "../src/lib/proxy/fetch.ts"],
4
- "sourcesContent": ["import { z } from \"zod\";\nconst getEnvVars = () => ({\n isIxDeploy: process.env.IX_DEPLOYMENT?.toLowerCase() === \"true\", // This needs to start as a bool for the discriminated union\n appName: process.env.IX_APP_NAME ?? \"\",\n environment: process.env.IX_ENVIRONMENT ?? \"\",\n workloadGroup: process.env.IX_WORKLOAD_GROUP ?? \"\",\n primaryAwsRegion: process.env.IX_PRIMARY_AWS_REGION ?? \"\",\n siteDomains: process.env.IX_SITE_DOMAINS ?? \"\",\n siteDomainAliases: process.env.IX_SITE_DOMAIN_ALIASES ?? \"\",\n isInternalApp: process.env.IX_INTERNAL_APP ?? \"\",\n deploymentType: process.env.IX_DEPLOYMENT_TYPE ?? \"\",\n sourceCommitRef: process.env.IX_SOURCE_COMMIT_REF ?? \"\",\n sourceCommitHash: process.env.IX_SOURCE_COMMIT_HASH ?? \"\",\n deployTriggeredBy: process.env.IX_DEPLOY_TRIGGERED_BY ?? \"\",\n smtpHost: process.env.SMTP_HOST ?? \"\",\n smtpPort: process.env.SMTP_PORT ?? \"\",\n clamAVUrl: process.env.CLAMAV_URL ?? \"\",\n vpcHttpProxy: process.env.VPC_HTTP_PROXY ?? \"\",\n}) satisfies Record<string, string | boolean>;\nconst ixDeployConfigSchema = z\n .object({\n isIxDeploy: z.literal(true),\n appName: z.string().min(1),\n environment: z.enum([\"dev\", \"test\", \"uat\", \"prod\"]),\n workloadGroup: z.enum([\"ds\", \"srs\"]),\n primaryAwsRegion: z.literal(\"ap-southeast-2\"),\n siteDomains: z.string().transform((val) => val\n .split(\",\")\n .map((domain) => domain.trim())\n .filter(Boolean)),\n siteDomainAliases: z.string().transform((val) => val\n .split(\",\")\n .map((domain) => domain.trim())\n .filter(Boolean)),\n isInternalApp: z.coerce.boolean(),\n deploymentType: z.enum([\"docker\", \"serverless\"]),\n sourceCommitRef: z.string().min(1),\n sourceCommitHash: z.string().min(1),\n deployTriggeredBy: z.string().min(1),\n smtpHost: z.string().min(1),\n smtpPort: z.coerce.number().int(),\n clamAVUrl: z.string().url(),\n vpcHttpProxy: z.string().url(),\n} satisfies Record<keyof ReturnType<typeof getEnvVars>, unknown>)\n .strip();\nconst nonIxDeployConfigSchema = z\n .object({\n isIxDeploy: z.literal(false),\n appName: z.string(),\n environment: z.string(),\n workloadGroup: z.string(),\n primaryAwsRegion: z.string(),\n siteDomains: z\n .string()\n .transform((val) => val.split(\",\").map((domain) => domain.trim())),\n siteDomainAliases: z\n .string()\n .transform((val) => val.split(\",\").map((domain) => domain.trim())),\n isInternalApp: z\n .string()\n .transform((val) => (val ? val.toLowerCase() === \"true\" : undefined)),\n deploymentType: z.string(),\n sourceCommitRef: z.string(),\n sourceCommitHash: z.string(),\n deployTriggeredBy: z.string(),\n smtpHost: z.string(),\n smtpPort: z\n .string()\n .transform((val) => isNaN(parseInt(val, 10)) ? undefined : parseInt(val, 10)),\n clamAVUrl: z.string(),\n vpcHttpProxy: z.string(),\n} satisfies Record<keyof ReturnType<typeof getEnvVars>, unknown>)\n .strip();\nconst schema = z.discriminatedUnion(\"isIxDeploy\", [\n ixDeployConfigSchema,\n nonIxDeployConfigSchema,\n]);\nexport const deployConfig = schema.parse(getEnvVars());\n// process.env values can change at runtime so we provide a way to re-parse the config as needed\nexport const getDeployConfig = () => schema.parse(getEnvVars());\n", "export * from \"./dns.js\";\nexport * from \"./InternalNetwork.js\";\n", "import crypto from \"crypto\";\nexport function logicalName(name: string) {\n name = name.replace(/[^a-zA-Z0-9]/g, \"\");\n return name.charAt(0).toUpperCase() + name.slice(1);\n}\nexport function physicalName(max: number, name: string, suffix: string = \"\") {\n // This function does the following:\n // - Removes all non-alphanumeric characters\n // - Prefixes the name with the app name and stage\n // - Truncates the name if it's too long\n // - Adds a random suffix\n // - Adds a suffix if provided\n const main = prefixName(max - 9 - suffix.length, name);\n const random = hashStringToPrettyString(crypto.randomBytes(8).toString(\"hex\"), 8);\n return `${main}-${random}${suffix}`;\n}\nexport function prefixName(max: number, name: string) {\n // This function does the following:\n // - Removes all non-alphanumeric characters\n // - Prefixes the name with the app name and stage\n // - Truncates the name if it's too long\n // ie. foo => app-stage-foo\n name = name.replace(/[^a-zA-Z0-9]/g, \"\");\n const stageLen = $app.stage.length;\n const nameLen = name.length;\n const strategy = nameLen + 1 >= max\n ? (\"name\" as const)\n : nameLen + stageLen + 2 >= max\n ? (\"stage+name\" as const)\n : (\"app+stage+name\" as const);\n if (strategy === \"name\")\n return `${name.substring(0, max)}`;\n if (strategy === \"stage+name\")\n return `${$app.stage.substring(0, max - nameLen - 1)}-${name}`;\n return `${$app.name.substring(0, max - stageLen - nameLen - 2)}-${$app.stage}-${name}`;\n}\nexport function hashNumberToPrettyString(number: number, length: number) {\n const charLength = PRETTY_CHARS.length;\n let hash = \"\";\n while (number > 0) {\n hash = PRETTY_CHARS[number % charLength] + hash;\n number = Math.floor(number / charLength);\n }\n // Padding with 's'\n hash = hash.slice(0, length);\n while (hash.length < length) {\n hash = \"s\" + hash;\n }\n return hash;\n}\nexport function hashStringToPrettyString(str: string, length: number) {\n const hash = crypto.createHash(\"sha256\");\n hash.update(str);\n const num = Number(\"0x\" + hash.digest(\"hex\").substring(0, 16));\n return hashNumberToPrettyString(num, length);\n}\nexport const PRETTY_CHARS = \"abcdefhkmnorstuvwxz\";\n", "// Based on https://github.com/anomalyco/sst/blob/3407c32b2cf97b85ea96a92361c6f4a0a8d55200/platform/src/components/aws/dns.ts\n/**\n * The AWS DNS Adapter is used to create DNS records to manage domains hosted on\n * [Route 53](https://aws.amazon.com/route53/).\n *\n * This adapter is passed in as `domain.dns` when setting a custom domain.\n *\n * @example\n *\n * ```ts\n * {\n * domain: {\n * name: \"example.com\",\n * dns: sst.aws.dns()\n * }\n * }\n * ```\n *\n * You can also specify a hosted zone ID if you have multiple hosted zones with the same domain.\n *\n * ```ts\n * {\n * domain: {\n * name: \"example.com\",\n * dns: sst.aws.dns({\n * zone: \"Z2FDTNDATAQYW2\"\n * })\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\nimport { AliasRecord, Dns, Record as DnsRecord, } from \"sst3/platform/src/components/dns\";\nimport { logicalName } from \"sst3/platform/src/components/naming\";\nimport { ComponentResourceOptions, output } from \"@pulumi/pulumi\";\nimport { Transform, transform } from \"sst3/platform/src/components/component\";\nimport { Input } from \"sst3/platform/src/components/input\";\nimport { useProvider } from \"sst3/platform/src/components/aws/helpers/provider\";\nimport { route53 } from \"@pulumi/aws\";\nimport { VisibleError } from \"sst3/platform/src/components/error\";\nimport * as awsSdk from \"@pulumi/aws\";\nexport interface DnsArgs {\n /**\n * Set the hosted zone ID if you have multiple hosted zones that have the same\n * domain in Route 53.\n *\n * The 14 letter ID of the [Route 53 hosted zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/hosted-zones-working-with.html) that contains the `domainName`. You can find the hosted zone ID in the Route 53 part of the AWS Console.\n *\n * @example\n * ```js\n * {\n * zone: \"Z2FDTNDATAQYW2\"\n * }\n * ```\n */\n zone?: Input<string>;\n /**\n * Set to `true` if you want to let the new DNS records replace the existing ones.\n *\n * :::tip\n * Use this to migrate over your domain without any downtime.\n * :::\n *\n * This is useful if your domain is currently used by another app and you want to switch it\n * to your current app. Without setting this, you'll first have to remove the existing DNS\n * records and then add the new one. This can cause downtime.\n *\n * You can avoid this by setting this to `true` and the existing DNS records will be replaced\n * without any downtime. Just make sure that when you remove your old app, you don't remove\n * the DNS records.\n *\n * @default `false`\n * @example\n * ```js\n * {\n * override: true\n * }\n * ```\n */\n override?: Input<boolean>;\n /**\n * [Transform](/docs/components#transform) how this component creates its underlying\n * resources.\n */\n transform?: {\n /**\n * Transform the AWS Route 53 record resource.\n */\n record?: Transform<route53.RecordArgs & {\n aliasIpType?: \"IPv4\" | \"IPv6\";\n // Can be used to override the raw input to the IX DNS lambda\n lambdaInput?: Record<string, unknown>;\n }>;\n };\n}\nexport function dns(args: DnsArgs = {}) {\n return {\n provider: \"aws\",\n createAlias,\n createCaa,\n createRecord,\n } satisfies Dns;\n /**\n * Creates alias records in the hosted zone.\n *\n * @param namePrefix The prefix to use for the resource names.\n * @param record The alias record to create.\n * @param opts The component resource options.\n */\n function createAlias(namePrefix: string, record: AliasRecord, opts: ComponentResourceOptions) {\n return [\"A\", \"AAAA\"].map((type) => _createRecord(namePrefix, {\n type,\n name: record.name,\n aliases: [\n {\n name: record.aliasName,\n zoneId: record.aliasZone,\n evaluateTargetHealth: true,\n },\n ],\n }, opts));\n }\n function createCaa(\n /* eslint-disable @typescript-eslint/no-unused-vars -- Kept for typing even though it's not used for this\n implementation of Dns */\n namePrefix: string, recordName: string, opts: ComponentResourceOptions) {\n // placeholder\n return undefined;\n }\n /**\n * Creates a DNS record in the hosted zone.\n *\n * @param namePrefix The prefix to use for the resource names.\n * @param record The DNS record to create.\n * @param opts The component resource options.\n */\n function createRecord(namePrefix: string, record: DnsRecord, opts: ComponentResourceOptions) {\n return _createRecord(namePrefix, {\n type: record.type,\n name: record.name,\n ttl: 60,\n records: [record.value],\n }, opts);\n }\n function _createRecord(namePrefix: string, partial: Omit<route53.RecordArgs, \"zoneId\">, opts: ComponentResourceOptions) {\n return output(partial).apply((partial) => {\n const nameSuffix = logicalName(partial.name);\n const zoneId = \"\"; // The IX dns lambda will determine the zone ID based on the domain name\n const dnsRecord = createRecord();\n return dnsRecord;\n function createRecord() {\n const [name, mergedArgs, mergedOpts] = transform(args.transform?.record, `${namePrefix}${partial.type}Record${nameSuffix}`, {\n zoneId,\n allowOverwrite: args.override,\n ...partial,\n }, opts);\n const lambdaInput = output(mergedArgs).apply((mergedArgs) => {\n const { aliases } = mergedArgs;\n let { aliasIpType } = mergedArgs;\n if (aliases && aliases.length > 1) {\n throw new VisibleError(\"Aliases with multiple targets are not supported\");\n }\n const [alias] = aliases || [];\n if (alias) {\n if (mergedArgs.type === \"A\") {\n aliasIpType = \"IPv4\";\n }\n else if (mergedArgs.type === \"AAAA\") {\n aliasIpType = \"IPv6\";\n }\n else {\n throw new VisibleError(\"Alias records can only be created for A or AAAA record types\");\n }\n }\n return {\n RecordType: mergedArgs.type,\n // Even though a trailing dot is valid a bug in the IX dns lambda means that an error occurs\n // when trying to find the hosted zone if there is a trailing dot.\n RecordFQDN: mergedArgs.name.replace(/\\.$/, \"\"),\n // If giving the IX dns lambda multiple values we need to wrap in 'Value' objects\n // unlike for single values where the lambda does it for us\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L133\n RecordValue: mergedArgs.records?.map((value) => ({ Value: value })),\n ...(mergedArgs.zoneId ? { HostedZoneId: mergedArgs.zoneId } : {}),\n ...(mergedArgs.ttl ? { RecordTTL: mergedArgs.ttl } : {}),\n ...(alias\n ? {\n RecordType: \"ALIAS\",\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L145\n RecordValue: alias.name,\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L144\n AliasZoneId: alias.zoneId,\n // alias.evaluateTargetHealth can't be set by the lambda\n IpAddressType: aliasIpType?.toLowerCase(),\n }\n : {}),\n ...mergedArgs.lambdaInput,\n };\n });\n // output([mergedArgs, lambdaInput]).apply(([mergedArgs, lambdaInput]) => console.log('________ BEFORE', mergedArgs, '___________ AFTER', lambdaInput));\n return new awsSdk.lambda.Invocation(name, {\n input: output(lambdaInput).apply((lambdaInput) => JSON.stringify({\n RequestType: \"Create\",\n ResourceProperties: lambdaInput,\n // We need some value so that the lambda doesn't throw an error but we don't want the lambda to actually\n // send a response to this url (the response is for CloudFormation which we're not using). Setting an\n // invalid domain will cause it to log an error but not throw so the lambda is considered successful.\n ResponseURL: \"invalid://make-it-so-dns\",\n StackId: \"\",\n RequestId: \"\",\n LogicalResourceId: \"\",\n })),\n functionName: awsSdk.ssm\n .getParameter({\n name: \"/shared-services/route53/lambdaArn\",\n })\n .then((param) => param.value),\n }, {\n ...mergedOpts,\n // Function can only be invoked from within the same region it is deployed\n provider: useProvider(\"ap-southeast-2\"),\n });\n }\n });\n }\n}\n", "import { ComponentResource, ComponentResourceOptions, Inputs, runtime, output, asset as pulumiAsset, Input, all, Output, } from \"@pulumi/pulumi\";\nimport { prefixName, physicalName } from \"./naming.js\";\nimport { VisibleError } from \"./error.js\";\nimport path from \"path\";\nimport { statSync } from \"fs\";\n// Previously, `this.api.id` was used as the ID. `this.api.id` was of type Output<string>\n// the value evaluates to the mistake id.\n// In the future version, we will release a breaking change to fix this.\nexport const outputId = \"Calling [toString] on an [Output<T>] is not supported.\\n\\nTo get the value of an Output<T> as an Output<string> consider either:\\n1: o.apply(v => `prefix${v}suffix`)\\n2: pulumi.interpolate `prefix${v}suffix`\\n\\nSee https://www.pulumi.com/docs/concepts/inputs-outputs for more details.\\nThis function may throw in a future version of @pulumi/pulumi.\";\n/**\n * Helper type to inline nested types\n */\nexport type Prettify<T> = {\n [K in keyof T]: T[K];\n} & {};\nexport type Transform<T> = Partial<T> | ((args: T, opts: $util.CustomResourceOptions, name: string) => undefined);\nexport function transform<T extends object>(transform: Transform<T> | undefined, name: string, args: T, opts: $util.CustomResourceOptions) {\n // Case: transform is a function\n if (typeof transform === \"function\") {\n transform(args, opts, name);\n return [name, args, opts] as const;\n }\n // Case: no transform\n // Case: transform is an argument\n return [name, { ...args, ...transform }, opts] as const;\n}\nexport class Component extends ComponentResource {\n private componentType: string;\n private componentName: string;\n constructor(type: string, name: string, args?: Inputs, opts?: ComponentResourceOptions) {\n const transforms = ComponentTransforms.get(type) ?? [];\n for (const transform of transforms) {\n transform({ name, props: args, opts });\n }\n super(type, name, args, {\n transformations: [\n // Ensure logical and physical names are prefixed\n (args) => {\n // Ensure component names do not contain spaces\n if (name.includes(\" \"))\n throw new Error(`Invalid component name \"${name}\" (${args.type}). Component names cannot contain spaces.`);\n // Ensure names are prefixed with parent's name\n if (args.type !== type &&\n // @ts-expect-error\n !args.name.startsWith(args.opts.parent!.__name)) {\n throw new Error(`In \"${name}\" component, the logical name of \"${args.name}\" (${args.type}) is not prefixed with parent's name ${\n // @ts-expect-error\n args.opts.parent!.__name}`);\n }\n // Ensure physical names are prefixed with app/stage\n // note: We are setting the default names here instead of inline when creating\n // the resource is b/c the physical name is inferred from the logical name.\n // And it's convenient to access the logical name here.\n if (args.type.startsWith(\"sst:\"))\n return;\n if ([\n // resources manually named\n \"aws:cloudwatch/logGroup:LogGroup\",\n \"aws:ecs/service:Service\",\n \"aws:ecs/taskDefinition:TaskDefinition\",\n \"aws:lb/targetGroup:TargetGroup\",\n \"aws:servicediscovery/privateDnsNamespace:PrivateDnsNamespace\",\n \"aws:servicediscovery/service:Service\",\n // resources not prefixed\n \"pulumi-nodejs:dynamic:Resource\",\n \"random:index/randomId:RandomId\",\n \"random:index/randomPassword:RandomPassword\",\n \"command:local:Command\",\n \"tls:index/privateKey:PrivateKey\",\n \"aws:acm/certificate:Certificate\",\n \"aws:acm/certificateValidation:CertificateValidation\",\n \"aws:apigateway/basePathMapping:BasePathMapping\",\n \"aws:apigateway/deployment:Deployment\",\n \"aws:apigateway/domainName:DomainName\",\n \"aws:apigateway/integration:Integration\",\n \"aws:apigateway/integrationResponse:IntegrationResponse\",\n \"aws:apigateway/method:Method\",\n \"aws:apigateway/methodResponse:MethodResponse\",\n \"aws:apigateway/resource:Resource\",\n \"aws:apigateway/response:Response\",\n \"aws:apigateway/stage:Stage\",\n \"aws:apigateway/usagePlanKey:UsagePlanKey\",\n \"aws:apigatewayv2/apiMapping:ApiMapping\",\n \"aws:apigatewayv2/domainName:DomainName\",\n \"aws:apigatewayv2/integration:Integration\",\n \"aws:apigatewayv2/route:Route\",\n \"aws:apigatewayv2/stage:Stage\",\n \"aws:appautoscaling/target:Target\",\n \"aws:appsync/dataSource:DataSource\",\n \"aws:appsync/domainName:DomainName\",\n \"aws:appsync/domainNameApiAssociation:DomainNameApiAssociation\",\n \"aws:appsync/function:Function\",\n \"aws:appsync/resolver:Resolver\",\n \"aws:ec2/routeTableAssociation:RouteTableAssociation\",\n \"aws:ec2/eipAssociation:EipAssociation\",\n \"aws:ecs/clusterCapacityProviders:ClusterCapacityProviders\",\n \"aws:efs/fileSystem:FileSystem\",\n \"aws:efs/mountTarget:MountTarget\",\n \"aws:efs/accessPoint:AccessPoint\",\n \"aws:iam/accessKey:AccessKey\",\n \"aws:iam/instanceProfile:InstanceProfile\",\n \"aws:iam/policy:Policy\",\n \"aws:iam/userPolicy:UserPolicy\",\n \"aws:cloudfront/cachePolicy:CachePolicy\",\n \"aws:cloudfront/distribution:Distribution\",\n \"aws:cognito/identityPoolRoleAttachment:IdentityPoolRoleAttachment\",\n \"aws:cognito/identityProvider:IdentityProvider\",\n \"aws:cognito/userPoolClient:UserPoolClient\",\n \"aws:lambda/eventSourceMapping:EventSourceMapping\",\n \"aws:lambda/functionEventInvokeConfig:FunctionEventInvokeConfig\",\n \"aws:lambda/functionUrl:FunctionUrl\",\n \"aws:lambda/invocation:Invocation\",\n \"aws:lambda/permission:Permission\",\n \"aws:lambda/provisionedConcurrencyConfig:ProvisionedConcurrencyConfig\",\n \"aws:lb/listener:Listener\",\n \"aws:lb/listenerRule:ListenerRule\",\n \"aws:opensearch/domainPolicy:DomainPolicy\",\n \"aws:rds/proxyDefaultTargetGroup:ProxyDefaultTargetGroup\",\n \"aws:rds/proxyTarget:ProxyTarget\",\n \"aws:route53/record:Record\",\n \"aws:s3/bucketCorsConfigurationV2:BucketCorsConfigurationV2\",\n \"aws:s3/bucketNotification:BucketNotification\",\n \"aws:s3/bucketObject:BucketObject\",\n \"aws:s3/bucketObjectv2:BucketObjectv2\",\n \"aws:s3/bucketPolicy:BucketPolicy\",\n \"aws:s3/bucketPublicAccessBlock:BucketPublicAccessBlock\",\n \"aws:s3/bucketVersioningV2:BucketVersioningV2\",\n \"aws:s3/bucketLifecycleConfigurationV2:BucketLifecycleConfigurationV2\",\n \"aws:s3/bucketWebsiteConfigurationV2:BucketWebsiteConfigurationV2\",\n \"aws:secretsmanager/secretVersion:SecretVersion\",\n \"aws:ses/domainIdentityVerification:DomainIdentityVerification\",\n \"aws:sesv2/configurationSetEventDestination:ConfigurationSetEventDestination\",\n \"aws:sesv2/emailIdentity:EmailIdentity\",\n \"aws:sns/topicPolicy:TopicPolicy\",\n \"aws:sns/topicSubscription:TopicSubscription\",\n \"aws:sqs/queuePolicy:QueuePolicy\",\n \"aws:ssm/parameter:Parameter\",\n \"cloudflare:index/dnsRecord:DnsRecord\",\n \"cloudflare:index/workersCronTrigger:WorkersCronTrigger\",\n \"cloudflare:index/workersCustomDomain:WorkersCustomDomain\",\n \"docker-build:index:Image\",\n \"vercel:index/dnsRecord:DnsRecord\",\n ].includes(args.type))\n return;\n const namingRules: Record<string, [\n string,\n number,\n {\n lower?: boolean;\n replace?: (name: string) => string;\n suffix?: () => Output<string>;\n }?\n ]> = {\n \"aws:apigateway/apiKey:ApiKey\": [\"name\", 1024],\n \"aws:apigateway/authorizer:Authorizer\": [\"name\", 128],\n \"aws:apigateway/restApi:RestApi\": [\"name\", 128],\n \"aws:apigateway/usagePlan:UsagePlan\": [\"name\", 65536], // no length limit\n \"aws:apigatewayv2/api:Api\": [\"name\", 128],\n \"aws:apigatewayv2/authorizer:Authorizer\": [\"name\", 128],\n \"aws:apigatewayv2/vpcLink:VpcLink\": [\"name\", 128],\n \"aws:appautoscaling/policy:Policy\": [\"name\", 255],\n \"aws:appsync/graphQLApi:GraphQLApi\": [\"name\", 65536],\n \"aws:cloudwatch/eventBus:EventBus\": [\"name\", 256],\n \"aws:cloudwatch/eventTarget:EventTarget\": [\"targetId\", 64],\n \"aws:cloudwatch/eventRule:EventRule\": [\"name\", 64],\n \"aws:cloudfront/function:Function\": [\"name\", 64],\n \"aws:cloudfront/keyValueStore:KeyValueStore\": [\"name\", 64],\n \"aws:cognito/identityPool:IdentityPool\": [\"identityPoolName\", 128],\n \"aws:cognito/userPool:UserPool\": [\"name\", 128],\n \"aws:dynamodb/table:Table\": [\"name\", 255],\n \"aws:ec2/keyPair:KeyPair\": [\"keyName\", 255],\n \"aws:ec2/eip:Eip\": [\"tags\", 255],\n \"aws:ec2/instance:Instance\": [\"tags\", 255],\n \"aws:ec2/internetGateway:InternetGateway\": [\"tags\", 255],\n \"aws:ec2/natGateway:NatGateway\": [\"tags\", 255],\n \"aws:ec2/routeTable:RouteTable\": [\"tags\", 255],\n \"aws:ec2/securityGroup:SecurityGroup\": [\"tags\", 255],\n \"aws:ec2/defaultSecurityGroup:DefaultSecurityGroup\": [\"tags\", 255],\n \"aws:ec2/subnet:Subnet\": [\"tags\", 255],\n \"aws:ec2/vpc:Vpc\": [\"tags\", 255],\n \"aws:ecs/cluster:Cluster\": [\"name\", 255],\n \"aws:elasticache/parameterGroup:ParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:elasticache/replicationGroup:ReplicationGroup\": [\n \"replicationGroupId\",\n 40,\n { lower: true, replace: (name) => name.replaceAll(/-+/g, \"-\") },\n ],\n \"aws:elasticache/subnetGroup:SubnetGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:iam/role:Role\": [\"name\", 64],\n \"aws:iam/user:User\": [\"name\", 64],\n \"aws:iot/authorizer:Authorizer\": [\"name\", 128],\n \"aws:iot/topicRule:TopicRule\": [\n \"name\",\n 128,\n { replace: (name) => name.replaceAll(\"-\", \"_\") },\n ],\n \"aws:kinesis/stream:Stream\": [\"name\", 255],\n // AWS Load Balancer name allows 32 chars, but an 8 char suffix\n // ie. \"-1234567\" is automatically added\n \"aws:lb/loadBalancer:LoadBalancer\": [\"name\", 24],\n \"aws:lambda/function:Function\": [\"name\", 64],\n \"aws:opensearch/domain:Domain\": [\"domainName\", 28, { lower: true }],\n \"aws:rds/cluster:Cluster\": [\n \"clusterIdentifier\",\n 63,\n { lower: true },\n ],\n \"aws:rds/clusterInstance:ClusterInstance\": [\n \"identifier\",\n 63,\n { lower: true },\n ],\n \"aws:rds/instance:Instance\": [\"identifier\", 63, { lower: true }],\n \"aws:rds/proxy:Proxy\": [\"name\", 60, { lower: true }],\n \"aws:rds/clusterParameterGroup:ClusterParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:rds/parameterGroup:ParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:rds/subnetGroup:SubnetGroup\": [\"name\", 255, { lower: true }],\n \"aws:s3/bucketV2:BucketV2\": [\"bucket\", 63, { lower: true }],\n \"aws:secretsmanager/secret:Secret\": [\"name\", 512],\n \"aws:sesv2/configurationSet:ConfigurationSet\": [\n \"configurationSetName\",\n 64,\n { lower: true },\n ],\n \"aws:sfn/stateMachine:StateMachine\": [\"name\", 80],\n \"aws:sns/topic:Topic\": [\n \"name\",\n 256,\n {\n suffix: () => output(args.props.fifoTopic).apply((fifo) => fifo ? \".fifo\" : \"\"),\n },\n ],\n \"aws:sqs/queue:Queue\": [\n \"name\",\n 80,\n {\n suffix: () => output(args.props.fifoQueue).apply((fifo) => fifo ? \".fifo\" : \"\"),\n },\n ],\n \"cloudflare:index/d1Database:D1Database\": [\n \"name\",\n 64,\n { lower: true },\n ],\n \"cloudflare:index/r2Bucket:R2Bucket\": [\"name\", 64, { lower: true }],\n \"cloudflare:index/workersScript:WorkersScript\": [\n \"scriptName\",\n 64,\n { lower: true },\n ],\n \"cloudflare:index/queue:Queue\": [\"queueName\", 64, { lower: true }],\n \"cloudflare:index/workersKvNamespace:WorkersKvNamespace\": [\n \"title\",\n 64,\n { lower: true },\n ],\n };\n const rule = namingRules[args.type];\n if (!rule)\n throw new VisibleError(`In \"${name}\" component, the physical name of \"${args.name}\" (${args.type}) is not prefixed`);\n // name is already set\n const nameField = rule[0];\n const length = rule[1];\n const options = rule[2];\n if (args.props[nameField] && args.props[nameField] !== \"\")\n return;\n // Handle prefix field is tags\n if (nameField === \"tags\") {\n return {\n props: {\n ...args.props,\n tags: {\n // @ts-expect-error\n ...args.tags,\n Name: prefixName(length, args.name),\n },\n },\n opts: args.opts,\n };\n }\n // Handle prefix field is name\n const suffix = options?.suffix ? options.suffix() : output(\"\");\n return {\n props: {\n ...args.props,\n [nameField]: suffix.apply((suffix) => {\n let v = options?.lower\n ? physicalName(length, args.name, suffix).toLowerCase()\n : physicalName(length, args.name, suffix);\n if (options?.replace)\n v = options.replace(v);\n return v;\n }),\n },\n opts: {\n ...args.opts,\n ignoreChanges: [...(args.opts.ignoreChanges ?? []), nameField],\n },\n };\n },\n // Set child resources `retainOnDelete` if set on component\n (args) => ({\n props: args.props,\n opts: {\n ...args.opts,\n retainOnDelete: args.opts.retainOnDelete ?? opts?.retainOnDelete,\n },\n }),\n ...(opts?.transformations ?? []),\n ],\n ...opts,\n });\n this.componentType = type;\n this.componentName = name;\n }\n /** @internal */\n protected registerVersion(input: {\n new: number;\n old?: number;\n message?: string;\n forceUpgrade?: `v${number}`;\n }) {\n // Check component version\n const oldVersion = input.old;\n const newVersion = input.new ?? 1;\n if (oldVersion) {\n const className = this.componentType.replaceAll(\":\", \".\");\n // Invalid forceUpgrade value\n if (input.forceUpgrade && input.forceUpgrade !== `v${newVersion}`) {\n throw new VisibleError([\n `The value of \"forceUpgrade\" does not match the version of \"${className}\" component.`,\n `Set \"forceUpgrade\" to \"v${newVersion}\" to upgrade to the new version.`,\n ].join(\"\\n\"));\n }\n // Version upgraded without forceUpgrade\n if (oldVersion < newVersion && !input.forceUpgrade) {\n throw new VisibleError(input.message ?? \"\");\n }\n // Version downgraded\n if (oldVersion > newVersion) {\n throw new VisibleError([\n `It seems you are trying to use an older version of \"${className}\".`,\n `You need to recreate this component to rollback - https://sst.dev/docs/components/#versioning`,\n ].join(\"\\n\"));\n }\n }\n // Set version\n if (newVersion > 1) {\n new Version(this.componentName, newVersion, { parent: this });\n }\n }\n}\nconst ComponentTransforms = new Map<string, any[]>();\nexport function $transform<T, Args, Options>(resource: {\n new (name: string, args: Args, opts?: Options): T;\n}, cb: (args: Args, opts: Options, name: string) => void) {\n // @ts-expect-error\n const type = resource.__pulumiType;\n if (type.startsWith(\"sst:\")) {\n let transforms = ComponentTransforms.get(type);\n if (!transforms) {\n transforms = [];\n ComponentTransforms.set(type, transforms);\n }\n transforms.push((input: any) => {\n cb(input.props, input.opts, input.name);\n return input;\n });\n return;\n }\n runtime.registerStackTransformation((input) => {\n if (input.type !== type)\n return;\n cb(input.props as any, input.opts as any, input.name);\n return input;\n });\n}\nexport function $asset(assetPath: string) {\n const fullPath = path.isAbsolute(assetPath)\n ? assetPath\n : path.join($cli.paths.root, assetPath);\n try {\n return statSync(fullPath).isDirectory()\n ? new pulumiAsset.FileArchive(fullPath)\n : new pulumiAsset.FileAsset(fullPath);\n }\n catch (e) {\n throw new VisibleError(`Asset not found: ${fullPath}`);\n }\n}\nexport function $lazy<T>(fn: () => T) {\n return output(undefined)\n .apply(async () => output(fn()))\n .apply((x) => x);\n}\nexport function $print(...msg: Input<any>[]) {\n return all(msg).apply((msg) => console.log(...msg));\n}\nexport class Version extends ComponentResource {\n constructor(target: string, version: number, opts: ComponentResourceOptions) {\n super(\"sst:sst:Version\", target + \"Version\", {}, opts);\n this.registerOutputs({ target, version });\n }\n}\nexport type ComponentVersion = {\n major: number;\n minor: number;\n};\nexport function parseComponentVersion(version: string): ComponentVersion {\n const [major, minor] = version.split(\".\");\n return { major: parseInt(major), minor: parseInt(minor) };\n}\n", "export class VisibleError extends Error {\n constructor(...message: string[]) {\n super(message.join(\"\\n\"));\n }\n}\n", "import { runtime } from \"@pulumi/pulumi\";\nimport { Provider, Region } from \"@pulumi/aws\";\nimport { lazy } from \"../../../util/lazy\";\nconst useProviderCache = lazy(() => new Map<string, Provider>());\nexport const useProvider = (region: Region) => {\n const cache = useProviderCache();\n const existing = cache.get(region);\n if (existing)\n return existing;\n const config = runtime.allConfig();\n for (const key in config) {\n const value = config[key];\n delete config[key];\n const [prefix, real] = key.split(\":\");\n if (prefix !== \"aws\")\n continue;\n // Array and Object values are JSON encoded, ie.\n // {\n // allowedAccountIds: '[\"112245769880\"]',\n // defaultTags: '{\"tags\":{\"sst:app\":\"playground\",\"sst:stage\":\"frank\"}}',\n // region: 'us-east-1'\n // }\n try {\n config[real] = JSON.parse(value);\n }\n catch (e) {\n config[real] = value;\n }\n }\n const provider = new Provider(`AwsProvider.sst.${region}`, {\n ...config,\n region,\n });\n cache.set(region, provider);\n return provider;\n};\n", "export function lazy<T>(callback: () => T) {\n let loaded = false;\n let result: T;\n return () => {\n if (!loaded) {\n loaded = true;\n result = callback();\n }\n return result;\n };\n}\n", "import * as pulumi from \"@pulumi/pulumi\";\nimport * as awsSdk from \"@pulumi/aws\";\nimport { deployConfig } from \"@infoxchange/make-it-so\";\nimport { Transform, transform } from \"sst3/platform/src/components/component\";\nexport interface InternalNetworkArgs {\n name?: string;\n transform?: {\n securityGroup?: Transform<aws.ec2.SecurityGroupArgs>;\n };\n}\nexport class InternalNetwork extends pulumi.ComponentResource {\n public readonly vpc: pulumi.Output<aws.ec2.GetVpcResult>;\n public readonly subnetIds: pulumi.Output<string[]>;\n public readonly securityGroup: pulumi.Output<aws.ec2.SecurityGroup>;\n constructor(name: string, args: InternalNetworkArgs = {}, opts?: pulumi.ComponentResourceOptions) {\n super(\"ix:aws:InternalNetwork\", name, args, opts);\n // Get VPC ID from SSM parameter\n const vpcIdParam = awsSdk.ssm.getParameterOutput({\n name: \"/vpc/id\",\n }, { parent: this });\n const vpcId = vpcIdParam.value;\n // Get VPC details\n this.vpc = vpcId.apply(async (vpcId) => await awsSdk.ec2.getVpc({ id: vpcId }));\n // Get subnet IDs\n this.subnetIds = InternalNetwork.getVpcSubnetIds();\n this.securityGroup = this.vpc.apply((vpc) => this.createSecurityGroup({\n parentName: name,\n vpc: vpc,\n args: args.transform?.securityGroup,\n opts: { parent: this },\n }));\n this.registerOutputs({\n vpc: this.vpc,\n subnetIds: this.subnetIds,\n });\n }\n public get securityGroupIds(): pulumi.Output<pulumi.Output<string>[]> {\n return pulumi.output(this.securityGroup).apply((sg) => [sg.id]);\n }\n static getVpcSubnetIds(): pulumi.Output<string[]> {\n const { workloadGroup, appName } = deployConfig;\n let suffix = \"\";\n if (workloadGroup === \"ds\") {\n const possibleSuffixes = [\"\", \"-2\"];\n // Randomly select a suffix to spread workload's IP usage across both sets of subnets. Use the app name as a seed\n // to ensure consistent selection on redeploys.\n const hash = appName\n .split(\"\")\n .reduce((acc, char) => acc + char.charCodeAt(0), 0);\n suffix = possibleSuffixes[hash % possibleSuffixes.length];\n }\n const subnetOutputs = [1, 2, 3].map((subnetNum) => awsSdk.ssm.getParameterOutput({\n name: `/vpc/subnet/private-${workloadGroup}${suffix}/${subnetNum}/id`,\n }).value);\n return pulumi.all(subnetOutputs);\n }\n // Based on https://github.com/anomalyco/sst/blob/3407c32b2cf97b85ea96a92361c6f4a0a8d55200/platform/src/components/aws/vpc.ts#L840\n createSecurityGroup({ parentName, vpc, args, opts, }: {\n parentName: string;\n vpc: aws.ec2.GetVpcResult;\n args?: Transform<aws.ec2.SecurityGroupArgs>;\n opts: pulumi.ComponentResourceOptions;\n }) {\n return new awsSdk.ec2.SecurityGroup(...transform(args, `${parentName}SecurityGroup`, {\n description: \"Managed by make-it-so\",\n vpcId: vpc.id,\n egress: [\n {\n fromPort: 0,\n toPort: 0,\n protocol: \"-1\",\n cidrBlocks: [\"0.0.0.0/0\"],\n },\n ],\n ingress: [\n {\n fromPort: 0,\n toPort: 0,\n protocol: \"-1\",\n // Restricts inbound traffic to only within the VPC\n cidrBlocks: [vpc.cidrBlock],\n },\n ],\n }, opts));\n }\n}\n", "import { ix } from \"./index.js\";\nimport { ComponentResourceOptions, output } from \"@pulumi/pulumi\";\nimport { getDeployConfig } from \"@infoxchange/make-it-so\";\nexport function setup() {\n const siteConstructs = [\n sst.aws.StaticSite,\n sst.aws.Nextjs,\n sst.aws.Nuxt,\n sst.aws.Remix,\n sst.aws.React,\n sst.aws.TanStackStart,\n sst.aws.Astro,\n sst.aws.SvelteKit,\n sst.aws.SolidStart,\n sst.aws.Analog,\n ];\n type SiteArgs = ConstructorParameters<(typeof siteConstructs)[number]>[1];\n type Site = {\n new (name: string, args: SiteArgs, opts?: ComponentResourceOptions): unknown;\n };\n for (const construct of siteConstructs) {\n $transform(construct as Site, (args, opts, name) => {\n addDefaultDomain(args, name);\n });\n }\n function addDefaultDomain(args: SiteArgs | undefined, name: string) {\n if (!args) {\n throw new Error(`No args provided to ${name}`);\n }\n const domainArgs = {\n name: getDeployConfig().siteDomains[0],\n dns: ix.dns(),\n };\n if (!(\"domain\" in args)) {\n args.domain = domainArgs;\n }\n else if (args.domain) {\n args.domain = output(args.domain).apply((domain) => {\n if (typeof domain === \"string\") {\n return {\n name: domain,\n dns: domainArgs.dns,\n };\n }\n else if (!(\"dns\" in domain)) {\n domain.dns = domainArgs.dns;\n }\n return domain;\n });\n }\n }\n}\n", "import { setGlobalDispatcher, getGlobalDispatcher, EnvHttpProxyAgent, fetch as undiciFetch, } from \"undici\";\nimport { bootstrap } from \"global-agent\";\nexport function setupProxyGlobally() {\n // Make operation idempotent\n if (getGlobalDispatcher() instanceof EnvHttpProxyAgent)\n return;\n if (!process.env.HTTP_PROXY || !process.env.HTTPS_PROXY)\n return;\n // To cover libraries that use fetch\n // See https://nodejs.org/api/globals.html#custom-dispatcher\n // This might stop being needed at some point: https://github.com/actions/create-github-app-token/pull/143#discussion_r1747641337\n const envHttpProxyAgent = new EnvHttpProxyAgent();\n setGlobalDispatcher(envHttpProxyAgent);\n // To cover libraries that use the http/https object\n if (!process.env.GLOBAL_AGENT_HTTP_PROXY) {\n process.env.GLOBAL_AGENT_HTTP_PROXY = process.env.HTTP_PROXY;\n process.env.GLOBAL_AGENT_HTTPS_PROXY =\n process.env.HTTPS_PROXY ?? process.env.HTTP_PROXY;\n }\n bootstrap();\n}\nexport function getProxiedFetch() {\n const fetch: typeof undiciFetch = (input, init = {}) => {\n if (init.dispatcher) {\n console.warn(\"A custom dispatcher was provided to fetch but this is ignored as a proxy agent is being used.\");\n }\n const envHttpProxyAgent = new EnvHttpProxyAgent();\n return undiciFetch(input, { ...init, dispatcher: envHttpProxyAgent });\n };\n return fetch;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from \"zod\";\nconst getEnvVars = () => ({\n isIxDeploy: process.env.IX_DEPLOYMENT?.toLowerCase() === \"true\", // This needs to start as a bool for the discriminated union\n appName: process.env.IX_APP_NAME ?? \"\",\n environment: process.env.IX_ENVIRONMENT ?? \"\",\n workloadGroup: process.env.IX_WORKLOAD_GROUP ?? \"\",\n primaryAwsRegion: process.env.IX_PRIMARY_AWS_REGION ?? \"\",\n siteDomains: process.env.IX_SITE_DOMAINS ?? \"\",\n siteDomainAliases: process.env.IX_SITE_DOMAIN_ALIASES ?? \"\",\n isInternalApp: process.env.IX_INTERNAL_APP ?? \"\",\n deploymentType: process.env.IX_DEPLOYMENT_TYPE ?? \"\",\n sourceCommitRef: process.env.IX_SOURCE_COMMIT_REF ?? \"\",\n sourceCommitHash: process.env.IX_SOURCE_COMMIT_HASH ?? \"\",\n deployTriggeredBy: process.env.IX_DEPLOY_TRIGGERED_BY ?? \"\",\n smtpHost: process.env.SMTP_HOST ?? \"\",\n smtpPort: process.env.SMTP_PORT ?? \"\",\n clamAVUrl: process.env.CLAMAV_URL ?? \"\",\n vpcHttpProxy: process.env.VPC_HTTP_PROXY ?? \"\",\n alarmSnsTopic: process.env.IX_ALARM_SNS_TOPIC ?? \"\",\n}) satisfies Record<string, string | boolean>;\nconst ixDeployConfigSchema = z\n .object({\n isIxDeploy: z.literal(true),\n appName: z.string().min(1),\n environment: z.enum([\"dev\", \"test\", \"uat\", \"prod\"]),\n workloadGroup: z.enum([\"ds\", \"srs\"]),\n primaryAwsRegion: z.literal(\"ap-southeast-2\"),\n siteDomains: z.string().transform((val) => val\n .split(\",\")\n .map((domain) => domain.trim())\n .filter(Boolean)),\n siteDomainAliases: z.string().transform((val) => val\n .split(\",\")\n .map((domain) => domain.trim())\n .filter(Boolean)),\n isInternalApp: z.coerce.boolean(),\n deploymentType: z.enum([\"docker\", \"serverless\"]),\n sourceCommitRef: z.string().min(1),\n sourceCommitHash: z.string().min(1),\n deployTriggeredBy: z.string().min(1),\n smtpHost: z.string().min(1),\n smtpPort: z.coerce.number().int(),\n clamAVUrl: z.string().url(),\n vpcHttpProxy: z.string().url(),\n alarmSnsTopic: z.string().min(1),\n} satisfies Record<keyof ReturnType<typeof getEnvVars>, unknown>)\n .strip();\nconst nonIxDeployConfigSchema = z\n .object({\n isIxDeploy: z.literal(false),\n appName: z.string(),\n environment: z.string(),\n workloadGroup: z.string(),\n primaryAwsRegion: z.string(),\n siteDomains: z\n .string()\n .transform((val) => val.split(\",\").map((domain) => domain.trim())),\n siteDomainAliases: z\n .string()\n .transform((val) => val.split(\",\").map((domain) => domain.trim())),\n isInternalApp: z\n .string()\n .transform((val) => (val ? val.toLowerCase() === \"true\" : undefined)),\n deploymentType: z.string(),\n sourceCommitRef: z.string(),\n sourceCommitHash: z.string(),\n deployTriggeredBy: z.string(),\n smtpHost: z.string(),\n smtpPort: z\n .string()\n .transform((val) => isNaN(parseInt(val, 10)) ? undefined : parseInt(val, 10)),\n clamAVUrl: z.string(),\n vpcHttpProxy: z.string(),\n alarmSnsTopic: z.string(),\n} satisfies Record<keyof ReturnType<typeof getEnvVars>, unknown>)\n .strip();\nconst schema = z.discriminatedUnion(\"isIxDeploy\", [\n ixDeployConfigSchema,\n nonIxDeployConfigSchema,\n]);\nexport const deployConfig = schema.parse(getEnvVars());\n// process.env values can change at runtime so we provide a way to re-parse the config as needed\nexport const getDeployConfig = () => schema.parse(getEnvVars());\n", "export * from \"./dns.js\";\nexport * from \"./InternalNetwork.js\";\n", "import crypto from \"crypto\";\nexport function logicalName(name: string) {\n name = name.replace(/[^a-zA-Z0-9]/g, \"\");\n return name.charAt(0).toUpperCase() + name.slice(1);\n}\nexport function physicalName(max: number, name: string, suffix: string = \"\") {\n // This function does the following:\n // - Removes all non-alphanumeric characters\n // - Prefixes the name with the app name and stage\n // - Truncates the name if it's too long\n // - Adds a random suffix\n // - Adds a suffix if provided\n const main = prefixName(max - 9 - suffix.length, name);\n const random = hashStringToPrettyString(crypto.randomBytes(8).toString(\"hex\"), 8);\n return `${main}-${random}${suffix}`;\n}\nexport function prefixName(max: number, name: string) {\n // This function does the following:\n // - Removes all non-alphanumeric characters\n // - Prefixes the name with the app name and stage\n // - Truncates the name if it's too long\n // ie. foo => app-stage-foo\n name = name.replace(/[^a-zA-Z0-9]/g, \"\");\n const stageLen = $app.stage.length;\n const nameLen = name.length;\n const strategy = nameLen + 1 >= max\n ? (\"name\" as const)\n : nameLen + stageLen + 2 >= max\n ? (\"stage+name\" as const)\n : (\"app+stage+name\" as const);\n if (strategy === \"name\")\n return `${name.substring(0, max)}`;\n if (strategy === \"stage+name\")\n return `${$app.stage.substring(0, max - nameLen - 1)}-${name}`;\n return `${$app.name.substring(0, max - stageLen - nameLen - 2)}-${$app.stage}-${name}`;\n}\nexport function hashNumberToPrettyString(number: number, length: number) {\n const charLength = PRETTY_CHARS.length;\n let hash = \"\";\n while (number > 0) {\n hash = PRETTY_CHARS[number % charLength] + hash;\n number = Math.floor(number / charLength);\n }\n // Padding with 's'\n hash = hash.slice(0, length);\n while (hash.length < length) {\n hash = \"s\" + hash;\n }\n return hash;\n}\nexport function hashStringToPrettyString(str: string, length: number) {\n const hash = crypto.createHash(\"sha256\");\n hash.update(str);\n const num = Number(\"0x\" + hash.digest(\"hex\").substring(0, 16));\n return hashNumberToPrettyString(num, length);\n}\nexport const PRETTY_CHARS = \"abcdefhkmnorstuvwxz\";\n", "// Based on https://github.com/anomalyco/sst/blob/3407c32b2cf97b85ea96a92361c6f4a0a8d55200/platform/src/components/aws/dns.ts\n/**\n * The AWS DNS Adapter is used to create DNS records to manage domains hosted on\n * [Route 53](https://aws.amazon.com/route53/).\n *\n * This adapter is passed in as `domain.dns` when setting a custom domain.\n *\n * @example\n *\n * ```ts\n * {\n * domain: {\n * name: \"example.com\",\n * dns: sst.aws.dns()\n * }\n * }\n * ```\n *\n * You can also specify a hosted zone ID if you have multiple hosted zones with the same domain.\n *\n * ```ts\n * {\n * domain: {\n * name: \"example.com\",\n * dns: sst.aws.dns({\n * zone: \"Z2FDTNDATAQYW2\"\n * })\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\nimport { AliasRecord, Dns, Record as DnsRecord, } from \"sst3/platform/src/components/dns\";\nimport { logicalName } from \"sst3/platform/src/components/naming\";\nimport { ComponentResourceOptions, output } from \"@pulumi/pulumi\";\nimport { Transform, transform } from \"sst3/platform/src/components/component\";\nimport { Input } from \"sst3/platform/src/components/input\";\nimport { useProvider } from \"sst3/platform/src/components/aws/helpers/provider\";\nimport { route53 } from \"@pulumi/aws\";\nimport { VisibleError } from \"sst3/platform/src/components/error\";\nimport * as awsSdk from \"@pulumi/aws\";\nexport interface DnsArgs {\n /**\n * Set the hosted zone ID if you have multiple hosted zones that have the same\n * domain in Route 53.\n *\n * The 14 letter ID of the [Route 53 hosted zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/hosted-zones-working-with.html) that contains the `domainName`. You can find the hosted zone ID in the Route 53 part of the AWS Console.\n *\n * @example\n * ```js\n * {\n * zone: \"Z2FDTNDATAQYW2\"\n * }\n * ```\n */\n zone?: Input<string>;\n /**\n * Set to `true` if you want to let the new DNS records replace the existing ones.\n *\n * :::tip\n * Use this to migrate over your domain without any downtime.\n * :::\n *\n * This is useful if your domain is currently used by another app and you want to switch it\n * to your current app. Without setting this, you'll first have to remove the existing DNS\n * records and then add the new one. This can cause downtime.\n *\n * You can avoid this by setting this to `true` and the existing DNS records will be replaced\n * without any downtime. Just make sure that when you remove your old app, you don't remove\n * the DNS records.\n *\n * @default `false`\n * @example\n * ```js\n * {\n * override: true\n * }\n * ```\n */\n override?: Input<boolean>;\n /**\n * [Transform](/docs/components#transform) how this component creates its underlying\n * resources.\n */\n transform?: {\n /**\n * Transform the AWS Route 53 record resource.\n */\n record?: Transform<route53.RecordArgs & {\n aliasIpType?: \"IPv4\" | \"IPv6\";\n // Can be used to override the raw input to the IX DNS lambda\n lambdaInput?: Record<string, unknown>;\n }>;\n };\n}\nexport function dns(args: DnsArgs = {}) {\n return {\n provider: \"aws\",\n createAlias,\n createCaa,\n createRecord,\n } satisfies Dns;\n /**\n * Creates alias records in the hosted zone.\n *\n * @param namePrefix The prefix to use for the resource names.\n * @param record The alias record to create.\n * @param opts The component resource options.\n */\n function createAlias(namePrefix: string, record: AliasRecord, opts: ComponentResourceOptions) {\n return [\"A\", \"AAAA\"].map((type) => _createRecord(namePrefix, {\n type,\n name: record.name,\n aliases: [\n {\n name: record.aliasName,\n zoneId: record.aliasZone,\n evaluateTargetHealth: true,\n },\n ],\n }, opts));\n }\n function createCaa(\n /* eslint-disable @typescript-eslint/no-unused-vars -- Kept for typing even though it's not used for this\n implementation of Dns */\n namePrefix: string, recordName: string, opts: ComponentResourceOptions) {\n // placeholder\n return undefined;\n }\n /**\n * Creates a DNS record in the hosted zone.\n *\n * @param namePrefix The prefix to use for the resource names.\n * @param record The DNS record to create.\n * @param opts The component resource options.\n */\n function createRecord(namePrefix: string, record: DnsRecord, opts: ComponentResourceOptions) {\n return _createRecord(namePrefix, {\n type: record.type,\n name: record.name,\n ttl: 60,\n records: [record.value],\n }, opts);\n }\n function _createRecord(namePrefix: string, partial: Omit<route53.RecordArgs, \"zoneId\">, opts: ComponentResourceOptions) {\n return output(partial).apply((partial) => {\n const nameSuffix = logicalName(partial.name);\n const zoneId = \"\"; // The IX dns lambda will determine the zone ID based on the domain name\n const dnsRecord = createRecord();\n return dnsRecord;\n function createRecord() {\n const [name, mergedArgs, mergedOpts] = transform(args.transform?.record, `${namePrefix}${partial.type}Record${nameSuffix}`, {\n zoneId,\n allowOverwrite: args.override,\n ...partial,\n }, opts);\n const lambdaInput = output(mergedArgs).apply((mergedArgs) => {\n const { aliases } = mergedArgs;\n let { aliasIpType } = mergedArgs;\n if (aliases && aliases.length > 1) {\n throw new VisibleError(\"Aliases with multiple targets are not supported\");\n }\n const [alias] = aliases || [];\n if (alias) {\n if (mergedArgs.type === \"A\") {\n aliasIpType = \"IPv4\";\n }\n else if (mergedArgs.type === \"AAAA\") {\n aliasIpType = \"IPv6\";\n }\n else {\n throw new VisibleError(\"Alias records can only be created for A or AAAA record types\");\n }\n }\n return {\n RecordType: mergedArgs.type,\n // Even though a trailing dot is valid a bug in the IX dns lambda means that an error occurs\n // when trying to find the hosted zone if there is a trailing dot.\n RecordFQDN: mergedArgs.name.replace(/\\.$/, \"\"),\n // If giving the IX dns lambda multiple values we need to wrap in 'Value' objects\n // unlike for single values where the lambda does it for us\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L133\n RecordValue: mergedArgs.records?.map((value) => ({ Value: value })),\n ...(mergedArgs.zoneId ? { HostedZoneId: mergedArgs.zoneId } : {}),\n ...(mergedArgs.ttl ? { RecordTTL: mergedArgs.ttl } : {}),\n ...(alias\n ? {\n RecordType: \"ALIAS\",\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L145\n RecordValue: alias.name,\n // https://github.com/InfoxchangeTS/aws-gov/blob/213609c2e91b021375b93290efdaf38936ee98e1/components/xaccount-route53/dns-record-updater-lambda/src/index.py#L144\n AliasZoneId: alias.zoneId,\n // alias.evaluateTargetHealth can't be set by the lambda\n IpAddressType: aliasIpType?.toLowerCase(),\n }\n : {}),\n ...mergedArgs.lambdaInput,\n };\n });\n // output([mergedArgs, lambdaInput]).apply(([mergedArgs, lambdaInput]) => console.log('________ BEFORE', mergedArgs, '___________ AFTER', lambdaInput));\n return new awsSdk.lambda.Invocation(name, {\n input: output(lambdaInput).apply((lambdaInput) => JSON.stringify({\n RequestType: \"Create\",\n ResourceProperties: lambdaInput,\n // We need some value so that the lambda doesn't throw an error but we don't want the lambda to actually\n // send a response to this url (the response is for CloudFormation which we're not using). Setting an\n // invalid domain will cause it to log an error but not throw so the lambda is considered successful.\n ResponseURL: \"invalid://make-it-so-dns\",\n StackId: \"\",\n RequestId: \"\",\n LogicalResourceId: \"\",\n })),\n functionName: awsSdk.ssm\n .getParameter({\n name: \"/shared-services/route53/lambdaArn\",\n })\n .then((param) => param.value),\n }, {\n ...mergedOpts,\n // Function can only be invoked from within the same region it is deployed\n provider: useProvider(\"ap-southeast-2\"),\n });\n }\n });\n }\n}\n", "import { ComponentResource, ComponentResourceOptions, Inputs, runtime, output, asset as pulumiAsset, Input, all, Output, } from \"@pulumi/pulumi\";\nimport { prefixName, physicalName } from \"./naming.js\";\nimport { VisibleError } from \"./error.js\";\nimport path from \"path\";\nimport { statSync } from \"fs\";\n// Previously, `this.api.id` was used as the ID. `this.api.id` was of type Output<string>\n// the value evaluates to the mistake id.\n// In the future version, we will release a breaking change to fix this.\nexport const outputId = \"Calling [toString] on an [Output<T>] is not supported.\\n\\nTo get the value of an Output<T> as an Output<string> consider either:\\n1: o.apply(v => `prefix${v}suffix`)\\n2: pulumi.interpolate `prefix${v}suffix`\\n\\nSee https://www.pulumi.com/docs/concepts/inputs-outputs for more details.\\nThis function may throw in a future version of @pulumi/pulumi.\";\n/**\n * Helper type to inline nested types\n */\nexport type Prettify<T> = {\n [K in keyof T]: T[K];\n} & {};\nexport type Transform<T> = Partial<T> | ((args: T, opts: $util.CustomResourceOptions, name: string) => undefined);\nexport function transform<T extends object>(transform: Transform<T> | undefined, name: string, args: T, opts: $util.CustomResourceOptions) {\n // Case: transform is a function\n if (typeof transform === \"function\") {\n transform(args, opts, name);\n return [name, args, opts] as const;\n }\n // Case: no transform\n // Case: transform is an argument\n return [name, { ...args, ...transform }, opts] as const;\n}\nexport class Component extends ComponentResource {\n private componentType: string;\n private componentName: string;\n constructor(type: string, name: string, args?: Inputs, opts?: ComponentResourceOptions) {\n const transforms = ComponentTransforms.get(type) ?? [];\n for (const transform of transforms) {\n transform({ name, props: args, opts });\n }\n super(type, name, {}, {\n transformations: [\n // Ensure logical and physical names are prefixed\n (args) => {\n // Ensure component names do not contain spaces\n if (name.includes(\" \"))\n throw new Error(`Invalid component name \"${name}\" (${args.type}). Component names cannot contain spaces.`);\n // Ensure names are prefixed with parent's name\n if (args.type !== type &&\n // @ts-expect-error\n !args.name.startsWith(args.opts.parent!.__name)) {\n throw new Error(`In \"${name}\" component, the logical name of \"${args.name}\" (${args.type}) is not prefixed with parent's name ${\n // @ts-expect-error\n args.opts.parent!.__name}`);\n }\n // Ensure physical names are prefixed with app/stage\n // note: We are setting the default names here instead of inline when creating\n // the resource is b/c the physical name is inferred from the logical name.\n // And it's convenient to access the logical name here.\n if (args.type.startsWith(\"sst:\"))\n return;\n if ([\n // resources manually named\n \"aws:cloudwatch/logGroup:LogGroup\",\n \"aws:ecs/service:Service\",\n \"aws:ecs/taskDefinition:TaskDefinition\",\n \"aws:lb/targetGroup:TargetGroup\",\n \"aws:servicediscovery/privateDnsNamespace:PrivateDnsNamespace\",\n \"aws:servicediscovery/service:Service\",\n // resources not prefixed\n \"pulumi-nodejs:dynamic:Resource\",\n \"random:index/randomId:RandomId\",\n \"random:index/randomPassword:RandomPassword\",\n \"command:local:Command\",\n \"tls:index/privateKey:PrivateKey\",\n \"aws:acm/certificate:Certificate\",\n \"aws:acm/certificateValidation:CertificateValidation\",\n \"aws:apigateway/basePathMapping:BasePathMapping\",\n \"aws:apigateway/deployment:Deployment\",\n \"aws:apigateway/domainName:DomainName\",\n \"aws:apigateway/integration:Integration\",\n \"aws:apigateway/integrationResponse:IntegrationResponse\",\n \"aws:apigateway/method:Method\",\n \"aws:apigateway/methodResponse:MethodResponse\",\n \"aws:apigateway/resource:Resource\",\n \"aws:apigateway/response:Response\",\n \"aws:apigateway/stage:Stage\",\n \"aws:apigateway/usagePlanKey:UsagePlanKey\",\n \"aws:apigatewayv2/apiMapping:ApiMapping\",\n \"aws:apigatewayv2/domainName:DomainName\",\n \"aws:apigatewayv2/integration:Integration\",\n \"aws:apigatewayv2/route:Route\",\n \"aws:apigatewayv2/stage:Stage\",\n \"aws:appautoscaling/target:Target\",\n \"aws:appsync/dataSource:DataSource\",\n \"aws:appsync/domainName:DomainName\",\n \"aws:appsync/domainNameApiAssociation:DomainNameApiAssociation\",\n \"aws:appsync/function:Function\",\n \"aws:appsync/resolver:Resolver\",\n \"aws:ec2/routeTableAssociation:RouteTableAssociation\",\n \"aws:ec2/eipAssociation:EipAssociation\",\n \"aws:ecs/clusterCapacityProviders:ClusterCapacityProviders\",\n \"aws:efs/fileSystem:FileSystem\",\n \"aws:efs/mountTarget:MountTarget\",\n \"aws:efs/accessPoint:AccessPoint\",\n \"aws:iam/accessKey:AccessKey\",\n \"aws:iam/instanceProfile:InstanceProfile\",\n \"aws:iam/policy:Policy\",\n \"aws:iam/userPolicy:UserPolicy\",\n \"aws:cloudfront/cachePolicy:CachePolicy\",\n \"aws:cloudfront/distribution:Distribution\",\n \"aws:cognito/identityPoolRoleAttachment:IdentityPoolRoleAttachment\",\n \"aws:cognito/identityProvider:IdentityProvider\",\n \"aws:cognito/userPoolClient:UserPoolClient\",\n \"aws:lambda/eventSourceMapping:EventSourceMapping\",\n \"aws:lambda/functionEventInvokeConfig:FunctionEventInvokeConfig\",\n \"aws:lambda/functionUrl:FunctionUrl\",\n \"aws:lambda/invocation:Invocation\",\n \"aws:lambda/permission:Permission\",\n \"aws:lambda/provisionedConcurrencyConfig:ProvisionedConcurrencyConfig\",\n \"aws:lb/listener:Listener\",\n \"aws:lb/listenerRule:ListenerRule\",\n \"aws:opensearch/domainPolicy:DomainPolicy\",\n \"aws:rds/proxyDefaultTargetGroup:ProxyDefaultTargetGroup\",\n \"aws:rds/proxyTarget:ProxyTarget\",\n \"aws:route53/record:Record\",\n \"aws:s3/bucketCorsConfigurationV2:BucketCorsConfigurationV2\",\n \"aws:s3/bucketNotification:BucketNotification\",\n \"aws:s3/bucketObject:BucketObject\",\n \"aws:s3/bucketObjectv2:BucketObjectv2\",\n \"aws:s3/bucketPolicy:BucketPolicy\",\n \"aws:s3/bucketPublicAccessBlock:BucketPublicAccessBlock\",\n \"aws:s3/bucketVersioningV2:BucketVersioningV2\",\n \"aws:s3/bucketLifecycleConfigurationV2:BucketLifecycleConfigurationV2\",\n \"aws:s3/bucketWebsiteConfigurationV2:BucketWebsiteConfigurationV2\",\n \"aws:secretsmanager/secretVersion:SecretVersion\",\n \"aws:ses/domainIdentityVerification:DomainIdentityVerification\",\n \"aws:sesv2/configurationSetEventDestination:ConfigurationSetEventDestination\",\n \"aws:sesv2/emailIdentity:EmailIdentity\",\n \"aws:sns/topicPolicy:TopicPolicy\",\n \"aws:sns/topicSubscription:TopicSubscription\",\n \"aws:sqs/queuePolicy:QueuePolicy\",\n \"aws:ssm/parameter:Parameter\",\n \"cloudflare:index/dnsRecord:DnsRecord\",\n \"cloudflare:index/workersCronTrigger:WorkersCronTrigger\",\n \"cloudflare:index/workersCustomDomain:WorkersCustomDomain\",\n \"docker-build:index:Image\",\n \"vercel:index/dnsRecord:DnsRecord\",\n ].includes(args.type))\n return;\n const namingRules: Record<string, [\n string,\n number,\n {\n lower?: boolean;\n replace?: (name: string) => string;\n suffix?: () => Output<string>;\n }?\n ]> = {\n \"aws:apigateway/apiKey:ApiKey\": [\"name\", 1024],\n \"aws:apigateway/authorizer:Authorizer\": [\"name\", 128],\n \"aws:apigateway/restApi:RestApi\": [\"name\", 128],\n \"aws:apigateway/usagePlan:UsagePlan\": [\"name\", 65536], // no length limit\n \"aws:apigatewayv2/api:Api\": [\"name\", 128],\n \"aws:apigatewayv2/authorizer:Authorizer\": [\"name\", 128],\n \"aws:apigatewayv2/vpcLink:VpcLink\": [\"name\", 128],\n \"aws:appautoscaling/policy:Policy\": [\"name\", 255],\n \"aws:appsync/graphQLApi:GraphQLApi\": [\"name\", 65536],\n \"aws:cloudwatch/eventBus:EventBus\": [\"name\", 256],\n \"aws:cloudwatch/eventTarget:EventTarget\": [\"targetId\", 64],\n \"aws:cloudwatch/eventRule:EventRule\": [\"name\", 64],\n \"aws:cloudfront/function:Function\": [\"name\", 64],\n \"aws:cloudfront/keyValueStore:KeyValueStore\": [\"name\", 64],\n \"aws:cognito/identityPool:IdentityPool\": [\"identityPoolName\", 128],\n \"aws:cognito/userPool:UserPool\": [\"name\", 128],\n \"aws:dynamodb/table:Table\": [\"name\", 255],\n \"aws:ec2/keyPair:KeyPair\": [\"keyName\", 255],\n \"aws:ec2/eip:Eip\": [\"tags\", 255],\n \"aws:ec2/instance:Instance\": [\"tags\", 255],\n \"aws:ec2/internetGateway:InternetGateway\": [\"tags\", 255],\n \"aws:ec2/natGateway:NatGateway\": [\"tags\", 255],\n \"aws:ec2/routeTable:RouteTable\": [\"tags\", 255],\n \"aws:ec2/securityGroup:SecurityGroup\": [\"tags\", 255],\n \"aws:ec2/defaultSecurityGroup:DefaultSecurityGroup\": [\"tags\", 255],\n \"aws:ec2/subnet:Subnet\": [\"tags\", 255],\n \"aws:ec2/vpc:Vpc\": [\"tags\", 255],\n \"aws:ecs/cluster:Cluster\": [\"name\", 255],\n \"aws:elasticache/parameterGroup:ParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:elasticache/replicationGroup:ReplicationGroup\": [\n \"replicationGroupId\",\n 40,\n { lower: true, replace: (name) => name.replaceAll(/-+/g, \"-\") },\n ],\n \"aws:elasticache/subnetGroup:SubnetGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:iam/role:Role\": [\"name\", 64],\n \"aws:iam/user:User\": [\"name\", 64],\n \"aws:iot/authorizer:Authorizer\": [\"name\", 128],\n \"aws:iot/topicRule:TopicRule\": [\n \"name\",\n 128,\n { replace: (name) => name.replaceAll(\"-\", \"_\") },\n ],\n \"aws:kinesis/stream:Stream\": [\"name\", 255],\n // AWS Load Balancer name allows 32 chars, but an 8 char suffix\n // ie. \"-1234567\" is automatically added\n \"aws:lb/loadBalancer:LoadBalancer\": [\"name\", 24],\n \"aws:lambda/function:Function\": [\"name\", 64],\n \"aws:opensearch/domain:Domain\": [\"domainName\", 28, { lower: true }],\n \"aws:rds/cluster:Cluster\": [\n \"clusterIdentifier\",\n 63,\n { lower: true },\n ],\n \"aws:rds/clusterInstance:ClusterInstance\": [\n \"identifier\",\n 63,\n { lower: true },\n ],\n \"aws:rds/instance:Instance\": [\"identifier\", 63, { lower: true }],\n \"aws:rds/proxy:Proxy\": [\"name\", 60, { lower: true }],\n \"aws:rds/clusterParameterGroup:ClusterParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:rds/parameterGroup:ParameterGroup\": [\n \"name\",\n 255,\n { lower: true },\n ],\n \"aws:rds/subnetGroup:SubnetGroup\": [\"name\", 255, { lower: true }],\n \"aws:s3/bucketV2:BucketV2\": [\"bucket\", 63, { lower: true }],\n \"aws:secretsmanager/secret:Secret\": [\"name\", 512],\n \"aws:sesv2/configurationSet:ConfigurationSet\": [\n \"configurationSetName\",\n 64,\n { lower: true },\n ],\n \"aws:sfn/stateMachine:StateMachine\": [\"name\", 80],\n \"aws:sns/topic:Topic\": [\n \"name\",\n 256,\n {\n suffix: () => output(args.props.fifoTopic).apply((fifo) => fifo ? \".fifo\" : \"\"),\n },\n ],\n \"aws:sqs/queue:Queue\": [\n \"name\",\n 80,\n {\n suffix: () => output(args.props.fifoQueue).apply((fifo) => fifo ? \".fifo\" : \"\"),\n },\n ],\n \"cloudflare:index/d1Database:D1Database\": [\n \"name\",\n 64,\n { lower: true },\n ],\n \"cloudflare:index/r2Bucket:R2Bucket\": [\"name\", 64, { lower: true }],\n \"cloudflare:index/workersScript:WorkersScript\": [\n \"scriptName\",\n 64,\n { lower: true },\n ],\n \"cloudflare:index/queue:Queue\": [\"queueName\", 64, { lower: true }],\n \"cloudflare:index/workersKvNamespace:WorkersKvNamespace\": [\n \"title\",\n 64,\n { lower: true },\n ],\n };\n const rule = namingRules[args.type];\n if (!rule)\n throw new VisibleError(`In \"${name}\" component, the physical name of \"${args.name}\" (${args.type}) is not prefixed`);\n // name is already set\n const nameField = rule[0];\n const length = rule[1];\n const options = rule[2];\n if (args.props[nameField] && args.props[nameField] !== \"\")\n return;\n // Handle prefix field is tags\n if (nameField === \"tags\") {\n return {\n props: {\n ...args.props,\n tags: {\n // @ts-expect-error\n ...args.tags,\n Name: prefixName(length, args.name),\n },\n },\n opts: args.opts,\n };\n }\n // Handle prefix field is name\n const suffix = options?.suffix ? options.suffix() : output(\"\");\n return {\n props: {\n ...args.props,\n [nameField]: suffix.apply((suffix) => {\n let v = options?.lower\n ? physicalName(length, args.name, suffix).toLowerCase()\n : physicalName(length, args.name, suffix);\n if (options?.replace)\n v = options.replace(v);\n return v;\n }),\n },\n opts: {\n ...args.opts,\n ignoreChanges: [...(args.opts.ignoreChanges ?? []), nameField],\n },\n };\n },\n // Set child resources `retainOnDelete` if set on component\n (args) => ({\n props: args.props,\n opts: {\n ...args.opts,\n retainOnDelete: args.opts.retainOnDelete ?? opts?.retainOnDelete,\n },\n }),\n ...(opts?.transformations ?? []),\n ],\n ...opts,\n });\n this.componentType = type;\n this.componentName = name;\n }\n /** @internal */\n protected registerVersion(input: {\n new: number;\n old?: number;\n message?: string;\n forceUpgrade?: `v${number}`;\n }) {\n // Check component version\n const oldVersion = input.old;\n const newVersion = input.new ?? 1;\n if (oldVersion) {\n const className = this.componentType.replaceAll(\":\", \".\");\n // Invalid forceUpgrade value\n if (input.forceUpgrade && input.forceUpgrade !== `v${newVersion}`) {\n throw new VisibleError([\n `The value of \"forceUpgrade\" does not match the version of \"${className}\" component.`,\n `Set \"forceUpgrade\" to \"v${newVersion}\" to upgrade to the new version.`,\n ].join(\"\\n\"));\n }\n // Version upgraded without forceUpgrade\n if (oldVersion < newVersion && !input.forceUpgrade) {\n throw new VisibleError(input.message ?? \"\");\n }\n // Version downgraded\n if (oldVersion > newVersion) {\n throw new VisibleError([\n `It seems you are trying to use an older version of \"${className}\".`,\n `You need to recreate this component to rollback - https://sst.dev/docs/components/#versioning`,\n ].join(\"\\n\"));\n }\n }\n // Set version\n if (newVersion > 1) {\n new Version(this.componentName, newVersion, { parent: this });\n }\n }\n}\nconst ComponentTransforms = new Map<string, any[]>();\nexport function $transform<T, Args, Options>(resource: {\n new (name: string, args: Args, opts?: Options): T;\n}, cb: (args: Args, opts: Options, name: string) => void) {\n // @ts-expect-error\n const type = resource.__pulumiType;\n if (type.startsWith(\"sst:\")) {\n let transforms = ComponentTransforms.get(type);\n if (!transforms) {\n transforms = [];\n ComponentTransforms.set(type, transforms);\n }\n transforms.push((input: any) => {\n cb(input.props, input.opts, input.name);\n return input;\n });\n return;\n }\n runtime.registerStackTransformation((input) => {\n if (input.type !== type)\n return;\n cb(input.props as any, input.opts as any, input.name);\n return input;\n });\n}\nexport function $asset(assetPath: string) {\n const fullPath = path.isAbsolute(assetPath)\n ? assetPath\n : path.join($cli.paths.root, assetPath);\n try {\n return statSync(fullPath).isDirectory()\n ? new pulumiAsset.FileArchive(fullPath)\n : new pulumiAsset.FileAsset(fullPath);\n }\n catch (e) {\n throw new VisibleError(`Asset not found: ${fullPath}`);\n }\n}\nexport function $lazy<T>(fn: () => T) {\n return output(undefined)\n .apply(async () => output(fn()))\n .apply((x) => x);\n}\nexport function $print(...msg: Input<any>[]) {\n return all(msg).apply((msg) => console.log(...msg));\n}\nexport class Version extends ComponentResource {\n constructor(target: string, version: number, opts: ComponentResourceOptions) {\n super(\"sst:sst:Version\", target + \"Version\", {}, opts);\n this.registerOutputs({ target, version });\n }\n}\nexport type ComponentVersion = {\n major: number;\n minor: number;\n};\nexport function parseComponentVersion(version: string): ComponentVersion {\n const [major, minor] = version.split(\".\");\n return { major: parseInt(major), minor: parseInt(minor) };\n}\n", "export class VisibleError extends Error {\n constructor(...message: string[]) {\n super(message.join(\"\\n\"));\n }\n}\n", "import { runtime } from \"@pulumi/pulumi\";\nimport { Provider, Region } from \"@pulumi/aws\";\nimport { lazy } from \"../../../util/lazy\";\nconst useProviderCache = lazy(() => new Map<string, Provider>());\nexport const useProvider = (region: Region) => {\n const cache = useProviderCache();\n const existing = cache.get(region);\n if (existing)\n return existing;\n const config = runtime.allConfig();\n for (const key in config) {\n const value = config[key];\n delete config[key];\n const [prefix, real] = key.split(\":\");\n if (prefix !== \"aws\")\n continue;\n // Array and Object values are JSON encoded, ie.\n // {\n // allowedAccountIds: '[\"112245769880\"]',\n // defaultTags: '{\"tags\":{\"sst:app\":\"playground\",\"sst:stage\":\"frank\"}}',\n // region: 'us-east-1'\n // }\n try {\n config[real] = JSON.parse(value);\n }\n catch (e) {\n config[real] = value;\n }\n }\n const provider = new Provider(`AwsProvider.sst.${region}`, {\n ...config,\n region,\n });\n cache.set(region, provider);\n return provider;\n};\n", "export function lazy<T>(callback: () => T) {\n let loaded = false;\n let result: T;\n return () => {\n if (!loaded) {\n loaded = true;\n result = callback();\n }\n return result;\n };\n}\n", "import * as pulumi from \"@pulumi/pulumi\";\nimport * as awsSdk from \"@pulumi/aws\";\nimport { deployConfig } from \"@infoxchange/make-it-so\";\nimport { Transform, transform } from \"sst3/platform/src/components/component\";\nexport interface InternalNetworkArgs {\n name?: string;\n transform?: {\n securityGroup?: Transform<aws.ec2.SecurityGroupArgs>;\n };\n}\nexport class InternalNetwork extends pulumi.ComponentResource {\n public readonly vpc: pulumi.Output<aws.ec2.GetVpcResult>;\n public readonly subnetIds: pulumi.Output<string[]>;\n public readonly securityGroup: pulumi.Output<aws.ec2.SecurityGroup>;\n constructor(name: string, args: InternalNetworkArgs = {}, opts?: pulumi.ComponentResourceOptions) {\n super(\"ix:aws:InternalNetwork\", name, args, opts);\n // Get VPC ID from SSM parameter\n const vpcIdParam = awsSdk.ssm.getParameterOutput({\n name: \"/vpc/id\",\n }, { parent: this });\n const vpcId = vpcIdParam.value;\n // Get VPC details\n this.vpc = vpcId.apply(async (vpcId) => await awsSdk.ec2.getVpc({ id: vpcId }));\n // Get subnet IDs\n this.subnetIds = InternalNetwork.getVpcSubnetIds();\n this.securityGroup = this.vpc.apply((vpc) => this.createSecurityGroup({\n parentName: name,\n vpc: vpc,\n args: args.transform?.securityGroup,\n opts: { parent: this },\n }));\n this.registerOutputs({\n vpc: this.vpc,\n subnetIds: this.subnetIds,\n });\n }\n public get securityGroupIds(): pulumi.Output<pulumi.Output<string>[]> {\n return pulumi.output(this.securityGroup).apply((sg) => [sg.id]);\n }\n static getVpcSubnetIds(): pulumi.Output<string[]> {\n const { workloadGroup, appName } = deployConfig;\n let suffix = \"\";\n if (workloadGroup === \"ds\") {\n const possibleSuffixes = [\"\", \"-2\"];\n // Randomly select a suffix to spread workload's IP usage across both sets of subnets. Use the app name as a seed\n // to ensure consistent selection on redeploys.\n const hash = appName\n .split(\"\")\n .reduce((acc, char) => acc + char.charCodeAt(0), 0);\n suffix = possibleSuffixes[hash % possibleSuffixes.length];\n }\n const subnetOutputs = [1, 2, 3].map((subnetNum) => awsSdk.ssm.getParameterOutput({\n name: `/vpc/subnet/private-${workloadGroup}${suffix}/${subnetNum}/id`,\n }).value);\n return pulumi.all(subnetOutputs);\n }\n // Based on https://github.com/anomalyco/sst/blob/3407c32b2cf97b85ea96a92361c6f4a0a8d55200/platform/src/components/aws/vpc.ts#L840\n createSecurityGroup({ parentName, vpc, args, opts, }: {\n parentName: string;\n vpc: aws.ec2.GetVpcResult;\n args?: Transform<aws.ec2.SecurityGroupArgs>;\n opts: pulumi.ComponentResourceOptions;\n }) {\n return new awsSdk.ec2.SecurityGroup(...transform(args, `${parentName}SecurityGroup`, {\n description: \"Managed by make-it-so\",\n vpcId: vpc.id,\n egress: [\n {\n fromPort: 0,\n toPort: 0,\n protocol: \"-1\",\n cidrBlocks: [\"0.0.0.0/0\"],\n },\n ],\n ingress: [\n {\n fromPort: 0,\n toPort: 0,\n protocol: \"-1\",\n // Restricts inbound traffic to only within the VPC\n cidrBlocks: [vpc.cidrBlock],\n },\n ],\n }, opts));\n }\n}\n", "import { ix } from \"./index.js\";\nimport { ComponentResourceOptions, output } from \"@pulumi/pulumi\";\nimport { getDeployConfig } from \"@infoxchange/make-it-so\";\nexport function setup() {\n const siteConstructs = [\n sst.aws.StaticSite,\n sst.aws.Nextjs,\n sst.aws.Nuxt,\n sst.aws.Remix,\n sst.aws.React,\n sst.aws.TanStackStart,\n sst.aws.Astro,\n sst.aws.SvelteKit,\n sst.aws.SolidStart,\n sst.aws.Analog,\n ];\n type SiteArgs = ConstructorParameters<(typeof siteConstructs)[number]>[1];\n type Site = {\n new (name: string, args: SiteArgs, opts?: ComponentResourceOptions): unknown;\n };\n for (const construct of siteConstructs) {\n $transform(construct as Site, (args, opts, name) => {\n addDefaultDomain(args, name);\n });\n }\n function addDefaultDomain(args: SiteArgs | undefined, name: string) {\n if (!args) {\n throw new Error(`No args provided to ${name}`);\n }\n const domainArgs = {\n name: getDeployConfig().siteDomains[0],\n dns: ix.dns(),\n };\n if (!(\"domain\" in args)) {\n args.domain = domainArgs;\n }\n else if (args.domain) {\n args.domain = output(args.domain).apply((domain) => {\n if (typeof domain === \"string\") {\n return {\n name: domain,\n dns: domainArgs.dns,\n };\n }\n else if (!(\"dns\" in domain)) {\n domain.dns = domainArgs.dns;\n }\n return domain;\n });\n }\n }\n}\n", "import { setGlobalDispatcher, getGlobalDispatcher, EnvHttpProxyAgent, fetch as undiciFetch, } from \"undici\";\nimport { bootstrap } from \"global-agent\";\nexport function setupProxyGlobally() {\n // Make operation idempotent\n if (getGlobalDispatcher() instanceof EnvHttpProxyAgent)\n return;\n if (!process.env.HTTP_PROXY || !process.env.HTTPS_PROXY)\n return;\n // To cover libraries that use fetch\n // See https://nodejs.org/api/globals.html#custom-dispatcher\n // This might stop being needed at some point: https://github.com/actions/create-github-app-token/pull/143#discussion_r1747641337\n const envHttpProxyAgent = new EnvHttpProxyAgent();\n setGlobalDispatcher(envHttpProxyAgent);\n // To cover libraries that use the http/https object\n if (!process.env.GLOBAL_AGENT_HTTP_PROXY) {\n process.env.GLOBAL_AGENT_HTTP_PROXY = process.env.HTTP_PROXY;\n process.env.GLOBAL_AGENT_HTTPS_PROXY =\n process.env.HTTPS_PROXY ?? process.env.HTTP_PROXY;\n }\n bootstrap();\n}\nexport function getProxiedFetch() {\n const fetch: typeof undiciFetch = (input, init = {}) => {\n if (init.dispatcher) {\n console.warn(\"A custom dispatcher was provided to fetch but this is ignored as a proxy agent is being used.\");\n }\n const envHttpProxyAgent = new EnvHttpProxyAgent();\n return undiciFetch(input, { ...init, dispatcher: envHttpProxyAgent });\n };\n return fetch;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["output", "transform", "runtime", "runtime", "output", "partial", "createRecord", "mergedArgs", "lambdaInput", "awsSdk", "deployConfig", "vpcId", "deployConfig", "output", "getDeployConfig"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infoxchange/make-it-so",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Makes deploying services to IX infra easy",
5
5
  "repository": "github:infoxchange/make-it-so",
6
6
  "publishConfig": {
@@ -29,6 +29,9 @@
29
29
  "prettier --write --ignore-unknown"
30
30
  ]
31
31
  },
32
+ "overrides": {
33
+ "fast-jwt": "^4.0.1"
34
+ },
32
35
  "devDependencies": {
33
36
  "@commitlint/cli": "^19.3.0",
34
37
  "@commitlint/config-conventional": "^19.2.2",
@@ -46,7 +49,7 @@
46
49
  "husky": "^9.0.11",
47
50
  "lint-staged": "^15.2.5",
48
51
  "prettier": "3.2.5",
49
- "semantic-release": "^23.1.1",
52
+ "semantic-release": "^25.0.3",
50
53
  "sst3": "github:anomalyco/sst",
51
54
  "tsx": "^4.7.0",
52
55
  "typescript": "^5.4.5",
@@ -18,6 +18,7 @@ const getEnvVars = () =>
18
18
  smtpPort: process.env.SMTP_PORT ?? "",
19
19
  clamAVUrl: process.env.CLAMAV_URL ?? "",
20
20
  vpcHttpProxy: process.env.VPC_HTTP_PROXY ?? "",
21
+ alarmSnsTopic: process.env.IX_ALARM_SNS_TOPIC ?? "",
21
22
  }) satisfies Record<string, string | boolean>;
22
23
 
23
24
  const ixDeployConfigSchema = z
@@ -48,6 +49,7 @@ const ixDeployConfigSchema = z
48
49
  smtpPort: z.coerce.number().int(),
49
50
  clamAVUrl: z.string().url(),
50
51
  vpcHttpProxy: z.string().url(),
52
+ alarmSnsTopic: z.string().min(1),
51
53
  } satisfies Record<keyof ReturnType<typeof getEnvVars>, unknown>)
52
54
  .strip();
53
55
 
@@ -79,6 +81,7 @@ const nonIxDeployConfigSchema = z
79
81
  ),
80
82
  clamAVUrl: z.string(),
81
83
  vpcHttpProxy: z.string(),
84
+ alarmSnsTopic: z.string(),
82
85
  } satisfies Record<keyof ReturnType<typeof getEnvVars>, unknown>)
83
86
  .strip();
84
87