@alienplatform/bindings 1.0.0 → 2.0.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.
Files changed (56) hide show
  1. package/LICENSE.md +105 -0
  2. package/README.md +59 -0
  3. package/dist/errors.d.ts +56 -0
  4. package/dist/errors.d.ts.map +1 -0
  5. package/dist/factories.d.ts +26 -0
  6. package/dist/factories.d.ts.map +1 -0
  7. package/dist/index.d.ts +19 -1768
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +23 -44772
  10. package/dist/loader.d.ts +171 -0
  11. package/dist/loader.d.ts.map +1 -0
  12. package/dist/loader.js +3712 -0
  13. package/dist/native.d.ts +41 -0
  14. package/dist/native.d.ts.map +1 -0
  15. package/dist/native.js +46 -0
  16. package/dist/types.d.ts +150 -0
  17. package/dist/types.d.ts.map +1 -0
  18. package/package.json +39 -21
  19. package/AGENTS.md +0 -70
  20. package/dist/index.js.map +0 -1
  21. package/scripts/generate-proto.sh +0 -46
  22. package/src/bindings/AGENTS.md +0 -105
  23. package/src/bindings/artifact-registry.ts +0 -314
  24. package/src/bindings/build.ts +0 -195
  25. package/src/bindings/function.ts +0 -164
  26. package/src/bindings/index.ts +0 -12
  27. package/src/bindings/kv.ts +0 -240
  28. package/src/bindings/queue.ts +0 -191
  29. package/src/bindings/service-account.ts +0 -113
  30. package/src/bindings/storage.ts +0 -535
  31. package/src/bindings/vault.ts +0 -133
  32. package/src/channel.ts +0 -94
  33. package/src/commands.ts +0 -76
  34. package/src/context.ts +0 -368
  35. package/src/errors.ts +0 -259
  36. package/src/events.ts +0 -463
  37. package/src/generated/artifact_registry.ts +0 -1934
  38. package/src/generated/build.ts +0 -1263
  39. package/src/generated/container.ts +0 -485
  40. package/src/generated/control.ts +0 -1574
  41. package/src/generated/function.ts +0 -741
  42. package/src/generated/google/protobuf/duration.ts +0 -196
  43. package/src/generated/google/protobuf/timestamp.ts +0 -225
  44. package/src/generated/kv.ts +0 -1137
  45. package/src/generated/queue.ts +0 -729
  46. package/src/generated/service_account.ts +0 -766
  47. package/src/generated/storage.ts +0 -3653
  48. package/src/generated/vault.ts +0 -519
  49. package/src/generated/wait_until.ts +0 -781
  50. package/src/global.ts +0 -316
  51. package/src/grpc-utils.ts +0 -159
  52. package/src/index.ts +0 -156
  53. package/src/types.ts +0 -384
  54. package/src/wait-until.ts +0 -257
  55. package/tsconfig.json +0 -8
  56. package/tsdown.config.ts +0 -14
