@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.
- package/LICENSE.md +105 -0
- package/README.md +59 -0
- package/dist/errors.d.ts +56 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/factories.d.ts +26 -0
- package/dist/factories.d.ts.map +1 -0
- package/dist/index.d.ts +19 -1768
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -44772
- package/dist/loader.d.ts +171 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +3712 -0
- package/dist/native.d.ts +41 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +46 -0
- package/dist/types.d.ts +150 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +39 -21
- package/AGENTS.md +0 -70
- package/dist/index.js.map +0 -1
- package/scripts/generate-proto.sh +0 -46
- package/src/bindings/AGENTS.md +0 -105
- package/src/bindings/artifact-registry.ts +0 -314
- package/src/bindings/build.ts +0 -195
- package/src/bindings/function.ts +0 -164
- package/src/bindings/index.ts +0 -12
- package/src/bindings/kv.ts +0 -240
- package/src/bindings/queue.ts +0 -191
- package/src/bindings/service-account.ts +0 -113
- package/src/bindings/storage.ts +0 -535
- package/src/bindings/vault.ts +0 -133
- package/src/channel.ts +0 -94
- package/src/commands.ts +0 -76
- package/src/context.ts +0 -368
- package/src/errors.ts +0 -259
- package/src/events.ts +0 -463
- package/src/generated/artifact_registry.ts +0 -1934
- package/src/generated/build.ts +0 -1263
- package/src/generated/container.ts +0 -485
- package/src/generated/control.ts +0 -1574
- package/src/generated/function.ts +0 -741
- package/src/generated/google/protobuf/duration.ts +0 -196
- package/src/generated/google/protobuf/timestamp.ts +0 -225
- package/src/generated/kv.ts +0 -1137
- package/src/generated/queue.ts +0 -729
- package/src/generated/service_account.ts +0 -766
- package/src/generated/storage.ts +0 -3653
- package/src/generated/vault.ts +0 -519
- package/src/generated/wait_until.ts +0 -781
- package/src/global.ts +0 -316
- package/src/grpc-utils.ts +0 -159
- package/src/index.ts +0 -156
- package/src/types.ts +0 -384
- package/src/wait-until.ts +0 -257
- package/tsconfig.json +0 -8
- package/tsdown.config.ts +0 -14
package/src/channel.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* gRPC channel management for the Alien bindings SDK.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { AlienError } from "@alienplatform/core"
|
|
6
|
-
import { type Channel, createChannel } from "nice-grpc"
|
|
7
|
-
import { GrpcConnectionError, MissingEnvVarError } from "./errors.js"
|
|
8
|
-
|
|
9
|
-
/** Environment variable containing the gRPC endpoint */
|
|
10
|
-
const GRPC_ENDPOINT_VAR = "ALIEN_BINDINGS_GRPC_ADDRESS"
|
|
11
|
-
|
|
12
|
-
/** Cached channels by address */
|
|
13
|
-
const channelCache = new Map<string, Channel>()
|
|
14
|
-
|
|
15
|
-
/** Re-export the Channel type */
|
|
16
|
-
export type GrpcChannel = Channel
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Get the gRPC endpoint from environment variables.
|
|
20
|
-
*/
|
|
21
|
-
export function getGrpcEndpoint(): string {
|
|
22
|
-
const endpoint = process.env[GRPC_ENDPOINT_VAR]
|
|
23
|
-
if (!endpoint) {
|
|
24
|
-
throw new AlienError(
|
|
25
|
-
MissingEnvVarError.create({
|
|
26
|
-
variable: GRPC_ENDPOINT_VAR,
|
|
27
|
-
description:
|
|
28
|
-
"This variable is set by alien-runtime when running inside the Alien environment.",
|
|
29
|
-
}),
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
return endpoint
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Create a gRPC channel to the specified address.
|
|
37
|
-
*
|
|
38
|
-
* @param address - The gRPC server address
|
|
39
|
-
* @returns The created channel
|
|
40
|
-
*/
|
|
41
|
-
export async function createGrpcChannel(address: string): Promise<Channel> {
|
|
42
|
-
try {
|
|
43
|
-
return createChannel(address)
|
|
44
|
-
} catch (error) {
|
|
45
|
-
throw (await AlienError.from(error)).withContext(
|
|
46
|
-
GrpcConnectionError.create({
|
|
47
|
-
endpoint: address,
|
|
48
|
-
reason: error instanceof Error ? error.message : String(error),
|
|
49
|
-
}),
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Get or create a cached gRPC channel to the specified address.
|
|
56
|
-
*
|
|
57
|
-
* @param address - The gRPC server address
|
|
58
|
-
* @returns The cached or newly created channel
|
|
59
|
-
*/
|
|
60
|
-
export async function getOrCreateChannel(address: string): Promise<Channel> {
|
|
61
|
-
let channel = channelCache.get(address)
|
|
62
|
-
if (!channel) {
|
|
63
|
-
channel = await createGrpcChannel(address)
|
|
64
|
-
channelCache.set(address, channel)
|
|
65
|
-
}
|
|
66
|
-
return channel
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Get a gRPC channel to the alien-runtime using the default env var.
|
|
71
|
-
* The channel is cached for reuse across all bindings.
|
|
72
|
-
*/
|
|
73
|
-
export async function getChannel(): Promise<Channel> {
|
|
74
|
-
const endpoint = getGrpcEndpoint()
|
|
75
|
-
return await getOrCreateChannel(endpoint)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Close all cached gRPC channels.
|
|
80
|
-
* This should be called when shutting down the application.
|
|
81
|
-
*/
|
|
82
|
-
export function closeChannel(): void {
|
|
83
|
-
for (const channel of channelCache.values()) {
|
|
84
|
-
channel.close()
|
|
85
|
-
}
|
|
86
|
-
channelCache.clear()
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Reset the cached channels (useful for testing).
|
|
91
|
-
*/
|
|
92
|
-
export function resetChannel(): void {
|
|
93
|
-
channelCache.clear()
|
|
94
|
-
}
|
package/src/commands.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Command handling for Alien bindings.
|
|
3
|
-
*
|
|
4
|
-
* Provides ARC command registration and execution.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Command definition.
|
|
9
|
-
*/
|
|
10
|
-
export interface CommandDefinition {
|
|
11
|
-
/** Command name */
|
|
12
|
-
name: string
|
|
13
|
-
/** Handler function that receives params and returns a result */
|
|
14
|
-
handler: (params: unknown) => Promise<unknown>
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Internal storage for commands
|
|
18
|
-
const commands: Map<string, CommandDefinition> = new Map()
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Register an ARC command.
|
|
22
|
-
*
|
|
23
|
-
* @param name - Command name
|
|
24
|
-
* @param handler - Command handler function that receives params and returns a result
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```typescript
|
|
28
|
-
* import { command } from "@alienplatform/bindings"
|
|
29
|
-
*
|
|
30
|
-
* command("echo", async ({ message }: { message: string }) => {
|
|
31
|
-
* return {
|
|
32
|
-
* message,
|
|
33
|
-
* timestamp: new Date().toISOString(),
|
|
34
|
-
* }
|
|
35
|
-
* })
|
|
36
|
-
*
|
|
37
|
-
* command("process-data", async ({ data }: { data: string[] }) => {
|
|
38
|
-
* const result = await processData(data)
|
|
39
|
-
* return { processed: result.length }
|
|
40
|
-
* })
|
|
41
|
-
* ```
|
|
42
|
-
*/
|
|
43
|
-
export function command<TParams = unknown, TResult = unknown>(
|
|
44
|
-
name: string,
|
|
45
|
-
handler: (params: TParams) => Promise<TResult>,
|
|
46
|
-
): void {
|
|
47
|
-
commands.set(name, { name, handler: handler as (params: unknown) => Promise<unknown> })
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Get all registered commands.
|
|
52
|
-
*
|
|
53
|
-
* @internal
|
|
54
|
-
*/
|
|
55
|
-
export function getCommands(): Map<string, CommandDefinition> {
|
|
56
|
-
return commands
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Execute an ARC command by name.
|
|
61
|
-
*
|
|
62
|
-
* @param name - Command name to execute
|
|
63
|
-
* @param params - Command parameters
|
|
64
|
-
* @returns Command result
|
|
65
|
-
*
|
|
66
|
-
* @internal
|
|
67
|
-
*/
|
|
68
|
-
export async function runCommand(name: string, params: unknown): Promise<unknown> {
|
|
69
|
-
const cmd = commands.get(name)
|
|
70
|
-
|
|
71
|
-
if (!cmd) {
|
|
72
|
-
throw new Error(`Unknown command: ${name}. Available: ${[...commands.keys()].join(", ")}`)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return await cmd.handler(params)
|
|
76
|
-
}
|
package/src/context.ts
DELETED
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AlienContext - Main entry point for Alien bindings.
|
|
3
|
-
*
|
|
4
|
-
* Provides access to all bindings and control plane functionality.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { StorageEvent } from "@alienplatform/core"
|
|
8
|
-
import { AlienError } from "@alienplatform/core"
|
|
9
|
-
import type { Channel } from "nice-grpc"
|
|
10
|
-
import { createClient } from "nice-grpc"
|
|
11
|
-
import { ArtifactRegistry } from "./bindings/artifact-registry.js"
|
|
12
|
-
import { Build } from "./bindings/build.js"
|
|
13
|
-
import { FunctionBinding } from "./bindings/function.js"
|
|
14
|
-
import { Kv } from "./bindings/kv.js"
|
|
15
|
-
import { Queue } from "./bindings/queue.js"
|
|
16
|
-
import { ServiceAccount } from "./bindings/service-account.js"
|
|
17
|
-
import { Storage } from "./bindings/storage.js"
|
|
18
|
-
import { Vault } from "./bindings/vault.js"
|
|
19
|
-
import { createGrpcChannel, getOrCreateChannel } from "./channel.js"
|
|
20
|
-
import { command } from "./commands.js"
|
|
21
|
-
import { InvalidBindingConfigError } from "./errors.js"
|
|
22
|
-
import {
|
|
23
|
-
type CronEvent,
|
|
24
|
-
EventLoop,
|
|
25
|
-
type QueueMessageEvent,
|
|
26
|
-
onCronEvent,
|
|
27
|
-
onQueueMessage,
|
|
28
|
-
onStorageEvent,
|
|
29
|
-
} from "./events.js"
|
|
30
|
-
import { ControlServiceDefinition } from "./generated/control.js"
|
|
31
|
-
import { wrapGrpcCall } from "./grpc-utils.js"
|
|
32
|
-
import type { AlienBindingsConfig, AlienBindingsProvider } from "./types.js"
|
|
33
|
-
import { type WaitUntilManager, initWaitUntilManager, waitUntil } from "./wait-until.js"
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Instance ID for this function instance.
|
|
37
|
-
*/
|
|
38
|
-
function generateInstanceId(): string {
|
|
39
|
-
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* AlienContext provides the main entry point for accessing Alien bindings
|
|
44
|
-
* and control plane functionality.
|
|
45
|
-
*
|
|
46
|
-
* @example
|
|
47
|
-
* ```typescript
|
|
48
|
-
* import { AlienContext } from "@alienplatform/bindings"
|
|
49
|
-
*
|
|
50
|
-
* // Create context from environment
|
|
51
|
-
* const ctx = AlienContext.fromEnv()
|
|
52
|
-
*
|
|
53
|
-
* // Access bindings
|
|
54
|
-
* const bucket = ctx.storage("my-bucket")
|
|
55
|
-
* await bucket.put("hello.txt", "Hello, World!")
|
|
56
|
-
*
|
|
57
|
-
* // Register event handlers
|
|
58
|
-
* ctx.onStorageEvent("uploads", async (event) => {
|
|
59
|
-
* console.log("File uploaded:", event.key)
|
|
60
|
-
* })
|
|
61
|
-
*
|
|
62
|
-
* // Start the runtime
|
|
63
|
-
* await ctx.run()
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
export class AlienContext implements AlienBindingsProvider {
|
|
67
|
-
private readonly channel: Channel
|
|
68
|
-
private readonly instanceId: string
|
|
69
|
-
private readonly bindingCache = new Map<string, unknown>()
|
|
70
|
-
private eventLoop: EventLoop | undefined
|
|
71
|
-
private waitUntilManager: WaitUntilManager | undefined
|
|
72
|
-
|
|
73
|
-
private constructor(channel: Channel, instanceId?: string) {
|
|
74
|
-
this.channel = channel
|
|
75
|
-
this.instanceId = instanceId ?? generateInstanceId()
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Create a context from environment variables.
|
|
80
|
-
*
|
|
81
|
-
* Reads the ALIEN_BINDINGS_GRPC_ADDRESS environment variable.
|
|
82
|
-
*/
|
|
83
|
-
static async fromEnv(): Promise<AlienContext> {
|
|
84
|
-
const address = process.env.ALIEN_BINDINGS_GRPC_ADDRESS
|
|
85
|
-
|
|
86
|
-
if (!address) {
|
|
87
|
-
throw new AlienError(
|
|
88
|
-
InvalidBindingConfigError.create({
|
|
89
|
-
message: "ALIEN_BINDINGS_GRPC_ADDRESS environment variable is not set",
|
|
90
|
-
suggestion:
|
|
91
|
-
"Make sure you're running inside an Alien function or set the variable manually",
|
|
92
|
-
}),
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const channel = await getOrCreateChannel(address)
|
|
97
|
-
return new AlienContext(channel)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Create a context with explicit configuration.
|
|
102
|
-
*/
|
|
103
|
-
static async create(config: AlienBindingsConfig): Promise<AlienContext> {
|
|
104
|
-
if (!config.grpcAddress) {
|
|
105
|
-
throw new AlienError(
|
|
106
|
-
InvalidBindingConfigError.create({
|
|
107
|
-
message: "gRPC address is required",
|
|
108
|
-
suggestion: "Provide grpcAddress in the config",
|
|
109
|
-
}),
|
|
110
|
-
)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const channel = await createGrpcChannel(config.grpcAddress)
|
|
114
|
-
return new AlienContext(channel)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Create a context for connecting to a remote agent.
|
|
119
|
-
*
|
|
120
|
-
* @param address - gRPC address of the remote agent
|
|
121
|
-
*/
|
|
122
|
-
// TODO: Wtf? this is completely hallucinated :) See 05-bindings.md.
|
|
123
|
-
static async forRemoteAgent(address: string): Promise<AlienContext> {
|
|
124
|
-
const channel = await createGrpcChannel(address)
|
|
125
|
-
return new AlienContext(channel)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Get or create a cached binding instance.
|
|
130
|
-
*/
|
|
131
|
-
private getBinding<T>(key: string, factory: () => T): T {
|
|
132
|
-
let binding = this.bindingCache.get(key) as T | undefined
|
|
133
|
-
if (!binding) {
|
|
134
|
-
binding = factory()
|
|
135
|
-
this.bindingCache.set(key, binding)
|
|
136
|
-
}
|
|
137
|
-
return binding
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// ============================================================================
|
|
141
|
-
// Binding Accessors
|
|
142
|
-
// ============================================================================
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Get a storage binding.
|
|
146
|
-
*
|
|
147
|
-
* @param name - Binding name
|
|
148
|
-
* @returns Storage binding instance
|
|
149
|
-
*/
|
|
150
|
-
storage(name: string): Storage {
|
|
151
|
-
return this.getBinding(`storage:${name}`, () => new Storage(this.channel, name))
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Get a KV binding.
|
|
156
|
-
*
|
|
157
|
-
* @param name - Binding name
|
|
158
|
-
* @returns KV binding instance
|
|
159
|
-
*/
|
|
160
|
-
kv(name: string): Kv {
|
|
161
|
-
return this.getBinding(`kv:${name}`, () => new Kv(this.channel, name))
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Get a queue binding.
|
|
166
|
-
*
|
|
167
|
-
* @param name - Binding name
|
|
168
|
-
* @returns Queue binding instance
|
|
169
|
-
*/
|
|
170
|
-
queue(name: string): Queue {
|
|
171
|
-
return this.getBinding(`queue:${name}`, () => new Queue(this.channel, name))
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Get a vault binding.
|
|
176
|
-
*
|
|
177
|
-
* @param name - Binding name
|
|
178
|
-
* @returns Vault binding instance
|
|
179
|
-
*/
|
|
180
|
-
vault(name: string): Vault {
|
|
181
|
-
return this.getBinding(`vault:${name}`, () => new Vault(this.channel, name))
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Get a build binding.
|
|
186
|
-
*
|
|
187
|
-
* @param name - Binding name
|
|
188
|
-
* @returns Build binding instance
|
|
189
|
-
*/
|
|
190
|
-
build(name: string): Build {
|
|
191
|
-
return this.getBinding(`build:${name}`, () => new Build(this.channel, name))
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Get an artifact registry binding.
|
|
196
|
-
*
|
|
197
|
-
* @param name - Binding name
|
|
198
|
-
* @returns ArtifactRegistry binding instance
|
|
199
|
-
*/
|
|
200
|
-
artifactRegistry(name: string): ArtifactRegistry {
|
|
201
|
-
return this.getBinding(
|
|
202
|
-
`artifact-registry:${name}`,
|
|
203
|
-
() => new ArtifactRegistry(this.channel, name),
|
|
204
|
-
)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Get a function binding.
|
|
209
|
-
*
|
|
210
|
-
* @param name - Binding name
|
|
211
|
-
* @returns Function binding instance
|
|
212
|
-
*/
|
|
213
|
-
func(name: string): FunctionBinding {
|
|
214
|
-
return this.getBinding(`function:${name}`, () => new FunctionBinding(this.channel, name))
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Get a service account binding.
|
|
219
|
-
*
|
|
220
|
-
* @param name - Binding name
|
|
221
|
-
* @returns ServiceAccount binding instance
|
|
222
|
-
*/
|
|
223
|
-
serviceAccount(name: string): ServiceAccount {
|
|
224
|
-
return this.getBinding(`service-account:${name}`, () => new ServiceAccount(this.channel, name))
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// ============================================================================
|
|
228
|
-
// Event Handlers
|
|
229
|
-
// ============================================================================
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Register a storage event handler.
|
|
233
|
-
*
|
|
234
|
-
* @param bucket - Bucket name
|
|
235
|
-
* @param handler - Event handler
|
|
236
|
-
* @param options - Handler options
|
|
237
|
-
* @returns Unsubscribe function
|
|
238
|
-
*/
|
|
239
|
-
onStorageEvent(
|
|
240
|
-
bucket: string,
|
|
241
|
-
handler: (event: StorageEvent) => Promise<void>,
|
|
242
|
-
options?: { prefix?: string },
|
|
243
|
-
): () => void {
|
|
244
|
-
return onStorageEvent(bucket, handler, options)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Register a cron event handler.
|
|
249
|
-
*
|
|
250
|
-
* @param schedule - Cron schedule expression
|
|
251
|
-
* @param handler - Event handler
|
|
252
|
-
* @returns Unsubscribe function
|
|
253
|
-
*/
|
|
254
|
-
onCronEvent(schedule: string, handler: (event: CronEvent) => Promise<void>): () => void {
|
|
255
|
-
return onCronEvent(schedule, handler)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Register a queue message handler.
|
|
260
|
-
*
|
|
261
|
-
* @param queueName - Queue name
|
|
262
|
-
* @param handler - Message handler
|
|
263
|
-
* @returns Unsubscribe function
|
|
264
|
-
*/
|
|
265
|
-
onQueueMessage<T = unknown>(
|
|
266
|
-
queueName: string,
|
|
267
|
-
handler: (message: QueueMessageEvent<T>) => Promise<void>,
|
|
268
|
-
): () => void {
|
|
269
|
-
return onQueueMessage(queueName, handler)
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// ============================================================================
|
|
273
|
-
// Commands
|
|
274
|
-
// ============================================================================
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Register an ARC command.
|
|
278
|
-
*
|
|
279
|
-
* @param name - Command name
|
|
280
|
-
* @param handler - Command handler that receives params and returns a result
|
|
281
|
-
*/
|
|
282
|
-
command<TParams = unknown, TResult = unknown>(
|
|
283
|
-
name: string,
|
|
284
|
-
handler: (params: TParams) => Promise<TResult>,
|
|
285
|
-
): void {
|
|
286
|
-
command(name, handler)
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// ============================================================================
|
|
290
|
-
// HTTP Server Registration
|
|
291
|
-
// ============================================================================
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Register an HTTP server with the control plane.
|
|
295
|
-
*
|
|
296
|
-
* @param port - Port the server is listening on
|
|
297
|
-
*/
|
|
298
|
-
async registerHttpServer(port: number): Promise<void> {
|
|
299
|
-
const client = createClient(ControlServiceDefinition, this.channel)
|
|
300
|
-
|
|
301
|
-
await wrapGrpcCall(
|
|
302
|
-
"ControlService",
|
|
303
|
-
"RegisterHttpServer",
|
|
304
|
-
async () => {
|
|
305
|
-
await client.registerHttpServer({ port })
|
|
306
|
-
},
|
|
307
|
-
{},
|
|
308
|
-
)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// ============================================================================
|
|
312
|
-
// WaitUntil
|
|
313
|
-
// ============================================================================
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Register a background task.
|
|
317
|
-
*
|
|
318
|
-
* @param promise - The promise to track
|
|
319
|
-
*/
|
|
320
|
-
waitUntil(promise: Promise<unknown>): void {
|
|
321
|
-
waitUntil(promise)
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// ============================================================================
|
|
325
|
-
// Lifecycle
|
|
326
|
-
// ============================================================================
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Start the Alien runtime.
|
|
330
|
-
*
|
|
331
|
-
* This initializes event handlers, registers with the control plane,
|
|
332
|
-
* and starts processing events.
|
|
333
|
-
*/
|
|
334
|
-
async run(): Promise<void> {
|
|
335
|
-
// Initialize wait-until manager
|
|
336
|
-
this.waitUntilManager = initWaitUntilManager(this.channel, this.instanceId)
|
|
337
|
-
|
|
338
|
-
// Initialize event loop
|
|
339
|
-
this.eventLoop = new EventLoop(this.channel, this.instanceId)
|
|
340
|
-
|
|
341
|
-
// Register event handlers with the control plane
|
|
342
|
-
await this.eventLoop.registerHandlers()
|
|
343
|
-
|
|
344
|
-
// Start event loop (handles ARC commands, events, etc.)
|
|
345
|
-
await this.eventLoop.start()
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Stop the runtime gracefully.
|
|
350
|
-
*/
|
|
351
|
-
async shutdown(): Promise<void> {
|
|
352
|
-
// Stop event loop
|
|
353
|
-
this.eventLoop?.stop()
|
|
354
|
-
|
|
355
|
-
// Wait for all background tasks
|
|
356
|
-
await this.waitUntilManager?.waitForAll()
|
|
357
|
-
|
|
358
|
-
// Notify drain complete
|
|
359
|
-
const tasks = this.waitUntilManager?.getTasks()
|
|
360
|
-
if (tasks) {
|
|
361
|
-
const taskArray = Array.from(tasks.values())
|
|
362
|
-
const tasksDrained = taskArray.length
|
|
363
|
-
const allSuccess = taskArray.every(t => !t.error)
|
|
364
|
-
const errorMessage = taskArray.find(t => t.error)?.error?.message
|
|
365
|
-
await this.waitUntilManager?.notifyDrainComplete(tasksDrained, allSuccess, errorMessage)
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|