freestyle-sandboxes 0.0.68 → 0.0.70

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.
Files changed (60) hide show
  1. package/dist/ai/inde.d.cts +1 -1
  2. package/dist/ai/inde.d.mts +1 -1
  3. package/dist/ai/index.d.cts +1 -1
  4. package/dist/ai/index.d.mts +1 -1
  5. package/dist/inde.d.cts +103 -25
  6. package/dist/inde.d.mts +103 -25
  7. package/dist/index-BBXyg0JQ.cjs +3253 -0
  8. package/dist/index-BQHqnjZK.mjs +3231 -0
  9. package/dist/index-CEEa9WHp.cjs +3238 -0
  10. package/dist/index-D1ulQeJR.mjs +3247 -0
  11. package/dist/index-DCF70Xbq.mjs +3246 -0
  12. package/dist/index-H7UNEAjs.cjs +3254 -0
  13. package/dist/index.cjs +249 -12
  14. package/dist/index.d-CXx1AdyW.d.ts +4210 -0
  15. package/dist/index.d.cts +103 -25
  16. package/dist/index.d.mts +103 -25
  17. package/dist/index.mjs +249 -12
  18. package/dist/langgraph/inde.d.cts +1 -1
  19. package/dist/langgraph/inde.d.mts +1 -1
  20. package/dist/langgraph/index.d.cts +1 -1
  21. package/dist/langgraph/index.d.mts +1 -1
  22. package/dist/mastra/inde.d.cts +1 -1
  23. package/dist/mastra/inde.d.mts +1 -1
  24. package/dist/mastra/index.d.cts +1 -1
  25. package/dist/mastra/index.d.mts +1 -1
  26. package/dist/types.gen-1sd31qLV.d.ts +172 -0
  27. package/dist/types.gen-627pxroW.d.ts +830 -0
  28. package/dist/types.gen-BCdfx7yt.d.ts +760 -0
  29. package/dist/types.gen-BVXmFV7d.d.ts +1299 -0
  30. package/dist/types.gen-BaMKzqxQ.d.ts +233 -0
  31. package/dist/types.gen-BtK6PMQy.d.ts +195 -0
  32. package/dist/types.gen-BuhQ5LpB.d.ts +764 -0
  33. package/dist/types.gen-BzRtj_TA.d.ts +725 -0
  34. package/dist/types.gen-C03gaIPq.d.ts +297 -0
  35. package/dist/types.gen-CMuCas4r.d.ts +183 -0
  36. package/dist/types.gen-CZUnqmzP.d.ts +789 -0
  37. package/dist/types.gen-CnEkmbco.d.ts +314 -0
  38. package/dist/types.gen-DDYpuDzZ.d.ts +764 -0
  39. package/dist/types.gen-DHmdEOOa.d.ts +172 -0
  40. package/dist/types.gen-DLYohMJT.d.ts +382 -0
  41. package/dist/types.gen-DbTb_SrD.d.ts +156 -0
  42. package/dist/types.gen-DkQ-Dbs1.d.ts +764 -0
  43. package/dist/{types.gen-BoJEFWW-.d.ts → types.gen-DyY7Deri.d.ts} +55 -1
  44. package/dist/types.gen-MBZCvIhE.d.ts +311 -0
  45. package/dist/types.gen-YhJAHBw8.d.ts +233 -0
  46. package/dist/types.gen-cCnnhnB6.d.ts +182 -0
  47. package/dist/types.gen-mg_JNXrq.d.ts +830 -0
  48. package/dist/types.gen-uDTr6v-7.d.ts +731 -0
  49. package/dist/utils/inde.d.cts +1 -1
  50. package/dist/utils/inde.d.mts +1 -1
  51. package/dist/utils/index.d.cts +1 -1
  52. package/dist/utils/index.d.mts +1 -1
  53. package/openapi/sdk.gen.ts +71 -10
  54. package/openapi/types.gen.ts +233 -28
  55. package/openapi.json +1 -1
  56. package/package.json +2 -2
  57. package/src/dev-server.ts +92 -0
  58. package/src/index.ts +319 -27
  59. package/src/react/dev-server/index.tsx +3 -3
  60. package/.env +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freestyle-sandboxes",
3
- "version": "0.0.68",
3
+ "version": "0.0.70",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -108,4 +108,4 @@
108
108
  "zod": "^3.24.1"
109
109
  },
