@animaapp/anima-sdk-react 0.3.1 → 0.3.5
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/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3192 -3147
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/.storybook/main.ts +0 -25
- package/.storybook/preview.ts +0 -13
- package/.turbo/turbo-build.log +0 -13
- package/.turbo/turbo-dev.log +0 -48
- package/.turbo/turbo-test.log +0 -161
- package/src/index.ts +0 -2
- package/src/stories/useAnimaCodegen.stories.tsx +0 -222
- package/src/useAnimaCodegen.ts +0 -306
- package/src/useFigmaFile.ts +0 -44
- package/src/utils.ts +0 -10
- package/vite.config.ts +0 -27
package/src/useAnimaCodegen.ts
DELETED
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
import { arrayBufferToBase64 } from "./utils";
|
|
2
|
-
import type {
|
|
3
|
-
AnimaSDKResult,
|
|
4
|
-
GetCodeParams,
|
|
5
|
-
StreamCodgenMessage,
|
|
6
|
-
} from "@animaapp/anima-sdk";
|
|
7
|
-
import { CodegenError } from "@animaapp/anima-sdk";
|
|
8
|
-
import { EventSource } from "eventsource";
|
|
9
|
-
import { useImmer } from "use-immer";
|
|
10
|
-
|
|
11
|
-
type LocalAssetsStorage =
|
|
12
|
-
| { strategy: "local"; path: string }
|
|
13
|
-
| { strategy: "local"; filePath: string; referencePath: string };
|
|
14
|
-
|
|
15
|
-
export type UseAnimaParams = Omit<GetCodeParams, "assetsStorage"> & {
|
|
16
|
-
assetsStorage?: GetCodeParams["assetsStorage"] | LocalAssetsStorage;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
type Status = "idle" | "pending" | "success" | "aborted" | "error";
|
|
20
|
-
|
|
21
|
-
type TaskStatus = "pending" | "running" | "finished";
|
|
22
|
-
|
|
23
|
-
type CodegenStatus = {
|
|
24
|
-
status: Status;
|
|
25
|
-
error: CodegenError | null;
|
|
26
|
-
result: AnimaSDKResult | null;
|
|
27
|
-
tasks: {
|
|
28
|
-
fetchDesign: { status: TaskStatus };
|
|
29
|
-
codeGeneration: { status: TaskStatus; progress: number };
|
|
30
|
-
uploadAssets: { status: TaskStatus };
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const defaultProgress: CodegenStatus = {
|
|
35
|
-
status: "idle",
|
|
36
|
-
error: null,
|
|
37
|
-
result: null,
|
|
38
|
-
tasks: {
|
|
39
|
-
fetchDesign: { status: "pending" },
|
|
40
|
-
codeGeneration: { status: "pending", progress: 0 },
|
|
41
|
-
uploadAssets: { status: "pending" },
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
type StreamMessageByType<T extends StreamCodgenMessage["type"]> = Extract<
|
|
46
|
-
StreamCodgenMessage,
|
|
47
|
-
{ type: T }
|
|
48
|
-
>;
|
|
49
|
-
|
|
50
|
-
const getAssetsLocalStrategyParams = (
|
|
51
|
-
localAssetsStorage: LocalAssetsStorage
|
|
52
|
-
) => {
|
|
53
|
-
if ("path" in localAssetsStorage) {
|
|
54
|
-
return {
|
|
55
|
-
filePath: localAssetsStorage.path.replace(/^\//, ""),
|
|
56
|
-
referencePath:
|
|
57
|
-
localAssetsStorage.path === "/" ? "" : localAssetsStorage.path, // Workaround to avoid duplicated slashes in the URL. Ideally, the fix should be done in Codegen.
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
filePath: localAssetsStorage.filePath.replace(/^\//, ""),
|
|
63
|
-
referencePath:
|
|
64
|
-
localAssetsStorage.referencePath === "/"
|
|
65
|
-
? ""
|
|
66
|
-
: localAssetsStorage.referencePath,
|
|
67
|
-
};
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export const useAnimaCodegen = ({
|
|
71
|
-
url,
|
|
72
|
-
method = "POST",
|
|
73
|
-
}: {
|
|
74
|
-
url: string;
|
|
75
|
-
method?: string;
|
|
76
|
-
}) => {
|
|
77
|
-
const [status, updateStatus] = useImmer<CodegenStatus>(defaultProgress);
|
|
78
|
-
|
|
79
|
-
const getCode = async <T extends UseAnimaParams = UseAnimaParams>(
|
|
80
|
-
params: T
|
|
81
|
-
) => {
|
|
82
|
-
updateStatus((draft) => {
|
|
83
|
-
draft.status = "pending";
|
|
84
|
-
draft.error = null;
|
|
85
|
-
draft.result = null;
|
|
86
|
-
draft.tasks = defaultProgress.tasks;
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const initialParams = structuredClone(params);
|
|
90
|
-
|
|
91
|
-
if (params.assetsStorage?.strategy === "local") {
|
|
92
|
-
const { referencePath } = getAssetsLocalStrategyParams(
|
|
93
|
-
params.assetsStorage
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
params.assetsStorage = {
|
|
97
|
-
strategy: "external",
|
|
98
|
-
url: referencePath,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// TODO: We have two workarounds here because of limitations on the `eventsource` package:
|
|
103
|
-
// 1. We need to use the `fetch` function from the `EventSource` constructor to send the request with the correct method and body (https://github.com/EventSource/eventsource/issues/316#issuecomment-2525315835).
|
|
104
|
-
// 2. We need to store the last fetch response to handle errors to read its body response, since it isn't expoted by the package (https://github.com/EventSource/eventsource/blob/8aa7057bccd7fb819372a3b2c1292e7b53424d52/src/EventSource.ts#L348-L376)
|
|
105
|
-
// We might need to use other library, or do it from our self, to improve the code quality.
|
|
106
|
-
let lastFetchResponse: ReturnType<typeof fetch>;
|
|
107
|
-
const es = new EventSource(url, {
|
|
108
|
-
fetch: (url, init) => {
|
|
109
|
-
lastFetchResponse = fetch(url, {
|
|
110
|
-
...init,
|
|
111
|
-
method,
|
|
112
|
-
body: JSON.stringify(params),
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
return lastFetchResponse;
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const promise = new Promise<{
|
|
120
|
-
result: AnimaSDKResult | null;
|
|
121
|
-
error: CodegenError | null;
|
|
122
|
-
}>((resolve) => {
|
|
123
|
-
const result: Partial<AnimaSDKResult> = {};
|
|
124
|
-
|
|
125
|
-
// Add specific event listeners
|
|
126
|
-
es.addEventListener("start", (event) => {
|
|
127
|
-
const message = JSON.parse(event.data) as StreamMessageByType<"start">;
|
|
128
|
-
result.sessionId = message.sessionId;
|
|
129
|
-
|
|
130
|
-
updateStatus((draft) => {
|
|
131
|
-
draft.tasks.fetchDesign.status = "running";
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
es.addEventListener("pre_codegen", (event) => {
|
|
136
|
-
const message = JSON.parse(
|
|
137
|
-
event.data
|
|
138
|
-
) as StreamMessageByType<"pre_codegen">;
|
|
139
|
-
if (message.message === "Anima model built") {
|
|
140
|
-
updateStatus((draft) => {
|
|
141
|
-
draft.tasks.fetchDesign.status = "finished";
|
|
142
|
-
draft.tasks.codeGeneration.status = "running";
|
|
143
|
-
draft.tasks.uploadAssets.status = "running";
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
es.addEventListener("figma_metadata", (e) => {
|
|
149
|
-
const message = JSON.parse(
|
|
150
|
-
e.data
|
|
151
|
-
) as StreamMessageByType<"figma_metadata">;
|
|
152
|
-
result.figmaFileName = message.figmaFileName;
|
|
153
|
-
result.figmaSelectedFrameName = message.figmaSelectedFrameName;
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
es.addEventListener("aborted", () => {
|
|
157
|
-
const error = new CodegenError({ name: "Aborted", reason: "Unknown" });
|
|
158
|
-
|
|
159
|
-
updateStatus((draft) => {
|
|
160
|
-
draft.status = "aborted";
|
|
161
|
-
(draft.result = null), (draft.error = error);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
resolve({
|
|
165
|
-
result: null,
|
|
166
|
-
error,
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
es.addEventListener("generating_code", (event) => {
|
|
171
|
-
const message = JSON.parse(
|
|
172
|
-
event.data
|
|
173
|
-
) as StreamMessageByType<"generating_code">;
|
|
174
|
-
if (message.payload.status === "success") {
|
|
175
|
-
result.files = message.payload.files;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
updateStatus((draft) => {
|
|
179
|
-
draft.tasks.codeGeneration.progress = message.payload.progress;
|
|
180
|
-
draft.tasks.codeGeneration.status = "running";
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
es.addEventListener("codegen_completed", () => {
|
|
185
|
-
updateStatus((draft) => {
|
|
186
|
-
draft.tasks.codeGeneration.status = "finished";
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
es.addEventListener("assets_uploaded", () => {
|
|
191
|
-
updateStatus((draft) => {
|
|
192
|
-
draft.tasks.uploadAssets.status = "finished";
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
es.addEventListener("assets_list", (event) => {
|
|
197
|
-
const message = JSON.parse(
|
|
198
|
-
event.data
|
|
199
|
-
) as StreamMessageByType<"assets_list">;
|
|
200
|
-
|
|
201
|
-
result.assets = message.payload.assets;
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
// TODO: For some reason, we receive errors even after the `done` event is triggered.
|
|
205
|
-
es.addEventListener("error", async (error: ErrorEvent | MessageEvent) => {
|
|
206
|
-
let errorPayload: StreamMessageByType<"error"> | undefined;
|
|
207
|
-
|
|
208
|
-
try {
|
|
209
|
-
if (error instanceof MessageEvent) {
|
|
210
|
-
errorPayload = JSON.parse(error.data);
|
|
211
|
-
} else {
|
|
212
|
-
const response = await lastFetchResponse;
|
|
213
|
-
errorPayload = await response.json();
|
|
214
|
-
}
|
|
215
|
-
} catch {}
|
|
216
|
-
|
|
217
|
-
const codegenError = new CodegenError({
|
|
218
|
-
name: errorPayload?.payload.name ?? "Unknown error",
|
|
219
|
-
reason: errorPayload?.payload.message ?? "Unknown",
|
|
220
|
-
status: errorPayload?.payload.status,
|
|
221
|
-
detail: errorPayload?.payload.detail,
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
updateStatus((draft) => {
|
|
225
|
-
draft.status = "error";
|
|
226
|
-
draft.error = codegenError;
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
resolve({
|
|
230
|
-
result: null,
|
|
231
|
-
error: codegenError,
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
es.addEventListener("done", (event) => {
|
|
236
|
-
const message = JSON.parse(event.data) as StreamMessageByType<"done">;
|
|
237
|
-
result.tokenUsage = message.payload.tokenUsage;
|
|
238
|
-
|
|
239
|
-
updateStatus((draft) => {
|
|
240
|
-
draft.status = "success";
|
|
241
|
-
draft.result = result as AnimaSDKResult;
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
resolve({ result: result as AnimaSDKResult, error: null });
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
try {
|
|
249
|
-
const { result: r, error } = await promise;
|
|
250
|
-
|
|
251
|
-
const result = structuredClone(r);
|
|
252
|
-
|
|
253
|
-
// Ideally, we should download the assets within the `assets_uploaded` event handler, since it'll improve the performance.
|
|
254
|
-
// But for some reason, it doesn't work. So, we download the assets here.
|
|
255
|
-
if (
|
|
256
|
-
initialParams.assetsStorage?.strategy === "local" &&
|
|
257
|
-
result?.assets?.length
|
|
258
|
-
) {
|
|
259
|
-
const { filePath } = getAssetsLocalStrategyParams(
|
|
260
|
-
initialParams.assetsStorage
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
const downloadAssetsPromises = result.assets.map(async (asset) => {
|
|
264
|
-
const response = await fetch(asset.url);
|
|
265
|
-
const buffer = await response.arrayBuffer();
|
|
266
|
-
return {
|
|
267
|
-
assetName: asset.name,
|
|
268
|
-
base64: arrayBufferToBase64(buffer),
|
|
269
|
-
};
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
const assets = await Promise.allSettled(downloadAssetsPromises);
|
|
273
|
-
for (const assetPromise of assets) {
|
|
274
|
-
const assetsList: Record<string, string> = {};
|
|
275
|
-
if (assetPromise.status === "fulfilled") {
|
|
276
|
-
const { assetName, base64 } = assetPromise.value;
|
|
277
|
-
|
|
278
|
-
assetsList[assetName] = base64;
|
|
279
|
-
|
|
280
|
-
const assetPath = filePath ? `${filePath}/${assetName}` : assetName;
|
|
281
|
-
result.files[assetPath] = {
|
|
282
|
-
content: base64,
|
|
283
|
-
isBinary: true,
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (error) {
|
|
290
|
-
return { result: null, error };
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return { result, error };
|
|
294
|
-
} finally {
|
|
295
|
-
es.close();
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
return {
|
|
300
|
-
getCode,
|
|
301
|
-
status: status.status,
|
|
302
|
-
tasks: status.tasks,
|
|
303
|
-
error: status.error,
|
|
304
|
-
result: status.result,
|
|
305
|
-
};
|
|
306
|
-
};
|
package/src/useFigmaFile.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import useSWR from "swr";
|
|
2
|
-
import { getFigmaFile } from "@animaapp/anima-sdk";
|
|
3
|
-
|
|
4
|
-
export const useFigmaFile = ({
|
|
5
|
-
fileKey,
|
|
6
|
-
authToken,
|
|
7
|
-
enabled = true,
|
|
8
|
-
params = {},
|
|
9
|
-
}: {
|
|
10
|
-
fileKey: string;
|
|
11
|
-
authToken: string;
|
|
12
|
-
enabled?: boolean;
|
|
13
|
-
params?: {
|
|
14
|
-
depth?: number;
|
|
15
|
-
};
|
|
16
|
-
}) => {
|
|
17
|
-
const isEnabled = Boolean(enabled && fileKey && authToken);
|
|
18
|
-
|
|
19
|
-
const { data, isLoading, error } = useSWR(
|
|
20
|
-
["figma", fileKey, authToken, params],
|
|
21
|
-
() => {
|
|
22
|
-
if (!isEnabled) {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return getFigmaFile({
|
|
27
|
-
fileKey,
|
|
28
|
-
authToken,
|
|
29
|
-
params,
|
|
30
|
-
});
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
revalidateIfStale: false,
|
|
34
|
-
revalidateOnFocus: false,
|
|
35
|
-
revalidateOnReconnect: false,
|
|
36
|
-
}
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
data: data ?? null,
|
|
41
|
-
isLoading,
|
|
42
|
-
error,
|
|
43
|
-
};
|
|
44
|
-
};
|
package/src/utils.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export const arrayBufferToBase64 = (buffer: ArrayBuffer) => {
|
|
2
|
-
let binary = "";
|
|
3
|
-
const bytes = new Uint8Array(buffer);
|
|
4
|
-
const len = bytes.byteLength;
|
|
5
|
-
for (let i = 0; i < len; i++) {
|
|
6
|
-
binary += String.fromCharCode(bytes[i]);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
return btoa(binary);
|
|
10
|
-
};
|
package/vite.config.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vite";
|
|
2
|
-
import dts from "vite-plugin-dts";
|
|
3
|
-
import tsconfigPaths from "vite-tsconfig-paths";
|
|
4
|
-
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
build: {
|
|
7
|
-
lib: {
|
|
8
|
-
entry: "./src/index.ts",
|
|
9
|
-
formats: ["cjs", "es"],
|
|
10
|
-
fileName: "index",
|
|
11
|
-
},
|
|
12
|
-
outDir: "./dist",
|
|
13
|
-
emptyOutDir: true,
|
|
14
|
-
target: "es6",
|
|
15
|
-
sourcemap: true,
|
|
16
|
-
rollupOptions: {
|
|
17
|
-
external: ["react"],
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
plugins: [
|
|
21
|
-
tsconfigPaths(),
|
|
22
|
-
dts({
|
|
23
|
-
rollupTypes: true,
|
|
24
|
-
insertTypesEntry: true,
|
|
25
|
-
}),
|
|
26
|
-
],
|
|
27
|
-
});
|