@alienplatform/core 1.7.1 → 1.9.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/.turbo/turbo-build.log +12 -11
- package/dist/index.d.ts +783 -100
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +199 -33
- package/dist/index.js.map +1 -1
- package/dist/stack.js +579 -44
- package/dist/stack.js.map +1 -1
- package/dist/tests/index.js +1 -1
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/stack.test.ts.snap +10 -4
- package/src/__tests__/error.test.ts +1 -1
- package/src/__tests__/stack.test.ts +184 -2
- package/src/compute-cluster.ts +211 -0
- package/src/container.ts +38 -26
- package/src/daemon.ts +79 -0
- package/src/generated/index.ts +42 -2
- package/src/generated/schemas/architecture.json +1 -0
- package/src/generated/schemas/capacityGroup.json +1 -0
- package/src/generated/schemas/capacityGroupScalePolicy.json +1 -0
- package/src/generated/schemas/computeChoiceRange.json +1 -0
- package/src/generated/schemas/computeCluster.json +1 -0
- package/src/generated/schemas/computePoolSelection.json +1 -0
- package/src/generated/schemas/computeSettings.json +1 -0
- package/src/generated/schemas/container.json +1 -1
- package/src/generated/schemas/containerOutputs.json +1 -1
- package/src/generated/schemas/containerPort.json +1 -1
- package/src/generated/schemas/daemon.json +1 -1
- package/src/generated/schemas/daemonOutputs.json +1 -1
- package/src/generated/schemas/daemonRuntime.json +1 -0
- package/src/generated/schemas/daemonRuntimeMount.json +1 -0
- package/src/generated/schemas/exposeProtocol.json +1 -1
- package/src/generated/schemas/gpuSpec.json +1 -0
- package/src/generated/schemas/machineProfile.json +1 -0
- package/src/generated/schemas/publicEndpoint.json +1 -0
- package/src/generated/schemas/publicEndpointOutput.json +1 -0
- package/src/generated/schemas/stack.json +1 -1
- package/src/generated/schemas/stackImportRequest.json +1 -1
- package/src/generated/schemas/stackImportResponse.json +1 -1
- package/src/generated/schemas/stackInputDefaultValue.json +1 -0
- package/src/generated/schemas/stackInputDefinition.json +1 -0
- package/src/generated/schemas/stackInputEnvironmentMapping.json +1 -0
- package/src/generated/schemas/stackInputEnvironmentVariableType.json +1 -0
- package/src/generated/schemas/stackInputKind.json +1 -0
- package/src/generated/schemas/stackInputProvider.json +1 -0
- package/src/generated/schemas/stackInputValidation.json +1 -0
- package/src/generated/schemas/stackSettings.json +1 -1
- package/src/generated/schemas/worker.json +1 -1
- package/src/generated/schemas/workerOutputs.json +1 -1
- package/src/generated/schemas/workerPublicEndpoint.json +1 -0
- package/src/generated/zod/architecture-schema.ts +13 -0
- package/src/generated/zod/capacity-group-scale-policy-schema.ts +27 -0
- package/src/generated/zod/capacity-group-schema.ts +27 -0
- package/src/generated/zod/compute-choice-range-schema.ts +17 -0
- package/src/generated/zod/compute-cluster-schema.ts +20 -0
- package/src/generated/zod/compute-pool-selection-schema.ts +22 -0
- package/src/generated/zod/compute-settings-schema.ts +18 -0
- package/src/generated/zod/container-outputs-schema.ts +5 -6
- package/src/generated/zod/container-port-schema.ts +1 -5
- package/src/generated/zod/container-schema.ts +7 -3
- package/src/generated/zod/daemon-outputs-schema.ts +4 -0
- package/src/generated/zod/daemon-runtime-mount-schema.ts +14 -0
- package/src/generated/zod/daemon-runtime-schema.ts +19 -0
- package/src/generated/zod/daemon-schema.ts +14 -2
- package/src/generated/zod/expose-protocol-schema.ts +2 -2
- package/src/generated/zod/gpu-spec-schema.ts +16 -0
- package/src/generated/zod/index.ts +42 -2
- package/src/generated/zod/machine-profile-schema.ts +25 -0
- package/src/generated/zod/public-endpoint-output-schema.ts +21 -0
- package/src/generated/zod/public-endpoint-schema.ts +22 -0
- package/src/generated/zod/stack-import-request-schema.ts +3 -0
- package/src/generated/zod/stack-input-default-value-schema.ts +25 -0
- package/src/generated/zod/stack-input-definition-schema.ts +43 -0
- package/src/generated/zod/stack-input-environment-mapping-schema.ts +20 -0
- package/src/generated/zod/stack-input-environment-variable-type-schema.ts +13 -0
- package/src/generated/zod/stack-input-kind-schema.ts +13 -0
- package/src/generated/zod/stack-input-provider-schema.ts +13 -0
- package/src/generated/zod/stack-input-validation-schema.ts +23 -0
- package/src/generated/zod/stack-schema.ts +4 -0
- package/src/generated/zod/stack-settings-schema.ts +5 -1
- package/src/generated/zod/worker-outputs-schema.ts +4 -5
- package/src/generated/zod/worker-public-endpoint-schema.ts +17 -0
- package/src/generated/zod/worker-schema.ts +4 -4
- package/src/index.ts +9 -0
- package/src/input.ts +380 -0
- package/src/stack.ts +19 -0
- package/src/worker.ts +24 -14
- package/src/generated/schemas/ingress.json +0 -1
- package/src/generated/zod/ingress-schema.ts +0 -13
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by Kubb (https://kubb.dev/).
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
import { PlatformSchema } from "./platform-schema.js";
|
|
8
|
+
import { StackInputDefaultValueSchema } from "./stack-input-default-value-schema.js";
|
|
9
|
+
import { StackInputEnvironmentMappingSchema } from "./stack-input-environment-mapping-schema.js";
|
|
10
|
+
import { StackInputKindSchema } from "./stack-input-kind-schema.js";
|
|
11
|
+
import { StackInputProviderSchema } from "./stack-input-provider-schema.js";
|
|
12
|
+
import { StackInputValidationSchema } from "./stack-input-validation-schema.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @description Stack input definition serialized into a release stack.
|
|
16
|
+
*/
|
|
17
|
+
export const StackInputDefinitionSchema = z.object({
|
|
18
|
+
get "default"(){
|
|
19
|
+
return z.union([StackInputDefaultValueSchema, z.null()]).optional()
|
|
20
|
+
},
|
|
21
|
+
"description": z.string().describe("Human-facing helper text."),
|
|
22
|
+
get "env"(){
|
|
23
|
+
return z.array(StackInputEnvironmentMappingSchema.describe("How a resolved stack input is injected into runtime environment variables.")).describe("Runtime env-var mappings for v1 input resolution.").optional()
|
|
24
|
+
},
|
|
25
|
+
"id": z.string().describe("Stable input ID used by CLI/API calls."),
|
|
26
|
+
get "kind"(){
|
|
27
|
+
return StackInputKindSchema.describe("Primitive stack input kind.")
|
|
28
|
+
},
|
|
29
|
+
"label": z.string().describe("Human-facing field label."),
|
|
30
|
+
"placeholder": z.string().describe("Example placeholder shown in UI.").nullish(),
|
|
31
|
+
get "platforms"(){
|
|
32
|
+
return z.array(PlatformSchema.describe("Represents the target cloud platform.")).describe("Platforms where this input applies.").nullish()
|
|
33
|
+
},
|
|
34
|
+
get "providedBy"(){
|
|
35
|
+
return z.array(StackInputProviderSchema.describe("Who can provide a stack input value.")).describe("Who can provide this value.")
|
|
36
|
+
},
|
|
37
|
+
"required": z.boolean().describe("Whether a resolved value is required before deployment can proceed."),
|
|
38
|
+
get "validation"(){
|
|
39
|
+
return z.union([StackInputValidationSchema, z.null()]).optional()
|
|
40
|
+
}
|
|
41
|
+
}).describe("Stack input definition serialized into a release stack.")
|
|
42
|
+
|
|
43
|
+
export type StackInputDefinition = z.infer<typeof StackInputDefinitionSchema>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by Kubb (https://kubb.dev/).
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
import { StackInputEnvironmentVariableTypeSchema } from "./stack-input-environment-variable-type-schema.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @description How a resolved stack input is injected into runtime environment variables.
|
|
11
|
+
*/
|
|
12
|
+
export const StackInputEnvironmentMappingSchema = z.object({
|
|
13
|
+
"name": z.string().describe("Environment variable name."),
|
|
14
|
+
"targetResources": z.array(z.string()).describe("Target resource IDs or patterns. None means every env-capable resource.").nullish(),
|
|
15
|
+
get "type"(){
|
|
16
|
+
return z.union([StackInputEnvironmentVariableTypeSchema, z.null()]).optional()
|
|
17
|
+
}
|
|
18
|
+
}).describe("How a resolved stack input is injected into runtime environment variables.")
|
|
19
|
+
|
|
20
|
+
export type StackInputEnvironmentMapping = z.infer<typeof StackInputEnvironmentMappingSchema>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by Kubb (https://kubb.dev/).
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description Environment variable handling for a stack input mapping.
|
|
10
|
+
*/
|
|
11
|
+
export const StackInputEnvironmentVariableTypeSchema = z.enum(["plain", "secret"]).describe("Environment variable handling for a stack input mapping.")
|
|
12
|
+
|
|
13
|
+
export type StackInputEnvironmentVariableType = z.infer<typeof StackInputEnvironmentVariableTypeSchema>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by Kubb (https://kubb.dev/).
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description Primitive stack input kind.
|
|
10
|
+
*/
|
|
11
|
+
export const StackInputKindSchema = z.enum(["string", "secret", "number", "integer", "boolean", "enum", "stringList"]).describe("Primitive stack input kind.")
|
|
12
|
+
|
|
13
|
+
export type StackInputKind = z.infer<typeof StackInputKindSchema>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by Kubb (https://kubb.dev/).
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description Who can provide a stack input value.
|
|
10
|
+
*/
|
|
11
|
+
export const StackInputProviderSchema = z.enum(["developer", "deployer"]).describe("Who can provide a stack input value.")
|
|
12
|
+
|
|
13
|
+
export type StackInputProvider = z.infer<typeof StackInputProviderSchema>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by Kubb (https://kubb.dev/).
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description Portable stack input validation constraints.
|
|
10
|
+
*/
|
|
11
|
+
export const StackInputValidationSchema = z.object({
|
|
12
|
+
"format": z.string().describe("Semantic format hint such as url.").nullish(),
|
|
13
|
+
"max": z.string().describe("Maximum number.").nullish(),
|
|
14
|
+
"maxItems": z.int().min(0).describe("Maximum string-list items.").nullish(),
|
|
15
|
+
"maxLength": z.int().min(0).describe("Maximum string length.").nullish(),
|
|
16
|
+
"min": z.string().describe("Minimum number.").nullish(),
|
|
17
|
+
"minItems": z.int().min(0).describe("Minimum string-list items.").nullish(),
|
|
18
|
+
"minLength": z.int().min(0).describe("Minimum string length.").nullish(),
|
|
19
|
+
"pattern": z.string().describe("Portable whole-value regex pattern.").nullish(),
|
|
20
|
+
"values": z.array(z.string()).describe("Allowed string enum values.").nullish()
|
|
21
|
+
}).describe("Portable stack input validation constraints.")
|
|
22
|
+
|
|
23
|
+
export type StackInputValidation = z.infer<typeof StackInputValidationSchema>
|
|
@@ -7,12 +7,16 @@ import * as z from "zod";
|
|
|
7
7
|
import { PermissionsConfigSchema } from "./permissions-config-schema.js";
|
|
8
8
|
import { PlatformSchema } from "./platform-schema.js";
|
|
9
9
|
import { ResourceEntrySchema } from "./resource-entry-schema.js";
|
|
10
|
+
import { StackInputDefinitionSchema } from "./stack-input-definition-schema.js";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* @description A bag of resources, unaware of any cloud.
|
|
13
14
|
*/
|
|
14
15
|
export const StackSchema = z.object({
|
|
15
16
|
"id": z.string().describe("Unique identifier for the stack"),
|
|
17
|
+
get "inputs"(){
|
|
18
|
+
return z.array(StackInputDefinitionSchema.describe("Stack input definition serialized into a release stack.")).describe("Input definitions required before setup or deployment can proceed.").optional()
|
|
19
|
+
},
|
|
16
20
|
get "permissions"(){
|
|
17
21
|
return PermissionsConfigSchema.describe("Combined permissions configuration that contains both profiles and management").optional()
|
|
18
22
|
},
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import * as z from "zod";
|
|
7
|
+
import { ComputeSettingsSchema } from "./compute-settings-schema.js";
|
|
7
8
|
import { DeploymentModelSchema } from "./deployment-model-schema.js";
|
|
8
9
|
import { DomainSettingsSchema } from "./domain-settings-schema.js";
|
|
9
10
|
import { HeartbeatsModeSchema } from "./heartbeats-mode-schema.js";
|
|
@@ -16,7 +17,10 @@ import { UpdatesModeSchema } from "./updates-mode-schema.js";
|
|
|
16
17
|
* @description User-customizable deployment settings specified at deploy time.\n\nThese settings are provided by the customer via CloudFormation parameters,\nTerraform attributes, CLI flags, or Helm values. They customize how the\ndeployment runs and what capabilities are enabled.\n\n**Key distinction**: StackSettings is user-customizable, while ManagementConfig\nis platform-derived (from the Manager\'s ServiceAccount).
|
|
17
18
|
*/
|
|
18
19
|
export const StackSettingsSchema = z.object({
|
|
19
|
-
get "
|
|
20
|
+
get "compute"(){
|
|
21
|
+
return z.union([ComputeSettingsSchema, z.null()]).optional()
|
|
22
|
+
},
|
|
23
|
+
get "deploymentModel"(){
|
|
20
24
|
return DeploymentModelSchema.describe("Deployment model: how updates are delivered to the remote environment.").optional()
|
|
21
25
|
},
|
|
22
26
|
get "domains"(){
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import * as z from "zod";
|
|
7
|
-
import {
|
|
7
|
+
import { PublicEndpointOutputSchema } from "./public-endpoint-output-schema.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @description Outputs generated by a successfully provisioned Worker.
|
|
@@ -12,10 +12,9 @@ import { LoadBalancerEndpointSchema } from "./load-balancer-endpoint-schema.js";
|
|
|
12
12
|
export const WorkerOutputsSchema = z.object({
|
|
13
13
|
"commandsPushTarget": z.string().describe("Push target for commands delivery. Platform-specific:\n- AWS: Lambda function name or ARN\n- GCP: Full Pub/Sub topic path (projects/{project}/topics/{topic})\n- Azure: Service Bus \"{namespace}/{queue}\"").nullish(),
|
|
14
14
|
"identifier": z.string().describe("The ARN or platform-specific identifier.").nullish(),
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"url": z.string().describe("The invocation URL (if applicable, e.g., for public ingress or specific platforms).").nullish(),
|
|
15
|
+
"publicEndpoints": z.optional(z.object({
|
|
16
|
+
|
|
17
|
+
}).catchall(z.lazy(() => PublicEndpointOutputSchema).describe("Runtime-resolved public endpoint metadata.")).describe("Public endpoints resolved for this worker.")),
|
|
19
18
|
"workerName": z.string().describe("The platform-specific worker name.")
|
|
20
19
|
}).describe("Outputs generated by a successfully provisioned Worker.")
|
|
21
20
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by Kubb (https://kubb.dev/).
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description Public endpoint configuration for Worker resources.
|
|
10
|
+
*/
|
|
11
|
+
export const WorkerPublicEndpointSchema = z.object({
|
|
12
|
+
"hostLabel": z.string().describe("Optional DNS label override for generated endpoint hostnames.").nullish(),
|
|
13
|
+
"name": z.string().describe("Endpoint name within the resource."),
|
|
14
|
+
"wildcardSubdomains": z.optional(z.boolean().describe("Whether to route wildcard subdomains to this endpoint."))
|
|
15
|
+
}).describe("Public endpoint configuration for Worker resources.")
|
|
16
|
+
|
|
17
|
+
export type WorkerPublicEndpoint = z.infer<typeof WorkerPublicEndpointSchema>
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import * as z from "zod";
|
|
7
|
-
import { IngressSchema } from "./ingress-schema.js";
|
|
8
7
|
import { ReadinessProbeSchema } from "./readiness-probe-schema.js";
|
|
9
8
|
import { ResourceRefSchema } from "./resource-ref-schema.js";
|
|
10
9
|
import { WorkerCodeSchema } from "./worker-code-schema.js";
|
|
10
|
+
import { WorkerPublicEndpointSchema } from "./worker-public-endpoint-schema.js";
|
|
11
11
|
import { WorkerTriggerSchema } from "./worker-trigger-schema.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -23,14 +23,14 @@ export const WorkerSchema = z.object({
|
|
|
23
23
|
|
|
24
24
|
}).catchall(z.string()).describe("Key-value pairs to set as environment variables for the worker.")),
|
|
25
25
|
"id": z.string().describe("Identifier for the worker. Must contain only alphanumeric characters, hyphens, and underscores ([A-Za-z0-9-_]).\nMaximum 64 characters."),
|
|
26
|
-
get "ingress"(){
|
|
27
|
-
return IngressSchema.default("private").optional()
|
|
28
|
-
},
|
|
29
26
|
get "links"(){
|
|
30
27
|
return z.array(ResourceRefSchema.describe("New ResourceRef that works with any resource type.\nThis can eventually replace the enum-based ResourceRef for full extensibility.")).describe("List of resource references this worker depends on.")
|
|
31
28
|
},
|
|
32
29
|
"memoryMb": z.optional(z.int().min(0).default(256).describe("Memory allocated to the worker in megabytes (MB).\nDefault: 256\n\nPlatform-specific constraints:\n- **AWS Lambda**: 128–10240 MB in 1 MB increments\n- **GCP Cloud Run**: 128–32768 MB\n- **Azure Container Apps**: fixed CPU/memory pairs — 512, 1024, 1536, 2048, 2560,\n 3072, 3584, 4096 MB. Values below 512 are automatically rounded up at deploy time.")),
|
|
33
30
|
"permissions": z.string().describe("Permission profile name that defines the permissions granted to this worker.\nThis references a profile defined in the stack's permission definitions."),
|
|
31
|
+
get "publicEndpoints"(){
|
|
32
|
+
return z.array(WorkerPublicEndpointSchema.describe("Public endpoint configuration for Worker resources.")).describe("Public endpoints exposed by this worker.")
|
|
33
|
+
},
|
|
34
34
|
get "readinessProbe"(){
|
|
35
35
|
return z.union([ReadinessProbeSchema, z.null()]).optional()
|
|
36
36
|
},
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from "./resource.js"
|
|
|
2
2
|
export * from "./storage.js"
|
|
3
3
|
export * from "./worker.js"
|
|
4
4
|
export * from "./container.js"
|
|
5
|
+
export * from "./compute-cluster.js"
|
|
5
6
|
export * from "./daemon.js"
|
|
6
7
|
export * from "./build.js"
|
|
7
8
|
export * from "./artifact-registry.js"
|
|
@@ -10,6 +11,7 @@ export * from "./kv.js"
|
|
|
10
11
|
export * from "./queue.js"
|
|
11
12
|
export * from "./service-account.js"
|
|
12
13
|
export * from "./stack.js"
|
|
14
|
+
export * from "./input.js"
|
|
13
15
|
export * from "./get-resource-outputs.js"
|
|
14
16
|
export * from "./error.js"
|
|
15
17
|
export * from "./common-errors.js"
|
|
@@ -177,6 +179,13 @@ export {
|
|
|
177
179
|
ResourceLifecycleSchema,
|
|
178
180
|
ResourceRefSchema,
|
|
179
181
|
StackStateSchema,
|
|
182
|
+
StackInputDefaultValueSchema,
|
|
183
|
+
StackInputDefinitionSchema,
|
|
184
|
+
StackInputEnvironmentMappingSchema,
|
|
185
|
+
StackInputEnvironmentVariableTypeSchema,
|
|
186
|
+
StackInputKindSchema,
|
|
187
|
+
StackInputProviderSchema,
|
|
188
|
+
StackInputValidationSchema,
|
|
180
189
|
AwsArtifactRegistryImportDataSchema,
|
|
181
190
|
AwsBuildImportDataSchema,
|
|
182
191
|
AwsComputeClusterImportDataSchema,
|
package/src/input.ts
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Platform,
|
|
3
|
+
StackInputDefaultValue,
|
|
4
|
+
StackInputDefinition,
|
|
5
|
+
StackInputEnvironmentMapping,
|
|
6
|
+
StackInputEnvironmentVariableType,
|
|
7
|
+
StackInputKind,
|
|
8
|
+
StackInputProvider,
|
|
9
|
+
StackInputValidation,
|
|
10
|
+
} from "./generated/index.js"
|
|
11
|
+
|
|
12
|
+
const stackInputDraftSymbol = Symbol("alien.stackInputDraft")
|
|
13
|
+
const stackInputDefinitionsSymbol = Symbol("alien.stackInputDefinitions")
|
|
14
|
+
|
|
15
|
+
export type StackInputValue = string | number | boolean | string[]
|
|
16
|
+
|
|
17
|
+
type OneOrMany<T> = T | readonly T[]
|
|
18
|
+
|
|
19
|
+
export type StackInputEnvMapping =
|
|
20
|
+
| string
|
|
21
|
+
| {
|
|
22
|
+
name: string
|
|
23
|
+
targetResources?: readonly string[]
|
|
24
|
+
type?: StackInputEnvironmentVariableType
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface CommonInputOptions<TDefault extends StackInputValue> {
|
|
28
|
+
providedBy: OneOrMany<StackInputProvider>
|
|
29
|
+
required: boolean
|
|
30
|
+
label: string
|
|
31
|
+
description: string
|
|
32
|
+
placeholder?: string
|
|
33
|
+
default?: TDefault
|
|
34
|
+
platforms?: readonly Platform[]
|
|
35
|
+
env?: OneOrMany<StackInputEnvMapping>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface StringInputOptions extends CommonInputOptions<string> {
|
|
39
|
+
minLength?: number
|
|
40
|
+
maxLength?: number
|
|
41
|
+
pattern?: string
|
|
42
|
+
format?: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface SecretInputOptions extends Omit<CommonInputOptions<string>, "default"> {
|
|
46
|
+
minLength?: number
|
|
47
|
+
maxLength?: number
|
|
48
|
+
pattern?: string
|
|
49
|
+
format?: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface NumberInputOptions extends CommonInputOptions<number> {
|
|
53
|
+
min?: number
|
|
54
|
+
max?: number
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface IntegerInputOptions extends CommonInputOptions<number> {
|
|
58
|
+
min?: number
|
|
59
|
+
max?: number
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface BooleanInputOptions extends CommonInputOptions<boolean> {}
|
|
63
|
+
|
|
64
|
+
export interface EnumInputOptions extends CommonInputOptions<string> {
|
|
65
|
+
placeholder?: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface StringListInputOptions extends CommonInputOptions<string[]> {
|
|
69
|
+
minItems?: number
|
|
70
|
+
maxItems?: number
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface StackInputRef<TValue extends StackInputValue = StackInputValue> {
|
|
74
|
+
readonly id: string
|
|
75
|
+
readonly kind: StackInputKind
|
|
76
|
+
readonly __value?: TValue
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type StackInputCollection = {
|
|
80
|
+
readonly [stackInputDefinitionsSymbol]: readonly StackInputDefinition[]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface StackInputDraft<TValue extends StackInputValue = StackInputValue> {
|
|
84
|
+
readonly [stackInputDraftSymbol]: true
|
|
85
|
+
readonly kind: StackInputKind
|
|
86
|
+
readonly options: CommonInputOptions<TValue>
|
|
87
|
+
readonly validation: StackInputValidation
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type StackInputSet<T extends Record<string, StackInputDraft>> = {
|
|
91
|
+
readonly [K in keyof T]: T[K] extends StackInputDraft<infer TValue>
|
|
92
|
+
? StackInputRef<TValue>
|
|
93
|
+
: never
|
|
94
|
+
} & StackInputCollection
|
|
95
|
+
|
|
96
|
+
export function inputs<const T extends Record<string, StackInputDraft>>(
|
|
97
|
+
drafts: T,
|
|
98
|
+
): StackInputSet<T> {
|
|
99
|
+
const result = {} as Record<string, StackInputRef>
|
|
100
|
+
const definitions: StackInputDefinition[] = []
|
|
101
|
+
|
|
102
|
+
for (const [id, draft] of Object.entries(drafts)) {
|
|
103
|
+
validateInputId(id)
|
|
104
|
+
validateDraft(id, draft)
|
|
105
|
+
|
|
106
|
+
result[id] = { id, kind: draft.kind }
|
|
107
|
+
definitions.push({
|
|
108
|
+
id,
|
|
109
|
+
kind: draft.kind,
|
|
110
|
+
providedBy: normalizeArray(draft.options.providedBy),
|
|
111
|
+
required: draft.options.required,
|
|
112
|
+
label: draft.options.label,
|
|
113
|
+
description: draft.options.description,
|
|
114
|
+
placeholder: draft.options.placeholder,
|
|
115
|
+
default: toDefaultValue(draft.kind, draft.options.default),
|
|
116
|
+
platforms: draft.options.platforms ? [...draft.options.platforms] : undefined,
|
|
117
|
+
validation: Object.keys(draft.validation).length > 0 ? draft.validation : undefined,
|
|
118
|
+
env: normalizeEnv(draft.options.env),
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
Object.defineProperty(result, stackInputDefinitionsSymbol, {
|
|
123
|
+
value: Object.freeze(definitions),
|
|
124
|
+
enumerable: false,
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
return result as StackInputSet<T>
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function getStackInputDefinitions(
|
|
131
|
+
value: StackInputCollection | readonly StackInputDefinition[],
|
|
132
|
+
): StackInputDefinition[] {
|
|
133
|
+
if (Array.isArray(value)) {
|
|
134
|
+
return [...(value as readonly StackInputDefinition[])]
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return [...(value as StackInputCollection)[stackInputDefinitionsSymbol]]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function defineInput<TValue extends StackInputValue>(
|
|
141
|
+
kind: StackInputKind,
|
|
142
|
+
options: CommonInputOptions<TValue>,
|
|
143
|
+
validation: StackInputValidation = {},
|
|
144
|
+
): StackInputDraft<TValue> {
|
|
145
|
+
return {
|
|
146
|
+
[stackInputDraftSymbol]: true,
|
|
147
|
+
kind,
|
|
148
|
+
options,
|
|
149
|
+
validation,
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function defineStringInput(options: StringInputOptions): StackInputDraft<string> {
|
|
154
|
+
return defineInput("string", options, {
|
|
155
|
+
minLength: options.minLength,
|
|
156
|
+
maxLength: options.maxLength,
|
|
157
|
+
pattern: options.pattern,
|
|
158
|
+
format: options.format,
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function defineSecretInput(options: SecretInputOptions): StackInputDraft<string> {
|
|
163
|
+
return defineInput("secret", options, {
|
|
164
|
+
minLength: options.minLength,
|
|
165
|
+
maxLength: options.maxLength,
|
|
166
|
+
pattern: options.pattern,
|
|
167
|
+
format: options.format,
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function defineNumberInput(options: NumberInputOptions): StackInputDraft<number> {
|
|
172
|
+
return defineInput("number", options, {
|
|
173
|
+
min: numberToString(options.min),
|
|
174
|
+
max: numberToString(options.max),
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function defineIntegerInput(options: IntegerInputOptions): StackInputDraft<number> {
|
|
179
|
+
return defineInput("integer", options, {
|
|
180
|
+
min: integerToString(options.min, "min"),
|
|
181
|
+
max: integerToString(options.max, "max"),
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function defineBooleanInput(options: BooleanInputOptions): StackInputDraft<boolean> {
|
|
186
|
+
return defineInput("boolean", options)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function defineEnumInput<const TValues extends readonly [string, ...string[]]>(
|
|
190
|
+
values: TValues,
|
|
191
|
+
options: EnumInputOptions,
|
|
192
|
+
): StackInputDraft<TValues[number]> {
|
|
193
|
+
return defineInput("enum", options, {
|
|
194
|
+
values: [...values],
|
|
195
|
+
}) as StackInputDraft<TValues[number]>
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function defineStringListInput(options: StringListInputOptions): StackInputDraft<string[]> {
|
|
199
|
+
return defineInput("stringList", options, {
|
|
200
|
+
minItems: options.minItems,
|
|
201
|
+
maxItems: options.maxItems,
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function normalizeArray<T>(value: OneOrMany<T>): T[] {
|
|
206
|
+
return Array.isArray(value) ? [...(value as readonly T[])] : [value as T]
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function normalizeEnv(
|
|
210
|
+
value: OneOrMany<StackInputEnvMapping> | undefined,
|
|
211
|
+
): StackInputEnvironmentMapping[] {
|
|
212
|
+
if (!value) {
|
|
213
|
+
return []
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return normalizeArray(value).map(mapping => {
|
|
217
|
+
if (typeof mapping === "string") {
|
|
218
|
+
return { name: mapping }
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
name: mapping.name,
|
|
223
|
+
targetResources: mapping.targetResources ? [...mapping.targetResources] : undefined,
|
|
224
|
+
type: mapping.type,
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function toDefaultValue(
|
|
230
|
+
kind: StackInputKind,
|
|
231
|
+
value: StackInputValue | undefined,
|
|
232
|
+
): StackInputDefaultValue | undefined {
|
|
233
|
+
if (value === undefined) {
|
|
234
|
+
return undefined
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
switch (kind) {
|
|
238
|
+
case "string":
|
|
239
|
+
case "enum":
|
|
240
|
+
return { type: "string", value: String(value) }
|
|
241
|
+
case "number":
|
|
242
|
+
return { type: "number", value: numberToString(value as number) ?? "" }
|
|
243
|
+
case "integer":
|
|
244
|
+
return { type: "number", value: integerToString(value as number, "default") ?? "" }
|
|
245
|
+
case "boolean":
|
|
246
|
+
return { type: "boolean", value: Boolean(value) }
|
|
247
|
+
case "stringList":
|
|
248
|
+
return { type: "stringList", value: [...(value as string[])] }
|
|
249
|
+
case "secret":
|
|
250
|
+
throw new Error("Secret stack inputs cannot declare a default value")
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function validateDraft(id: string, draft: StackInputDraft): void {
|
|
255
|
+
if (!draft || draft[stackInputDraftSymbol] !== true) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Stack input '${id}' must be created with alien.string(), alien.secret(), or another input helper`,
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (normalizeArray(draft.options.providedBy).length === 0) {
|
|
262
|
+
throw new Error(`Stack input '${id}' must include at least one providedBy value`)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!draft.options.label.trim()) {
|
|
266
|
+
throw new Error(`Stack input '${id}' must include a label`)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (draft.options.required && !draft.options.description.trim()) {
|
|
270
|
+
throw new Error(`Stack input '${id}' must include a description when required is true`)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
validateValidation(id, draft.kind, draft.validation)
|
|
274
|
+
|
|
275
|
+
for (const mapping of normalizeEnv(draft.options.env)) {
|
|
276
|
+
validateEnvName(id, mapping.name)
|
|
277
|
+
if (mapping.targetResources?.length === 0) {
|
|
278
|
+
throw new Error(
|
|
279
|
+
`Stack input '${id}' env mapping '${mapping.name}' cannot use an empty targetResources list`,
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function validateInputId(id: string): void {
|
|
286
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(id)) {
|
|
287
|
+
throw new Error(
|
|
288
|
+
`Stack input '${id}' id must start with a letter or underscore and contain only letters, digits, and underscores`,
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (!/[a-z]/.test(id)) {
|
|
293
|
+
throw new Error(`Stack input '${id}' id must not be all-caps env-var style`)
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function validateEnvName(id: string, name: string): void {
|
|
298
|
+
if (!/^[A-Z_][A-Z0-9_]*$/.test(name)) {
|
|
299
|
+
throw new Error(
|
|
300
|
+
`Stack input '${id}' env name '${name}' must use uppercase letters, digits, and underscores`,
|
|
301
|
+
)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function validateValidation(
|
|
306
|
+
id: string,
|
|
307
|
+
kind: StackInputKind,
|
|
308
|
+
validation: StackInputValidation,
|
|
309
|
+
): void {
|
|
310
|
+
const minLength = validation.minLength ?? undefined
|
|
311
|
+
const maxLength = validation.maxLength ?? undefined
|
|
312
|
+
const minItems = validation.minItems ?? undefined
|
|
313
|
+
const maxItems = validation.maxItems ?? undefined
|
|
314
|
+
|
|
315
|
+
if (minLength !== undefined && maxLength !== undefined && minLength > maxLength) {
|
|
316
|
+
throw new Error(`Stack input '${id}' minLength must be less than or equal to maxLength`)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (minItems !== undefined && maxItems !== undefined && minItems > maxItems) {
|
|
320
|
+
throw new Error(`Stack input '${id}' minItems must be less than or equal to maxItems`)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (kind === "enum" && (!validation.values || validation.values.length === 0)) {
|
|
324
|
+
throw new Error(`Stack input '${id}' enum values must not be empty`)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (validation.pattern) {
|
|
328
|
+
validatePortablePattern(id, validation.pattern)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function validatePortablePattern(id: string, pattern: string): void {
|
|
333
|
+
if (pattern.length === 0) {
|
|
334
|
+
throw new Error(`Stack input '${id}' pattern must not be empty`)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (pattern.startsWith("/") && pattern.endsWith("/") && pattern.length > 1) {
|
|
338
|
+
throw new Error(`Stack input '${id}' pattern must not use regex delimiters`)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (/\\[1-9pPk]/.test(pattern) || /\(\?/.test(pattern) || /\[[^\]]*\[/.test(pattern)) {
|
|
342
|
+
throw new Error(
|
|
343
|
+
`Stack input '${id}' pattern is not portable across TypeScript, CloudFormation, and Terraform`,
|
|
344
|
+
)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function numberToString(value: number | undefined): string | undefined {
|
|
349
|
+
if (value === undefined) {
|
|
350
|
+
return undefined
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (!Number.isFinite(value)) {
|
|
354
|
+
throw new Error("Stack input number constraints must be finite")
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return String(value)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function integerToString(value: number | undefined, field: string): string | undefined {
|
|
361
|
+
if (value === undefined) {
|
|
362
|
+
return undefined
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (!Number.isInteger(value)) {
|
|
366
|
+
throw new Error(`Stack input integer ${field} must be an integer`)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return String(value)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export {
|
|
373
|
+
defineBooleanInput as boolean,
|
|
374
|
+
defineEnumInput as enum,
|
|
375
|
+
defineIntegerInput as integer,
|
|
376
|
+
defineNumberInput as number,
|
|
377
|
+
defineSecretInput as secret,
|
|
378
|
+
defineStringInput as string,
|
|
379
|
+
defineStringListInput as stringList,
|
|
380
|
+
}
|