Skip to content

Commit ef92b52

Browse files
committed
Release v0.2.0
1 parent 09cc4f8 commit ef92b52

261 files changed

Lines changed: 26396 additions & 4759 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ accounts you control.
66

77
## Deploy
88

9-
Node.js 22.19 or newer, pnpm 9, a Cloudflare account, and an E2B API key are
10-
required.
9+
Node.js 22.19 or newer, pnpm 9, a Cloudflare account, and at least one Orb
10+
provider are required: an E2B API key, or Cloudflare Containers (Workers Paid
11+
plan and Docker on the deploying machine).
1112

1213
```sh
1314
pnpm install --frozen-lockfile

‎RELEASE.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
2-
"version": "0.1.2",
2+
"version": "0.2.0",
33
"license": "FSL-1.1-ALv2",
44
"baselineSha256": "7847f65a9b20b366a60d52d19ca3cd6bdd1bb09b8cb506659a270f27a21d8877",
55
"e2b": {
6-
"recipeSha256": "8159896206584133aec265e481f4c915ed48b6736d6b24b7569712b4672bf5d6",
6+
"recipeSha256": "761809ee2efa2b6c750451ace29283cbb8e55b6ce3b5b14c2bb4509df71df801",
77
"profileSha256": "414dbecee2d47de36016ea05c736e2edff3a0deb298babf923887ea184a01c10"
88
},
99
"dxd": {
10-
"url": "https://github.com/dxcode-dev/dxcode/releases/download/v0.1.2/dxd-linux-x64",
10+
"url": "https://github.com/dxcode-dev/dxcode/releases/download/v0.2.0/dxd-linux-x64",
1111
"sha256": "810626730c00c4bbe3952566b2ebfdc92bf375fd87446fb61d6c0a8041e65bac"
1212
},
1313
"toolchain": {

‎THIRD_PARTY_NOTICES.md‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,37 @@ from the Flue `sandbox/e2b@1` blueprint distributed with Flue 2.0.3:
6363

6464
The source/version marker is retained in the copied file so later changes can
6565
be reviewed against the licensed upstream blueprint.
66+
67+
## QuickJS and quickjs-emscripten
68+
69+
The Code plugin distributes QuickJS WebAssembly through
70+
`quickjs-emscripten-core` and `@jitl/quickjs-wasmfile-release-sync` 0.32.0.
71+
72+
- Source: <https://github.com/justjake/quickjs-emscripten>
73+
- QuickJS source: <https://bellard.org/quickjs/>
74+
- License: MIT
75+
76+
quickjs-emscripten copyright (c) 2019-2024 Jake Teton-Landis
77+
78+
QuickJS Javascript Engine
79+
80+
Copyright (c) 2017-2021 Fabrice Bellard
81+
Copyright (c) 2017-2021 Charlie Gordon
82+
83+
Permission is hereby granted, free of charge, to any person obtaining a copy
84+
of this software and associated documentation files (the "Software"), to deal
85+
in the Software without restriction, including without limitation the rights
86+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
87+
copies of the Software, and to permit persons to whom the Software is
88+
furnished to do so, subject to the following conditions:
89+
90+
The above copyright notice and this permission notice shall be included in all
91+
copies or substantial portions of the Software.
92+
93+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
94+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
95+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
96+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
97+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
98+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
99+
SOFTWARE.

‎alchemy.run.ts‎

Lines changed: 154 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@ import {
1818
E2BProfiles,
1919
e2bRecipeHash,
2020
HeldSecret,
21+
OrbContainers,
22+
orbRecipeHash,
2123
selfhostProviders,
2224
} from "./deploy/selfhost/alchemy-resources.ts";
23-
import { E2B_ORB_PROFILES } from "./packages/domain/src/settings/runner-profile.ts";
25+
import CLOUDFLARE_ORB_PROFILES from "./packages/domain/cloudflare-orb-profiles.json" with {
26+
type: "json",
27+
};
28+
import E2B_ORB_PROFILES from "./packages/domain/e2b-orb-profiles.json" with {
29+
type: "json",
30+
};
2431
import { decodeGitHubAppDeploymentConfiguration } from "./packages/domain/src/source-control/github-app-configuration.ts";
2532

2633
type RecordValue<T> = T extends Record<string, infer Value> ? Value : never;
@@ -81,6 +88,28 @@ const defaultE2BOrbProfile = E2B_ORB_PROFILES.find(
8188
);
8289
if (defaultE2BOrbProfile === undefined)
8390
throw new Error("The default E2B Orb profile is missing from the catalog.");
91+
const defaultCloudflareOrbProfile = CLOUDFLARE_ORB_PROFILES.find(
92+
({ id }) => id === "cf.standard-2",
93+
);
94+
if (defaultCloudflareOrbProfile === undefined)
95+
throw new Error(
96+
"The default Cloudflare Orb profile is missing from the catalog.",
97+
);
98+
/** What every deployed Orb size offers; see RunnerProfileCatalogConfiguration. */
99+
const deployedOrbCapabilities = [
100+
"git",
101+
"environment-variables",
102+
"internet-access",
103+
"persistent-workspace",
104+
"pause-resume",
105+
] as const;
106+
const cloudflareOrbProfiles = CLOUDFLARE_ORB_PROFILES.map((profile) => ({
107+
...profile,
108+
adapter: "cloudflare",
109+
isolation: "container",
110+
availability: "available",
111+
capabilities: deployedOrbCapabilities,
112+
}));
84113

85114
const productionWorkerBindings = <
86115
Groups extends Record<string, Record<string, unknown>>,
@@ -264,6 +293,16 @@ export default Alchemy.Stack(
264293
e2bApiKey: Config.option(Config.redacted("E2B_API_KEY")),
265294
githubApp: Config.option(Config.redacted("DX_INTEGRATION_GITHUB_APP")),
266295
sarvamApiKey: Config.option(Config.redacted("SARVAM_API_KEY")),
296+
exaApiKey: Config.option(Config.redacted("EXA_API_KEY")),
297+
plugins: Config.withDefault(Config.string("DX_DEPLOYMENT_PLUGINS"), ""),
298+
// Orb providers the deployment installs: e2b, cloudflare, or both.
299+
orbProviders: Config.withDefault(
300+
Config.string("DX_DEPLOYMENT_ORB_PROVIDERS"),
301+
"e2b",
302+
),
303+
orbWorkerName: Config.option(
304+
Config.nonEmptyString("DX_DEPLOYMENT_ORB_WORKER_NAME"),
305+
),
267306
workloadIdentitySigningKeys: Config.option(
268307
Config.redacted("DX_WORKLOAD_IDENTITY_SIGNING_KEYS"),
269308
),
@@ -323,13 +362,29 @@ export default Alchemy.Stack(
323362
const integrations = new Set(
324363
configuration.integrations.split(",").filter(Boolean),
325364
);
326-
const e2bApiKey = selfhost
327-
? (yield* HeldSecret("E2BApiKey", {
328-
value: Option.getOrUndefined(configuration.e2bApiKey),
329-
})).value
330-
: Option.isSome(configuration.e2bApiKey)
331-
? configuration.e2bApiKey.value
332-
: yield* Effect.die("E2B_API_KEY is required.");
365+
const orbProviders = new Set(
366+
configuration.orbProviders.split(",").filter(Boolean),
367+
);
368+
if (
369+
orbProviders.size === 0 ||
370+
[...orbProviders].some(
371+
(provider) => provider !== "e2b" && provider !== "cloudflare",
372+
)
373+
)
374+
return yield* Effect.die(
375+
"DX_DEPLOYMENT_ORB_PROVIDERS must name e2b, cloudflare, or both.",
376+
);
377+
const e2bInstalled = orbProviders.has("e2b");
378+
const cloudflareInstalled = orbProviders.has("cloudflare");
379+
const e2bApiKey = !e2bInstalled
380+
? undefined
381+
: selfhost
382+
? (yield* HeldSecret("E2BApiKey", {
383+
value: Option.getOrUndefined(configuration.e2bApiKey),
384+
})).value
385+
: Option.isSome(configuration.e2bApiKey)
386+
? configuration.e2bApiKey.value
387+
: yield* Effect.die("E2B_API_KEY is required.");
333388
const githubApp = selfhost
334389
? integrations.has("github")
335390
? (yield* HeldSecret("GitHubAppSecret", {
@@ -351,22 +406,59 @@ export default Alchemy.Stack(
351406
value: Option.getOrUndefined(configuration.bitbucketOAuth),
352407
})).value
353408
: Option.getOrUndefined(configuration.bitbucketOAuth);
409+
// The Speech plugin's deployment-scope Sarvam key. The self-host
410+
// integration keeps its `sarvam` name and HeldSecret ID.
354411
const sarvamApiKey =
355412
selfhost && integrations.has("sarvam")
356413
? (yield* HeldSecret("SarvamApiKey", {
357414
value: Option.getOrUndefined(configuration.sarvamApiKey),
358415
})).value
359416
: Option.getOrUndefined(configuration.sarvamApiKey);
360-
const selfhostProfiles = selfhost
361-
? yield* E2BProfiles("E2BProfiles", {
362-
apiKey: e2bApiKey,
363-
deploymentName: Option.getOrElse(
364-
configuration.deploymentName,
365-
() => "",
366-
),
367-
recipeHash: yield* Effect.promise(() => e2bRecipeHash()),
368-
} as never)
369-
: undefined;
417+
// Plugin installation is deployment scope. Hosted targets install every
418+
// first-party plugin; self-host installs what `pnpm dx:deploy` recorded.
419+
const installedPlugins = selfhost ? configuration.plugins : "search,speech";
420+
const exaApiKey = selfhost
421+
? integrations.has("exa")
422+
? (yield* HeldSecret("ExaApiKey", {
423+
value: Option.getOrUndefined(configuration.exaApiKey),
424+
})).value
425+
: undefined
426+
: Option.getOrUndefined(configuration.exaApiKey);
427+
const selfhostProfiles =
428+
selfhost && e2bApiKey !== undefined
429+
? yield* E2BProfiles("E2BProfiles", {
430+
apiKey: e2bApiKey,
431+
deploymentName: Option.getOrElse(
432+
configuration.deploymentName,
433+
() => "",
434+
),
435+
recipeHash: yield* Effect.promise(() => e2bRecipeHash()),
436+
} as never)
437+
: undefined;
438+
// Cloudflare Containers runs in this account: the Orb Worker owns one
439+
// container per Thread, and Core binds its namespace across scripts.
440+
const orbContainers = !cloudflareInstalled
441+
? undefined
442+
: Option.isSome(configuration.orbWorkerName)
443+
? yield* OrbContainers("OrbContainers", {
444+
workerName: configuration.orbWorkerName.value,
445+
recipeHash: orbRecipeHash(import.meta.dirname),
446+
})
447+
: yield* Effect.die(
448+
"DX_DEPLOYMENT_ORB_WORKER_NAME is required for Cloudflare Containers.",
449+
);
450+
const defaultOrbProfileId = e2bInstalled
451+
? defaultE2BOrbProfile.id
452+
: defaultCloudflareOrbProfile.id;
453+
const runnerProfileCatalog = (e2bProfiles: ReadonlyArray<unknown>) =>
454+
JSON.stringify({
455+
version: 1,
456+
defaultProfileId: defaultOrbProfileId,
457+
profiles: [
458+
...e2bProfiles,
459+
...(cloudflareInstalled ? cloudflareOrbProfiles : []),
460+
],
461+
});
370462

371463
if (
372464
configuration.turnstileTestKeys &&
@@ -495,12 +587,17 @@ export default Alchemy.Stack(
495587
: {}),
496588
DX_AUTH_URL: configuration.origin,
497589
DX_AUTH_TRUSTED_ORIGINS: configuration.origin,
498-
DX_E2B_TEMPLATE:
499-
selfhostProfiles?.defaultTemplate ??
500-
`${configuration.e2bTemplate}-${defaultE2BOrbProfile.templateSuffix}`,
501-
DX_E2B_TEMPLATE_BUILD_ID:
502-
selfhostProfiles?.defaultBuildId ?? configuration.e2bTemplateBuildId,
503-
DX_E2B_TIMEOUT_MS: "300000",
590+
...(e2bInstalled
591+
? {
592+
DX_E2B_TEMPLATE:
593+
selfhostProfiles?.defaultTemplate ??
594+
`${configuration.e2bTemplate}-${defaultE2BOrbProfile.templateSuffix}`,
595+
DX_E2B_TEMPLATE_BUILD_ID:
596+
selfhostProfiles?.defaultBuildId ??
597+
configuration.e2bTemplateBuildId,
598+
DX_E2B_TIMEOUT_MS: "300000",
599+
}
600+
: {}),
504601
...(Option.isSome(configuration.workspaceInactivityMs)
505602
? {
506603
DX_WORKSPACE_INACTIVITY_MS: String(
@@ -518,50 +615,39 @@ export default Alchemy.Stack(
518615
DX_MIGRATION_MANIFEST_VERSION: String(migrationManifest.version),
519616
DX_RUNNER_PROFILE_CATALOG:
520617
selfhostProfiles === undefined
521-
? JSON.stringify({
522-
version: 1,
523-
defaultProfileId: defaultE2BOrbProfile.id,
524-
profiles: E2B_ORB_PROFILES.map((profile) => ({
525-
...profile,
526-
adapter: "e2b",
527-
template: `${configuration.e2bTemplate}-${profile.templateSuffix}`,
528-
isolation: "sandbox",
529-
availability: "available",
530-
capabilities: [
531-
"git",
532-
"environment-variables",
533-
"internet-access",
534-
"persistent-workspace",
535-
"pause-resume",
536-
],
537-
})),
538-
})
618+
? runnerProfileCatalog(
619+
e2bInstalled
620+
? E2B_ORB_PROFILES.map((profile) => ({
621+
...profile,
622+
adapter: "e2b",
623+
template: `${configuration.e2bTemplate}-${profile.templateSuffix}`,
624+
isolation: "sandbox",
625+
availability: "available",
626+
capabilities: deployedOrbCapabilities,
627+
}))
628+
: [],
629+
)
539630
: Output.map(selfhostProfiles.profilesJson, (profilesJson) =>
540-
JSON.stringify({
541-
version: 1,
542-
defaultProfileId: defaultE2BOrbProfile.id,
543-
profiles: JSON.parse(profilesJson).map(
631+
runnerProfileCatalog(
632+
JSON.parse(profilesJson).map(
544633
(profile: Record<string, unknown>) => ({
545634
...profile,
546635
adapter: "e2b",
547636
isolation: "sandbox",
548637
availability: "available",
549-
capabilities: [
550-
"git",
551-
"environment-variables",
552-
"internet-access",
553-
"persistent-workspace",
554-
"pause-resume",
555-
],
638+
capabilities: deployedOrbCapabilities,
556639
}),
557640
),
558-
}),
641+
),
559642
),
560643
DX_SOURCE_CONTROL_SCHEMA_VERSION: sourceControlSchemaVersion,
561644
DX_SOURCE_SHALLOW_CLONE: configuration.sourceShallowClone
562645
? "true"
563646
: "false",
564647
DX_MANAGED_SSH_SIGNING_ENABLED: "true",
648+
...(installedPlugins === ""
649+
? {}
650+
: { DX_INSTALLED_PLUGINS: installedPlugins }),
565651
...(configuration.signupEnabled ? { DX_SIGNUP_ENABLED: "true" } : {}),
566652
...(Option.isSome(configuration.githubCopilotClientId)
567653
? {
@@ -603,8 +689,9 @@ export default Alchemy.Stack(
603689
DX_CONFIG_ENCRYPTION_KEYS: encryptionKeyring,
604690
DX_INTEGRATION_GITHUB_APP: githubApp,
605691
DX_WORKLOAD_IDENTITY_SIGNING_KEYS: workloadIdentitySigningKeys,
606-
E2B_API_KEY: e2bApiKey,
692+
...(e2bApiKey === undefined ? {} : { E2B_API_KEY: e2bApiKey }),
607693
...(sarvamApiKey !== undefined ? { SARVAM_API_KEY: sarvamApiKey } : {}),
694+
...(exaApiKey !== undefined ? { EXA_API_KEY: exaApiKey } : {}),
608695
...(bitbucketOAuth !== undefined
609696
? {
610697
DX_INTEGRATION_BITBUCKET_OAUTH: bitbucketOAuth,
@@ -619,7 +706,17 @@ export default Alchemy.Stack(
619706
"workers-ai": {
620707
[aiBinding.name]: Cloudflare.Workers.AI(aiBinding.name),
621708
},
622-
"durable-object": durableObjectBindings,
709+
"durable-object": {
710+
...durableObjectBindings,
711+
...(orbContainers === undefined
712+
? {}
713+
: {
714+
ORB_CONTAINER: Cloudflare.DurableObject("ORB_CONTAINER", {
715+
className: "OrbContainerObject",
716+
scriptName: orbContainers.workerName,
717+
}),
718+
}),
719+
},
623720
});
624721

625722
const bootstrap = yield* Command.Exec("Bootstrap", {
@@ -651,7 +748,7 @@ export default Alchemy.Stack(
651748
DX_BOOTSTRAP_REPOSITORY: configuration.bootstrapRepository,
652749
}),
653750
DX_BOOTSTRAP_DATABASE_ID: database.databaseId,
654-
DX_BOOTSTRAP_RUNNER_PROFILE_ID: defaultE2BOrbProfile.id,
751+
DX_BOOTSTRAP_RUNNER_PROFILE_ID: defaultOrbProfileId,
655752
},
656753
memo: false,
657754
timeout: "3 minutes",

‎apps/core/migration-manifest.json‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
"version": 1,
33
"d1Directory": "migrations",
44
"previousAcceptedD1Migration": "0000_baseline_v0.1.0.sql",
5-
"acceptedDestructiveD1Migrations": ["0002_release_v0.1.2.sql"],
5+
"acceptedDestructiveD1Migrations": [
6+
"0002_release_v0.1.2.sql",
7+
"0003_release_v0.2.0.sql"
8+
],
69
"d1": [
710
{
811
"filename": "0000_baseline_v0.1.0.sql",
@@ -18,6 +21,11 @@
1821
"filename": "0002_release_v0.1.2.sql",
1922
"sha256": "cf1f518a05062a8c4204694833640c5c9f6b811bb1b020826fa2a0500a308c55",
2023
"classification": "destructive"
24+
},
25+
{
26+
"filename": "0003_release_v0.2.0.sql",
27+
"sha256": "d6418d54cff30515745be2f50b114813bb9ad31e5125058b95cb4b8eb0720a4a",
28+
"classification": "destructive"
2129
}
2230
],
2331
"durableObjects": [

0 commit comments

Comments
 (0)