@tscircuit/fake-snippets 0.0.7 → 0.0.9

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 (37) hide show
  1. package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +2 -5
  2. package/bun-tests/fake-snippets-api/routes/packages/{list.test.ts → list-1.test.ts} +0 -55
  3. package/bun-tests/fake-snippets-api/routes/packages/list-2.test.ts +59 -0
  4. package/bun-tests/fake-snippets-api/routes/snippets/add_star.test.ts +32 -27
  5. package/bun-tests/fake-snippets-api/routes/snippets/create.test.ts +34 -1
  6. package/bun-tests/fake-snippets-api/routes/snippets/get.test.ts +114 -0
  7. package/bun-tests/fake-snippets-api/routes/snippets/get_image.test.ts +10 -6
  8. package/bun-tests/fake-snippets-api/routes/snippets/images.test.ts +8 -6
  9. package/bun-tests/fake-snippets-api/routes/snippets/list_newest.test.ts +2 -2
  10. package/bun-tests/fake-snippets-api/routes/snippets/list_trending.test.ts +10 -10
  11. package/bun-tests/fake-snippets-api/routes/snippets/remove_star.test.ts +8 -6
  12. package/bun-tests/fake-snippets-api/routes/snippets/search.test.ts +1 -1
  13. package/bun-tests/fake-snippets-api/routes/snippets/star-count.test.ts +19 -12
  14. package/bun-tests/fake-snippets-api/routes/snippets/update.test.ts +57 -16
  15. package/bun.lock +148 -569
  16. package/dist/bundle.js +844 -194
  17. package/fake-snippets-api/lib/db/db-client.ts +761 -147
  18. package/fake-snippets-api/lib/db/schema.ts +27 -6
  19. package/fake-snippets-api/lib/public-mapping/public-map-package.ts +8 -0
  20. package/fake-snippets-api/routes/api/packages/list.ts +4 -1
  21. package/fake-snippets-api/routes/api/snippets/add_star.ts +30 -8
  22. package/fake-snippets-api/routes/api/snippets/create.ts +123 -29
  23. package/fake-snippets-api/routes/api/snippets/delete.ts +5 -5
  24. package/fake-snippets-api/routes/api/snippets/download.ts +24 -10
  25. package/fake-snippets-api/routes/api/snippets/get.ts +46 -13
  26. package/fake-snippets-api/routes/api/snippets/list.ts +37 -2
  27. package/fake-snippets-api/routes/api/snippets/update.ts +36 -14
  28. package/package.json +4 -5
  29. package/src/components/CodeAndPreview.tsx +13 -48
  30. package/src/components/CodeEditor.tsx +10 -7
  31. package/src/components/EditorNav.tsx +0 -21
  32. package/src/components/PreviewContent.tsx +2 -2
  33. package/src/components/ViewSnippetHeader.tsx +4 -0
  34. package/src/hooks/use-global-store.ts +0 -5
  35. package/src/hooks/use-package-as-snippet.ts +78 -0
  36. package/src/hooks/use-run-tsx/index.tsx +4 -0
  37. package/src/lib/jlc-parts-engine.ts +4 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/fake-snippets",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -66,9 +66,7 @@
66
66
  "@tscircuit/layout": "^0.0.29",
67
67
  "@tscircuit/math-utils": "^0.0.10",
68
68
  "@tscircuit/mm": "^0.0.8",
69
- "@tscircuit/pcb-viewer": "^1.11.12",
70
69
  "@tscircuit/props": "^0.0.143",
71
- "@tscircuit/schematic-viewer": "^1.4.3",
72
70
  "@types/file-saver": "^2.0.7",
73
71
  "@types/ms": "^0.7.34",
74
72
  "@typescript/ata": "^0.9.7",
@@ -130,9 +128,9 @@
130
128
  "@babel/standalone": "^7.26.2",
131
129
  "@biomejs/biome": "^1.9.2",
132
130
  "@playwright/test": "^1.48.0",
133
- "@tscircuit/core": "^0.0.315",
131
+ "@tscircuit/core": "^0.0.345",
134
132
  "@tscircuit/prompt-benchmarks": "^0.0.28",