@@ -1,46 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Generate TypeScript types from proto files using ts-proto + nice-grpc
4
-
5
- set -e
6
-
7
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
- PACKAGE_DIR="$(dirname "$SCRIPT_DIR")"
9
- PROTO_DIR="$PACKAGE_DIR/../../crates/alien-bindings/proto"
10
- OUT_DIR="$PACKAGE_DIR/src/generated"
11
-
12
- # Clean and create output directory
13
- rm -rf "$OUT_DIR"
14
- mkdir -p "$OUT_DIR"
15
-
16
- # Find protoc - prefer system installation
17
- if command -v protoc &> /dev/null; then
18
- PROTOC="protoc"
19
- else
20
- echo "Error: protoc not found. Install via 'brew install protobuf' on macOS."
21
- exit 1
22
- fi
23
-
24
- # Find ts-proto plugin
25
- TS_PROTO_PLUGIN="$PACKAGE_DIR/node_modules/.bin/protoc-gen-ts_proto"
26
-
27
- if [ ! -f "$TS_PROTO_PLUGIN" ]; then
28
- echo "Error: protoc-gen-ts_proto not found. Run 'pnpm install' first."
29
- exit 1
30
- fi
31
-
32
- echo "Using protoc: $PROTOC"
33
- echo "Using ts-proto plugin: $TS_PROTO_PLUGIN"
34
- echo "Generating TypeScript types from proto files..."
35
-
36
- # Generate types for all proto files
37
- # Using nice-grpc options as per the playbook
38
- "$PROTOC" \
39
- --plugin="protoc-gen-ts_proto=$TS_PROTO_PLUGIN" \
40
- --ts_proto_out="$OUT_DIR" \
41
- --ts_proto_opt=outputServices=nice-grpc,outputServices=generic-definitions,useExactTypes=false,esModuleInterop=true,importSuffix=.js \
42
- --proto_path="$PROTO_DIR" \
43
- "$PROTO_DIR"/*.proto
44
-
45
- echo "Generated TypeScript types in $OUT_DIR"
46
- echo "Done!"
@@ -1,105 +0,0 @@
1
- # Binding Implementations
2
-
3
- Each TypeScript binding must match its Rust counterpart in `alien-bindings/src/providers/<name>/grpc.rs`.
4
-
5
- **Examples:**
6
- - `kv.ts` → `providers/kv/grpc.rs`
7
- - `storage.ts` → `providers/storage/grpc.rs`
8
- - `build.ts` → `providers/build/grpc.rs`
9
-
10
- ## Core Pattern: Public API → gRPC → Public API
11
-
12
- ```
13
- ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
14
- │ Public API │ → │ gRPC Proto │ → │ Public API │
15
- │ (SDK types) │ │ (wire format) │ │ (SDK types) │
16
- └─────────────────┘ └─────────────────┘ └─────────────────┘
17
- User calls Internal only User receives
18
- ```
19
-
20
- **Public API types** come from `@alienplatform/core` or `../types.ts`. Proto types are **internal only** - never exposed to users.
21
-
22
- ```typescript
23
- // ❌ Bad - exposing proto types
24
- async getStatus(buildId: string): Promise<BuildExecutionProto>
25
-
26
- // ✅ Good - convert proto to public types
27
- async getStatus(buildId: string): Promise<BuildExecution> {
28
- const response = await this.client.getBuildStatus({ ... })
29
- return this.fromProtoExecution(response.execution!) // Transform here
30
- }
31
- ```
32
-
33
- ## Guidelines
34
-
35
- ### 1. Match All Rust Trait Methods
36
- Every method in the Rust trait must have a TypeScript equivalent. Check for missing methods when adding bindings.
37
-
38
- ### 2. Match Rust Enum Fallbacks Exactly
39
- Rust often maps unknown/unspecified enum values to a specific fallback. TypeScript must match:
40
-
41
- ```rust
42
- // Rust: maps Unspecified → Failed
43
- BuildStatus::Unspecified => BuildStatus::Failed,
44
- ```
45
- ```typescript
46
- // TypeScript: must match
47
- [BuildStatusProto.BUILD_STATUS_UNSPECIFIED]: "FAILED", // NOT "QUEUED"
48
- ```
49
-
50
- ### 3. Transform Types in Private Helpers
51
- Keep transformations consistent and testable:
52
-
53
- ```typescript
54
- private fromProtoExecution(proto: BuildExecutionProto): BuildExecution {
55
- return {
56
- id: proto.id,
57
- status: statusMap[proto.status] ?? "FAILED",
58
- startTime: proto.startTime ? new Date(proto.startTime) : undefined,
59
- }
60
- }
61
-
62
- private toProtoConfig(config: BuildStartConfig): BuildConfigProto {
63
- return {
64
- script: config.script,
65
- computeType: computeTypeMap[config.computeType] ?? ComputeType.UNSPECIFIED,
66
- }
67
- }
68
- ```
69
-
70
- ### 4. Convert Units Consistently
71
- Rust uses `Duration`, TypeScript uses milliseconds:
72
-
73
- ```typescript
74
- ttlSeconds: options.ttlMs ? Math.floor(options.ttlMs / 1000) : undefined
75
- timeoutSeconds: request.timeoutMs ? Math.floor(request.timeoutMs / 1000) : undefined
76
- ```
77
-
78
- ### 5. Use wrapGrpcCall for Error Handling
79
- Always wrap gRPC calls with context for proper error mapping:
80
-
81
- ```typescript
82
- return await wrapGrpcCall(
83
- "BuildService",
84
- "GetBuildStatus",
85
- async () => { ... },
86
- { bindingName: this.bindingName }, // Context for error mapping
87
- )
88
- ```
89
-
90
- ### 6. Handle Optional Proto Fields
91
- Rust `Option<T>` becomes `T | undefined`. Use nullish coalescing:
92
-
93
- ```typescript
94
- uri: proto.uri ?? "",
95
- createdAt: proto.createdAt ? new Date(proto.createdAt) : undefined,
96
- ```
97
-
98
- ## Convenience Methods
99
-
100
- TypeScript may add convenience methods not in Rust (e.g., `getJson()`, `exists()`, `waitForCompletion()`). These are fine if they build on core methods.
101
-
102
- ## See Also
103
-
104
- - Parent: `packages/bindings/AGENTS.md` - Package overview and type architecture
105
- - Proto definitions: `crates/alien-bindings/proto/`
@@ -1,314 +0,0 @@
1
- /**
2
- * ArtifactRegistry binding implementation.
3
- *
4
- * Provides container image repository management.
5
- */
6
-
7
- import { type Channel, createClient } from "nice-grpc"
8
- import {
9
- ArtifactRegistryServiceDefinition,
10
- ComputeServiceType as ComputeServiceTypeProto,
11
- type Credentials,
12
- type CrossAccountAccess as CrossAccountAccessProto,
13
- type CrossAccountPermissions as CrossAccountPermissionsProto,
14
- type ArtifactRegistryServiceClient as GeneratedClient,
15
- ArtifactRegistryPermissions as PermissionsProto,
16
- type RepositoryResult,
17
- } from "../generated/artifact_registry.js"
18
- import { wrapGrpcCall } from "../grpc-utils.js"
19
- import type {
20
- ArtifactRegistryCredentials,
21
- ArtifactRegistryPermissions,
22
- ComputeServiceType,
23
- CrossAccountAccess,
24
- CrossAccountPermissions,
25
- RepositoryInfo,
26
- } from "../types.js"
27
-
28
- // Permission map
29
- const permissionMap: Record<ArtifactRegistryPermissions, PermissionsProto> = {
30
- pull: PermissionsProto.PULL,
31
- "push-pull": PermissionsProto.PUSH_PULL,
32
- }
33
-
34
- /**
35
- * ArtifactRegistry binding for container repository management.
36
- *
37
- * @example
38
- * ```typescript
39
- * import { artifactRegistry } from "@alienplatform/bindings"
40
- *
41
- * const registry = artifactRegistry("my-registry")
42
- *
43
- * // Create a repository
44
- * const repo = await registry.createRepository("my-app")
45
- * console.log("Repository URI:", repo.uri)
46
- *
47
- * // Generate push credentials
48
- * const creds = await registry.generateCredentials("my-app", "push-pull")
49
- * console.log("Username:", creds.username)
50
- * ```
51
- */
52
- export class ArtifactRegistry {
53
- private readonly client: GeneratedClient
54
- private readonly bindingName: string
55
-
56
- constructor(channel: Channel, bindingName: string) {
57
- this.client = createClient(ArtifactRegistryServiceDefinition, channel)
58
- this.bindingName = bindingName
59
- }
60
-
61
- /**
62
- * Create a repository.
63
- *
64
- * @param repoName - Name of the repository
65
- * @returns Repository information
66
- */
67
- async createRepository(repoName: string): Promise<RepositoryInfo> {
68
- return await wrapGrpcCall(
69
- "ArtifactRegistryService",
70
- "CreateRepository",
71
- async () => {
72
- const response = await this.client.createRepository({
73
- bindingName: this.bindingName,
74
- repoName,
75
- })
76
- return this.fromProtoResult(response.result!)
77
- },
78
- { bindingName: this.bindingName },
79
- )
80
- }
81
-
82
- /**
83
- * Get repository details.
84
- *
85
- * @param repoId - Repository ID
86
- * @returns Repository information
87
- */
88
- async getRepository(repoId: string): Promise<RepositoryInfo> {
89
- return await wrapGrpcCall(
90
- "ArtifactRegistryService",
91
- "GetRepository",
92
- async () => {
93
- const response = await this.client.getRepository({
94
- bindingName: this.bindingName,
95
- repoId,
96
- })
97
- return this.fromProtoResult(response.result!)
98
- },
99
- { bindingName: this.bindingName },
100
- )
101
- }
102
-
103
- /**
104
- * Add cross-account access to a repository.
105
- *
106
- * @param repoId - Repository ID
107
- * @param access - Cross-account access configuration
108
- */
109
- async addCrossAccountAccess(repoId: string, access: CrossAccountAccess): Promise<void> {
110
- await wrapGrpcCall(
111
- "ArtifactRegistryService",
112
- "AddCrossAccountAccess",
113
- async () => {
114
- await this.client.addCrossAccountAccess({
115
- bindingName: this.bindingName,
116
- repoId,
117
- access: this.toProtoCrossAccountAccess(access),
118
- })
119
- },
120
- { bindingName: this.bindingName },
121
- )
122
- }
123
-
124
- /**
125
- * Remove cross-account access from a repository.
126
- *
127
- * @param repoId - Repository ID
128
- * @param access - Cross-account access configuration to remove
129
- */
130
- async removeCrossAccountAccess(repoId: string, access: CrossAccountAccess): Promise<void> {
131
- await wrapGrpcCall(
132
- "ArtifactRegistryService",
133
- "RemoveCrossAccountAccess",
134
- async () => {
135
- await this.client.removeCrossAccountAccess({
136
- bindingName: this.bindingName,
137
- repoId,
138
- access: this.toProtoCrossAccountAccess(access),
139
- })
140
- },
141
- { bindingName: this.bindingName },
142
- )
143
- }
144
-
145
- /**
146
- * Get current cross-account access permissions for a repository.
147
- *
148
- * @param repoId - Repository ID
149
- * @returns Current cross-account permissions
150
- */
151
- async getCrossAccountAccess(repoId: string): Promise<CrossAccountPermissions> {
152
- return await wrapGrpcCall(
153
- "ArtifactRegistryService",
154
- "GetCrossAccountAccess",
155
- async () => {
156
- const response = await this.client.getCrossAccountAccess({
157
- bindingName: this.bindingName,
158
- repoId,
159
- })
160
- return this.fromProtoCrossAccountPermissions(response.permissions!)
161
- },
162
- { bindingName: this.bindingName },
163
- )
164
- }
165
-
166
- /**
167
- * Generate credentials for repository access.
168
- *
169
- * @param repoId - Repository ID
170
- * @param permissions - Permission level (pull or push-pull)
171
- * @param ttlSeconds - Optional TTL in seconds
172
- * @returns Repository credentials
173
- */
174
- async generateCredentials(
175
- repoId: string,
176
- permissions: ArtifactRegistryPermissions,
177
- ttlSeconds?: number,
178
- ): Promise<ArtifactRegistryCredentials> {
179
- return await wrapGrpcCall(
180
- "ArtifactRegistryService",
181
- "GenerateCredentials",
182
- async () => {
183
- const response = await this.client.generateCredentials({
184
- bindingName: this.bindingName,
185
- repoId,
186
- permissions: permissionMap[permissions],
187
- ttlSeconds,
188
- })
189
- return this.fromProtoCredentials(response.credentials!)
190
- },
191
- { bindingName: this.bindingName },
192
- )
193
- }
194
-
195
- /**
196
- * Delete a repository.
197
- *
198
- * @param repoId - Repository ID
199
- */
200
- async deleteRepository(repoId: string): Promise<void> {
201
- await wrapGrpcCall(
202
- "ArtifactRegistryService",
203
- "DeleteRepository",
204
- async () => {
205
- await this.client.deleteRepository({
206
- bindingName: this.bindingName,
207
- repoId,
208
- })
209
- },
210
- { bindingName: this.bindingName },
211
- )
212
- }
213
-
214
- // Private helpers
215
-
216
- private fromProtoResult(proto: RepositoryResult): RepositoryInfo {
217
- return {
218
- name: proto.name,
219
- uri: proto.uri ?? "",
220
- createdAt: proto.createdAt ? new Date(proto.createdAt) : undefined,
221
- }
222
- }
223
-
224
- private fromProtoCredentials(proto: Credentials): ArtifactRegistryCredentials {
225
- return {
226
- username: proto.username,
227
- password: proto.password,
228
- expiresAt: proto.expiresAt ? new Date(proto.expiresAt) : undefined,
229
- }
230
- }
231
-
232
- private toProtoCrossAccountAccess(access: CrossAccountAccess): CrossAccountAccessProto {
233
- if (access.type === "aws") {
234
- return {
235
- aws: {
236
- accountIds: access.aws.accountIds,
237
- allowedServiceTypes: access.aws.allowedServiceTypes.map(st =>
238
- this.computeServiceTypeToProto(st),
239
- ),
240
- roleArns: access.aws.roleArns,
241
- },
242
- gcp: undefined,
243
- }
244
- }
245
- return {
246
- aws: undefined,
247
- gcp: {
248
- projectNumbers: access.gcp.projectNumbers,
249
- allowedServiceTypes: access.gcp.allowedServiceTypes.map(st =>
250
- this.computeServiceTypeToProto(st),
251
- ),
252
- serviceAccountEmails: access.gcp.serviceAccountEmails,
253
- },
254
- }
255
- }
256
-
257
- private fromProtoCrossAccountAccess(proto: CrossAccountAccessProto): CrossAccountAccess {
258
- if (proto.aws) {
259
- return {
260
- type: "aws",
261
- aws: {
262
- accountIds: proto.aws.accountIds,
263
- allowedServiceTypes: proto.aws.allowedServiceTypes
264
- .map(st => this.protoToComputeServiceType(st))
265
- .filter((st): st is ComputeServiceType => st !== undefined),
266
- roleArns: proto.aws.roleArns,
267
- },
268
- }
269
- }
270
- if (proto.gcp) {
271
- return {
272
- type: "gcp",
273
- gcp: {
274
- projectNumbers: proto.gcp.projectNumbers,
275
- allowedServiceTypes: proto.gcp.allowedServiceTypes
276
- .map(st => this.protoToComputeServiceType(st))
277
- .filter((st): st is ComputeServiceType => st !== undefined),
278
- serviceAccountEmails: proto.gcp.serviceAccountEmails,
279
- },
280
- }
281
- }
282
- throw new Error("Invalid CrossAccountAccess: neither aws nor gcp set")
283
- }
284
-
285
- private fromProtoCrossAccountPermissions(
286
- proto: CrossAccountPermissionsProto,
287
- ): CrossAccountPermissions {
288
- if (!proto.access) {
289
- throw new Error("Invalid CrossAccountPermissions: access is missing")
290
- }
291
- return {
292
- access: this.fromProtoCrossAccountAccess(proto.access),
293
- lastUpdated: proto.lastUpdated,
294
- }
295
- }
296
-
297
- private computeServiceTypeToProto(st: ComputeServiceType): ComputeServiceTypeProto {
298
- switch (st) {
299
- case "function":
300
- return ComputeServiceTypeProto.FUNCTION
301
- default:
302
- return ComputeServiceTypeProto.UNRECOGNIZED
303
- }
304
- }
305
-
306
- private protoToComputeServiceType(st: ComputeServiceTypeProto): ComputeServiceType | undefined {
307
- switch (st) {
308
- case ComputeServiceTypeProto.FUNCTION:
309
- return "function"
310
- default:
311
- return undefined
312
- }
313
- }
314
- }
@@ -1,195 +0,0 @@
1
- /**
2
- * Build binding implementation.
3
- *
4
- * Provides build execution capabilities.
5
- */
6
-
7
- import type { BuildStatus } from "@alienplatform/core"
8
- import { type Channel, createClient } from "nice-grpc"
9
- import {
10
- type BuildConfig as BuildConfigProto,
11
- type BuildExecution as BuildExecutionProto,
12
- BuildServiceDefinition,
13
- BuildStatus as BuildStatusProto,
14
- ComputeType,
15
- type BuildServiceClient as GeneratedBuildServiceClient,
16
- } from "../generated/build.js"
17
- import { wrapGrpcCall } from "../grpc-utils.js"
18
- import type { BuildExecution, BuildStartConfig } from "../types.js"
19
-
20
- // Map proto status to core BuildStatus (matches Rust: Unspecified → Failed)
21
- const statusMap: Record<number, BuildStatus> = {
22
- [BuildStatusProto.BUILD_STATUS_UNSPECIFIED]: "FAILED",
23
- [BuildStatusProto.BUILD_STATUS_QUEUED]: "QUEUED",
24
- [BuildStatusProto.BUILD_STATUS_RUNNING]: "RUNNING",
25
- [BuildStatusProto.BUILD_STATUS_SUCCEEDED]: "SUCCEEDED",
26
- [BuildStatusProto.BUILD_STATUS_FAILED]: "FAILED",
27
- [BuildStatusProto.BUILD_STATUS_CANCELLED]: "CANCELLED",
28
- [BuildStatusProto.BUILD_STATUS_TIMED_OUT]: "TIMED_OUT",
29
- }
30
-
31
- // Map compute type to proto
32
- const computeTypeMap: Record<string, ComputeType> = {
33
- small: ComputeType.COMPUTE_TYPE_SMALL,
34
- medium: ComputeType.COMPUTE_TYPE_MEDIUM,
35
- large: ComputeType.COMPUTE_TYPE_LARGE,
36
- "x-large": ComputeType.COMPUTE_TYPE_XLARGE,
37
- }
38
-
39
- /**
40
- * Build binding for executing build operations.
41
- *
42
- * @example
43
- * ```typescript
44
- * import { build } from "@alienplatform/bindings"
45
- *
46
- * const builder = build("my-builder")
47
- *
48
- * // Start a build
49
- * const execution = await builder.start({
50
- * script: "npm run build",
51
- * computeType: "medium",
52
- * timeoutSeconds: 600,
53
- * })
54
- *
55
- * // Wait for completion
56
- * const result = await builder.waitForCompletion(execution.id)
57
- * console.log("Build status:", result.status)
58
- * ```
59
- */
60
- export class Build {
61
- private readonly client: GeneratedBuildServiceClient
62
- private readonly bindingName: string
63
-
64
- constructor(channel: Channel, bindingName: string) {
65
- this.client = createClient(BuildServiceDefinition, channel)
66
- this.bindingName = bindingName
67
- }
68
-
69
- /**
70
- * Start a new build.
71
- *
72
- * @param config - Build configuration
73
- * @returns Build execution information
74
- */
75
- async start(config: BuildStartConfig): Promise<BuildExecution> {
76
- const protoConfig = this.toProtoConfig(config)
77
-
78
- return await wrapGrpcCall(
79
- "BuildService",
80
- "StartBuild",
81
- async () => {
82
- const response = await this.client.startBuild({
83
- bindingName: this.bindingName,
84
- config: protoConfig,
85
- })
86
- return this.fromProtoExecution(response.execution!)
87
- },
88
- { bindingName: this.bindingName },
89
- )
90
- }
91
-
92
- /**
93
- * Get the status of a build.
94
- *
95
- * @param buildId - Build execution ID
96
- * @returns Build execution information
97
- */
98
- async getStatus(buildId: string): Promise<BuildExecution> {
99
- return await wrapGrpcCall(
100
- "BuildService",
101
- "GetBuildStatus",
102
- async () => {
103
- const response = await this.client.getBuildStatus({
104
- bindingName: this.bindingName,
105
- buildId,
106
- })
107
- return this.fromProtoExecution(response.execution!)
108
- },
109
- { bindingName: this.bindingName },
110
- )
111
- }
112
-
113
- /**
114
- * Stop a running build.
115
- *
116
- * @param buildId - Build execution ID
117
- */
118
- async stop(buildId: string): Promise<void> {
119
- await wrapGrpcCall(
120
- "BuildService",
121
- "StopBuild",
122
- async () => {
123
- await this.client.stopBuild({
124
- bindingName: this.bindingName,
125
- buildId,
126
- })
127
- },
128
- { bindingName: this.bindingName },
129
- )
130
- }
131
-
132
- /**
133
- * Wait for a build to complete.
134
- *
135
- * @param buildId - Build execution ID
136
- * @param options - Polling options
137
- * @returns Final build execution information
138
- */
139
- async waitForCompletion(
140
- buildId: string,
141
- options?: { pollIntervalMs?: number; timeoutMs?: number },
142
- ): Promise<BuildExecution> {
143
- const pollInterval = options?.pollIntervalMs ?? 5000
144
- const timeout = options?.timeoutMs ?? 30 * 60 * 1000 // 30 minutes default
145
- const startTime = Date.now()
146
-
147
- while (Date.now() - startTime < timeout) {
148
- const execution = await this.getStatus(buildId)
149
-
150
- if (
151
- execution.status === "SUCCEEDED" ||
152
- execution.status === "FAILED" ||
153
- execution.status === "CANCELLED" ||
154
- execution.status === "TIMED_OUT"
155
- ) {
156
- return execution
157
- }
158
-
159
- await new Promise(resolve => setTimeout(resolve, pollInterval))
160
- }
161
-
162
- throw new Error(`Build ${buildId} did not complete within timeout`)
163
- }
164
-
165
- // Private helpers
166
-
167
- private toProtoConfig(config: BuildStartConfig): BuildConfigProto {
168
- return {
169
- script: config.script,
170
- environment: config.environment ?? {},
171
- computeType: config.computeType
172
- ? (computeTypeMap[config.computeType] ?? ComputeType.COMPUTE_TYPE_UNSPECIFIED)
173
- : ComputeType.COMPUTE_TYPE_UNSPECIFIED,
174
- timeoutSeconds: config.timeoutSeconds,
175
- monitoring: config.monitoring
176
- ? {
177
- endpoint: config.monitoring.endpoint,
178
- headers: config.monitoring.headers ?? {},
179
- logsUri: config.monitoring.logsUri ?? "/v1/logs",
180
- tlsEnabled: config.monitoring.tlsEnabled ?? true,
181
- tlsVerify: config.monitoring.tlsVerify ?? true,
182
- }
183
- : undefined,
184
- }
185
- }
186
-
187
- private fromProtoExecution(proto: BuildExecutionProto): BuildExecution {
188
- return {
189
- id: proto.id,
190
- status: statusMap[proto.status] ?? "QUEUED",
191
- startTime: proto.startTime ? new Date(proto.startTime) : undefined,
192
- endTime: proto.endTime ? new Date(proto.endTime) : undefined,
193
- }
194
- }
195
- }