effect-cf 0.27.0 → 0.28.1
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/CHANGELOG.md +18 -0
- package/README.md +6 -0
- package/dist/{Artifacts-DcoXcRP5.d.mts → Artifacts-DnHQA-Ax.d.mts} +42 -25
- package/dist/{Artifacts-BhWrdyqX.mjs → Artifacts-rq3hUKQE.mjs} +46 -30
- package/dist/{Binding-COCtoJXa.d.mts → Binding-xJJJPmiD.d.mts} +6 -5
- package/dist/ComputerArtifacts.d.mts +1 -1
- package/dist/ComputerArtifacts.mjs +9 -9
- package/dist/ComputerWorkspace.d.mts +5 -5
- package/dist/ComputerWorkspace.mjs +107 -75
- package/dist/ComputerWorkspaceHost.d.mts +1 -1
- package/dist/ComputerWorkspaceHost.mjs +18 -16
- package/dist/{DurableObjectState-Dux8KfjG.mjs → DurableObjectState-BjkK2kwH.mjs} +3 -3
- package/dist/{DurableObjectState-biHrHwrh.d.mts → DurableObjectState-OupNMMUl.d.mts} +89 -64
- package/dist/{ErrorMessage-_lg53p3W.mjs → ErrorMessage-BM0K-Nik.mjs} +1 -4
- package/dist/{Hyperdrive-6p59yyVk.d.mts → Hyperdrive-z-9fFz15.d.mts} +2 -2
- package/dist/HyperdrivePg.d.mts +2 -2
- package/dist/Vitest.d.mts +6 -5
- package/dist/Vitest.mjs +2 -2
- package/dist/{WorkflowBinding-zlRPCXVf.d.mts → WorkflowBinding-DUZtKCVM.d.mts} +5 -10
- package/dist/index.d.mts +88 -62
- package/dist/index.mjs +291 -181
- package/package.json +1 -1
- package/src/AiGateway.ts +62 -7
- package/src/AnalyticsEngine.ts +17 -13
- package/src/Artifacts.ts +111 -47
- package/src/Binding.ts +34 -23
- package/src/BrowserRendering.ts +72 -33
- package/src/CloudflareOtlp.ts +21 -11
- package/src/ComputerArtifacts.ts +17 -9
- package/src/ComputerWorkspace.ts +202 -98
- package/src/ComputerWorkspaceHost.ts +55 -27
- package/src/ContainerNamespace.ts +8 -9
- package/src/D1.ts +8 -14
- package/src/DurableObject.ts +33 -13
- package/src/DurableObjectAlarm.ts +17 -5
- package/src/DurableObjectDefinition.ts +89 -72
- package/src/DurableObjectNamespace.ts +26 -12
- package/src/DurableObjectRpcWebSocket.ts +9 -10
- package/src/DurableObjectState.ts +1 -0
- package/src/DurableObjectStorage.ts +5 -2
- package/src/DurableObjectWebSocket.ts +4 -1
- package/src/Email.ts +26 -25
- package/src/Hyperdrive.ts +4 -10
- package/src/Images.ts +12 -14
- package/src/Kv.ts +15 -17
- package/src/Queue.ts +2 -1
- package/src/QueueBinding.ts +7 -12
- package/src/QueueDefinition.ts +7 -2
- package/src/R2.ts +33 -24
- package/src/Rpc.ts +15 -21
- package/src/RpcDefinition.ts +33 -38
- package/src/ServiceBinding.ts +26 -8
- package/src/Vectorize.ts +45 -18
- package/src/Vitest.ts +9 -3
- package/src/WebTransport.ts +11 -5
- package/src/Worker.ts +97 -24
- package/src/WorkerDefinition.ts +143 -63
- package/src/WorkersAi.ts +50 -28
- package/src/Workflow.ts +66 -13
- package/src/WorkflowBinding.ts +18 -25
- package/src/WorkflowDefinition.ts +4 -2
- package/src/internal/Entrypoint.ts +29 -13
- package/src/internal/ErrorMessage.ts +7 -6
- package/src/internal/RpcInvocation.ts +34 -11
- package/src/internal/Runtime.ts +33 -22
- package/src/internal/Telemetry.ts +17 -10
- package/src/internal/WorkerContext.ts +3 -3
package/src/ComputerWorkspace.ts
CHANGED
|
@@ -27,7 +27,7 @@ import type {
|
|
|
27
27
|
GitLogOptions as CloudflareGitLogOptions,
|
|
28
28
|
GitUpdateRefOptions as CloudflareGitUpdateRefOptions,
|
|
29
29
|
} from "@cloudflare/computer/git";
|
|
30
|
-
import { Context, Effect, Layer, Schema, type Scope, Stream } from "effect";
|
|
30
|
+
import { Context, Effect, Layer, Predicate, Schema, type Scope, Stream } from "effect";
|
|
31
31
|
|
|
32
32
|
import * as ComputerArtifacts from "./ComputerArtifacts";
|
|
33
33
|
import { DurableObjectState } from "./DurableObjectState";
|
|
@@ -369,7 +369,7 @@ export type ComputerWorkspaceThink = {
|
|
|
369
369
|
};
|
|
370
370
|
|
|
371
371
|
/** Effect service over every client surface exposed by Cloudflare Computer. */
|
|
372
|
-
export interface
|
|
372
|
+
export interface ComputerWorkspaceService {
|
|
373
373
|
readonly fs: ComputerWorkspaceFilesystem;
|
|
374
374
|
readonly git: ComputerWorkspaceGit;
|
|
375
375
|
readonly runtime: ComputerWorkspaceRuntime;
|
|
@@ -403,52 +403,95 @@ export interface ComputerWorkspaceShape {
|
|
|
403
403
|
readonly disposeExec: ComputerWorkspaceRuntime["disposeExec"];
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
export type { ComputerWorkspaceService as "ComputerWorkspaceShape" };
|
|
407
|
+
|
|
408
|
+
interface WorkspaceFsErrorProperties {
|
|
409
|
+
operation: string;
|
|
410
|
+
path: string;
|
|
411
|
+
message: string;
|
|
412
|
+
cause: unknown;
|
|
413
|
+
code?: string;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
interface WorkspaceOperationErrorProperties {
|
|
417
|
+
operation: string;
|
|
418
|
+
message: string;
|
|
419
|
+
cause: unknown;
|
|
420
|
+
code?: string;
|
|
421
|
+
}
|
|
422
|
+
|
|
406
423
|
const errorMessage = (cause: unknown): string =>
|
|
407
424
|
cause instanceof Error ? cause.message : String(cause);
|
|
408
425
|
|
|
409
426
|
const errorCode = (cause: unknown): string | undefined => {
|
|
410
|
-
if (
|
|
411
|
-
return
|
|
427
|
+
if (Predicate.hasProperty(cause, "code") && Predicate.isString(cause.code)) {
|
|
428
|
+
return cause.code;
|
|
412
429
|
}
|
|
413
430
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
return typeof code === "string" ? code : undefined;
|
|
431
|
+
return undefined;
|
|
417
432
|
};
|
|
418
433
|
|
|
419
|
-
const fsError = (operation: string, path: string, cause: unknown) =>
|
|
420
|
-
|
|
434
|
+
const fsError = (operation: string, path: string, cause: unknown) => {
|
|
435
|
+
const properties: WorkspaceFsErrorProperties = {
|
|
421
436
|
operation,
|
|
422
437
|
path,
|
|
423
438
|
message: errorMessage(cause),
|
|
424
439
|
cause,
|
|
425
|
-
|
|
426
|
-
|
|
440
|
+
};
|
|
441
|
+
const code = errorCode(cause);
|
|
442
|
+
|
|
443
|
+
if (code !== undefined) {
|
|
444
|
+
properties.code = code;
|
|
445
|
+
}
|
|
427
446
|
|
|
428
|
-
|
|
429
|
-
|
|
447
|
+
return WorkspaceFsError.make(properties);
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
const gitError = (operation: string, cause: unknown) => {
|
|
451
|
+
const properties: WorkspaceOperationErrorProperties = {
|
|
430
452
|
operation,
|
|
431
453
|
message: errorMessage(cause),
|
|
432
454
|
cause,
|
|
433
|
-
|
|
434
|
-
|
|
455
|
+
};
|
|
456
|
+
const code = errorCode(cause);
|
|
457
|
+
|
|
458
|
+
if (code !== undefined) {
|
|
459
|
+
properties.code = code;
|
|
460
|
+
}
|
|
435
461
|
|
|
436
|
-
|
|
437
|
-
|
|
462
|
+
return WorkspaceGitError.make(properties);
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
const execError = (operation: string, cause: unknown) => {
|
|
466
|
+
const properties: WorkspaceOperationErrorProperties = {
|
|
438
467
|
operation,
|
|
439
468
|
message: errorMessage(cause),
|
|
440
469
|
cause,
|
|
441
|
-
|
|
442
|
-
|
|
470
|
+
};
|
|
471
|
+
const code = errorCode(cause);
|
|
443
472
|
|
|
444
|
-
|
|
445
|
-
|
|
473
|
+
if (code !== undefined) {
|
|
474
|
+
properties.code = code;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return WorkspaceExecError.make(properties);
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
const assetsError = (operation: string, path: string, cause: unknown) => {
|
|
481
|
+
const properties: WorkspaceFsErrorProperties = {
|
|
446
482
|
operation,
|
|
447
483
|
path,
|
|
448
484
|
message: errorMessage(cause),
|
|
449
485
|
cause,
|
|
450
|
-
|
|
451
|
-
|
|
486
|
+
};
|
|
487
|
+
const code = errorCode(cause);
|
|
488
|
+
|
|
489
|
+
if (code !== undefined) {
|
|
490
|
+
properties.code = code;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return WorkspaceAssetsError.make(properties);
|
|
494
|
+
};
|
|
452
495
|
|
|
453
496
|
const tryFs = <A>(operation: string, path: string, evaluate: () => Promise<A>) =>
|
|
454
497
|
Effect.tryPromise({
|
|
@@ -479,6 +522,8 @@ const makeFilesystem = (fsClient: CloudflareWorkspaceFilesystem): ComputerWorksp
|
|
|
479
522
|
);
|
|
480
523
|
});
|
|
481
524
|
|
|
525
|
+
// SAFETY: the implementation branches on the declared encoding discriminant and returns the
|
|
526
|
+
// corresponding Cloudflare read result for both overloads.
|
|
482
527
|
const readFile = readFileImplementation as WorkspaceReadFile;
|
|
483
528
|
|
|
484
529
|
const stat = Effect.fn("ComputerWorkspace.fs.stat", {
|
|
@@ -640,14 +685,14 @@ const makeGit = (gitClient: CloudflareGitClient): ComputerWorkspaceGit => {
|
|
|
640
685
|
attributes: { family: "git", operation: "log" },
|
|
641
686
|
})(function* (options?: WorkspaceGitLogOptions) {
|
|
642
687
|
const { maxCount, ...upstreamOptions } = options ?? {};
|
|
688
|
+
const logOptions: CloudflareGitLogOptions = { ...upstreamOptions };
|
|
689
|
+
|
|
690
|
+
if (logOptions.depth === undefined && maxCount !== undefined) {
|
|
691
|
+
logOptions.depth = maxCount;
|
|
692
|
+
}
|
|
693
|
+
|
|
643
694
|
const commits = yield* Effect.tryPromise({
|
|
644
|
-
try: () =>
|
|
645
|
-
gitClient.log({
|
|
646
|
-
...upstreamOptions,
|
|
647
|
-
...(upstreamOptions.depth === undefined && maxCount !== undefined
|
|
648
|
-
? { depth: maxCount }
|
|
649
|
-
: {}),
|
|
650
|
-
}),
|
|
695
|
+
try: () => gitClient.log(logOptions),
|
|
651
696
|
catch: (cause) => gitError("log", cause),
|
|
652
697
|
});
|
|
653
698
|
|
|
@@ -657,7 +702,7 @@ const makeGit = (gitClient: CloudflareGitClient): ComputerWorkspaceGit => {
|
|
|
657
702
|
const revParseImplementation = Effect.fn("ComputerWorkspace.git.revParse", {
|
|
658
703
|
attributes: { family: "git", operation: "revParse" },
|
|
659
704
|
})(function* (input: string | Parameters<CloudflareGitClient["revParse"]>[0]) {
|
|
660
|
-
const options =
|
|
705
|
+
const options = Predicate.isString(input) ? { ref: input } : input;
|
|
661
706
|
|
|
662
707
|
return yield* Effect.tryPromise({
|
|
663
708
|
try: () => gitClient.revParse(options),
|
|
@@ -665,19 +710,21 @@ const makeGit = (gitClient: CloudflareGitClient): ComputerWorkspaceGit => {
|
|
|
665
710
|
});
|
|
666
711
|
});
|
|
667
712
|
|
|
713
|
+
// SAFETY: the implementation normalizes the string overload to the exact options object accepted
|
|
714
|
+
// by Cloudflare and forwards the options overload unchanged.
|
|
668
715
|
const revParse = revParseImplementation as ComputerWorkspaceGit["revParse"];
|
|
669
716
|
|
|
670
717
|
return {
|
|
671
|
-
clone: method("clone", (options) => gitClient.clone(options
|
|
672
|
-
diff: method("diff", (options) => gitClient.diff(options
|
|
673
|
-
diffSummary: method("diffSummary", (options) =>
|
|
674
|
-
gitClient.diffSummary(options
|
|
718
|
+
clone: method("clone", (options: CloudflareGitCloneOptions) => gitClient.clone(options)),
|
|
719
|
+
diff: method("diff", (options?: CloudflareGitDiffOptions) => gitClient.diff(options)),
|
|
720
|
+
diffSummary: method("diffSummary", (options?: CloudflareGitDiffOptions) =>
|
|
721
|
+
gitClient.diffSummary(options),
|
|
675
722
|
),
|
|
676
723
|
init: method("init", (options) => gitClient.init(options)),
|
|
677
724
|
status: method("status", (options) => gitClient.status(options)),
|
|
678
725
|
add: method("add", (options) => gitClient.add(options)),
|
|
679
726
|
rm: method("rm", (options) => gitClient.rm(options)),
|
|
680
|
-
commit: method("commit", (options) => gitClient.commit(options
|
|
727
|
+
commit: method("commit", (options: CloudflareGitCommitOptions) => gitClient.commit(options)),
|
|
681
728
|
log,
|
|
682
729
|
show: method("show", (options) => gitClient.show(options)),
|
|
683
730
|
revParse,
|
|
@@ -692,7 +739,7 @@ const makeGit = (gitClient: CloudflareGitClient): ComputerWorkspaceGit => {
|
|
|
692
739
|
tagDelete: method("tagDelete", (options) => gitClient.tagDelete(options)),
|
|
693
740
|
tagList: method("tagList", (options) => gitClient.tagList(options)),
|
|
694
741
|
checkout: method("checkout", (options) => gitClient.checkout(options)),
|
|
695
|
-
fetch: method("fetch", (options) => gitClient.fetch(options
|
|
742
|
+
fetch: method("fetch", (options?: CloudflareGitFetchOptions) => gitClient.fetch(options)),
|
|
696
743
|
push: method("push", (options) => gitClient.push(options)),
|
|
697
744
|
pull: method("pull", (options) => gitClient.pull(options)),
|
|
698
745
|
merge: method("merge", (options) => gitClient.merge(options)),
|
|
@@ -701,8 +748,8 @@ const makeGit = (gitClient: CloudflareGitClient): ComputerWorkspaceGit => {
|
|
|
701
748
|
remoteList: method("remoteList", (options) => gitClient.remoteList(options)),
|
|
702
749
|
hashObject: method("hashObject", (options) => gitClient.hashObject(options)),
|
|
703
750
|
catFile: method("catFile", (options) => gitClient.catFile(options)),
|
|
704
|
-
updateRef: method("updateRef", (options) =>
|
|
705
|
-
gitClient.updateRef(options
|
|
751
|
+
updateRef: method("updateRef", (options: CloudflareGitUpdateRefOptions) =>
|
|
752
|
+
gitClient.updateRef(options),
|
|
706
753
|
),
|
|
707
754
|
configGet: method("configGet", (options) => gitClient.configGet(options)),
|
|
708
755
|
configSet: method("configSet", (options) => gitClient.configSet(options)),
|
|
@@ -712,7 +759,7 @@ const makeGit = (gitClient: CloudflareGitClient): ComputerWorkspaceGit => {
|
|
|
712
759
|
reset: method("reset", (options) => gitClient.reset(options)),
|
|
713
760
|
clean: method("clean", (options) => gitClient.clean(options)),
|
|
714
761
|
cli: method("cli", (input) => gitClient.cli(input)),
|
|
715
|
-
}
|
|
762
|
+
} satisfies ComputerWorkspaceGit;
|
|
716
763
|
};
|
|
717
764
|
|
|
718
765
|
const runtimeExecOptions = <Encoding extends WorkspaceExecEncoding>(
|
|
@@ -720,13 +767,19 @@ const runtimeExecOptions = <Encoding extends WorkspaceExecEncoding>(
|
|
|
720
767
|
): CloudflareRuntimeExecOptions => {
|
|
721
768
|
const { encoding = "utf8", timeoutMillis, timeoutMs, ...rest } = options ?? {};
|
|
722
769
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
770
|
+
const runtimeOptions: CloudflareRuntimeExecOptions = { ...rest };
|
|
771
|
+
|
|
772
|
+
if (encoding === "utf8") {
|
|
773
|
+
runtimeOptions.encoding = "utf8";
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
const selectedTimeout = timeoutMs ?? timeoutMillis;
|
|
777
|
+
|
|
778
|
+
if (selectedTimeout !== undefined) {
|
|
779
|
+
runtimeOptions.timeoutMs = selectedTimeout;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
return runtimeOptions;
|
|
730
783
|
};
|
|
731
784
|
|
|
732
785
|
const runtimeGetOptions = <Encoding extends WorkspaceExecEncoding>(
|
|
@@ -734,34 +787,47 @@ const runtimeGetOptions = <Encoding extends WorkspaceExecEncoding>(
|
|
|
734
787
|
): CloudflareRuntimeGetOptions => {
|
|
735
788
|
const { encoding = "utf8", ...rest } = options ?? {};
|
|
736
789
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
790
|
+
const runtimeOptions: CloudflareRuntimeGetOptions = { ...rest };
|
|
791
|
+
|
|
792
|
+
if (encoding === "utf8") {
|
|
793
|
+
runtimeOptions.encoding = "utf8";
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
return runtimeOptions;
|
|
741
797
|
};
|
|
742
798
|
|
|
743
799
|
const wrapRuntimeResult = <Encoding extends WorkspaceExecEncoding>(
|
|
744
800
|
result: CloudflareWorkspaceRuntimeResult<CloudflareEncoding<Encoding>>,
|
|
745
|
-
): WorkspaceExecResult<Encoding> =>
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
stdout
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
801
|
+
): WorkspaceExecResult<Encoding> => {
|
|
802
|
+
// SAFETY: Cloudflare's result encoding generic determines stdout and stderr in the same way as
|
|
803
|
+
// WorkspaceExecChunk; CloudflareEncoding maps the public "binary" name to upstream undefined.
|
|
804
|
+
const stdout = result.stdout as WorkspaceExecChunk<Encoding>;
|
|
805
|
+
// SAFETY: the same encoding invariant applies independently to stderr.
|
|
806
|
+
const stderr = result.stderr as WorkspaceExecChunk<Encoding>;
|
|
807
|
+
const wrapped = {
|
|
808
|
+
status: result.status,
|
|
809
|
+
exitCode: result.exitCode,
|
|
810
|
+
stdout,
|
|
811
|
+
stderr,
|
|
812
|
+
pushed: result.pushed,
|
|
813
|
+
pulled: result.pulled,
|
|
814
|
+
skipped: result.skipped,
|
|
815
|
+
sync: result.sync,
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
return result.value === undefined ? wrapped : { ...wrapped, value: result.value };
|
|
819
|
+
};
|
|
756
820
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
821
|
+
type AnyWorkspaceExecEvent = WorkspaceExecEvent<"utf8"> | WorkspaceExecEvent<"binary">;
|
|
822
|
+
|
|
823
|
+
const wrapRuntimeEvent = (
|
|
824
|
+
event: CloudflareWorkspaceRuntimeEvent<"utf8" | undefined>,
|
|
825
|
+
): AnyWorkspaceExecEvent => {
|
|
760
826
|
switch (event.name) {
|
|
761
827
|
case "stdout": {
|
|
762
|
-
const chunk = event.value
|
|
828
|
+
const chunk = event.value;
|
|
763
829
|
|
|
764
|
-
return (
|
|
830
|
+
return Predicate.isString(chunk)
|
|
765
831
|
? { _tag: "Stdout", id: event.id, sequence: event.seq, chunk, text: chunk }
|
|
766
832
|
: {
|
|
767
833
|
_tag: "Stdout",
|
|
@@ -769,12 +835,12 @@ const wrapRuntimeEvent = <Encoding extends WorkspaceExecEncoding>(
|
|
|
769
835
|
sequence: event.seq,
|
|
770
836
|
chunk,
|
|
771
837
|
bytes: chunk,
|
|
772
|
-
}
|
|
838
|
+
};
|
|
773
839
|
}
|
|
774
840
|
case "stderr": {
|
|
775
|
-
const chunk = event.value
|
|
841
|
+
const chunk = event.value;
|
|
776
842
|
|
|
777
|
-
return (
|
|
843
|
+
return Predicate.isString(chunk)
|
|
778
844
|
? { _tag: "Stderr", id: event.id, sequence: event.seq, chunk, text: chunk }
|
|
779
845
|
: {
|
|
780
846
|
_tag: "Stderr",
|
|
@@ -782,29 +848,35 @@ const wrapRuntimeEvent = <Encoding extends WorkspaceExecEncoding>(
|
|
|
782
848
|
sequence: event.seq,
|
|
783
849
|
chunk,
|
|
784
850
|
bytes: chunk,
|
|
785
|
-
}
|
|
851
|
+
};
|
|
786
852
|
}
|
|
787
853
|
case "exit":
|
|
788
|
-
|
|
789
|
-
_tag: "Exit",
|
|
854
|
+
const exitEvent = {
|
|
855
|
+
_tag: "Exit" as const,
|
|
790
856
|
id: event.id,
|
|
791
857
|
sequence: event.seq,
|
|
792
858
|
exitCode: event.code,
|
|
793
|
-
...(event.result === undefined ? {} : { value: event.result }),
|
|
794
859
|
};
|
|
860
|
+
|
|
861
|
+
return event.result === undefined ? exitEvent : { ...exitEvent, value: event.result };
|
|
795
862
|
}
|
|
796
863
|
};
|
|
797
864
|
|
|
798
865
|
const wrapRun = <Encoding extends WorkspaceExecEncoding>(
|
|
799
866
|
handle: CloudflareWorkspaceRuntimeExecHandle<CloudflareEncoding<Encoding>>,
|
|
800
867
|
): WorkspaceExecRun<Encoding> => {
|
|
868
|
+
// SAFETY: wrapRuntimeEvent preserves Cloudflare's encoding-specific event arm; this adapter
|
|
869
|
+
// restores the correlation hidden when the implementation handles both upstream encodings.
|
|
870
|
+
const mapRuntimeEvent = wrapRuntimeEvent as (
|
|
871
|
+
event: CloudflareWorkspaceRuntimeEvent<CloudflareEncoding<Encoding>>,
|
|
872
|
+
) => WorkspaceExecEvent<Encoding>;
|
|
801
873
|
const events = Stream.fromReadableStream<
|
|
802
874
|
CloudflareWorkspaceRuntimeEvent<CloudflareEncoding<Encoding>>,
|
|
803
875
|
WorkspaceExecError
|
|
804
876
|
>({
|
|
805
877
|
evaluate: () => handle,
|
|
806
878
|
onError: (cause) => execError("events", cause),
|
|
807
|
-
}).pipe(Stream.map(
|
|
879
|
+
}).pipe(Stream.map(mapRuntimeEvent));
|
|
808
880
|
|
|
809
881
|
const result = Effect.tryPromise({
|
|
810
882
|
try: () => handle.result(),
|
|
@@ -834,23 +906,29 @@ const makeRuntime = (client: CloudflareWorkspaceClient): ComputerWorkspaceRuntim
|
|
|
834
906
|
optionsOrValue?: WorkspaceExecOptions<Encoding> | CloudflareShellValue,
|
|
835
907
|
...remainingValues: Array<CloudflareShellValue>
|
|
836
908
|
) {
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
909
|
+
// SAFETY: the WorkspaceExec overload associates string sources with an options object; template
|
|
910
|
+
// invocations associate the second argument with a shell interpolation value.
|
|
911
|
+
const options = Predicate.isString(source)
|
|
912
|
+
? (optionsOrValue as WorkspaceExecOptions<Encoding> | undefined)
|
|
913
|
+
: undefined;
|
|
841
914
|
|
|
842
915
|
yield* Effect.annotateCurrentSpan({ backend: options?.backend, runId: options?.id });
|
|
843
916
|
const handle = yield* Effect.acquireRelease(
|
|
844
917
|
Effect.tryPromise({
|
|
845
918
|
try: () => {
|
|
846
|
-
if (
|
|
919
|
+
if (Predicate.isString(source)) {
|
|
847
920
|
return client.runtime.exec(source, runtimeExecOptions(options));
|
|
848
921
|
}
|
|
849
922
|
|
|
850
923
|
const values =
|
|
851
924
|
optionsOrValue === undefined
|
|
852
925
|
? remainingValues
|
|
853
|
-
: [
|
|
926
|
+
: [
|
|
927
|
+
// SAFETY: this branch is reachable only for the tagged-template overload, whose
|
|
928
|
+
// second argument is the first Cloudflare shell interpolation value.
|
|
929
|
+
optionsOrValue as CloudflareShellValue,
|
|
930
|
+
...remainingValues,
|
|
931
|
+
];
|
|
854
932
|
|
|
855
933
|
return client.runtime.exec(source, ...values);
|
|
856
934
|
},
|
|
@@ -859,10 +937,13 @@ const makeRuntime = (client: CloudflareWorkspaceClient): ComputerWorkspaceRuntim
|
|
|
859
937
|
releaseRun,
|
|
860
938
|
);
|
|
861
939
|
|
|
940
|
+
// SAFETY: runtimeExecOptions carries Encoding to Cloudflare's corresponding handle overload.
|
|
862
941
|
return wrapRun<Encoding>(
|
|
863
942
|
handle as CloudflareWorkspaceRuntimeExecHandle<CloudflareEncoding<Encoding>>,
|
|
864
943
|
);
|
|
865
944
|
});
|
|
945
|
+
// SAFETY: execImplementation implements each overload by preserving the source/encoding
|
|
946
|
+
// relationship and delegates tagged-template inputs to Cloudflare's tagged-template overload.
|
|
866
947
|
const exec = execImplementation as WorkspaceExec;
|
|
867
948
|
|
|
868
949
|
const getExecImplementation = Effect.fn("ComputerWorkspace.runtime.getExec", {
|
|
@@ -880,10 +961,13 @@ const makeRuntime = (client: CloudflareWorkspaceClient): ComputerWorkspaceRuntim
|
|
|
880
961
|
releaseRun,
|
|
881
962
|
);
|
|
882
963
|
|
|
964
|
+
// SAFETY: runtimeGetOptions carries Encoding to Cloudflare's corresponding handle overload.
|
|
883
965
|
return wrapRun<Encoding>(
|
|
884
966
|
handle as CloudflareWorkspaceRuntimeExecHandle<CloudflareEncoding<Encoding>>,
|
|
885
967
|
);
|
|
886
968
|
});
|
|
969
|
+
// SAFETY: getExecImplementation preserves the option encoding and therefore satisfies each
|
|
970
|
+
// WorkspaceGetExec overload.
|
|
887
971
|
const getExec = getExecImplementation as WorkspaceGetExec;
|
|
888
972
|
|
|
889
973
|
const killExec = Effect.fn("ComputerWorkspace.runtime.killExec", {
|
|
@@ -921,6 +1005,8 @@ const makeRuntime = (client: CloudflareWorkspaceClient): ComputerWorkspaceRuntim
|
|
|
921
1005
|
}),
|
|
922
1006
|
);
|
|
923
1007
|
});
|
|
1008
|
+
// SAFETY: execCollectImplementation delegates to the checked exec overload implementation and
|
|
1009
|
+
// returns the result associated with that same encoding.
|
|
924
1010
|
const execCollect = execCollectImplementation as WorkspaceExecCollect;
|
|
925
1011
|
|
|
926
1012
|
return { exec, execCollect, getExec, killExec, disposeExec };
|
|
@@ -973,50 +1059,59 @@ const makeThink = (client: CloudflareWorkspaceClient): ComputerWorkspaceThink |
|
|
|
973
1059
|
return yield* tryFs(`think.${operation}`, path, () => evaluate(...args));
|
|
974
1060
|
});
|
|
975
1061
|
|
|
1062
|
+
const readFile = client.readFile.bind(client);
|
|
1063
|
+
const readFileBytes = client.readFileBytes.bind(client);
|
|
1064
|
+
const writeFile = client.writeFile.bind(client);
|
|
1065
|
+
const readDir = client.readDir.bind(client);
|
|
1066
|
+
const rm = client.rm.bind(client);
|
|
1067
|
+
const glob = client.glob.bind(client);
|
|
1068
|
+
const mkdir = client.mkdir.bind(client);
|
|
1069
|
+
const stat = client.stat.bind(client);
|
|
1070
|
+
|
|
976
1071
|
return {
|
|
977
1072
|
readFile: method(
|
|
978
1073
|
"readFile",
|
|
979
|
-
(path) => path
|
|
980
|
-
(path) =>
|
|
1074
|
+
(path: string) => path,
|
|
1075
|
+
(path: string) => readFile(path),
|
|
981
1076
|
),
|
|
982
1077
|
readFileBytes: method(
|
|
983
1078
|
"readFileBytes",
|
|
984
|
-
(path) => path
|
|
985
|
-
(path) =>
|
|
1079
|
+
(path: string) => path,
|
|
1080
|
+
(path: string) => readFileBytes(path),
|
|
986
1081
|
),
|
|
987
1082
|
writeFile: method(
|
|
988
1083
|
"writeFile",
|
|
989
1084
|
(path: string, _content: string) => path,
|
|
990
|
-
(path: string, content: string) =>
|
|
1085
|
+
(path: string, content: string) => writeFile(path, content),
|
|
991
1086
|
),
|
|
992
1087
|
readDir: method(
|
|
993
1088
|
"readDir",
|
|
994
1089
|
(path: string, _options?: { readonly limit?: number; readonly offset?: number }) => path,
|
|
995
1090
|
(path: string, options?: { readonly limit?: number; readonly offset?: number }) =>
|
|
996
|
-
|
|
1091
|
+
readDir(path, options),
|
|
997
1092
|
),
|
|
998
1093
|
rm: method(
|
|
999
1094
|
"rm",
|
|
1000
1095
|
(path: string, _options?: { readonly recursive?: boolean; readonly force?: boolean }) => path,
|
|
1001
1096
|
(path: string, options?: { readonly recursive?: boolean; readonly force?: boolean }) =>
|
|
1002
|
-
|
|
1097
|
+
rm(path, options),
|
|
1003
1098
|
),
|
|
1004
1099
|
glob: method(
|
|
1005
1100
|
"glob",
|
|
1006
|
-
(pattern) => pattern
|
|
1007
|
-
(pattern) =>
|
|
1101
|
+
(pattern: string) => pattern,
|
|
1102
|
+
(pattern: string) => glob(pattern),
|
|
1008
1103
|
),
|
|
1009
1104
|
mkdir: method(
|
|
1010
1105
|
"mkdir",
|
|
1011
1106
|
(path: string, _options?: { readonly recursive?: boolean }) => path,
|
|
1012
|
-
(path: string, options?: { readonly recursive?: boolean }) =>
|
|
1107
|
+
(path: string, options?: { readonly recursive?: boolean }) => mkdir(path, options),
|
|
1013
1108
|
),
|
|
1014
1109
|
stat: method(
|
|
1015
1110
|
"stat",
|
|
1016
|
-
(path) => path
|
|
1017
|
-
(path) =>
|
|
1111
|
+
(path: string) => path,
|
|
1112
|
+
(path: string) => stat(path),
|
|
1018
1113
|
),
|
|
1019
|
-
}
|
|
1114
|
+
} satisfies ComputerWorkspaceThink;
|
|
1020
1115
|
};
|
|
1021
1116
|
|
|
1022
1117
|
/**
|
|
@@ -1024,14 +1119,22 @@ const makeThink = (client: CloudflareWorkspaceClient): ComputerWorkspaceThink |
|
|
|
1024
1119
|
* {@link ComputerWorkspace.layer} in Durable Objects so the parent client and
|
|
1025
1120
|
* every runtime handle are disposed by Effect `Scope`.
|
|
1026
1121
|
*/
|
|
1027
|
-
export const fromWorkspaceClient = (
|
|
1122
|
+
export const fromWorkspaceClient = (
|
|
1123
|
+
client: CloudflareWorkspaceClient,
|
|
1124
|
+
): ComputerWorkspaceService => {
|
|
1028
1125
|
const fs = makeFilesystem(client.fs);
|
|
1126
|
+
// SAFETY: @cloudflare/computer currently publishes these WorkspaceClient properties as `any`,
|
|
1127
|
+
// while its runtime exposes the concrete clients imported above.
|
|
1029
1128
|
const git = makeGit(client.git as CloudflareGitClient);
|
|
1030
1129
|
const runtime = makeRuntime(client);
|
|
1031
1130
|
const artifacts = ComputerArtifacts.fromClient(
|
|
1131
|
+
// SAFETY: the upstream WorkspaceClient declaration erases this concrete artifact client to
|
|
1132
|
+
// `any`; Workspace always exposes its ArtifactClient here.
|
|
1032
1133
|
client.artifacts as CloudflareComputerArtifactClient,
|
|
1033
1134
|
{ binding: "ComputerWorkspace.artifacts" },
|
|
1034
1135
|
);
|
|
1136
|
+
// SAFETY: the upstream WorkspaceClient declaration erases this optional concrete assets client
|
|
1137
|
+
// to `any`; Workspace exposes AssetsClient | undefined here.
|
|
1035
1138
|
const assets = makeAssets(client.assets as CloudflareComputerAssetsClient | undefined);
|
|
1036
1139
|
const think = makeThink(client);
|
|
1037
1140
|
|
|
@@ -1067,9 +1170,10 @@ export const fromWorkspaceClient = (client: CloudflareWorkspaceClient): Computer
|
|
|
1067
1170
|
};
|
|
1068
1171
|
|
|
1069
1172
|
/** Effect service for the workspace owned by the enclosing Durable Object. */
|
|
1070
|
-
export class ComputerWorkspace extends Context.Service<
|
|
1071
|
-
|
|
1072
|
-
|
|
1173
|
+
export class ComputerWorkspace extends Context.Service<
|
|
1174
|
+
ComputerWorkspace,
|
|
1175
|
+
ComputerWorkspaceService
|
|
1176
|
+
>()("effect-cf/ComputerWorkspace") {
|
|
1073
1177
|
/**
|
|
1074
1178
|
* Acquires the single workspace registered by `withComputerWorkspace` and
|
|
1075
1179
|
* releases its RPC client when the layer scope closes.
|