135
- "@tscircuit/runframe": "^0.0.193",
133
+ "@tscircuit/runframe": "^0.0.231",
136
134
  "@types/babel__standalone": "^7.1.7",
137
135
  "@types/bun": "^1.1.10",
138
136
  "@types/country-list": "^2.1.4",
@@ -146,6 +144,7 @@
146
144
  "@vitejs/plugin-react": "^4.3.1",
147
145
  "autoprefixer": "^10.4.20",
148
146
  "circuit-to-svg": "^0.0.101",
147
+ "get-port": "^7.1.0",
149
148
  "globals": "^15.9.0",
150
149
  "postcss": "^8.4.47",
151
150
  "prismjs": "^1.29.0",
@@ -2,7 +2,6 @@ import { CodeEditor } from "@/components/CodeEditor"
2
2
  import { useAxios } from "@/hooks/use-axios"
3
3
  import { useCreateSnippetMutation } from "@/hooks/use-create-snippet-mutation"
4
4
  import { useGlobalStore } from "@/hooks/use-global-store"
5
- import { useRunTsx } from "@/hooks/use-run-tsx"
6
5
  import { useToast } from "@/hooks/use-toast"
7
6
  import { useUrlParams } from "@/hooks/use-url-params"
8
7
  import useWarnUserOnPageChange from "@/hooks/use-warn-user-on-page-change"
@@ -16,7 +15,6 @@ import { useEffect, useMemo, useState } from "react"
16
15
  import { useMutation, useQueryClient } from "react-query"
17
16
  import EditorNav from "./EditorNav"
18
17
  import { parseJsonOrNull } from "@/lib/utils/parseJsonOrNull"
19
- import { PreviewContent } from "./PreviewContent"
20
18
  import { SuspenseRunFrame } from "./SuspenseRunFrame"
21
19
 
