@alchemy.run/daytona 0.0.0-stage → 2.0.0-beta.86
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 +201 -0
- package/README.md +80 -2
- package/lib/ApiKey.d.ts +99 -0
- package/lib/ApiKey.d.ts.map +1 -0
- package/lib/ApiKey.js +152 -0
- package/lib/ApiKey.js.map +1 -0
- package/lib/AuthProvider.d.ts +55 -0
- package/lib/AuthProvider.d.ts.map +1 -0
- package/lib/AuthProvider.js +280 -0
- package/lib/AuthProvider.js.map +1 -0
- package/lib/Bootstrap.d.ts +8 -0
- package/lib/Bootstrap.d.ts.map +1 -0
- package/lib/Bootstrap.js +28 -0
- package/lib/Bootstrap.js.map +1 -0
- package/lib/ConnectSandbox.d.ts +72 -0
- package/lib/ConnectSandbox.d.ts.map +1 -0
- package/lib/ConnectSandbox.js +3 -0
- package/lib/ConnectSandbox.js.map +1 -0
- package/lib/ConnectSandboxHttp.d.ts +5 -0
- package/lib/ConnectSandboxHttp.d.ts.map +1 -0
- package/lib/ConnectSandboxHttp.js +22 -0
- package/lib/ConnectSandboxHttp.js.map +1 -0
- package/lib/Contributions.d.ts +7 -0
- package/lib/Contributions.d.ts.map +1 -0
- package/lib/Contributions.js +6 -0
- package/lib/Contributions.js.map +1 -0
- package/lib/CreateSandbox.d.ts +86 -0
- package/lib/CreateSandbox.d.ts.map +1 -0
- package/lib/CreateSandbox.js +3 -0
- package/lib/CreateSandbox.js.map +1 -0
- package/lib/CreateSandboxHttp.d.ts +5 -0
- package/lib/CreateSandboxHttp.d.ts.map +1 -0
- package/lib/CreateSandboxHttp.js +65 -0
- package/lib/CreateSandboxHttp.js.map +1 -0
- package/lib/CreateSecret.d.ts +56 -0
- package/lib/CreateSecret.d.ts.map +1 -0
- package/lib/CreateSecret.js +3 -0
- package/lib/CreateSecret.js.map +1 -0
- package/lib/CreateSecretHttp.d.ts +5 -0
- package/lib/CreateSecretHttp.d.ts.map +1 -0
- package/lib/CreateSecretHttp.js +39 -0
- package/lib/CreateSecretHttp.js.map +1 -0
- package/lib/CreateSnapshot.d.ts +80 -0
- package/lib/CreateSnapshot.d.ts.map +1 -0
- package/lib/CreateSnapshot.js +3 -0
- package/lib/CreateSnapshot.js.map +1 -0
- package/lib/CreateSnapshotHttp.d.ts +5 -0
- package/lib/CreateSnapshotHttp.d.ts.map +1 -0
- package/lib/CreateSnapshotHttp.js +47 -0
- package/lib/CreateSnapshotHttp.js.map +1 -0
- package/lib/CreateVolume.d.ts +81 -0
- package/lib/CreateVolume.d.ts.map +1 -0
- package/lib/CreateVolume.js +10 -0
- package/lib/CreateVolume.js.map +1 -0
- package/lib/CreateVolumeHttp.d.ts +5 -0
- package/lib/CreateVolumeHttp.d.ts.map +1 -0
- package/lib/CreateVolumeHttp.js +31 -0
- package/lib/CreateVolumeHttp.js.map +1 -0
- package/lib/Credentials.d.ts +9 -0
- package/lib/Credentials.d.ts.map +1 -0
- package/lib/Credentials.js +18 -0
- package/lib/Credentials.js.map +1 -0
- package/lib/DaytonaBindings.d.ts +51 -0
- package/lib/DaytonaBindings.d.ts.map +1 -0
- package/lib/DaytonaBindings.js +61 -0
- package/lib/DaytonaBindings.js.map +1 -0
- package/lib/IdentityProvider.d.ts +80 -0
- package/lib/IdentityProvider.d.ts.map +1 -0
- package/lib/IdentityProvider.js +111 -0
- package/lib/IdentityProvider.js.map +1 -0
- package/lib/MountVolume.d.ts +86 -0
- package/lib/MountVolume.d.ts.map +1 -0
- package/lib/MountVolume.js +27 -0
- package/lib/MountVolume.js.map +1 -0
- package/lib/OAuthClient.d.ts +14 -0
- package/lib/OAuthClient.d.ts.map +1 -0
- package/lib/OAuthClient.js +23 -0
- package/lib/OAuthClient.js.map +1 -0
- package/lib/Organization.d.ts +40 -0
- package/lib/Organization.d.ts.map +1 -0
- package/lib/Organization.js +80 -0
- package/lib/Organization.js.map +1 -0
- package/lib/OrganizationInvitation.d.ts +70 -0
- package/lib/OrganizationInvitation.d.ts.map +1 -0
- package/lib/OrganizationInvitation.js +109 -0
- package/lib/OrganizationInvitation.js.map +1 -0
- package/lib/OrganizationMember.d.ts +86 -0
- package/lib/OrganizationMember.d.ts.map +1 -0
- package/lib/OrganizationMember.js +109 -0
- package/lib/OrganizationMember.js.map +1 -0
- package/lib/OrganizationOtelConfig.d.ts +59 -0
- package/lib/OrganizationOtelConfig.d.ts.map +1 -0
- package/lib/OrganizationOtelConfig.js +87 -0
- package/lib/OrganizationOtelConfig.js.map +1 -0
- package/lib/OrganizationRole.d.ts +66 -0
- package/lib/OrganizationRole.d.ts.map +1 -0
- package/lib/OrganizationRole.js +106 -0
- package/lib/OrganizationRole.js.map +1 -0
- package/lib/OrganizationSettings.d.ts +76 -0
- package/lib/OrganizationSettings.d.ts.map +1 -0
- package/lib/OrganizationSettings.js +107 -0
- package/lib/OrganizationSettings.js.map +1 -0
- package/lib/Providers.d.ts +14 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +53 -0
- package/lib/Providers.js.map +1 -0
- package/lib/ReadAuditLogs.d.ts +30 -0
- package/lib/ReadAuditLogs.d.ts.map +1 -0
- package/lib/ReadAuditLogs.js +17 -0
- package/lib/ReadAuditLogs.js.map +1 -0
- package/lib/ReadOrganization.d.ts +39 -0
- package/lib/ReadOrganization.d.ts.map +1 -0
- package/lib/ReadOrganization.js +39 -0
- package/lib/ReadOrganization.js.map +1 -0
- package/lib/ReadUsage.d.ts +31 -0
- package/lib/ReadUsage.d.ts.map +1 -0
- package/lib/ReadUsage.js +17 -0
- package/lib/ReadUsage.js.map +1 -0
- package/lib/Region.d.ts +78 -0
- package/lib/Region.d.ts.map +1 -0
- package/lib/Region.js +169 -0
- package/lib/Region.js.map +1 -0
- package/lib/Registry.d.ts +84 -0
- package/lib/Registry.d.ts.map +1 -0
- package/lib/Registry.js +97 -0
- package/lib/Registry.js.map +1 -0
- package/lib/Runner.d.ts +66 -0
- package/lib/Runner.d.ts.map +1 -0
- package/lib/Runner.js +116 -0
- package/lib/Runner.js.map +1 -0
- package/lib/Sandbox.d.ts +376 -0
- package/lib/Sandbox.d.ts.map +1 -0
- package/lib/Sandbox.js +565 -0
- package/lib/Sandbox.js.map +1 -0
- package/lib/SandboxClient.d.ts +258 -0
- package/lib/SandboxClient.d.ts.map +1 -0
- package/lib/SandboxClient.js +233 -0
- package/lib/SandboxClient.js.map +1 -0
- package/lib/Secret.d.ts +93 -0
- package/lib/Secret.d.ts.map +1 -0
- package/lib/Secret.js +130 -0
- package/lib/Secret.js.map +1 -0
- package/lib/Snapshot.d.ts +327 -0
- package/lib/Snapshot.d.ts.map +1 -0
- package/lib/Snapshot.js +447 -0
- package/lib/Snapshot.js.map +1 -0
- package/lib/Volume.d.ts +99 -0
- package/lib/Volume.d.ts.map +1 -0
- package/lib/Volume.js +152 -0
- package/lib/Volume.js.map +1 -0
- package/lib/WarmPool.d.ts +61 -0
- package/lib/WarmPool.d.ts.map +1 -0
- package/lib/WarmPool.js +81 -0
- package/lib/WarmPool.js.map +1 -0
- package/lib/Webhooks.d.ts +58 -0
- package/lib/Webhooks.d.ts.map +1 -0
- package/lib/Webhooks.js +75 -0
- package/lib/Webhooks.js.map +1 -0
- package/lib/index.d.ts +37 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +36 -0
- package/lib/index.js.map +1 -0
- package/lib/internal/BuildContext.d.ts +16 -0
- package/lib/internal/BuildContext.d.ts.map +1 -0
- package/lib/internal/BuildContext.js +50 -0
- package/lib/internal/BuildContext.js.map +1 -0
- package/lib/internal/Declared.d.ts +29 -0
- package/lib/internal/Declared.d.ts.map +1 -0
- package/lib/internal/Declared.js +31 -0
- package/lib/internal/Declared.js.map +1 -0
- package/lib/internal/Derived.d.ts +40 -0
- package/lib/internal/Derived.d.ts.map +1 -0
- package/lib/internal/Derived.js +64 -0
- package/lib/internal/Derived.js.map +1 -0
- package/lib/internal/Errors.d.ts +4 -0
- package/lib/internal/Errors.d.ts.map +1 -0
- package/lib/internal/Errors.js +1 -0
- package/lib/internal/Errors.js.map +1 -0
- package/lib/internal/Labels.d.ts +20 -0
- package/lib/internal/Labels.d.ts.map +1 -0
- package/lib/internal/Labels.js +22 -0
- package/lib/internal/Labels.js.map +1 -0
- package/lib/internal/Names.d.ts +18 -0
- package/lib/internal/Names.d.ts.map +1 -0
- package/lib/internal/Names.js +25 -0
- package/lib/internal/Names.js.map +1 -0
- package/lib/internal/Organization.d.ts +27 -0
- package/lib/internal/Organization.d.ts.map +1 -0
- package/lib/internal/Organization.js +32 -0
- package/lib/internal/Organization.js.map +1 -0
- package/lib/internal/Process.d.ts +14 -0
- package/lib/internal/Process.d.ts.map +1 -0
- package/lib/internal/Process.js +15 -0
- package/lib/internal/Process.js.map +1 -0
- package/lib/internal/Program.d.ts +83 -0
- package/lib/internal/Program.d.ts.map +1 -0
- package/lib/internal/Program.js +169 -0
- package/lib/internal/Program.js.map +1 -0
- package/lib/internal/Ref.d.ts +14 -0
- package/lib/internal/Ref.d.ts.map +1 -0
- package/lib/internal/Ref.js +7 -0
- package/lib/internal/Ref.js.map +1 -0
- package/lib/internal/Scoped.d.ts +31 -0
- package/lib/internal/Scoped.d.ts.map +1 -0
- package/lib/internal/Scoped.js +48 -0
- package/lib/internal/Scoped.js.map +1 -0
- package/lib/internal/Tar.d.ts +13 -0
- package/lib/internal/Tar.d.ts.map +1 -0
- package/lib/internal/Tar.js +62 -0
- package/lib/internal/Tar.js.map +1 -0
- package/lib/internal/Toolbox.d.ts +11 -0
- package/lib/internal/Toolbox.d.ts.map +1 -0
- package/lib/internal/Toolbox.js +20 -0
- package/lib/internal/Toolbox.js.map +1 -0
- package/lib/internal/Wait.d.ts +49 -0
- package/lib/internal/Wait.d.ts.map +1 -0
- package/lib/internal/Wait.js +57 -0
- package/lib/internal/Wait.js.map +1 -0
- package/package.json +79 -3
- package/src/ApiKey.ts +221 -0
- package/src/AuthProvider.ts +406 -0
- package/src/Bootstrap.ts +55 -0
- package/src/ConnectSandbox.ts +76 -0
- package/src/ConnectSandboxHttp.ts +26 -0
- package/src/Contributions.ts +9 -0
- package/src/CreateSandbox.ts +107 -0
- package/src/CreateSandboxHttp.ts +97 -0
- package/src/CreateSecret.ts +73 -0
- package/src/CreateSecretHttp.ts +58 -0
- package/src/CreateSnapshot.ts +133 -0
- package/src/CreateSnapshotHttp.ts +77 -0
- package/src/CreateVolume.ts +104 -0
- package/src/CreateVolumeHttp.ts +50 -0
- package/src/Credentials.ts +37 -0
- package/src/DaytonaBindings.ts +111 -0
- package/src/IdentityProvider.ts +181 -0
- package/src/MountVolume.ts +122 -0
- package/src/OAuthClient.ts +27 -0
- package/src/Organization.ts +121 -0
- package/src/OrganizationInvitation.ts +174 -0
- package/src/OrganizationMember.ts +174 -0
- package/src/OrganizationOtelConfig.ts +138 -0
- package/src/OrganizationRole.ts +167 -0
- package/src/OrganizationSettings.ts +187 -0
- package/src/Providers.ts +93 -0
- package/src/ReadAuditLogs.ts +50 -0
- package/src/ReadOrganization.ts +83 -0
- package/src/ReadUsage.ts +51 -0
- package/src/Region.ts +226 -0
- package/src/Registry.ts +164 -0
- package/src/Runner.ts +166 -0
- package/src/Sandbox.ts +927 -0
- package/src/SandboxClient.ts +625 -0
- package/src/Secret.ts +203 -0
- package/src/Snapshot.ts +685 -0
- package/src/Volume.ts +229 -0
- package/src/WarmPool.ts +128 -0
- package/src/Webhooks.ts +121 -0
- package/src/globals.d.ts +2 -0
- package/src/index.ts +46 -0
- package/src/internal/BuildContext.ts +62 -0
- package/src/internal/Declared.ts +80 -0
- package/src/internal/Derived.ts +97 -0
- package/src/internal/Errors.ts +4 -0
- package/src/internal/Labels.ts +39 -0
- package/src/internal/Names.ts +37 -0
- package/src/internal/Organization.ts +40 -0
- package/src/internal/Process.ts +25 -0
- package/src/internal/Program.ts +239 -0
- package/src/internal/Ref.ts +15 -0
- package/src/internal/Scoped.ts +102 -0
- package/src/internal/Tar.ts +72 -0
- package/src/internal/Toolbox.ts +27 -0
- package/src/internal/Wait.ts +105 -0
package/src/Registry.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import * as registries from "@distilled.cloud/daytona/docker_registry";
|
|
2
|
+
import { Unowned } from "alchemy/AdoptPolicy";
|
|
3
|
+
import * as Provider from "alchemy/Provider";
|
|
4
|
+
import { Resource } from "alchemy/Resource";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import type * as Redacted from "effect/Redacted";
|
|
7
|
+
import { isOwnedName, resolveName } from "./internal/Names.ts";
|
|
8
|
+
import type { Providers } from "./Providers.ts";
|
|
9
|
+
|
|
10
|
+
export interface RegistryProps {
|
|
11
|
+
/**
|
|
12
|
+
* Registry name in Daytona. If omitted, a unique name is generated from
|
|
13
|
+
* the stack, stage and logical ID.
|
|
14
|
+
*/
|
|
15
|
+
name?: string;
|
|
16
|
+
/** Registry host, e.g. `ghcr.io`, `docker.io` or an ECR host. */
|
|
17
|
+
url: string;
|
|
18
|
+
/** User name for the registry. */
|
|
19
|
+
username: string;
|
|
20
|
+
/** Password or access token for the registry. Updated in place. */
|
|
21
|
+
password: string | Redacted.Redacted<string>;
|
|
22
|
+
/** Project or namespace within the registry, if it has them. */
|
|
23
|
+
project?: string;
|
|
24
|
+
/** IAM role Daytona assumes for mTLS to the registry (ECR). */
|
|
25
|
+
mtlsRoleArn?: string;
|
|
26
|
+
/** Secrets Manager ARN holding the mTLS client certificate. */
|
|
27
|
+
mtlsSecretArn?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface RegistryAttributes {
|
|
31
|
+
/** Registry ID. */
|
|
32
|
+
registryId: string;
|
|
33
|
+
/** Registry name. */
|
|
34
|
+
name: string;
|
|
35
|
+
/** Registry host. */
|
|
36
|
+
url: string;
|
|
37
|
+
/** User name. */
|
|
38
|
+
username: string;
|
|
39
|
+
/** Project or namespace. */
|
|
40
|
+
project: string;
|
|
41
|
+
/** `organization`, `internal`, … */
|
|
42
|
+
registryType: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type Registry = Resource<
|
|
46
|
+
"Daytona.Registry",
|
|
47
|
+
RegistryProps,
|
|
48
|
+
RegistryAttributes,
|
|
49
|
+
never,
|
|
50
|
+
Providers,
|
|
51
|
+
RegistryLookup
|
|
52
|
+
>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Props for {@link Registry.lookup}: find a container registry this
|
|
56
|
+
* stack doesn't manage by its name.
|
|
57
|
+
*/
|
|
58
|
+
export interface RegistryLookup {
|
|
59
|
+
/** Registry name. */
|
|
60
|
+
name: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Credentials for a private container registry, so Daytona can pull
|
|
65
|
+
* private images into a {@link Snapshot}. Daytona picks the registry whose
|
|
66
|
+
* `url` matches the image's host.
|
|
67
|
+
* @see https://www.daytona.io/docs/en/snapshots/#images-from-private-registries
|
|
68
|
+
*
|
|
69
|
+
* ### Pulling a Private Image
|
|
70
|
+
* **Example:** GitHub Container Registry
|
|
71
|
+
* ```typescript
|
|
72
|
+
* export const Ghcr = Daytona.Registry("Ghcr", {
|
|
73
|
+
* url: "ghcr.io",
|
|
74
|
+
* username: "alchemy-run",
|
|
75
|
+
* password: Config.Redacted("GHCR_TOKEN"),
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* export const Base = Daytona.Snapshot("Base", {
|
|
79
|
+
* image: "ghcr.io/alchemy-run/base:1.0.0",
|
|
80
|
+
* registry: Ghcr,
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* ### Looking up an existing registry
|
|
85
|
+
* `Registry.lookup` references a registry Alchemy doesn't manage (created in
|
|
86
|
+
* the Daytona dashboard or by another stack). It is read during plan/deploy,
|
|
87
|
+
* never created, updated or deleted.
|
|
88
|
+
*
|
|
89
|
+
* **Example:** Reference an existing registry
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const ghcr = Daytona.Registry.lookup({ name: "ghcr" });
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @resource
|
|
95
|
+
* @product Registry
|
|
96
|
+
*/
|
|
97
|
+
export const Registry = Resource<Registry>("Daytona.Registry");
|
|
98
|
+
|
|
99
|
+
const toAttributes = (r: registries.DockerRegistry2): RegistryAttributes => ({
|
|
100
|
+
registryId: r.id,
|
|
101
|
+
name: r.name,
|
|
102
|
+
url: r.url,
|
|
103
|
+
username: r.username,
|
|
104
|
+
project: r.project,
|
|
105
|
+
registryType: r.registryType,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const getById = (id: string) =>
|
|
109
|
+
registries.getRegistry({ id }).pipe(Effect.catchTag("RegistryNotFound", () => Effect.undefined));
|
|
110
|
+
|
|
111
|
+
const findByName = (name: string) =>
|
|
112
|
+
registries.listRegistries({}).pipe(Effect.map((all) => all.find((r) => r.name === name)));
|
|
113
|
+
|
|
114
|
+
export const RegistryProvider = () =>
|
|
115
|
+
Provider.effect(
|
|
116
|
+
Registry,
|
|
117
|
+
Effect.succeed({
|
|
118
|
+
stables: ["registryId"],
|
|
119
|
+
list: Effect.fn(function* () {
|
|
120
|
+
const all = yield* registries.listRegistries({});
|
|
121
|
+
return all.filter((r) => r.registryType === "organization").map(toAttributes);
|
|
122
|
+
}),
|
|
123
|
+
lookup: Effect.fn(function* ({ name }) {
|
|
124
|
+
const found = yield* findByName(name);
|
|
125
|
+
return found === undefined ? undefined : toAttributes(found);
|
|
126
|
+
}),
|
|
127
|
+
|
|
128
|
+
read: Effect.fn(function* ({ id, olds, output }) {
|
|
129
|
+
const name = yield* resolveName(id, olds?.name, output?.name);
|
|
130
|
+
const found =
|
|
131
|
+
(output ? yield* getById(output.registryId) : undefined) ?? (yield* findByName(name));
|
|
132
|
+
if (found === undefined) return undefined;
|
|
133
|
+
const attrs = toAttributes(found);
|
|
134
|
+
return (yield* isOwnedName(id, found.name, output !== undefined)) ? attrs : Unowned(attrs);
|
|
135
|
+
}),
|
|
136
|
+
reconcile: Effect.fn(function* ({ id, news, output }) {
|
|
137
|
+
const name = yield* resolveName(id, news.name, output?.name);
|
|
138
|
+
// Observe
|
|
139
|
+
const current =
|
|
140
|
+
(output ? yield* getById(output.registryId) : undefined) ?? (yield* findByName(name));
|
|
141
|
+
const desired = {
|
|
142
|
+
name,
|
|
143
|
+
url: news.url,
|
|
144
|
+
username: news.username,
|
|
145
|
+
password: news.password,
|
|
146
|
+
project: news.project,
|
|
147
|
+
mtlsRoleArn: news.mtlsRoleArn ?? null,
|
|
148
|
+
mtlsSecretArn: news.mtlsSecretArn ?? null,
|
|
149
|
+
};
|
|
150
|
+
// Ensure
|
|
151
|
+
if (current === undefined) {
|
|
152
|
+
return toAttributes(yield* registries.createRegistry(desired));
|
|
153
|
+
}
|
|
154
|
+
// Sync — the password can't be read back, so every reconcile
|
|
155
|
+
// writes the full registry (updateRegistry is a PATCH of all fields).
|
|
156
|
+
return toAttributes(yield* registries.updateRegistry({ id: current.id, ...desired }));
|
|
157
|
+
}),
|
|
158
|
+
delete: Effect.fn(function* ({ output }) {
|
|
159
|
+
yield* registries
|
|
160
|
+
.deleteRegistry({ id: output.registryId })
|
|
161
|
+
.pipe(Effect.catchTag("RegistryNotFound", () => Effect.void));
|
|
162
|
+
}),
|
|
163
|
+
}),
|
|
164
|
+
);
|
package/src/Runner.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import * as runners from "@distilled.cloud/daytona/runners";
|
|
2
|
+
import { Unowned } from "alchemy/AdoptPolicy";
|
|
3
|
+
import { deepEqual, isResolved } from "alchemy/Diff";
|
|
4
|
+
import * as Provider from "alchemy/Provider";
|
|
5
|
+
import { Resource } from "alchemy/Resource";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Redacted from "effect/Redacted";
|
|
8
|
+
import { declarable } from "./internal/Declared.ts";
|
|
9
|
+
import { isOwnedName, resolveName } from "./internal/Names.ts";
|
|
10
|
+
import { resolved, type Ref } from "./internal/Ref.ts";
|
|
11
|
+
import type { Providers } from "./Providers.ts";
|
|
12
|
+
|
|
13
|
+
/** A region, by id. Accepts a `Daytona.Region` or `{ regionId }`. */
|
|
14
|
+
export type RunnerRegion = { readonly regionId: string };
|
|
15
|
+
|
|
16
|
+
export interface RunnerProps {
|
|
17
|
+
/** Runner name. If omitted, generated from the stack, stage and logical ID. Changing it replaces the runner. */
|
|
18
|
+
name?: string;
|
|
19
|
+
/** Region the runner serves. Changing it replaces the runner. */
|
|
20
|
+
region: Ref<RunnerRegion>;
|
|
21
|
+
/** Tags the scheduler matches sandboxes against. Changing them replaces the runner. */
|
|
22
|
+
tags?: string[];
|
|
23
|
+
/** Sandbox class the runner hosts. Changing it replaces the runner. */
|
|
24
|
+
sandboxClass?: runners.CreateRunnerSandboxClass;
|
|
25
|
+
/** Stop scheduling new sandboxes on it. Updated in place. @default false */
|
|
26
|
+
unschedulable?: boolean;
|
|
27
|
+
/** Drain it: no new sandboxes, and existing ones move off. Updated in place. @default false */
|
|
28
|
+
draining?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface RunnerAttributes {
|
|
32
|
+
/** Runner ID. */
|
|
33
|
+
runnerId: string;
|
|
34
|
+
/** Runner name. */
|
|
35
|
+
name: string;
|
|
36
|
+
/** Region. */
|
|
37
|
+
region: string;
|
|
38
|
+
/** State. */
|
|
39
|
+
state: string;
|
|
40
|
+
/**
|
|
41
|
+
* The key the runner daemon authenticates with. Daytona shows it only at
|
|
42
|
+
* creation, so alchemy keeps it in state as a `Redacted` value.
|
|
43
|
+
*/
|
|
44
|
+
apiKey: Redacted.Redacted<string>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type Runner = Resource<"Daytona.Runner", RunnerProps, RunnerAttributes, never, Providers>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A runner: a machine you operate that hosts sandboxes for a custom
|
|
51
|
+
* {@link Region}. Declaring it registers the runner and mints the API key
|
|
52
|
+
* its daemon uses; you then start the daemon on the machine with that key.
|
|
53
|
+
*
|
|
54
|
+
* ### Registering a Runner
|
|
55
|
+
* **Example:** A runner for a custom region
|
|
56
|
+
* ```typescript
|
|
57
|
+
* export const Box1 = Daytona.Runner("Box1", { region: Home });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @resource
|
|
61
|
+
* @product Region
|
|
62
|
+
*/
|
|
63
|
+
export const Runner = declarable<Runner>()(Resource<Runner>("Daytona.Runner"));
|
|
64
|
+
|
|
65
|
+
const regionId = (region: RunnerProps["region"]) => Effect.succeed(resolved(region).regionId);
|
|
66
|
+
|
|
67
|
+
const getById = (id: string) =>
|
|
68
|
+
runners.getRunner({ id }).pipe(Effect.catchTag("RunnerNotFound", () => Effect.undefined));
|
|
69
|
+
|
|
70
|
+
export const RunnerProvider = () =>
|
|
71
|
+
Provider.effect(
|
|
72
|
+
Runner,
|
|
73
|
+
Effect.succeed({
|
|
74
|
+
stables: ["runnerId", "apiKey"],
|
|
75
|
+
nuke: { dependsOn: [] },
|
|
76
|
+
list: Effect.fn(function* () {
|
|
77
|
+
// Organizations without custom regions aren't served runners at all.
|
|
78
|
+
const all = yield* runners
|
|
79
|
+
.listRunners({})
|
|
80
|
+
.pipe(Effect.catchTag("RunnersUnavailable", () => Effect.succeed([])));
|
|
81
|
+
return all.map((r) => ({
|
|
82
|
+
runnerId: r.id,
|
|
83
|
+
name: r.name,
|
|
84
|
+
region: r.region,
|
|
85
|
+
state: r.state,
|
|
86
|
+
apiKey: Redacted.make(""),
|
|
87
|
+
}));
|
|
88
|
+
}),
|
|
89
|
+
diff: Effect.fn(function* ({ id, olds, news, output }) {
|
|
90
|
+
if (!isResolved(news) || output === undefined) return undefined;
|
|
91
|
+
const name = yield* resolveName(
|
|
92
|
+
id,
|
|
93
|
+
news.name,
|
|
94
|
+
news.name === undefined ? output.name : undefined,
|
|
95
|
+
);
|
|
96
|
+
if (
|
|
97
|
+
name !== output.name ||
|
|
98
|
+
(yield* regionId(news.region)) !== output.region ||
|
|
99
|
+
!deepEqual(news.tags ?? [], olds?.tags ?? []) ||
|
|
100
|
+
news.sandboxClass !== olds?.sandboxClass
|
|
101
|
+
) {
|
|
102
|
+
return { action: "replace", deleteFirst: name === output.name } as const;
|
|
103
|
+
}
|
|
104
|
+
}),
|
|
105
|
+
read: Effect.fn(function* ({ id, olds, output }) {
|
|
106
|
+
const name = yield* resolveName(id, olds?.name, output?.name);
|
|
107
|
+
const found =
|
|
108
|
+
(output ? yield* getById(output.runnerId) : undefined) ??
|
|
109
|
+
(yield* runners.listRunners({})).find((r) => r.name === name);
|
|
110
|
+
if (found === undefined) return undefined;
|
|
111
|
+
const attrs = {
|
|
112
|
+
runnerId: found.id,
|
|
113
|
+
name: found.name,
|
|
114
|
+
region: found.region,
|
|
115
|
+
state: found.state,
|
|
116
|
+
apiKey: output?.apiKey ?? Redacted.make(""),
|
|
117
|
+
};
|
|
118
|
+
return (yield* isOwnedName(id, found.name, output !== undefined)) ? attrs : Unowned(attrs);
|
|
119
|
+
}),
|
|
120
|
+
reconcile: Effect.fn(function* ({ id, news, output }) {
|
|
121
|
+
const name = yield* resolveName(id, news.name, output?.name);
|
|
122
|
+
const region = yield* regionId(news.region);
|
|
123
|
+
// Observe
|
|
124
|
+
let current = output ? yield* getById(output.runnerId) : undefined;
|
|
125
|
+
let apiKey = output?.apiKey;
|
|
126
|
+
// Ensure
|
|
127
|
+
if (current === undefined) {
|
|
128
|
+
const created = yield* runners.createRunner({
|
|
129
|
+
regionId: region,
|
|
130
|
+
name,
|
|
131
|
+
tags: news.tags,
|
|
132
|
+
sandboxClass: news.sandboxClass,
|
|
133
|
+
});
|
|
134
|
+
apiKey = Redacted.isRedacted(created.apiKey)
|
|
135
|
+
? created.apiKey
|
|
136
|
+
: Redacted.make(created.apiKey);
|
|
137
|
+
current = yield* runners.getRunner({ id: created.id });
|
|
138
|
+
}
|
|
139
|
+
// Sync scheduling flags.
|
|
140
|
+
if ((news.unschedulable ?? false) !== current.unschedulable) {
|
|
141
|
+
current = yield* runners.updateRunnerScheduling({
|
|
142
|
+
id: current.id,
|
|
143
|
+
unschedulable: news.unschedulable ?? false,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if ((news.draining ?? false) !== (current.draining ?? false)) {
|
|
147
|
+
current = yield* runners.updateRunnerDraining({
|
|
148
|
+
id: current.id,
|
|
149
|
+
draining: news.draining ?? false,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
runnerId: current.id,
|
|
154
|
+
name: current.name,
|
|
155
|
+
region: current.region,
|
|
156
|
+
state: current.state,
|
|
157
|
+
apiKey: apiKey ?? Redacted.make(""),
|
|
158
|
+
};
|
|
159
|
+
}),
|
|
160
|
+
delete: Effect.fn(function* ({ output }) {
|
|
161
|
+
yield* runners
|
|
162
|
+
.deleteRunner({ id: output.runnerId })
|
|
163
|
+
.pipe(Effect.catchTag("RunnerNotFound", () => Effect.void));
|
|
164
|
+
}),
|
|
165
|
+
}),
|
|
166
|
+
);
|