@tscircuit/fake-snippets 0.0.106 → 0.0.108

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 (43) hide show
  1. package/CLAUDE.md +92 -0
  2. package/api/generated-index.js +84 -25
  3. package/biome.json +7 -1
  4. package/bun-tests/fake-snippets-api/routes/package_builds/get.test.ts +0 -15
  5. package/bun-tests/fake-snippets-api/routes/package_builds/list.test.ts +0 -12
  6. package/dist/bundle.js +360 -434
  7. package/dist/index.d.ts +26 -15
  8. package/dist/index.js +40 -21
  9. package/dist/schema.d.ts +32 -24
  10. package/dist/schema.js +7 -5
  11. package/fake-snippets-api/lib/db/db-client.ts +19 -1
  12. package/fake-snippets-api/lib/db/schema.ts +6 -3
  13. package/fake-snippets-api/lib/db/seed.ts +23 -12
  14. package/fake-snippets-api/lib/public-mapping/public-map-package-build.ts +0 -3
  15. package/fake-snippets-api/lib/public-mapping/public-map-package-release.ts +3 -0
  16. package/fake-snippets-api/routes/api/package_builds/list.ts +0 -1
  17. package/package.json +3 -2
  18. package/src/App.tsx +27 -9
  19. package/src/components/FileSidebar.tsx +14 -159
  20. package/src/components/PackageBreadcrumb.tsx +111 -0
  21. package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +1 -1
  22. package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +18 -2
  23. package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +18 -8
  24. package/src/components/preview/BuildsList.tsx +84 -167
  25. package/src/components/preview/ConnectedPackagesList.tsx +92 -62
  26. package/src/components/preview/ConnectedRepoOverview.tsx +171 -155
  27. package/src/components/preview/{ConnectedRepoDashboard.tsx → PackageReleasesDashboard.tsx} +31 -69
  28. package/src/components/preview/index.tsx +20 -154
  29. package/src/hooks/use-package-builds.ts +0 -48
  30. package/src/hooks/use-package-release-by-id-or-version.ts +36 -0
  31. package/src/hooks/use-package-release.ts +32 -0
  32. package/src/index.css +24 -0
  33. package/src/lib/utils/isUuid.ts +5 -0
  34. package/src/lib/utils/transformFilesToTreeData.tsx +195 -0
  35. package/src/pages/404.tsx +3 -5
  36. package/src/pages/preview-release.tsx +269 -0
  37. package/src/pages/release-builds.tsx +99 -0
  38. package/src/pages/release-detail.tsx +120 -0
  39. package/src/pages/releases.tsx +55 -0
  40. package/fake-snippets-api/routes/api/package_builds/latest.ts +0 -109
  41. package/src/hooks/use-snippets-base-api-url.ts +0 -3
  42. package/src/pages/preview-build.tsx +0 -380
  43. package/src/pages/view-connected-repo.tsx +0 -49
