@tscircuit/fake-snippets 0.0.22 → 0.0.24
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/api/generated-index.js +121 -0
- package/bun-tests/fake-snippets-api/routes/orders/get.test.ts +54 -10
- package/bun.lock +11 -0
- package/dist/bundle.js +354 -276
- package/fake-snippets-api/lib/package_release/find-package-release-id.ts +0 -2
- package/fake-snippets-api/routes/api/_fake/move_orders_forward.ts +68 -0
- package/fake-snippets-api/routes/api/orders/get.ts +8 -9
- package/fake-snippets-api/utils/order-steps.ts +20 -0
- package/index.html +6 -0
- package/package.json +4 -1
- package/src/ContextProviders.tsx +4 -1
- package/src/components/FAQ.tsx +105 -31
- package/src/components/SnippetTypeIcon.tsx +29 -5
- package/src/lib/utils/load-prettier.ts +4 -2
- package/src/pages/editor.tsx +25 -0
- package/src/pages/view-snippet.tsx +19 -2
- package/tsconfig.json +1 -1
- package/vercel.json +1 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import ky from "ky"
|
|
2
|
+
import { readFileSync } from "fs"
|
|
3
|
+
import { join, dirname } from "path"
|
|
4
|
+
import { fileURLToPath } from "url"
|
|
5
|
+
import he from "he"
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
8
|
+
const __dirname = dirname(__filename)
|
|
9
|
+
|
|
10
|
+
const normalIndexFile = join(__dirname, "../dist/index.html")
|
|
11
|
+
const htmlContent = readFileSync(normalIndexFile, "utf-8")
|
|
12
|
+
|
|
13
|
+
const cacheControlHeader = "public, max-age=120, s-maxage=120"
|
|
14
|
+
|
|
15
|
+
function getHtmlWithModifiedSeoTags({
|
|
16
|
+
title,
|
|
17
|
+
description,
|
|
18
|
+
canonicalUrl,
|
|
19
|
+
imageUrl,
|
|
20
|
+
}) {
|
|
21
|
+
const seoStartTag = "<!-- SEO_START -->"
|
|
22
|
+
const seoEndTag = "<!-- SEO_END -->"
|
|
23
|
+
const startIndex = htmlContent.indexOf(seoStartTag)
|
|
24
|
+
const endIndex = htmlContent.indexOf(seoEndTag) + seoEndTag.length
|
|
25
|
+
|
|
26
|
+
const seoTags = `
|
|
27
|
+
<title>${title}</title>
|
|
28
|
+
<meta name="description"
|
|
29
|
+
content="${description}" />
|
|
30
|
+
<meta name="keywords"
|
|
31
|
+
content="electronic design, PCB design, schematic capture, React components, circuit design, electronics CAD, open source EDA, ${title}" />
|
|
32
|
+
<meta property="og:title" content="${title}" />
|
|
33
|
+
<meta property="og:description"
|
|
34
|
+
content="${description}" />
|
|
35
|
+
<meta property="og:type" content="website" />
|
|
36
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
37
|
+
<meta name="twitter:title" content="${title}" />
|
|
38
|
+
<meta name="twitter:description" content="${description}" />
|
|
39
|
+
${imageUrl ? `<meta property="og:image" content="${imageUrl}" />` : ""}
|
|
40
|
+
${imageUrl ? `<meta name="twitter:image" content="${imageUrl}" />` : ""}
|
|
41
|
+
<link rel="canonical" href="${canonicalUrl}" />
|
|
42
|
+
`
|
|
43
|
+
|
|
44
|
+
return `${htmlContent.substring(0, startIndex)}${seoTags}${htmlContent.substring(endIndex)}`
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function handleCustomPackageHtml(req, res) {
|
|
48
|
+
// Get the author and package name
|
|
49
|
+
const [_, author, unscopedPackageName] = req.url.split("?")[0].split("/")
|
|
50
|
+
if (!author || !unscopedPackageName) {
|
|
51
|
+
throw new Error("Invalid author/package URL")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const { package: packageInfo } = await ky
|
|
55
|
+
.get(`https://registry-api.tscircuit.com/packages/get`, {
|
|
56
|
+
searchParams: {
|
|
57
|
+
name: `${author}/${unscopedPackageName}`,
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
.json()
|
|
61
|
+
|
|
62
|
+
if (!packageInfo) {
|
|
63
|
+
throw new Error("Package not found")
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const description = he.encode(
|
|
67
|
+
`${packageInfo.description || packageInfo.ai_description || "A tscircuit component created by " + author} ${packageInfo.ai_usage_instructions ?? ""}`,
|
|
68
|
+
)
|
|
69
|
+
const title = he.encode(`${packageInfo.name} - tscircuit`)
|
|
70
|
+
|
|
71
|
+
const html = getHtmlWithModifiedSeoTags({
|
|
72
|
+
title,
|
|
73
|
+
description,
|
|
74
|
+
canonicalUrl: `https://tscircuit.com/${he.encode(author)}/${he.encode(unscopedPackageName)}`,
|
|
75
|
+
imageUrl: `https://registry-api.tscircuit.com/snippets/images/${he.encode(author)}/${he.encode(unscopedPackageName)}/pcb.png`,
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8")
|
|
79
|
+
res.setHeader("Cache-Control", cacheControlHeader)
|
|
80
|
+
res.status(200).send(html)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function handleCustomPage(req, res) {
|
|
84
|
+
const [_, page] = req.url.split("?")[0].split("/")
|
|
85
|
+
|
|
86
|
+
if (page === "landing" || !page) {
|
|
87
|
+
throw new Error("Use landing.html content")
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// TODO handle usernames
|
|
91
|
+
|
|
92
|
+
const html = getHtmlWithModifiedSeoTags({
|
|
93
|
+
title: `${page} - tscircuit`,
|
|
94
|
+
description: ``,
|
|
95
|
+
canonicalUrl: `https://tscircuit.com/${page}`,
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8")
|
|
99
|
+
res.setHeader("Cache-Control", cacheControlHeader)
|
|
100
|
+
res.status(200).send(html)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default async function handler(req, res) {
|
|
104
|
+
try {
|
|
105
|
+
await handleCustomPackageHtml(req, res)
|
|
106
|
+
return
|
|
107
|
+
} catch (e) {
|
|
108
|
+
console.warn(e)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
await handleCustomPage(req, res)
|
|
113
|
+
return
|
|
114
|
+
} catch (e) {
|
|
115
|
+
console.warn(e)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8")
|
|
119
|
+
res.setHeader("Cache-Control", cacheControlHeader)
|
|
120
|
+
res.status(200).send(htmlContent)
|
|
121
|
+
}
|
|
@@ -67,16 +67,16 @@ test("get order", async () => {
|
|
|
67
67
|
expect(getResponse.data.orderState).toBeDefined()
|
|
68
68
|
expect(getResponse.data.orderState.order_id).toBe(orderId)
|
|
69
69
|
|
|
70
|
-
expect(getResponse.data.orderState.are_gerbers_uploaded).toBe(
|
|
71
|
-
expect(getResponse.data.orderState.is_gerber_analyzed).toBe(
|
|
72
|
-
expect(getResponse.data.orderState.are_initial_costs_calculated).toBe(
|
|
73
|
-
expect(getResponse.data.orderState.is_pcb_added_to_cart).toBe(
|
|
74
|
-
expect(getResponse.data.orderState.is_bom_uploaded).toBe(
|
|
75
|
-
expect(getResponse.data.orderState.is_pnp_uploaded).toBe(
|
|
76
|
-
expect(getResponse.data.orderState.is_bom_pnp_analyzed).toBe(
|
|
77
|
-
expect(getResponse.data.orderState.is_bom_parsing_complete).toBe(
|
|
78
|
-
expect(getResponse.data.orderState.are_components_available).toBe(
|
|
79
|
-
expect(getResponse.data.orderState.is_patch_map_generated).toBe(
|
|
70
|
+
expect(getResponse.data.orderState.are_gerbers_uploaded).toBe(false)
|
|
71
|
+
expect(getResponse.data.orderState.is_gerber_analyzed).toBe(false)
|
|
72
|
+
expect(getResponse.data.orderState.are_initial_costs_calculated).toBe(false)
|
|
73
|
+
expect(getResponse.data.orderState.is_pcb_added_to_cart).toBe(false)
|
|
74
|
+
expect(getResponse.data.orderState.is_bom_uploaded).toBe(false)
|
|
75
|
+
expect(getResponse.data.orderState.is_pnp_uploaded).toBe(false)
|
|
76
|
+
expect(getResponse.data.orderState.is_bom_pnp_analyzed).toBe(false)
|
|
77
|
+
expect(getResponse.data.orderState.is_bom_parsing_complete).toBe(false)
|
|
78
|
+
expect(getResponse.data.orderState.are_components_available).toBe(false)
|
|
79
|
+
expect(getResponse.data.orderState.is_patch_map_generated).toBe(false)
|
|
80
80
|
})
|
|
81
81
|
|
|
82
82
|
test("get order with simulate scenario", async () => {
|
|
@@ -156,3 +156,47 @@ test("get order with simulate scenario [is_bom_uploaded ]", async () => {
|
|
|
156
156
|
|
|
157
157
|
expect(getResponse.data.orderState.is_pnp_uploaded).toBe(false)
|
|
158
158
|
})
|
|
159
|
+
|
|
160
|
+
test("get order after polling /move_orders_forward", async () => {
|
|
161
|
+
const {
|
|
162
|
+
axios,
|
|
163
|
+
seed: { order },
|
|
164
|
+
} = await getTestServer()
|
|
165
|
+
|
|
166
|
+
const createResponse = await axios.post("/api/orders/create", {
|
|
167
|
+
circuit_json: order.circuit_json,
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
expect(createResponse.status).toBe(200)
|
|
171
|
+
expect(createResponse.data.order).toBeDefined()
|
|
172
|
+
expect(createResponse.data.order.order_id).toBeDefined()
|
|
173
|
+
|
|
174
|
+
const getResponse = await axios.get("/api/orders/get", {
|
|
175
|
+
params: { order_id: createResponse.data.order.order_id },
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
expect(getResponse.status).toBe(200)
|
|
179
|
+
expect(getResponse.data.order).toBeDefined()
|
|
180
|
+
expect(getResponse.data.order.order_id).toBe(
|
|
181
|
+
createResponse.data.order.order_id,
|
|
182
|
+
)
|
|
183
|
+
expect(getResponse.data.orderState).toBeDefined()
|
|
184
|
+
|
|
185
|
+
expect(getResponse.data.orderState.are_gerbers_uploaded).toBe(false)
|
|
186
|
+
|
|
187
|
+
const moveOrdersForwardResponse = await axios.post(
|
|
188
|
+
"/api/_fake/move_orders_forward",
|
|
189
|
+
{
|
|
190
|
+
order_id: createResponse.data.order.order_id,
|
|
191
|
+
},
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
expect(moveOrdersForwardResponse.status).toBe(200)
|
|
195
|
+
|
|
196
|
+
const getResponseAfterMove = await axios.get("/api/orders/get", {
|
|
197
|
+
params: { order_id: createResponse.data.order.order_id },
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
expect(getResponseAfterMove.status).toBe(200)
|
|
201
|
+
expect(getResponseAfterMove.data.orderState.are_gerbers_generated).toBe(true)
|
|
202
|
+
})
|
package/bun.lock
CHANGED
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"react-day-picker": "8.10.1",
|
|
89
89
|
"react-dom": "^18.3.1",
|
|
90
90
|
"react-helmet": "^6.1.0",
|
|
91
|
+
"react-helmet-async": "^2.0.5",
|
|
91
92
|
"react-hook-form": "^7.53.0",
|
|
92
93
|
"react-intersection-observer": "^9.14.1",
|
|
93
94
|
"react-query": "^3.39.3",
|
|
@@ -128,6 +129,8 @@
|
|
|
128
129
|
"circuit-to-svg": "^0.0.101",
|
|
129
130
|
"get-port": "^7.1.0",
|
|
130
131
|
"globals": "^15.9.0",
|
|
132
|
+
"he": "^1.2.0",
|
|
133
|
+
"ky": "^1.7.5",
|
|
131
134
|
"postcss": "^8.4.47",
|
|
132
135
|
"prismjs": "^1.29.0",
|
|
133
136
|
"prompts": "^2.4.2",
|
|
@@ -1330,6 +1333,8 @@
|
|
|
1330
1333
|
|
|
1331
1334
|
"hastscript": ["hastscript@6.0.0", "", { "dependencies": { "@types/hast": "^2.0.0", "comma-separated-tokens": "^1.0.0", "hast-util-parse-selector": "^2.0.0", "property-information": "^5.0.0", "space-separated-tokens": "^1.0.0" } }, "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w=="],
|
|
1332
1335
|
|
|
1336
|
+
"he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="],
|
|
1337
|
+
|
|
1333
1338
|
"heap": ["heap@0.2.5", "", {}, "sha512-G7HLD+WKcrOyJP5VQwYZNC3Z6FcQ7YYjEFiFoIj8PfEr73mu421o8B1N5DKUcc8K37EsJ2XXWA8DtrDz/2dReg=="],
|
|
1334
1339
|
|
|
1335
1340
|
"highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="],
|
|
@@ -1366,6 +1371,8 @@
|
|
|
1366
1371
|
|
|
1367
1372
|
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
|
|
1368
1373
|
|
|
1374
|
+
"invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="],
|
|
1375
|
+
|
|
1369
1376
|
"ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="],
|
|
1370
1377
|
|
|
1371
1378
|
"is-alphabetical": ["is-alphabetical@1.0.4", "", {}, "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="],
|
|
@@ -1464,6 +1471,8 @@
|
|
|
1464
1471
|
|
|
1465
1472
|
"kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
|
1466
1473
|
|
|
1474
|
+
"ky": ["ky@1.7.5", "", {}, "sha512-HzhziW6sc5m0pwi5M196+7cEBtbt0lCYi67wNsiwMUmz833wloE0gbzJPWKs1gliFKQb34huItDQX97LyOdPdA=="],
|
|
1475
|
+
|
|
1467
1476
|
"lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="],
|
|
1468
1477
|
|
|
1469
1478
|
"light-my-request": ["light-my-request@6.6.0", "", { "dependencies": { "cookie": "^1.0.1", "process-warning": "^4.0.0", "set-cookie-parser": "^2.6.0" } }, "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A=="],
|
|
@@ -1828,6 +1837,8 @@
|
|
|
1828
1837
|
|
|
1829
1838
|
"react-helmet": ["react-helmet@6.1.0", "", { "dependencies": { "object-assign": "^4.1.1", "prop-types": "^15.7.2", "react-fast-compare": "^3.1.1", "react-side-effect": "^2.1.0" }, "peerDependencies": { "react": ">=16.3.0" } }, "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw=="],
|
|
1830
1839
|
|
|
1840
|
+
"react-helmet-async": ["react-helmet-async@2.0.5", "", { "dependencies": { "invariant": "^2.2.4", "react-fast-compare": "^3.2.2", "shallowequal": "^1.1.0" }, "peerDependencies": { "react": "^16.6.0 || ^17.0.0 || ^18.0.0" } }, "sha512-rYUYHeus+i27MvFE+Jaa4WsyBKGkL6qVgbJvSBoX8mbsWoABJXdEO0bZyi0F6i+4f0NuIb8AvqPMj3iXFHkMwg=="],
|
|
1841
|
+
|
|
1831
1842
|
"react-hook-form": ["react-hook-form@7.54.2", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-eHpAUgUjWbZocoQYUHposymRb4ZP6d0uwUnooL2uOybA9/3tPUvoAKqEWK1WaSiTxxOfTpffNZP7QwlnM3/gEg=="],
|
|
1832
1843
|
|
|
1833
1844
|
"react-intersection-observer": ["react-intersection-observer@9.16.0", "", { "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["react-dom"] }, "sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA=="],
|