@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
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as sandboxes from "@distilled.cloud/daytona/sandbox";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
|
+
import { CreateSandbox, type CreateSandboxClient } from "./CreateSandbox.ts";
|
|
5
|
+
import { makeAccess, makeOwnerLabels, withOwnerLabels } from "./DaytonaBindings.ts";
|
|
6
|
+
import { definedLabels } from "./internal/Labels.ts";
|
|
7
|
+
import { waitForState } from "./internal/Wait.ts";
|
|
8
|
+
import { volumeIdOf } from "./MountVolume.ts";
|
|
9
|
+
import { makeSandboxClient } from "./SandboxClient.ts";
|
|
10
|
+
import type { Snapshot } from "./Snapshot.ts";
|
|
11
|
+
|
|
12
|
+
/** {@link CreateSandbox} over Daytona's HTTP API; works on any host. */
|
|
13
|
+
export const CreateSandboxHttp = Layer.effect(
|
|
14
|
+
CreateSandbox,
|
|
15
|
+
Effect.gen(function* () {
|
|
16
|
+
const access = yield* makeAccess;
|
|
17
|
+
return Effect.fn(function* (base?: Snapshot) {
|
|
18
|
+
const purpose = `${base?.LogicalId ?? ""}Sandboxes`;
|
|
19
|
+
const { authorize, organizationId } = yield* access(purpose, [
|
|
20
|
+
"write:sandboxes",
|
|
21
|
+
"delete:sandboxes",
|
|
22
|
+
]);
|
|
23
|
+
const ownerLabels = yield* makeOwnerLabels;
|
|
24
|
+
const baseName = base ? yield* base.name : undefined;
|
|
25
|
+
|
|
26
|
+
const handle = (s: sandboxes.Sandbox2) =>
|
|
27
|
+
Effect.succeed(makeSandboxClient(s, organizationId, authorize));
|
|
28
|
+
|
|
29
|
+
const client: CreateSandboxClient = {
|
|
30
|
+
create: (input) =>
|
|
31
|
+
authorize(
|
|
32
|
+
Effect.gen(function* () {
|
|
33
|
+
const labels = withOwnerLabels(
|
|
34
|
+
input?.labels ? definedLabels(input.labels) : undefined,
|
|
35
|
+
yield* ownerLabels,
|
|
36
|
+
);
|
|
37
|
+
const snapshot = input?.snapshot ?? (baseName ? yield* baseName : undefined);
|
|
38
|
+
const { mounts, ...request } = input ?? {};
|
|
39
|
+
const volumes = mounts
|
|
40
|
+
? yield* Effect.forEach(mounts, (m) =>
|
|
41
|
+
Effect.map(volumeIdOf(m.volume), (volumeId) => ({
|
|
42
|
+
volumeId,
|
|
43
|
+
mountPath: m.path,
|
|
44
|
+
subpath: m.subpath,
|
|
45
|
+
})),
|
|
46
|
+
)
|
|
47
|
+
: undefined;
|
|
48
|
+
const created = yield* sandboxes.createSandbox({
|
|
49
|
+
...request,
|
|
50
|
+
snapshot,
|
|
51
|
+
labels,
|
|
52
|
+
volumes,
|
|
53
|
+
});
|
|
54
|
+
return yield* waitForState({
|
|
55
|
+
kind: "sandbox",
|
|
56
|
+
id: created.id,
|
|
57
|
+
observe: sandboxes.getSandbox({ sandboxIdOrName: created.id }),
|
|
58
|
+
want: ["started"],
|
|
59
|
+
fail: ["error", "build_failed", "destroyed"],
|
|
60
|
+
reason: (s) => s.errorReason,
|
|
61
|
+
budget: "5 minutes",
|
|
62
|
+
});
|
|
63
|
+
}),
|
|
64
|
+
).pipe(Effect.flatMap(handle)),
|
|
65
|
+
get: (idOrName) =>
|
|
66
|
+
authorize(
|
|
67
|
+
sandboxes.getSandbox({ sandboxIdOrName: idOrName }).pipe(
|
|
68
|
+
Effect.map((s) =>
|
|
69
|
+
s.state === "destroyed" || s.state === "destroying" ? undefined : s,
|
|
70
|
+
),
|
|
71
|
+
Effect.catchTag("SandboxNotFound", () => Effect.undefined),
|
|
72
|
+
),
|
|
73
|
+
).pipe(Effect.flatMap((s) => (s ? handle(s) : Effect.undefined))),
|
|
74
|
+
list: (input) =>
|
|
75
|
+
authorize(
|
|
76
|
+
Effect.gen(function* () {
|
|
77
|
+
const snapshots = input?.snapshots ?? (baseName ? [yield* baseName] : undefined);
|
|
78
|
+
const page = yield* sandboxes.listSandboxes({
|
|
79
|
+
...input,
|
|
80
|
+
snapshots,
|
|
81
|
+
labels: input?.labels ? JSON.stringify(input.labels) : undefined,
|
|
82
|
+
});
|
|
83
|
+
return page.items;
|
|
84
|
+
}),
|
|
85
|
+
),
|
|
86
|
+
delete: (idOrName) =>
|
|
87
|
+
authorize(
|
|
88
|
+
sandboxes.deleteSandbox({ sandboxIdOrName: idOrName }).pipe(
|
|
89
|
+
Effect.asVoid,
|
|
90
|
+
Effect.catchTag("SandboxNotFound", () => Effect.void),
|
|
91
|
+
),
|
|
92
|
+
),
|
|
93
|
+
};
|
|
94
|
+
return client;
|
|
95
|
+
});
|
|
96
|
+
}),
|
|
97
|
+
);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type * as secrets from "@distilled.cloud/daytona/secret";
|
|
2
|
+
import * as Binding from "alchemy/Binding";
|
|
3
|
+
import type { RuntimeContext } from "alchemy/RuntimeContext";
|
|
4
|
+
import type * as Effect from "effect/Effect";
|
|
5
|
+
import type * as Redacted from "effect/Redacted";
|
|
6
|
+
import type { SecretAttributes } from "./Secret.ts";
|
|
7
|
+
|
|
8
|
+
export interface CreateSecretClient {
|
|
9
|
+
/**
|
|
10
|
+
* Create the secret, or write a new value (and description and hosts)
|
|
11
|
+
* to the one with this name. Returns the same attributes as
|
|
12
|
+
* `Daytona.Secret`; pass `placeholder` into a sandbox's env or the
|
|
13
|
+
* secret's `name` in `secrets`.
|
|
14
|
+
*/
|
|
15
|
+
put(input: {
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly value: string | Redacted.Redacted<string>;
|
|
18
|
+
readonly description?: string;
|
|
19
|
+
readonly hosts?: string[];
|
|
20
|
+
}): Effect.Effect<
|
|
21
|
+
SecretAttributes,
|
|
22
|
+
secrets.CreateSecretError | secrets.UpdateSecretError | secrets.ListSecretsPaginatedError,
|
|
23
|
+
RuntimeContext
|
|
24
|
+
>;
|
|
25
|
+
/** The secret with this name, or `undefined`. Values are never returned. */
|
|
26
|
+
get(
|
|
27
|
+
name: string,
|
|
28
|
+
): Effect.Effect<SecretAttributes | undefined, secrets.ListSecretsPaginatedError, RuntimeContext>;
|
|
29
|
+
/** Every secret in the organization. */
|
|
30
|
+
list(): Effect.Effect<SecretAttributes[], secrets.ListSecretsPaginatedError, RuntimeContext>;
|
|
31
|
+
/** Delete the secret with this name. Deleting a missing one succeeds. */
|
|
32
|
+
delete(
|
|
33
|
+
name: string,
|
|
34
|
+
): Effect.Effect<
|
|
35
|
+
void,
|
|
36
|
+
secrets.DeleteSecretError | secrets.ListSecretsPaginatedError,
|
|
37
|
+
RuntimeContext
|
|
38
|
+
>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Store secrets in Daytona at runtime: a credential per user, injected
|
|
43
|
+
* into that user's sandboxes without the sandbox (or an agent in it)
|
|
44
|
+
* ever seeing the value. Daytona swaps the placeholder for the value only
|
|
45
|
+
* on requests to the secret's `hosts`.
|
|
46
|
+
*
|
|
47
|
+
* The host gets its own Daytona API key with `manage:secrets`. Secrets
|
|
48
|
+
* have no labels, so each one it creates carries `stack/stage/id` in its
|
|
49
|
+
* description. They are not deleted when the stack is destroyed: list them
|
|
50
|
+
* (`list()`) and match the description to clean them up.
|
|
51
|
+
*
|
|
52
|
+
* ### A Credential per User
|
|
53
|
+
* **Example:** The user's GitHub token, only sent to GitHub's API
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const secrets = yield* Daytona.CreateSecret();
|
|
56
|
+
* const github = yield* secrets.put({
|
|
57
|
+
* name: `github-${user}`,
|
|
58
|
+
* value: token,
|
|
59
|
+
* hosts: ["api.github.com"],
|
|
60
|
+
* });
|
|
61
|
+
* const sandbox = yield* sandboxes.create({ secrets: [{ GITHUB_TOKEN: github.name }] });
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @binding
|
|
65
|
+
* @product Secret
|
|
66
|
+
*/
|
|
67
|
+
export interface CreateSecret extends Binding.Service<
|
|
68
|
+
CreateSecret,
|
|
69
|
+
"Daytona.CreateSecret",
|
|
70
|
+
() => Effect.Effect<CreateSecretClient>
|
|
71
|
+
> {}
|
|
72
|
+
|
|
73
|
+
export const CreateSecret = Binding.Service<CreateSecret>("Daytona.CreateSecret");
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as secrets from "@distilled.cloud/daytona/secret";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
|
+
import * as Stream from "effect/Stream";
|
|
5
|
+
import { CreateSecret, type CreateSecretClient } from "./CreateSecret.ts";
|
|
6
|
+
import { makeAccess, makeOwnerLabels, ownerDescription } from "./DaytonaBindings.ts";
|
|
7
|
+
import { ensureSecret, findSecretByName, toSecretAttributes } from "./Secret.ts";
|
|
8
|
+
|
|
9
|
+
/** {@link CreateSecret} over Daytona's HTTP API; works on any host. */
|
|
10
|
+
export const CreateSecretHttp = Layer.effect(
|
|
11
|
+
CreateSecret,
|
|
12
|
+
Effect.gen(function* () {
|
|
13
|
+
const access = yield* makeAccess;
|
|
14
|
+
return Effect.fn(function* () {
|
|
15
|
+
const { authorize } = yield* access("Secrets", ["manage:secrets"]);
|
|
16
|
+
// Secrets have no labels, so the owner goes in the description.
|
|
17
|
+
const marker = Effect.map(yield* makeOwnerLabels, ownerDescription);
|
|
18
|
+
const client: CreateSecretClient = {
|
|
19
|
+
put: (input) =>
|
|
20
|
+
authorize(
|
|
21
|
+
Effect.gen(function* () {
|
|
22
|
+
const mark = yield* marker;
|
|
23
|
+
return yield* ensureSecret({
|
|
24
|
+
name: input.name,
|
|
25
|
+
value: input.value,
|
|
26
|
+
description: input.description ? `${input.description} (${mark})` : mark,
|
|
27
|
+
hosts: input.hosts,
|
|
28
|
+
});
|
|
29
|
+
}),
|
|
30
|
+
),
|
|
31
|
+
get: (name) =>
|
|
32
|
+
authorize(
|
|
33
|
+
findSecretByName(name).pipe(
|
|
34
|
+
Effect.map((s) => (s ? toSecretAttributes(s, "") : undefined)),
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
list: () =>
|
|
38
|
+
authorize(
|
|
39
|
+
secrets.listSecretsPaginated.items({}).pipe(
|
|
40
|
+
Stream.runCollect,
|
|
41
|
+
Effect.map((all) => Array.from(all, (s) => toSecretAttributes(s, ""))),
|
|
42
|
+
),
|
|
43
|
+
),
|
|
44
|
+
delete: (name) =>
|
|
45
|
+
authorize(
|
|
46
|
+
Effect.gen(function* () {
|
|
47
|
+
const found = yield* findSecretByName(name);
|
|
48
|
+
if (found === undefined) return;
|
|
49
|
+
yield* secrets
|
|
50
|
+
.deleteSecret({ secretId: found.id })
|
|
51
|
+
.pipe(Effect.catchTag("SecretNotFound", () => Effect.void));
|
|
52
|
+
}),
|
|
53
|
+
),
|
|
54
|
+
};
|
|
55
|
+
return client;
|
|
56
|
+
});
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { UnsupportedDockerfile } from "@alchemy.run/docker/BuildPlan";
|
|
2
|
+
import type { DockerfileSyntaxError } from "@alchemy.run/docker/DockerfileParser";
|
|
3
|
+
import type * as sandboxes from "@distilled.cloud/daytona/sandbox";
|
|
4
|
+
import type * as snapshots from "@distilled.cloud/daytona/snapshots";
|
|
5
|
+
import * as Binding from "alchemy/Binding";
|
|
6
|
+
import type { RuntimeContext } from "alchemy/RuntimeContext";
|
|
7
|
+
import type * as Effect from "effect/Effect";
|
|
8
|
+
import type { NameOutsidePrefix } from "./CreateVolume.ts";
|
|
9
|
+
import type { ProcessError } from "./internal/Errors.ts";
|
|
10
|
+
import type { StateFailed, StateTimeout } from "./internal/Wait.ts";
|
|
11
|
+
import type {
|
|
12
|
+
ResolvedSnapshotSource,
|
|
13
|
+
SnapshotAttributes,
|
|
14
|
+
SnapshotContextUnsupported,
|
|
15
|
+
SnapshotImageTagInvalid,
|
|
16
|
+
SnapshotRunFailed,
|
|
17
|
+
} from "./Snapshot.ts";
|
|
18
|
+
|
|
19
|
+
/** `create` input: a name and one source, as `Daytona.Snapshot` takes them (Dockerfile as content). */
|
|
20
|
+
export interface CreateSnapshotInput extends Omit<ResolvedSnapshotSource, "contextHashes"> {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CreateSnapshotClient {
|
|
25
|
+
/**
|
|
26
|
+
* Build a snapshot and wait until it is active: pull `image`, build
|
|
27
|
+
* `dockerfile` on Daytona, or start a sandbox from `from`, `run` the
|
|
28
|
+
* commands and capture it. Returns the same attributes as
|
|
29
|
+
* `Daytona.Snapshot`.
|
|
30
|
+
*/
|
|
31
|
+
create(
|
|
32
|
+
input: CreateSnapshotInput,
|
|
33
|
+
): Effect.Effect<
|
|
34
|
+
SnapshotAttributes,
|
|
35
|
+
| snapshots.CreateSnapshotError
|
|
36
|
+
| snapshots.GetSnapshotError
|
|
37
|
+
| snapshots.ActivateSnapshotError
|
|
38
|
+
| sandboxes.CreateSandboxError
|
|
39
|
+
| sandboxes.GetSandboxError
|
|
40
|
+
| sandboxes.CreateSandboxSnapshotError
|
|
41
|
+
| ProcessError
|
|
42
|
+
| SnapshotRunFailed
|
|
43
|
+
| SnapshotImageTagInvalid
|
|
44
|
+
| SnapshotContextUnsupported
|
|
45
|
+
| UnsupportedDockerfile
|
|
46
|
+
| DockerfileSyntaxError
|
|
47
|
+
| StateTimeout
|
|
48
|
+
| StateFailed
|
|
49
|
+
| NameOutsidePrefix,
|
|
50
|
+
RuntimeContext
|
|
51
|
+
>;
|
|
52
|
+
/** The snapshot with this id or name, or `undefined`. */
|
|
53
|
+
get(
|
|
54
|
+
idOrName: string,
|
|
55
|
+
): Effect.Effect<SnapshotAttributes | undefined, snapshots.GetSnapshotError, RuntimeContext>;
|
|
56
|
+
/** Snapshots matching Daytona's list filters. */
|
|
57
|
+
list(
|
|
58
|
+
input?: Omit<snapshots.GetAllSnapshotsRequest, "xDaytonaOrganizationID" | "page">,
|
|
59
|
+
): Effect.Effect<SnapshotAttributes[], snapshots.GetAllSnapshotsError, RuntimeContext>;
|
|
60
|
+
/** Make a deactivated snapshot usable again and wait until it is active. */
|
|
61
|
+
activate(
|
|
62
|
+
idOrName: string,
|
|
63
|
+
): Effect.Effect<
|
|
64
|
+
SnapshotAttributes,
|
|
65
|
+
snapshots.GetSnapshotError | snapshots.ActivateSnapshotError | StateTimeout | StateFailed,
|
|
66
|
+
RuntimeContext
|
|
67
|
+
>;
|
|
68
|
+
/** Deactivate a snapshot; sandboxes can't be created from it until it is activated. */
|
|
69
|
+
deactivate(
|
|
70
|
+
idOrName: string,
|
|
71
|
+
): Effect.Effect<void, snapshots.DeactivateSnapshotError, RuntimeContext>;
|
|
72
|
+
/** A URL streaming the snapshot's build logs. */
|
|
73
|
+
buildLogsUrl(
|
|
74
|
+
idOrName: string,
|
|
75
|
+
): Effect.Effect<snapshots.Url, snapshots.GetSnapshotBuildLogsUrlError, RuntimeContext>;
|
|
76
|
+
/** Delete a snapshot and wait until it is gone. Deleting a missing one succeeds. */
|
|
77
|
+
delete(
|
|
78
|
+
idOrName: string,
|
|
79
|
+
): Effect.Effect<
|
|
80
|
+
void,
|
|
81
|
+
snapshots.RemoveSnapshotError | snapshots.GetSnapshotError | StateTimeout,
|
|
82
|
+
RuntimeContext
|
|
83
|
+
>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Options for {@link CreateSnapshot}. Snapshots have only a name, no labels
|
|
88
|
+
* or description, so a `prefix` is how you find the ones a binding
|
|
89
|
+
* created: the binding refuses names that don't start with it.
|
|
90
|
+
*/
|
|
91
|
+
export interface CreateSnapshotOptions {
|
|
92
|
+
/** Every name the binding creates must start with this. */
|
|
93
|
+
readonly prefix?: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Build Daytona snapshots at runtime: a warm base per repository, built
|
|
98
|
+
* when it's first needed, that later sandboxes start from. To capture a
|
|
99
|
+
* sandbox you already have, use `sandbox.createSandboxSnapshot` on its
|
|
100
|
+
* handle.
|
|
101
|
+
*
|
|
102
|
+
* The host gets its own Daytona API key with `write:snapshots`,
|
|
103
|
+
* `delete:snapshots` and, for `from` builds, `write:sandboxes` and
|
|
104
|
+
* `delete:sandboxes`. Snapshots have only a name, so the `prefix` you give
|
|
105
|
+
* is how you find the ones it created. They are not deleted when the stack
|
|
106
|
+
* is destroyed: `list()` and delete the names with your prefix to clean
|
|
107
|
+
* them up.
|
|
108
|
+
*
|
|
109
|
+
* ### A Warm Base per Repository
|
|
110
|
+
* **Example:** Build it on first use, then start sandboxes from it
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const images = yield* Daytona.CreateSnapshot({ prefix: "repo-" });
|
|
113
|
+
* const name = `repo-${owner}-${repo}`;
|
|
114
|
+
* const base =
|
|
115
|
+
* (yield* images.get(name)) ??
|
|
116
|
+
* (yield* images.create({
|
|
117
|
+
* name,
|
|
118
|
+
* from: "daytonaio/sandbox:0.4.3",
|
|
119
|
+
* run: [`git clone https://github.com/${owner}/${repo} /home/daytona/repo`, "cd /home/daytona/repo && npm ci"],
|
|
120
|
+
* }));
|
|
121
|
+
* const sandbox = yield* sandboxes.create({ snapshot: base.name });
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* @binding
|
|
125
|
+
* @product Snapshot
|
|
126
|
+
*/
|
|
127
|
+
export interface CreateSnapshot extends Binding.Service<
|
|
128
|
+
CreateSnapshot,
|
|
129
|
+
"Daytona.CreateSnapshot",
|
|
130
|
+
(options?: CreateSnapshotOptions) => Effect.Effect<CreateSnapshotClient>
|
|
131
|
+
> {}
|
|
132
|
+
|
|
133
|
+
export const CreateSnapshot = Binding.Service<CreateSnapshot>("Daytona.CreateSnapshot");
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as snapshots from "@distilled.cloud/daytona/snapshots";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
|
+
import * as Stream from "effect/Stream";
|
|
5
|
+
import {
|
|
6
|
+
CreateSnapshot,
|
|
7
|
+
type CreateSnapshotClient,
|
|
8
|
+
type CreateSnapshotOptions,
|
|
9
|
+
} from "./CreateSnapshot.ts";
|
|
10
|
+
import { NameOutsidePrefix } from "./CreateVolume.ts";
|
|
11
|
+
import { makeAccess, makeOwnerLabels } from "./DaytonaBindings.ts";
|
|
12
|
+
import {
|
|
13
|
+
buildSnapshot,
|
|
14
|
+
checkRuntimeDockerfile,
|
|
15
|
+
deleteSnapshot,
|
|
16
|
+
getSnapshot,
|
|
17
|
+
toSnapshotAttributes,
|
|
18
|
+
waitForSnapshot,
|
|
19
|
+
} from "./Snapshot.ts";
|
|
20
|
+
|
|
21
|
+
/** {@link CreateSnapshot} over Daytona's HTTP API; works on any host. */
|
|
22
|
+
export const CreateSnapshotHttp = Layer.effect(
|
|
23
|
+
CreateSnapshot,
|
|
24
|
+
Effect.gen(function* () {
|
|
25
|
+
const access = yield* makeAccess;
|
|
26
|
+
return Effect.fn(function* (options?: CreateSnapshotOptions) {
|
|
27
|
+
const { authorize } = yield* access("Snapshots", [
|
|
28
|
+
"write:snapshots",
|
|
29
|
+
"delete:snapshots",
|
|
30
|
+
"write:sandboxes",
|
|
31
|
+
"delete:sandboxes",
|
|
32
|
+
]);
|
|
33
|
+
// A snapshot has only a name: `prefix` scopes it. The owner labels go
|
|
34
|
+
// on the sandbox a warm base is captured from.
|
|
35
|
+
const labels = yield* makeOwnerLabels;
|
|
36
|
+
const prefix = options?.prefix;
|
|
37
|
+
const client: CreateSnapshotClient = {
|
|
38
|
+
create: ({ name, ...source }) =>
|
|
39
|
+
prefix !== undefined && !name.startsWith(prefix)
|
|
40
|
+
? Effect.fail(new NameOutsidePrefix({ objectName: name, prefix }))
|
|
41
|
+
: authorize(
|
|
42
|
+
Effect.gen(function* () {
|
|
43
|
+
if (source.dockerfile !== undefined)
|
|
44
|
+
yield* checkRuntimeDockerfile(source.dockerfile);
|
|
45
|
+
const built = yield* buildSnapshot({
|
|
46
|
+
name,
|
|
47
|
+
source,
|
|
48
|
+
labels: yield* labels,
|
|
49
|
+
note: () => Effect.void,
|
|
50
|
+
});
|
|
51
|
+
return toSnapshotAttributes(built, "");
|
|
52
|
+
}),
|
|
53
|
+
),
|
|
54
|
+
get: (idOrName) =>
|
|
55
|
+
authorize(
|
|
56
|
+
getSnapshot(idOrName).pipe(
|
|
57
|
+
Effect.map((s) => (s ? toSnapshotAttributes(s, "") : undefined)),
|
|
58
|
+
),
|
|
59
|
+
),
|
|
60
|
+
list: (input) =>
|
|
61
|
+
authorize(
|
|
62
|
+
snapshots.getAllSnapshots.items({ ...input }).pipe(
|
|
63
|
+
Stream.runCollect,
|
|
64
|
+
Effect.map((all) => Array.from(all, (s) => toSnapshotAttributes(s, ""))),
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
activate: (idOrName) =>
|
|
68
|
+
authorize(waitForSnapshot(idOrName).pipe(Effect.map((s) => toSnapshotAttributes(s, "")))),
|
|
69
|
+
deactivate: (idOrName) =>
|
|
70
|
+
authorize(snapshots.deactivateSnapshot({ id: idOrName }).pipe(Effect.asVoid)),
|
|
71
|
+
buildLogsUrl: (idOrName) => authorize(snapshots.getSnapshotBuildLogsUrl({ id: idOrName })),
|
|
72
|
+
delete: (idOrName) => authorize(deleteSnapshot(idOrName)),
|
|
73
|
+
};
|
|
74
|
+
return client;
|
|
75
|
+
});
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type * as volumes from "@distilled.cloud/daytona/volumes";
|
|
2
|
+
import * as Binding from "alchemy/Binding";
|
|
3
|
+
import type { RuntimeContext } from "alchemy/RuntimeContext";
|
|
4
|
+
import * as Data from "effect/Data";
|
|
5
|
+
import type * as Effect from "effect/Effect";
|
|
6
|
+
import type { StateFailed, StateTimeout } from "./internal/Wait.ts";
|
|
7
|
+
import type { VolumeAttributes } from "./Volume.ts";
|
|
8
|
+
|
|
9
|
+
/** A name outside the binding's `prefix`. */
|
|
10
|
+
export class NameOutsidePrefix extends Data.TaggedError("Daytona.NameOutsidePrefix")<{
|
|
11
|
+
readonly objectName: string;
|
|
12
|
+
readonly prefix: string;
|
|
13
|
+
}> {
|
|
14
|
+
override get message() {
|
|
15
|
+
return `${this.objectName} must start with ${this.prefix}: the binding only manages names with that prefix`;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface CreateVolumeClient {
|
|
20
|
+
/**
|
|
21
|
+
* The volume named `name`, created (and waited on until ready) if it
|
|
22
|
+
* doesn't exist. Returns the same attributes as `Daytona.Volume`.
|
|
23
|
+
*/
|
|
24
|
+
getOrCreate(input: {
|
|
25
|
+
readonly name: string;
|
|
26
|
+
}): Effect.Effect<
|
|
27
|
+
VolumeAttributes,
|
|
28
|
+
| volumes.CreateVolumeError
|
|
29
|
+
| volumes.GetVolumeByNameError
|
|
30
|
+
| volumes.GetVolumeError
|
|
31
|
+
| StateTimeout
|
|
32
|
+
| StateFailed
|
|
33
|
+
| NameOutsidePrefix,
|
|
34
|
+
RuntimeContext
|
|
35
|
+
>;
|
|
36
|
+
/** The volume with this name, or `undefined`. */
|
|
37
|
+
get(
|
|
38
|
+
name: string,
|
|
39
|
+
): Effect.Effect<VolumeAttributes | undefined, volumes.GetVolumeByNameError, RuntimeContext>;
|
|
40
|
+
/** Every volume in the organization. */
|
|
41
|
+
list(): Effect.Effect<VolumeAttributes[], volumes.ListVolumesError, RuntimeContext>;
|
|
42
|
+
/**
|
|
43
|
+
* Delete a volume. Returns once Daytona has accepted the delete; it
|
|
44
|
+
* removes the volume in the background. Fails with `VolumeInUse` while a
|
|
45
|
+
* sandbox mounts it: Daytona releases a volume about a minute after the
|
|
46
|
+
* sandbox that wrote to it is deleted, so retry later. Deleting a missing
|
|
47
|
+
* one succeeds.
|
|
48
|
+
*/
|
|
49
|
+
delete(
|
|
50
|
+
volumeId: string,
|
|
51
|
+
): Effect.Effect<
|
|
52
|
+
void,
|
|
53
|
+
volumes.DeleteVolumeError | volumes.GetVolumeError | StateTimeout,
|
|
54
|
+
RuntimeContext
|
|
55
|
+
>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Options for {@link CreateVolume}. Volumes have only a name, no labels or
|
|
60
|
+
* description, so a `prefix` is how you find the ones a binding created:
|
|
61
|
+
* the binding refuses names that don't start with it.
|
|
62
|
+
*/
|
|
63
|
+
export interface CreateVolumeOptions {
|
|
64
|
+
/** Every name the binding creates or gets must start with this. */
|
|
65
|
+
readonly prefix?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create, find and delete Daytona volumes at runtime: a volume per user,
|
|
70
|
+
* per project or per session, mounted into the sandboxes you create.
|
|
71
|
+
*
|
|
72
|
+
* The host gets its own Daytona API key with `read:volumes`,
|
|
73
|
+
* `write:volumes` and `delete:volumes`. Volumes have only a name, so the
|
|
74
|
+
* `prefix` you give is how you find the ones it created. They are not
|
|
75
|
+
* deleted when the stack is destroyed: `list()` and delete the names with
|
|
76
|
+
* your prefix to clean them up.
|
|
77
|
+
*
|
|
78
|
+
* ### Volume per User
|
|
79
|
+
* **Example:** Mount the user's volume as their home directory
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const volumes = yield* Daytona.CreateVolume({ prefix: "user-" });
|
|
82
|
+
* const sandboxes = yield* Daytona.CreateSandbox(Base);
|
|
83
|
+
* return {
|
|
84
|
+
* fetch: Effect.gen(function* () {
|
|
85
|
+
* const home = yield* volumes.getOrCreate({ name: `user-${user}` });
|
|
86
|
+
* const sandbox = yield* sandboxes.create({
|
|
87
|
+
* mounts: [{ volume: home, path: "/home/daytona/work" }],
|
|
88
|
+
* });
|
|
89
|
+
* const ls = yield* sandbox.exec("ls /home/daytona/work");
|
|
90
|
+
* return yield* HttpServerResponse.json(ls);
|
|
91
|
+
* }),
|
|
92
|
+
* };
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @binding
|
|
96
|
+
* @product Volume
|
|
97
|
+
*/
|
|
98
|
+
export interface CreateVolume extends Binding.Service<
|
|
99
|
+
CreateVolume,
|
|
100
|
+
"Daytona.CreateVolume",
|
|
101
|
+
(options?: CreateVolumeOptions) => Effect.Effect<CreateVolumeClient>
|
|
102
|
+
> {}
|
|
103
|
+
|
|
104
|
+
export const CreateVolume = Binding.Service<CreateVolume>("Daytona.CreateVolume");
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as volumes from "@distilled.cloud/daytona/volumes";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
|
+
import {
|
|
5
|
+
CreateVolume,
|
|
6
|
+
NameOutsidePrefix,
|
|
7
|
+
type CreateVolumeClient,
|
|
8
|
+
type CreateVolumeOptions,
|
|
9
|
+
} from "./CreateVolume.ts";
|
|
10
|
+
import { makeAccess } from "./DaytonaBindings.ts";
|
|
11
|
+
import { deleteVolumeById, ensureVolume, getVolumeByName, toVolumeAttributes } from "./Volume.ts";
|
|
12
|
+
|
|
13
|
+
/** {@link CreateVolume} over Daytona's HTTP API; works on any host. */
|
|
14
|
+
export const CreateVolumeHttp = Layer.effect(
|
|
15
|
+
CreateVolume,
|
|
16
|
+
Effect.gen(function* () {
|
|
17
|
+
const access = yield* makeAccess;
|
|
18
|
+
return Effect.fn(function* (options?: CreateVolumeOptions) {
|
|
19
|
+
const { authorize } = yield* access("Volumes", [
|
|
20
|
+
"read:volumes",
|
|
21
|
+
"write:volumes",
|
|
22
|
+
"delete:volumes",
|
|
23
|
+
]);
|
|
24
|
+
// A volume has only a name: `prefix` scopes it.
|
|
25
|
+
const prefix = options?.prefix;
|
|
26
|
+
const client: CreateVolumeClient = {
|
|
27
|
+
getOrCreate: ({ name }) =>
|
|
28
|
+
prefix !== undefined && !name.startsWith(prefix)
|
|
29
|
+
? Effect.fail(new NameOutsidePrefix({ objectName: name, prefix }))
|
|
30
|
+
: authorize(ensureVolume(name).pipe(Effect.map(toVolumeAttributes))),
|
|
31
|
+
get: (name) =>
|
|
32
|
+
authorize(
|
|
33
|
+
getVolumeByName(name).pipe(Effect.map((v) => (v ? toVolumeAttributes(v) : undefined))),
|
|
34
|
+
),
|
|
35
|
+
list: () =>
|
|
36
|
+
authorize(
|
|
37
|
+
volumes
|
|
38
|
+
.listVolumes({})
|
|
39
|
+
.pipe(
|
|
40
|
+
Effect.map((all) =>
|
|
41
|
+
all.filter((v) => v.state !== "deleted").map(toVolumeAttributes),
|
|
42
|
+
),
|
|
43
|
+
),
|
|
44
|
+
),
|
|
45
|
+
delete: (volumeId) => authorize(deleteVolumeById(volumeId, { wait: false })),
|
|
46
|
+
};
|
|
47
|
+
return client;
|
|
48
|
+
});
|
|
49
|
+
}),
|
|
50
|
+
);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ConfigError } from "@distilled.cloud/core/errors";
|
|
2
|
+
import {
|
|
3
|
+
Credentials,
|
|
4
|
+
DEFAULT_ANALYTICS_BASE_URL,
|
|
5
|
+
DEFAULT_TOOLBOX_BASE_URL,
|
|
6
|
+
} from "@distilled.cloud/daytona/Credentials";
|
|
7
|
+
import { lazyCredentials } from "alchemy/Auth/Resolve";
|
|
8
|
+
import * as Layer from "effect/Layer";
|
|
9
|
+
import { DAYTONA_AUTH_PROVIDER_NAME, type DaytonaResolvedCredentials } from "./AuthProvider.ts";
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
Credentials,
|
|
13
|
+
CredentialsFromEnv,
|
|
14
|
+
DEFAULT_ANALYTICS_BASE_URL,
|
|
15
|
+
DEFAULT_API_BASE_URL,
|
|
16
|
+
DEFAULT_TOOLBOX_BASE_URL,
|
|
17
|
+
} from "@distilled.cloud/daytona/Credentials";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A `Credentials` layer that resolves Daytona credentials through the
|
|
21
|
+
* Alchemy AuthProvider for the current profile.
|
|
22
|
+
*/
|
|
23
|
+
export const fromAuthProvider = () =>
|
|
24
|
+
Layer.effect(
|
|
25
|
+
Credentials,
|
|
26
|
+
lazyCredentials<DaytonaResolvedCredentials, ConfigError>()(
|
|
27
|
+
DAYTONA_AUTH_PROVIDER_NAME,
|
|
28
|
+
(creds) => ({
|
|
29
|
+
apiKey: creds.token,
|
|
30
|
+
apiBaseUrl: creds.apiBaseUrl,
|
|
31
|
+
analyticsBaseUrl: DEFAULT_ANALYTICS_BASE_URL,
|
|
32
|
+
toolboxBaseUrl: DEFAULT_TOOLBOX_BASE_URL,
|
|
33
|
+
organizationId: creds.organizationId,
|
|
34
|
+
}),
|
|
35
|
+
{ expiresAt: (creds) => creds.expires },
|
|
36
|
+
),
|
|
37
|
+
);
|