package/CLAUDE.md ADDED
@@ -0,0 +1,92 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ tscircuit.com is a React-based web application for creating, sharing, and managing electronic circuit designs using TypeScript and React. It features a circuit editor, package management system, AI-assisted design tools, and visualization of PCB layouts and 3D models.
8
+
9
+ ## Development Commands
10
+
11
+ - `bun run dev` - Start development server (builds fake API and runs on localhost:5173)
12
+ - `bun run build` - Full production build (generates images, sitemap, builds fake API, compiles TypeScript, and builds with Vite)
13
+ - `bun run typecheck` - Run TypeScript type checking without emitting files
14
+ - `bun run format` - Format code using Biome
15
+ - `bun run lint` - Check code formatting with Biome
16
+ - `bun run playwright` - Run Playwright end-to-end tests
17
+ - `bun run playwright:update` - Update Playwright test snapshots
18
+ - `bun run snapshot` - Interactive snapshot updating tool (prompts for specific test file)
19
+
20
+ ### Fake API Development
21
+ - `bun run build:fake-api` - Build the complete fake API (TypeScript compilation, bundle generation, schema building)
22
+ - `bun run dev:registry` - Run dev server using registry API at localhost:3100
23
+
24
+ ## Architecture
25
+
26
+ ### Frontend Structure
27
+ - **React SPA** with Vite bundler, using Wouter for routing and lazy-loaded pages
28
+ - **State Management**: Zustand for global state, React Query for server state
29
+ - **UI Framework**: Tailwind CSS with Radix UI components and custom shadcn/ui components
30
+ - **Code Editor**: CodeMirror 6 with TypeScript support and AI completion
31
+
32
+ ### API Architecture
33
+ - **Fake API**: Development API built with Winterspec, providing full backend simulation
34
+ - **Database Schema**: Zod-validated schemas for packages, builds, releases, snippets, accounts, orders
35
+ - **Authentication**: Session-based auth with GitHub integration
36
+
37
+ ### Key Domains
38
+ - **Packages**: Reusable circuit components with versioning and releases
39
+ - **Package Builds**: Compilation artifacts with build status and logs
40
+ - **Package Releases**: Published versions with metadata and assets
41
+ - **Snippets**: Legacy circuit designs (being migrated to packages)
42
+ - **Circuit JSON**: Standard format for circuit data interchange
43
+
44
+ ### File Organization
45
+ - `src/components/` - Reusable UI components
46
+ - `src/pages/` - Route-based page components
47
+ - `src/hooks/` - Custom React hooks for data fetching and state
48
+ - `src/lib/` - Utilities, constants, and helper functions
49
+ - `fake-snippets-api/` - Mock API implementation with Winterspec
50
+ - `playwright-tests/` - End-to-end tests with visual regression snapshots
51
+
52
+ ## Testing Strategy
53
+
54
+ Uses Playwright for end-to-end testing with visual regression snapshots. Tests cover critical user flows including editor functionality, package management, authentication, and responsive design across viewport sizes.
55
+
56
+ ## Key Technical Patterns
57
+
58
+ ### Data Fetching
59
+ - React Query for server state with custom hooks (use-package-*, use-snippet-*, etc.)
60
+ - Fake API provides development backend with realistic data simulation
61
+ - SSR support via Vercel for SEO and performance
62
+
63
+ ### Circuit Visualization
64
+ - Multiple viewers: PCB viewer, schematic viewer, 3D viewer, assembly viewer
65
+ - SVG-based rendering with interactive controls
66
+ - Real-time preview updates during code editing
67
+
68
+ ### Code Compilation
69
+ - TypeScript compilation in browser using Monaco/TypeScript compiler API
70
+ - Circuit JSON generation from TypeScript code
71
+ - Error handling and display for compilation issues
72
+
73
+ ### Package Management
74
+ - Package files with hierarchical structure
75
+ - Build artifacts and release management
76
+ - GitHub integration for repository linking
77
+
78
+ ## Environment Variables
79
+
80
+ Development AI testing requires:
81
+ ```bash
82
+ VITE_USE_DIRECT_AI_REQUESTS=true
83
+ VITE_ANTHROPIC_API_KEY=<your-key-here>
84
+ ```
85
+
86
+ ## Build Tools
87
+
88
+ - **Bundler**: Vite with React plugin and image optimization
89
+ - **TypeScript**: Strict mode with path aliases (@/* → src/*)
90
+ - **Styling**: Tailwind CSS with custom design tokens
91
+ - **Code Quality**: Biome for formatting and linting
92
+ - **Package Manager**: Bun for fast installs and script execution
@@ -31,7 +31,7 @@ const PREFETCHABLE_PAGES = new Set([
31
31
  "latest",
32
32
  "settings",
33
33
  "quickstart",
34
- "view-connected-repo",
34
+ "releases",
35
35
  ])
36
36
 
37
37
  const pageDescriptions = {
@@ -51,8 +51,7 @@ const pageDescriptions = {
51
51
  "Get started quickly with tscircuit. Create new circuit packages, import components from JLCPCB, or start from templates to begin your electronic design journey.",
52
52
  settings:
53
53
  "Manage your tscircuit account settings, shipping information, and preferences for electronic design and PCB ordering.",
54
- "view-connected-repo":
55
- "View and manage your connected repositories. Monitor repository status, access build information, and configure build options.",
54
+ releases: "View all package releases, access build information.",
56
55
  }
57
56
 
58
57
  function getPageDescription(pageName) {
@@ -90,7 +89,10 @@ function getHtmlWithModifiedSeoTags({
90
89
  `
91
90
 
92
91
  // First replace SEO tags
93
- let modifiedHtml = `${htmlContent.substring(0, seoStartIndex)}${seoTags}${htmlContent.substring(seoEndIndex)}`
92
+ let modifiedHtml = `${htmlContent.substring(
93
+ 0,
94
+ seoStartIndex,
95
+ )}${seoTags}${htmlContent.substring(seoEndIndex)}`
94
96
 
95
97
  // Then handle SSR data injection
96
98
  if (ssrPackageData) {
@@ -177,21 +179,25 @@ async function handleDatasheetPage(req, res) {
177
179
 
178
180
  async function handleCustomPackageHtml(req, res) {
179
181
  // Get the author and package name
180
- const [_, author, unscopedPackageName] = req.url.split("?")[0].split("/")
182
+ const [_, author, unscopedPackageName, other] = req.url
183
+ .split("?")[0]
184
+ .split("/")
185
+ if (other == "releases" || other == "release") {
186
+ throw new Error("Release route")
187
+ }
181
188
  if (!author || !unscopedPackageName) {
182
189
  throw new Error("Invalid author/package URL")
183
190
  }
184
191
  if (author === "datasheets") {
185
192
  throw new Error("Datasheet route")
186
193
  }
187
- if (author === "build" || unscopedPackageName === "view-connected-repo") {
188
- throw new Error("Build route - not a package")
189
- }
190
194
 
191
195
  const packageNotFoundHtml = getHtmlWithModifiedSeoTags({
192
196
  title: "Package Not Found - tscircuit",
193
197
  description: `The package ${author}/${unscopedPackageName} could not be found.`,
194
- canonicalUrl: `${BASE_URL}/${he.encode(author)}/${he.encode(unscopedPackageName)}`,
198
+ canonicalUrl: `${BASE_URL}/${he.encode(author)}/${he.encode(
199
+ unscopedPackageName,
200
+ )}`,
195
201
  })
196
202
  const packageDetails = await ky
197
203
  .get(`${REGISTRY_URL}/packages/get`, {
@@ -250,19 +256,29 @@ async function handleCustomPackageHtml(req, res) {
250
256
  }
251
257
 
252
258
  const description = he.encode(
253
- `${packageInfo.description || packageInfo.ai_description || "A tscircuit component created by " + author} ${packageInfo.ai_usage_instructions ?? ""}`,
259
+ `${
260
+ packageInfo.description ||
261
+ packageInfo.ai_description ||
262
+ "A tscircuit component created by " + author
263
+ } ${packageInfo.ai_usage_instructions ?? ""}`,
254
264
  )
255
265
  const title = he.encode(`${packageInfo.name} - tscircuit`)
256
266
 
257
267
  const allowedViews = ["schematic", "pcb", "assembly", "3d"]
258
268
  const defaultView = packageInfo.default_view || "pcb"
259
269
  const thumbnailView = allowedViews.includes(defaultView) ? defaultView : "pcb"
260
- const imageUrl = `${REGISTRY_URL}/packages/images/${he.encode(author)}/${he.encode(unscopedPackageName)}/${thumbnailView}.png?fs_sha=${packageInfo.latest_package_release_fs_sha}`
270
+ const imageUrl = `${REGISTRY_URL}/packages/images/${he.encode(
271
+ author,
272
+ )}/${he.encode(unscopedPackageName)}/${thumbnailView}.png?fs_sha=${
273
+ packageInfo.latest_package_release_fs_sha
274
+ }`
261
275
 
262
276
  const html = getHtmlWithModifiedSeoTags({
263
277
  title,
264
278
  description,
265
- canonicalUrl: `${BASE_URL}/${he.encode(author)}/${he.encode(unscopedPackageName)}`,
279
+ canonicalUrl: `${BASE_URL}/${he.encode(author)}/${he.encode(
280
+ unscopedPackageName,
281
+ )}`,
266
282
  imageUrl,
267
283
  ssrPackageData: { package: packageInfo, packageRelease, packageFiles },
268
284
  })
@@ -273,7 +289,6 @@ async function handleCustomPackageHtml(req, res) {
273
289
  res.setHeader("Vary", "Accept-Encoding")
274
290
  res.status(200).send(html)
275
291
  }
276
-
277
292
  async function handleCustomPage(req, res) {
278
293
  const [_, page] = req.url.split("?")[0].split("/")
279
294
 
@@ -299,6 +314,57 @@ async function handleCustomPage(req, res) {
299
314
  res.status(200).send(html)
300
315
  }
301
316
 
317
+ async function handleReleasePreview(req, res) {
318
+ const [_, author, unscopedPackageName, releaseId] = req.url
319
+ .split("?")[0]
320
+ .split("/")
321
+
322
+ if (!author || !unscopedPackageName || !releaseId) {
323
+ throw new Error("Invalid author/package/release URL")
324
+ }
325
+ const packageDetails = await ky
326
+ .get(`${REGISTRY_URL}/packages/get`, {
327
+ searchParams: {
328
+ name: `${author}/${unscopedPackageName}`,
329
+ },
330
+ })
331
+ .json()
332
+ .catch((e) => {
333
+ if (String(e).includes("404")) {
334
+ return null
335
+ }
336
+ throw e
337
+ })
338
+ const packageNotFoundHtml = getHtmlWithModifiedSeoTags({
339
+ title: "Package Not Found - tscircuit",
340
+ description: `Release for package ${author}/${unscopedPackageName} could not be found.`,
341
+ canonicalUrl: `${BASE_URL}/${he.encode(author)}/${he.encode(
342
+ unscopedPackageName,
343
+ )}`,
344
+ })
345
+ if (!packageDetails) {
346
+ res.setHeader("Content-Type", "text/html; charset=utf-8")
347
+ res.setHeader("Cache-Control", cacheControlHeader)
348
+ res.setHeader("Vary", "Accept-Encoding")
349
+ res.status(404).send(packageNotFoundHtml)
350
+ return
351
+ }
352
+
353
+ const { package: packageInfo } = packageDetails
354
+ const title = he.encode(`Release preview for ${packageInfo.name} - tscircuit`)
355
+
356
+ const html = getHtmlWithModifiedSeoTags({
357
+ title,
358
+ description: pageDescriptions["releases"],
359
+ ssrPackageData: { package: packageInfo },
360
+ })
361
+
362
+ res.setHeader("Content-Type", "text/html; charset=utf-8")
363
+ res.setHeader("Cache-Control", cacheControlHeader)
364
+ res.setHeader("Vary", "Accept-Encoding")
365
+ res.status(200).send(html)
366
+ }
367
+
302
368
  export default async function handler(req, res) {
303
369
  const urlPath = req.url.split("?")[0]
304
370
  if (urlPath === "/api/generated-index") {
@@ -311,22 +377,15 @@ export default async function handler(req, res) {
311
377
 
312
378
  const pathParts = req.url.split("?")[0].split("/")
313
379
 
314
- if (pathParts[1] === "build" && pathParts[2]) {
315
- const pageDescription = getPageDescription("view-connected-repo")
316
- const html = getHtmlWithModifiedSeoTags({
317
- title: `Preview Build For ${pathParts[2]} - tscircuit`,
318
- description: pageDescription,
319
- canonicalUrl: `${BASE_URL}/build/${pathParts[2]}`,
320
- })
321
- res.setHeader("Content-Type", "text/html; charset=utf-8")
322
- res.setHeader("Cache-Control", cacheControlHeader)
323
- res.setHeader("Vary", "Accept-Encoding")
324
- res.status(200).send(html)
380
+ try {
381
+ await handleCustomPackageHtml(req, res)
325
382
  return
383
+ } catch (e) {
384
+ console.warn(e)
326
385
  }
327
386
 
328
387
  try {
329
- await handleCustomPackageHtml(req, res)
388
+ await handleReleasePreview(req, res)
330
389
  return
331
390
  } catch (e) {
332
391
  console.warn(e)
package/biome.json CHANGED
@@ -8,7 +8,13 @@
8
8
  "indentStyle": "space"
9
9
  },
10
10
  "files": {
11
- "ignore": ["cosmos-export", "dist", "package.json", ".vercel"]
11
+ "ignore": [
12
+ "cosmos-export",
13
+ "dist",
14
+ "package.json",
15
+ ".vercel",
16
+ "src/index.css"
17
+ ]
12
18
  },
13
19
  "javascript": {
14
20
  "formatter": {
@@ -71,9 +71,6 @@ test("GET /api/package_builds/get - returns 403 for unauthorized package build a
71
71
  build_error_last_updated_at: new Date().toISOString(),
72
72
  build_logs: null,
73
73
  preview_url: "https://preview.tscircuit.com/pb_test",
74
- branch_name: "main",
75
- commit_message: "Test build",
76
- commit_author: "jane.doe",
77
74
  })
78
75
 
79
76
  const res = await axios.get(
@@ -126,9 +123,6 @@ test("GET /api/package_builds/get - successfully returns package build with logs
126
123
  ).toISOString(),
127
124
  build_logs: buildLogs.join(" "),
128
125
  preview_url: "https://preview.tscircuit.com/pb_1a2b3c4d",
129
- branch_name: "main",
130
- commit_message: "Add new LED component with improved brightness control",
131
- commit_author: "john.doe",
132
126
  })
133
127
 
134
128
  const res = await axios.get(
@@ -174,9 +168,6 @@ test("GET /api/package_builds/get - returns package build without logs when incl
174
168
  build_error_last_updated_at: new Date().toISOString(),
175
169
  build_logs: "Some build logs",
176
170
  preview_url: "https://preview.tscircuit.com/pb_test",
177
- branch_name: "main",
178
- commit_message: "Test build",
179
- commit_author: "john.doe",
180
171
  })
181
172
 
182
173
  const res = await axios.get(
@@ -222,9 +213,6 @@ test("GET /api/package_builds/get - handles build with errors", async () => {
222
213
  build_error_last_updated_at: new Date().toISOString(),
223
214
  build_logs: null,
224
215
  preview_url: null,
225
- branch_name: "feature/new-component",
226
- commit_message: "Add broken component",
227
- commit_author: "john.doe",
228
216
  })
229
217
 
230
218
  const res = await axios.get(
@@ -274,9 +262,6 @@ test("GET /api/package_builds/get - handles build in progress", async () => {
274
262
  build_error_last_updated_at: new Date().toISOString(),
275
263
  build_logs: null,
276
264
  preview_url: null,
277
- branch_name: "main",
278
- commit_message: "Building in progress",
279
- commit_author: "john.doe",
280
265
  })
281
266
 
282
267
  const res = await axios.get(
@@ -125,9 +125,6 @@ test("GET /api/package_builds/list - returns created builds", async () => {
125
125
  ).toISOString(),
126
126
  build_logs: null,
127
127
  preview_url: "https://preview.tscircuit.com/pb_1a2b3c4d",
128
- branch_name: "main",
129
- commit_message: "Add new LED component with improved brightness control",
130
- commit_author: "john.doe",
131
128
  })
132
129
 
133
130
  const res = await axios.get(
@@ -175,9 +172,6 @@ test("GET /api/package_builds/list - sorts builds by created_at descending", asy
175
172
  ).toISOString(),
176
173
  build_logs: null,
177
174
  preview_url: "https://preview.tscircuit.com/pb_1",
178
- branch_name: "main",
179
- commit_message: "First build",
180
- commit_author: "john.doe",
181
175
  })
182
176
 
183
177
  db.addPackageBuild({
@@ -210,9 +204,6 @@ test("GET /api/package_builds/list - sorts builds by created_at descending", asy
210
204
  ).toISOString(),
211
205
  build_logs: null,
212
206
  preview_url: "https://preview.tscircuit.com/pb_2",
213
- branch_name: "main",
214
- commit_message: "Second build",
215
- commit_author: "john.doe",
216
207
  })
217
208
 
218
209
  const res = await axios.get(
@@ -286,9 +277,6 @@ test("GET /api/package_builds/list - returns created builds with logs or not", a
286
277
  ).toISOString(),
287
278
  build_logs: buildLogs.join(" "),
288
279
  preview_url: "https://preview.tscircuit.com/pb_1a2b3c4d",
289
- branch_name: "main",
290
- commit_message: "Add new LED component with improved brightness control",
291
- commit_author: "john.doe",
292
280
  })
293
281
 
294
282
  const resWithoutLogs = await axios.get(