22
20
  interface Props {
@@ -51,9 +49,7 @@ export function CodeAndPreview({ snippet }: Props) {
51
49
  const [showPreview, setShowPreview] = useState(true)
52
50
  const [lastRunCode, setLastRunCode] = useState(defaultCode ?? "")
53
51
  const [fullScreen, setFullScreen] = useState(false)
54
- const shouldUseWebworkerForRun = useGlobalStore(
55
- (s) => s.should_use_webworker_for_run,
56
- )
52
+ const [circuitJson, setCircuitJson] = useState<any>(null)
57
53
 
58
54
  const snippetType: "board" | "package" | "model" | "footprint" =
59
55
  snippet?.snippet_type ??
@@ -82,26 +78,6 @@ export function CodeAndPreview({ snippet }: Props) {
82
78
  [manualEditsFileContent],
83
79
  )
84
80
 
85
- const {
86
- message,
87
- circuitJson,
88
- compiledJs,
89
- triggerRunTsx,
90
- tsxRunTriggerCount,
91
- circuitJsonKey,
92
- isRunningCode,
93
- } = useRunTsx({
94
- code,
95
- userImports,
96
- type: snippetType,
97
- circuitDisplayName: snippet?.name,
98
- })
99
-
100
- // Update lastRunCode whenever the code is run
101
- useEffect(() => {
102
- setLastRunCode(code)
103
- }, [tsxRunTriggerCount])
104
-
105
81
  const qc = useQueryClient()
106
82
 
107
83
  const updateSnippetMutation = useMutation({
@@ -112,7 +88,7 @@ export function CodeAndPreview({ snippet }: Props) {
112
88
  snippet_id: snippet.snippet_id,
113
89
  code: code,
114
90
  dts: dts,
115
- compiled_js: compiledJs,
91
+ // compiled_js: compiledJs,
116
92
  circuit_json: circuitJson,
117
93
  manual_edits_json_content: manualEditsFileContent,
118
94
  }
@@ -276,28 +252,7 @@ export function CodeAndPreview({ snippet }: Props) {
276
252
  onDtsChange={(newDts) => setDts(newDts)}
277
253
  />
278
254
  </div>
279
- {showPreview && !shouldUseWebworkerForRun && (
280
- <PreviewContent
281
- className={cn(
282
- "flex p-2 flex-col min-h-[640px]",
283
- fullScreen
284
- ? "fixed inset-0 z-50 bg-white p-4 overflow-hidden"
285
- : "w-full md:w-1/2",
286
- )}
287
- code={code}
288
- triggerRunTsx={triggerRunTsx}
289
- tsxRunTriggerCount={tsxRunTriggerCount}
290
- errorMessage={message}
291
- circuitJsonKey={circuitJsonKey}
292
- circuitJson={circuitJson}
293
- isRunningCode={isRunningCode}
294
- manualEditsFileContent={manualEditsFileContent ?? ""}
295
- onManualEditsFileContentChange={setManualEditsFileContent}
296
- onToggleFullScreen={() => setFullScreen(!fullScreen)}
297
- isFullScreen={fullScreen}
298
- />
299
- )}
300
- {showPreview && shouldUseWebworkerForRun && (
255
+ {showPreview && (
301
256
  <div
302
257
  className={cn(
303
258
  "flex p-0 flex-col min-h-[640px]",
@@ -308,8 +263,18 @@ export function CodeAndPreview({ snippet }: Props) {
308
263
  >
309
264
  <SuspenseRunFrame
310
265
  showRunButton
266
+ forceLatestEvalVersion
267
+ onRenderStarted={() => {
268
+ setLastRunCode(code)
269
+ }}
270
+ onRenderFinished={({ circuitJson }) => {
271
+ setCircuitJson(circuitJson)
272
+ }}
311
273
  onEditEvent={() => {
312
274
  // TODO
275
+ window.alert(
276
+ "Edit events are temporarily disabled on tscircuit.com, use the CLI",
277
+ )
313
278
  }}
314
279
  fsMap={fsMap}
315
280
  entrypoint="main.tsx"
@@ -27,7 +27,7 @@ import { EditorView } from "codemirror"
27
27
  import { useEffect, useMemo, useRef, useState } from "react"
28
28
  import ts from "typescript"
29
29
  import CodeEditorHeader from "./CodeEditorHeader"
30
- import { copilotPlugin, Language } from "@valtown/codemirror-codeium"
30
+ // import { copilotPlugin, Language } from "@valtown/codemirror-codeium"
31
31
  import { useCodeCompletionApi } from "@/hooks/use-code-completion-ai-api"
32
32
  const defaultImports = `
33
33
  import React from "@types/react/jsx-runtime"
@@ -86,7 +86,6 @@ export const CodeEditor = ({
86
86
  // Whenever streaming completes, reset the code to the initial code
87
87
  useEffect(() => {
88
88
  if (!isStreaming && code !== initialCode && initialCode) {
89
- console.log("Resetting code to initial code", initialCode)
90
89
  setCode(initialCode)
91
90
 
92
91
  // HACK: Timeout because we need to wait for the editor to mount again
@@ -187,6 +186,8 @@ export const CodeEditor = ({
187
186
  const ata = setupTypeAcquisition(ataConfig)
188
187
  ataRef.current = ata
189
188
 
189
+ const lastFilesEventContent: Record<string, string> = {}
190
+
190
191
  // Set up base extensions
191
192
  const baseExtensions = [
192
193
  basicSetup,
@@ -198,7 +199,9 @@ export const CodeEditor = ({
198
199
  EditorView.updateListener.of((update) => {
199
200
  if (update.docChanged) {
200
201
  const newContent = update.state.doc.toString()
201
- if (newContent === files[currentFile]) return
202
+
203
+ if (newContent === lastFilesEventContent[currentFile]) return
204
+ lastFilesEventContent[currentFile] = newContent
202
205
 
203
206
  if (currentFile === "index.tsx") {
204
207
  setCode(newContent)
@@ -228,10 +231,10 @@ export const CodeEditor = ({
228
231
  ]
229
232
  if (codeCompletionApi?.apiKey) {
230
233
  baseExtensions.push(
231
- copilotPlugin({
232
- apiKey: codeCompletionApi.apiKey,
233
- language: Language.TYPESCRIPT,
234
- }),
234
+ // copilotPlugin({
235
+ // apiKey: codeCompletionApi.apiKey,
236
+ // language: Language.TYPESCRIPT,
237
+ // }),
235
238
  EditorView.theme({
236
239
  ".cm-ghostText, .cm-ghostText *": {
237
240
  opacity: "0.6",
@@ -76,12 +76,6 @@ export default function EditorNav({
76
76
  const [, navigate] = useLocation()
77
77
  const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
78
78
  const session = useGlobalStore((s) => s.session)
79
- const shouldUseWebworkerForRun = useGlobalStore(
80
- (s) => s.should_use_webworker_for_run,
81
- )
82
- const setShouldUseWebworkerForRun = useGlobalStore(
83
- (s) => s.setShouldUseWebworkerForRun,
84
- )
85
79
  const { Dialog: RenameDialog, openDialog: openRenameDialog } =
86
80
  useRenameSnippetDialog()
87
81
  const {
@@ -278,21 +272,6 @@ export default function EditorNav({
278
272
  <Share className="mr-1 h-3 w-3" />
279
273
  Copy URL
280
274
  </Button>
281
- <Button
282
- variant="ghost"
283
- size="sm"
284
- className="hidden md:flex px-2 text-xs"
285
- onClick={() =>
286
- setShouldUseWebworkerForRun(!shouldUseWebworkerForRun)
287
- }
288
- >
289
- {shouldUseWebworkerForRun ? (
290
- <CircleCheckBig className="mr-1 h-3 w-3" />
291
- ) : (
292
- <Square className="mr-1 h-3 w-3" />
293
- )}
294
- Webworker (Beta)
295
- </Button>
296
275
  {/* <Button
297
276
  variant="ghost"
298
277
  size="sm"
@@ -3,8 +3,8 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
3
3
  import { cn } from "@/lib/utils"
4
4
  import { applyPcbEditEvents } from "@/lib/utils/pcbManualEditEventHandler"
5
5
  import { CadViewer } from "@tscircuit/3d-viewer"
6
- import { PCBViewer } from "@tscircuit/pcb-viewer"
7
- import { Schematic } from "@tscircuit/schematic-viewer"
6
+ // import { PCBViewer } from "@tscircuit/pcb-viewer"
7
+ // import { SchematicViewer } from "@tscircuit/schematic-viewer"
8
8
  import { useEffect, useRef, useState } from "react"
9
9
  import { ErrorFallback } from "./ErrorFallback"
10
10
  import { ErrorBoundary } from "react-error-boundary"
@@ -18,6 +18,10 @@ export default function ViewSnippetHeader() {
18
18
  const session = useGlobalStore((s) => s.session)
19
19
  const [isStarred, setIsStarred] = useState(snippet?.is_starred || false)
20
20
 
21
+ useEffect(() => {
22
+ setIsStarred(snippet?.is_starred || false)
23
+ }, [snippet?.is_starred])
24
+
21
25
  const useForkSnippetMutation = ({
22
26
  snippet,
23
27
  onSuccess,
@@ -10,8 +10,6 @@ export type Store = {
10
10
  } | null
11
11
  setSession: (session: Store["session"]) => any
12
12
  should_onboarding_tips_be_closed: boolean
13
- should_use_webworker_for_run?: boolean
14
- setShouldUseWebworkerForRun: (should_use_webworker_for_run: boolean) => any
15
13
  setOnboardingTipsClosed: (closed: boolean) => any
16
14
  }
17
15
 
@@ -19,9 +17,6 @@ export const useGlobalStore = create<Store>()(
19
17
  persist(
20
18
  (set) => ({
21
19
  session: null,
22
- should_use_webworker_for_run: false,
23
- setShouldUseWebworkerForRun: (should_use_webworker_for_run: boolean) =>
24
- set({ should_use_webworker_for_run }),
25
20
  setSession: (session) => set({ session }),
26
21
  should_onboarding_tips_be_closed: false,
27
22
  setOnboardingTipsClosed: (closed) =>
@@ -0,0 +1,78 @@
1
+ import { useAxios } from "@/hooks/use-axios"
2
+ import type {
3
+ Package,
4
+ PackageFile,
5
+ Snippet,
6
+ } from "fake-snippets-api/lib/db/schema"
7
+ import { useQuery } from "react-query"
8
+
9
+ export const usePackageAsSnippet = (packageId: string | null) => {
10
+ const axios = useAxios()
11
+
12
+ console.log("packageId", packageId)
13
+
14
+ const packageQuery = useQuery<Package, Error & { status: number }>(
15
+ ["packages", packageId],
16
+ async () => {
17
+ if (!packageId) {
18
+ throw new Error("Package ID is required")
19
+ }
20
+ const { data } = await axios.get("/packages/get", {
21
+ params: { package_id: packageId },
22
+ })
23
+ return data.package
24
+ },
25
+ {
26
+ enabled: Boolean(packageId),
27
+ retry: false,
28
+ },
29
+ )
30
+
31
+ const filesQuery = useQuery<PackageFile[], Error & { status: number }>(
32
+ ["package-files", packageQuery.data?.latest_package_release_id],
33
+ async () => {
34
+ if (!packageQuery.data?.latest_package_release_id) {
35
+ throw new Error("No latest release ID available")
36
+ }
37
+ const { data } = await axios.post("/package_files/list", {
38
+ package_release_id: packageQuery.data.latest_package_release_id,
39
+ })
40
+ return data.package_files
41
+ },
42
+ {
43
+ enabled: Boolean(packageQuery.data?.latest_package_release_id),
44
+ retry: false,
45
+ // Add these options to ensure proper sequencing
46
+ staleTime: 0,
47
+ cacheTime: 0,
48
+ },
49
+ )
50
+
51
+ // Map package data to match Snippet structure
52
+ const snippetData: Snippet | undefined = packageQuery.data && {
53
+ snippet_id: packageId!,
54
+ package_release_id: packageQuery.data.latest_package_release_id || "",
55
+ unscoped_name: packageQuery.data.unscoped_name,
56
+ name: packageQuery.data.name,
57
+ is_starred: false,
58
+ version: packageQuery.data.latest_version || "",
59
+ owner_name: packageQuery.data.owner_github_username || "",
60
+ description: packageQuery.data.description || "",
61
+ snippet_type: "board",
62
+ code:
63
+ filesQuery.data?.find((file) => file.file_path === "index.tsx")
64
+ ?.content_text || "",
65
+ manual_edits_json_content:
66
+ filesQuery.data?.find((file) => file.file_path === "manual-edits.json")
67
+ ?.content_text || "",
68
+ created_at: packageQuery.data.created_at,
69
+ updated_at: packageQuery.data.updated_at,
70
+ star_count: packageQuery.data.star_count,
71
+ }
72
+
73
+ return {
74
+ data: snippetData,
75
+ isLoading: packageQuery.isLoading || filesQuery.isLoading,
76
+ error: packageQuery.error || filesQuery.error,
77
+ }
78
+ }
@@ -19,6 +19,10 @@ type RunTsxResult = {
19
19
  isRunningCode: boolean
20
20
  }
21
21
 
22
+ /**
23
+ * @deprecated will be removed in future version, use @tscircuit/eval or
24
+ * @tscircuit/runframe
25
+ */
22
26
  export const useRunTsx = ({
23
27
  code,
24
28
  userImports,
@@ -1,10 +1,12 @@
1
1
  import { type PartsEngine, SupplierPartNumbers } from "@tscircuit/props"
2
2
  import { AnySourceComponent } from "circuit-json"
3
- import qs from "qs"
4
3
 
5
4
  const cache = new Map<string, any>()
6
5
  const getJlcPartsCached = async (name: any, params: any) => {
7
- const paramString = qs.stringify({ ...params, json: "true" })
6
+ const paramString = new URLSearchParams({
7
+ ...params,
8
+ json: "true",
9
+ }).toString()
8
10
  if (cache.has(paramString)) {
9
11
  return cache.get(paramString)
10
12
  }