110
110
  "packageManager": "pnpm@9.11.0+sha512.0a203ffaed5a3f63242cd064c8fb5892366c103e328079318f78062f24ea8c9d50bc6a47aa3567cabefd824d170e78fa2745ed1f16b132e16436146b7688f19b"
111
- }
111
+ }
@@ -0,0 +1,92 @@
1
+ export interface FreestyleDevServer {
2
+ /**
3
+ * The URL for the dev server's HTTP API.
4
+ */
5
+ ephemeralUrl: string;
6
+
7
+ /**
8
+ * The URL to the MCP endpoint for the dev server.
9
+ */
10
+ mcpEphemeralUrl: string;
11
+
12
+ /**
13
+ * The URL for the VSCode server running in the dev server.
14
+ */
15
+ codeServerUrl: string;
16
+
17
+ /**
18
+ * Whether the dev server was just created.
19
+ */
20
+ isNew: boolean;
21
+
22
+ fs: FreestyleDevServerFilesystem;
23
+
24
+ process: FreestyleDevServerProcess;
25
+
26
+ /**
27
+ * Get the status of the dev server
28
+ */
29
+ status(): Promise<{
30
+ installing: boolean;
31
+ devRunning: boolean;
32
+ }>;
33
+
34
+ /**
35
+ * Commit and push changes to the dev server repository
36
+ * @param message The commit message
37
+ */
38
+ commitAndPush(message: string): Promise<void>;
39
+
40
+ /**
41
+ * Shutdown the dev server
42
+ */
43
+ shutdown(): Promise<{
44
+ success: boolean;
45
+ message: string;
46
+ }>;
47
+ }
48
+
49
+ export interface FreestyleDevServerFilesystem {
50
+ /**
51
+ * List files in the dev server directory
52
+ */
53
+ ls(path?: string): Promise<Array<string>>;
54
+
55
+ /**
56
+ * Read a file from the dev server
57
+ * @param path The path to the file
58
+ * @param encoding The encoding to use (defaults to utf-8)
59
+ */
60
+ readFile(path: string, encoding?: string): Promise<string>;
61
+
62
+ /**
63
+ * Write a file to the dev server
64
+ * @param path The path to write to
65
+ * @param content The content to write
66
+ * @param encoding The encoding to use (defaults to utf-8)
67
+ */
68
+ writeFile(
69
+ path: string,
70
+ content: string | ArrayBufferLike,
71
+ encoding?: string
72
+ ): Promise<void>;
73
+
74
+ watch(): AsyncGenerator<{ eventType: string; filename: string }>;
75
+ }
76
+
77
+ export interface FreestyleDevServerProcess {
78
+ /**
79
+ * Execute a command on the dev server
80
+ * @param cmd The command to execute
81
+ * @param background Whether to run the command in the background
82
+ */
83
+ exec(
84
+ cmd: string,
85
+ background?: boolean
86
+ ): Promise<{
87
+ id: string;
88
+ isNew: boolean;
89
+ stdout?: string[];
90
+ stderr?: string[];
91
+ }>;
92
+ }
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ import type {
6
6
  CreatedToken,
7
7
  CreateRepositoryResponseSuccess,
8
8
  DescribePermissionResponseSuccess,
9
+ DevServer,
9
10
  FreestyleCloudstateDeployRequest,
10
11
  FreestyleCloudstateDeploySuccessResponse,
11
12
  FreestyleDeployWebConfiguration,
@@ -30,6 +31,7 @@ import type {
30
31
  ListGitTokensResponseSuccess,
31
32
  ListPermissionResponseSuccess,
32
33
  } from "../openapi/index.ts";
34
+ import { FreestyleDevServer } from "./dev-server.ts";
33
35
 
34
36
  export type {
35
37
  AccessLevel,
@@ -62,22 +64,37 @@ export type {
62
64
  DeploymentBuildOptions,
63
65
  } from "../openapi/index.ts";
64
66
 
67
+ type Options = {
68
+ /**
69
+ * The base URL for the API.
70
+ */
71
+ baseUrl?: string;
72
+ /**
73
+ * The API key to use for requests.
74
+ */
75
+ apiKey?: string;
76
+ /**
77
+ * Custom Headers to be sent with each request.
78
+ */
79
+ headers?: Record<string, string>;
80
+ };
81
+
65
82
  export class FreestyleSandboxes {
66
83
  private client: Client;
67
- constructor(options: {
68
- /**
69
- * The base URL for the API.
70
- */
71
- baseUrl?: string;
72
- /**
73
- * The API key to use for requests.
74
- */
75
- apiKey: string;
76
- /**
77
- * Custom Headers to be sent with each request.
78
- */
79
- headers?: Record<string, string>;
80
- }) {
84
+ options: Options;
85
+
86
+ constructor(options?: Options) {
87
+ this.options = options ?? {};
88
+
89
+ if (!options?.apiKey) {
90
+ this.options.apiKey = process.env.FREESTYLE_API_KEY;
91
+ }
92
+ if (!this.options.apiKey) {
93
+ throw new Error(
94
+ "No API key provided. Please set the FREESTYLE_API_KEY environment variable or configure apiKey when constructing FreestyleSandboxes."
95
+ );
96
+ }
97
+
81
98
  //@ts-expect-error Deno has a weird behavior thats patched here
82
99
  if (typeof Deno !== "undefined") {
83
100
  class FreestyleRequest extends Request {
@@ -93,10 +110,10 @@ export class FreestyleSandboxes {
93
110
  Request = FreestyleRequest;
94
111
  }
95
112
  this.client = createClient({
96
- baseUrl: options.baseUrl ?? "https://api.freestyle.sh",
113
+ baseUrl: this.options?.baseUrl ?? "https://api.freestyle.sh",
97
114
  headers: {
98
- Authorization: `Bearer ${options.apiKey}`,
99
- ...options.headers,
115
+ Authorization: `Bearer ${this.options.apiKey}`,
116
+ ...this.options?.headers,
100
117
  },
101
118
  });
102
119
  }
@@ -803,10 +820,17 @@ export class FreestyleSandboxes {
803
820
  */
804
821
  repoUrl?: string;
805
822
  repoId?: string;
823
+ /**
824
+ * @deprecated
825
+ */
806
826
  repo?: string;
807
827
  baseId?: string;
808
828
  devCommand?: string;
809
- }) {
829
+ preDevCommandOnce?: string;
830
+ envVars?: Record<string, string>;
831
+ computeClass?: string;
832
+ timeout?: number;
833
+ }): Promise<FreestyleDevServer> {
810
834
  function formatHook(serverUrl: string, repoUrl: string) {
811
835
  const hook =
812
836
  serverUrl +
@@ -832,7 +856,7 @@ export class FreestyleSandboxes {
832
856
  }
833
857
 
834
858
  if (response.data.isNew) {
835
- const rId = options.repoId || options.repoUrl.split("/").at(-1)!;
859
+ const rId = options.repoId || options.repoUrl?.split("/").at(-1)!;
836
860
 
837
861
  await this.createGitTrigger({
838
862
  repoId: rId,
@@ -852,19 +876,287 @@ export class FreestyleSandboxes {
852
876
  if (!response.data) {
853
877
  throw new Error(`Failed to request dev server: ${response.error}`);
854
878
  }
879
+
880
+ const data: typeof response.data & { codeServerUrl?: string } =
881
+ response.data;
882
+
883
+ const devServerInstance: DevServer = {
884
+ repoId: options.repoId || options.repo || "",
885
+ kind: "repo",
886
+ };
887
+
888
+ const client = this.client;
889
+
890
+ const that = this;
891
+
855
892
  return {
856
- ...response.data,
857
- // @ts-ignore
858
- mcpEphemeralUrl:
859
- (response.data as any).mcpEphemeralUrl || response.data.url + "/mcp",
860
- ephemeralUrl: response.data.ephemeralUrl ?? response.data.url,
893
+ isNew: data.isNew,
894
+
895
+ ephemeralUrl: data.ephemeralUrl ?? data.url,
896
+
897
+ mcpEphemeralUrl: data.mcpEphemeralUrl ?? data.url + "/mcp",
898
+
861
899
  codeServerUrl:
862
- // @ts-ignore
863
- response.data.codeServerUrl ??
864
- response.data.ephemeralUrl +
900
+ data.codeServerUrl ??
901
+ (data.ephemeralUrl ?? data.url) +
865
902
  "/__freestyle_code_server/?folder=/template",
903
+
904
+ async status() {
905
+ const response = await sandbox_openapi.handleDevServerStatus({
906
+ client,
907
+ body: {
908
+ devServer: devServerInstance,
909
+ },
910
+ });
911
+
912
+ if (response.error) {
913
+ throw new Error(`Failed to get status: ${response.error}`);
914
+ }
915
+
916
+ return {
917
+ installing: response.data.installing,
918
+ devRunning: response.data.devRunning,
919
+ };
920
+ },
921
+
922
+ async commitAndPush(message: string) {
923
+ const response = await sandbox_openapi.handleGitCommitPush({
924
+ client,
925
+ body: {
926
+ devServer: devServerInstance,
927
+ message,
928
+ },
929
+ });
930
+
931
+ if (response.error) {
932
+ throw new Error(`Failed to commit and push: ${response.error}`);
933
+ }
934
+ },
935
+
936
+ async shutdown() {
937
+ const response = await sandbox_openapi.handleShutdownDevServer({
938
+ client,
939
+ body: {
940
+ devServer: devServerInstance,
941
+ },
942
+ });
943
+
944
+ if (response.error) {
945
+ throw new Error(`Failed to shutdown dev server: ${response.error}`);
946
+ }
947
+
948
+ return {
949
+ success: response.data.success,
950
+ message: response.data.message,
951
+ };
952
+ },
953
+
954
+ fs: {
955
+ async ls(path = "") {
956
+ const response =
957
+ await sandbox_openapi.handleReadFileFromEphemeralDevServer({
958
+ client,
959
+ path: {
960
+ filepath: path,
961
+ },
962
+ body: {
963
+ devServer: devServerInstance,
964
+ encoding: "utf-8",
965
+ },
966
+ });
967
+
968
+ if (response.error) {
969
+ throw new Error(`Failed to list directory: ${response.error}`);
970
+ }
971
+
972
+ if (!response.data?.content) {
973
+ return [];
974
+ }
975
+
976
+ if (response.data.content.kind === "directory") {
977
+ return response.data.content.files;
978
+ }
979
+
980
+ return [];
981
+ },
982
+
983
+ async *watch(): AsyncGenerator<{
984
+ eventType: string;
985
+ filename: string;
986
+ }> {
987
+ const response = await that.fetch(
988
+ "/ephemeral/v1/dev-servers/watch-files",
989
+ {
990
+ method: "POST",
991
+ body: JSON.stringify({
992
+ devServer: {
993
+ repoId: devServerInstance.repoId,
994
+ kind: devServerInstance.kind,
995
+ },
996
+ }),
997
+ }
998
+ );
999
+
1000
+ if (!response.ok) {
1001
+ throw new Error(
1002
+ `Failed to fetch stream: ${response.status} ${response.statusText}`
1003
+ );
1004
+ }
1005
+
1006
+ if (!response.body) {
1007
+ throw new Error("Failed to fetch stream: No response body");
1008
+ }
1009
+
1010
+ const reader = response.body.getReader();
1011
+ const decoder = new TextDecoder("utf-8");
1012
+ let buffer = "";
1013
+
1014
+ while (true) {
1015
+ const { done, value } = await reader.read();
1016
+ if (done) break;
1017
+
1018
+ buffer += decoder.decode(value, { stream: true });
1019
+
1020
+ let newlineIndex;
1021
+ while ((newlineIndex = buffer.indexOf("\n")) >= 0) {
1022
+ const line = buffer.slice(0, newlineIndex).trim();
1023
+ buffer = buffer.slice(newlineIndex + 1);
1024
+
1025
+ if (line) {
1026
+ yield JSON.parse(line) as {
1027
+ eventType: string;
1028
+ filename: string;
1029
+ };
1030
+ }
1031
+ }
1032
+ }
1033
+
1034
+ if (buffer.trim()) {
1035
+ yield JSON.parse(buffer.trim()) as {
1036
+ eventType: string;
1037
+ filename: string;
1038
+ };
1039
+ }
1040
+ },
1041
+
1042
+ async readFile(path: string, encoding = "utf-8") {
1043
+ const response =
1044
+ await sandbox_openapi.handleReadFileFromEphemeralDevServer({
1045
+ client,
1046
+ path: {
1047
+ filepath: path,
1048
+ },
1049
+ body: {
1050
+ devServer: devServerInstance,
1051
+ encoding,
1052
+ },
1053
+ });
1054
+
1055
+ if (response.error) {
1056
+ throw new Error(`Failed to read file: ${response.error}`);
1057
+ }
1058
+
1059
+ if (
1060
+ !response.data?.content ||
1061
+ response.data.content.kind !== "file"
1062
+ ) {
1063
+ throw new Error(`Not a file or file not found: ${path}`);
1064
+ }
1065
+
1066
+ return response.data.content.content;
1067
+ },
1068
+
1069
+ async writeFile(
1070
+ path: string,
1071
+ content: string | ArrayBuffer,
1072
+ encoding = "utf-8"
1073
+ ) {
1074
+ const contentStr =
1075
+ typeof content === "string"
1076
+ ? content
1077
+ : new TextDecoder(encoding).decode(content);
1078
+
1079
+ const response =
1080
+ await sandbox_openapi.handleWriteFileFromEphemeralDevServer({
1081
+ client,
1082
+ path: {
1083
+ filepath: path,
1084
+ },
1085
+ body: {
1086
+ devServer: devServerInstance,
1087
+ content: contentStr,
1088
+ encoding,
1089
+ },
1090
+ });
1091
+
1092
+ if (response.error) {
1093
+ throw new Error(`Failed to write file: ${response.error}`);
1094
+ }
1095
+ },
1096
+ },
1097
+
1098
+ process: {
1099
+ async exec(cmd: string, background = false) {
1100
+ const response = await sandbox_openapi.handleExecOnEphemeralDevServer(
1101
+ {
1102
+ client,
1103
+ body: {
1104
+ devServer: devServerInstance,
1105
+ command: cmd,
1106
+ background,
1107
+ },
1108
+ }
1109
+ );
1110
+
1111
+ if (response.error) {
1112
+ throw new Error(`Failed to execute command: ${response.error}`);
1113
+ }
1114
+
1115
+ return {
1116
+ id: response.data.id,
1117
+ isNew: response.data.isNew,
1118
+ stdout: response.data.stdout,
1119
+ stderr: response.data.stderr,
1120
+ };
1121
+ },
1122
+ },
866
1123
  };
867
1124
  }
1125
+
1126
+ fetch(path: string, init?: RequestInit) {
1127
+ const headers = new Headers(init?.headers);
1128
+
1129
+ for (const [key, value] of Object.entries(this.options.headers ?? {})) {
1130
+ if (!headers.has(key)) {
1131
+ headers.append(key, value);
1132
+ }
1133
+ }
1134
+
1135
+ if (!headers.has("Authorization")) {
1136
+ headers.append("Authorization", `Bearer ${this.options.apiKey}`);
1137
+ }
1138
+
1139
+ if (!headers.has("Content-Type")) {
1140
+ headers.append("Content-Type", "application/json");
1141
+ }
1142
+
1143
+ const url = new URL(
1144
+ path,
1145
+ this.options.baseUrl ?? "https://api.freestyle.sh"
1146
+ );
1147
+
1148
+ return fetch(url, {
1149
+ ...(init ?? {}),
1150
+ headers,
1151
+ });
1152
+ }
868
1153
  }
869
1154
 
870
1155
  export * from "../openapi/types.gen.ts";
1156
+
1157
+ // const { process, fs } = await api.requestDevServer({
1158
+ // repoId: "test",
1159
+ // });
1160
+ //
1161
+ // await process.exec()
1162
+ // await fs.ls()
@@ -90,7 +90,7 @@ const FreestyleDevServerInner = React.forwardRef<
90
90
  const iframeRef = React.useRef<HTMLIFrameElement>(null);
91
91
  const [wasLoaded, setWasLoaded] = React.useState(false);
92
92
  const [iframeLoaded, setIframeLoaded] = React.useState(false);
93
-
93
+
94
94
  // Function to refresh the iframe
95
95
  const refreshIframe = React.useCallback(() => {
96
96
  if (iframeRef.current && data?.ephemeralUrl) {
@@ -104,14 +104,14 @@ const FreestyleDevServerInner = React.forwardRef<
104
104
  }, 50);
105
105
  }
106
106
  }, [data?.ephemeralUrl]);
107
-
107
+
108
108
  // Expose refresh method through ref
109
109
  React.useImperativeHandle(
110
110
  ref,
111
111
  () => ({
112
112
  refresh: refreshIframe,
113
113
  }),
114
- [refreshIframe]
114
+ [refreshIframe],
115
115
  );
116
116
 
117
117
  React.useMemo(() => {
package/.env DELETED
@@ -1 +0,0 @@
1
- FREESTYLE_API_KEY=RoZ4n8eAY4ChcgdKV89LjY-Fhvp6Rzqx27bZ4BjHaVf7qpEw7vA7MekK84DdGgZYkR2