@tscircuit/cli 0.0.62 → 0.0.64

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 (33) hide show
  1. package/cli.ts +4 -2
  2. package/dev-server-api/bun.lockb +0 -0
  3. package/dev-server-api/routes/api/export_files/create.ts +32 -0
  4. package/dev-server-api/routes/api/export_files/download.ts +24 -0
  5. package/dev-server-api/routes/api/export_requests/create.ts +2 -8
  6. package/dev-server-api/routes/api/export_requests/get.ts +37 -0
  7. package/dev-server-api/routes/api/export_requests/list.ts +28 -0
  8. package/dev-server-api/routes/api/export_requests/update.ts +26 -0
  9. package/dev-server-api/src/db/get-db.ts +0 -1
  10. package/dev-server-api/src/lib/public-mapping/public-map-export-file.ts +17 -0
  11. package/dev-server-api/src/lib/public-mapping/public-map-export-request.ts +6 -2
  12. package/dev-server-api/src/lib/zod/export_file.ts +8 -0
  13. package/dev-server-api/src/lib/zod/export_parameters.ts +10 -0
  14. package/dev-server-api/src/lib/zod/export_request.ts +13 -7
  15. package/dev-server-frontend/bun.lockb +0 -0
  16. package/dev-server-frontend/package-lock.json +54 -6
  17. package/dev-server-frontend/package.json +1 -1
  18. package/dev-server-frontend/src/ExampleContentView.tsx +2 -0
  19. package/dev-server-frontend/src/components/dialogs/gerber-export-dialog.tsx +45 -8
  20. package/dist/cli.js +343 -115
  21. package/lib/cmd-fns/dev/fulfill-export-requests.ts +56 -0
  22. package/lib/cmd-fns/dev/index.ts +5 -2
  23. package/lib/cmd-fns/dev/start-export-request-watcher.ts +39 -0
  24. package/lib/cmd-fns/dev/upload-examples-from-directory.ts +5 -1
  25. package/lib/cmd-fns/dev-server-fulfill-export-requests.ts +43 -0
  26. package/lib/cmd-fns/index.ts +1 -0
  27. package/lib/export-gerbers.ts +10 -0
  28. package/lib/get-program.ts +4 -0
  29. package/package.json +3 -3
  30. package/tests/assets/example-project/package-lock.json +448 -0
  31. package/tests/assets/example-project/package.json +3 -3
  32. package/tests/assets/example-project/src/MyCircuit.tsx +3 -1
  33. package/dev-server-api/routes/api/export_files/create_or_update.ts +0 -0
package/cli.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import kleur from "kleur"
3
4
  import { AppContext } from "./lib/util/app-context"
4
5
  import { createContextAndRunProgram } from "./lib/util/create-context-and-run-program"
5
6
 
@@ -7,6 +8,7 @@ async function main() {
7
8
  await createContextAndRunProgram(process.argv)
8
9
  }
9
10
 
10
- main().catch((e) => {
11
- console.log("Error running CLI:", e.toString())
11
+ main().catch((e: any) => {
12
+ console.log(kleur.gray(e.stack))
13
+ console.log(kleur.red(`Error running CLI: ${e.toString()}`))
12
14
  })
Binary file
@@ -0,0 +1,32 @@
1
+ import { publicMapExportFile } from "src/lib/public-mapping/public-map-export-file"
2
+ import { export_file } from "src/lib/zod/export_file"
3
+ import { withEdgeSpec } from "src/with-edge-spec"
4
+ import { z } from "zod"
5
+
6
+ export default withEdgeSpec({
7
+ methods: ["POST"],
8
+ jsonBody: z.object({
9
+ export_request_id: z.number().int(),
10
+ file_name: z.string(),
11
+ file_content_base64: z.string().transform((a) => Buffer.from(a, "base64")),
12
+ }),
13
+ jsonResponse: z.object({
14
+ export_file,
15
+ }),
16
+ auth: "none",
17
+ })(async (req, ctx) => {
18
+ const db_export_file = await ctx.db
19
+ .insertInto("export_file")
20
+ .values({
21
+ export_request_id: req.jsonBody.export_request_id,
22
+ file_name: req.jsonBody.file_name,
23
+ file_content: req.jsonBody.file_content_base64,
24
+ created_at: new Date().toISOString(),
25
+ })
26
+ .returningAll()
27
+ .executeTakeFirstOrThrow()
28
+
29
+ return ctx.json({
30
+ export_file: publicMapExportFile(db_export_file),
31
+ })
32
+ })
@@ -0,0 +1,24 @@
1
+ import { publicMapExportFile } from "src/lib/public-mapping/public-map-export-file"
2
+ import { export_file } from "src/lib/zod/export_file"
3
+ import { withEdgeSpec } from "src/with-edge-spec"
4
+ import { z } from "zod"
5
+
6
+ export default withEdgeSpec({
7
+ methods: ["GET"],
8
+ queryParams: z.object({
9
+ export_file_id: z.coerce.number().int(),
10
+ }),
11
+ auth: "none",
12
+ })(async (req, ctx) => {
13
+ const db_export_file = await ctx.db
14
+ .selectFrom("export_file")
15
+ .selectAll()
16
+ .where("export_file_id", "=", req.query.export_file_id)
17
+ .executeTakeFirstOrThrow()
18
+
19
+ return new Response(db_export_file.file_content, {
20
+ headers: {
21
+ "Content-Disposition": `attachment; filename="${db_export_file.file_name}"`,
22
+ },
23
+ })
24
+ })
@@ -3,20 +3,14 @@ import { NotFoundError } from "edgespec/middleware"
3
3
  import { z } from "zod"
4
4
  import { export_request } from "src/lib/zod/export_request"
5
5
  import { publicMapExportRequest } from "src/lib/public-mapping/public-map-export-request"
6
+ import { export_parameters } from "../../../src/lib/zod/export_parameters"
6
7
 
7
8
  export default withEdgeSpec({
8
9
  methods: ["POST"],
9
10
  jsonBody: z.object({
10
11
  example_file_path: z.string(),
11
12
  export_name: z.string().nullable().optional(),
12
- export_parameters: z.object({
13
- should_export_gerber_zip: z.boolean().default(false),
14
- gerbers_zip_file_name: z
15
- .string()
16
- .nullable()
17
- .optional()
18
- .default("gerbers.zip"),
19
- }),
13
+ export_parameters: export_parameters,
20
14
  }),
21
15
  jsonResponse: z.object({
22
16
  export_request,
@@ -0,0 +1,37 @@
1
+ import { withEdgeSpec } from "src/with-edge-spec"
2
+ import { z } from "zod"
3
+ import { export_request } from "src/lib/zod/export_request"
4
+ import { publicMapExportRequest } from "src/lib/public-mapping/public-map-export-request"
5
+
6
+ export default withEdgeSpec({
7
+ methods: ["GET", "POST"],
8
+ commonParams: z.object({
9
+ export_request_id: z.coerce.number(),
10
+ }),
11
+ jsonResponse: z.object({
12
+ export_request: export_request,
13
+ }),
14
+ auth: "none",
15
+ })(async (req, ctx) => {
16
+ const { export_request_id } = req.commonParams
17
+ const db_export_request: any = await ctx.db
18
+ .selectFrom("export_request")
19
+ .selectAll()
20
+ .where("export_request_id", "=", export_request_id)
21
+ .executeTakeFirstOrThrow()
22
+
23
+ db_export_request.file_summary = (
24
+ await ctx.db
25
+ .selectFrom("export_file")
26
+ .where("export_request_id", "=", export_request_id)
27
+ .selectAll()
28
+ .execute()
29
+ ).map((ef) => ({
30
+ file_name: ef.file_name,
31
+ export_file_id: ef.export_file_id,
32
+ }))
33
+
34
+ return ctx.json({
35
+ export_request: publicMapExportRequest(db_export_request),
36
+ })
37
+ })
@@ -0,0 +1,28 @@
1
+ import { withEdgeSpec } from "src/with-edge-spec"
2
+ import { z } from "zod"
3
+ import { export_request } from "src/lib/zod/export_request"
4
+ import { publicMapExportRequest } from "src/lib/public-mapping/public-map-export-request"
5
+
6
+ export default withEdgeSpec({
7
+ methods: ["GET", "POST"],
8
+ commonParams: z.object({
9
+ is_complete: z.boolean().nullable().default(null),
10
+ }),
11
+ jsonResponse: z.object({
12
+ export_requests: z.array(export_request),
13
+ }),
14
+ auth: "none",
15
+ })(async (req, ctx) => {
16
+ const { is_complete } = req.commonParams
17
+ const db_export_requests = await ctx.db
18
+ .selectFrom("export_request")
19
+ .selectAll()
20
+ .$if(is_complete !== null, (q) =>
21
+ q.where("export_request.is_complete", "=", is_complete ? 1 : 0)
22
+ )
23
+ .execute()
24
+
25
+ return ctx.json({
26
+ export_requests: db_export_requests.map((er) => publicMapExportRequest(er)),
27
+ })
28
+ })
@@ -0,0 +1,26 @@
1
+ import { withEdgeSpec } from "src/with-edge-spec"
2
+ import { NotFoundError } from "edgespec/middleware"
3
+ import { z } from "zod"
4
+ import { export_request } from "src/lib/zod/export_request"
5
+ import { publicMapExportRequest } from "src/lib/public-mapping/public-map-export-request"
6
+ import { export_parameters } from "src/lib/zod/export_parameters"
7
+
8
+ export default withEdgeSpec({
9
+ methods: ["POST"],
10
+ jsonBody: z.object({
11
+ export_request_id: z.coerce.number(),
12
+ is_complete: z.boolean(),
13
+ }),
14
+ jsonResponse: z.object({}),
15
+ auth: "none",
16
+ })(async (req, ctx) => {
17
+ await ctx.db
18
+ .updateTable("export_request")
19
+ .set({
20
+ is_complete: req.jsonBody.is_complete ? 1 : 0,
21
+ })
22
+ .where("export_request_id", "=", req.jsonBody.export_request_id)
23
+ .execute()
24
+
25
+ return ctx.json({})
26
+ })
@@ -26,7 +26,6 @@ export interface ExportFile {
26
26
  export_file_id: Generated<number>
27
27
  file_name: string
28
28
  file_content: Buffer
29
- is_complete: 1 | 0
30
29
  export_request_id: number
31
30
  created_at: string
32
31
  }
@@ -0,0 +1,17 @@
1
+ import type { ExportRequest } from "src/db/get-db"
2
+ import { export_file } from "src/lib/zod/export_file"
3
+ import { z } from "zod"
4
+
5
+ export const publicMapExportFile = (db_export_file: {
6
+ export_file_id: number
7
+ export_request_id: number
8
+ file_name: string
9
+ created_at: string
10
+ }): z.infer<typeof export_file> => {
11
+ return {
12
+ export_request_id: db_export_file.export_request_id as any,
13
+ export_file_id: db_export_file.export_file_id as any,
14
+ file_name: db_export_file.file_name,
15
+ created_at: db_export_file.created_at,
16
+ }
17
+ }
@@ -8,12 +8,16 @@ export const publicMapExportRequest = (db_export_request: {
8
8
  export_parameters: string
9
9
  export_name: string
10
10
  is_complete: 1 | 0
11
+ file_summary?: Array<any>
11
12
  created_at: string
12
13
  }): z.infer<typeof export_request> => {
13
14
  return {
14
15
  export_request_id: db_export_request.export_request_id as any,
15
- is_completed: db_export_request.is_complete === 1,
16
+ example_file_path: db_export_request.example_file_path,
17
+ export_name: db_export_request.export_name,
18
+ is_complete: db_export_request.is_complete === 1,
19
+ export_parameters: JSON.parse(db_export_request.export_parameters),
20
+ file_summary: db_export_request.file_summary,
16
21
  created_at: db_export_request.created_at,
17
- file_summary: [],
18
22
  }
19
23
  }
@@ -0,0 +1,8 @@
1
+ import { z } from "zod"
2
+
3
+ export const export_file = z.object({
4
+ export_file_id: z.number().int(),
5
+ export_request_id: z.number().int(),
6
+ file_name: z.string(),
7
+ created_at: z.string(),
8
+ })
@@ -0,0 +1,10 @@
1
+ import { z } from "zod"
2
+
3
+ export const export_parameters = z.object({
4
+ should_export_gerber_zip: z.boolean().default(false),
5
+ gerbers_zip_file_name: z
6
+ .string()
7
+ .nullable()
8
+ .optional()
9
+ .default("gerbers.zip"),
10
+ })
@@ -1,13 +1,19 @@
1
1
  import { z } from "zod"
2
+ import { export_parameters } from "./export_parameters"
2
3
 
3
4
  export const export_request = z.object({
4
5
  export_request_id: z.coerce.number(),
5
- is_completed: z.boolean(),
6
+ is_complete: z.boolean(),
6
7
  created_at: z.string(),
7
- file_summary: z.array(
8
- z.object({
9
- file_name: z.string(),
10
- is_complete: z.boolean(),
11
- })
12
- ),
8
+ export_name: z.string(),
9
+ example_file_path: z.string(),
10
+ export_parameters,
11
+ file_summary: z
12
+ .array(
13
+ z.object({
14
+ file_name: z.string(),
15
+ export_file_id: z.number().int(),
16
+ })
17
+ )
18
+ .optional(),
13
19
  })
Binary file
@@ -8,6 +8,7 @@
8
8
  "name": "@tscircuit/dev-server-frontend",
9
9
  "version": "0.0.0",
10
10
  "dependencies": {
11
+ "@headlessui/react": "^1.7.18",
11
12
  "@radix-ui/react-alert-dialog": "^1.0.5",
12
13
  "@radix-ui/react-context-menu": "^2.1.5",
13
14
  "@radix-ui/react-dialog": "^1.0.5",
@@ -21,8 +22,8 @@
21
22
  "@radix-ui/react-toggle": "^1.0.3",
22
23
  "@radix-ui/react-toggle-group": "^1.0.4",
23
24
  "@radix-ui/react-tooltip": "^1.0.7",
24
- "@tscircuit/builder": "^1.5.29",
25
- "@tscircuit/pcb-viewer": "^1.2.23",
25
+ "@tscircuit/builder": "latest",
26
+ "@tscircuit/pcb-viewer": "^1.2.24",
26
27
  "@tscircuit/schematic-viewer": "^1.1.22",
27
28
  "axios": "^1.6.7",
28
29
  "class-variance-authority": "^0.7.0",
@@ -660,6 +661,22 @@
660
661
  "version": "0.2.1",
661
662
  "license": "MIT"
662
663
  },
664
+ "node_modules/@headlessui/react": {
665
+ "version": "1.7.18",
666
+ "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.18.tgz",
667
+ "integrity": "sha512-4i5DOrzwN4qSgNsL4Si61VMkUcWbcSKueUV7sFhpHzQcSShdlHENE5+QBntMSRvHt8NyoFO2AGG8si9lq+w4zQ==",
668
+ "dependencies": {
669
+ "@tanstack/react-virtual": "^3.0.0-beta.60",
670
+ "client-only": "^0.0.1"
671
+ },
672
+ "engines": {
673
+ "node": ">=10"
674
+ },
675
+ "peerDependencies": {
676
+ "react": "^16 || ^17 || ^18",
677
+ "react-dom": "^16 || ^17 || ^18"
678
+ }
679
+ },
663
680
  "node_modules/@humanwhocodes/config-array": {
664
681
  "version": "0.11.14",
665
682
  "dev": true,
@@ -1786,6 +1803,31 @@
1786
1803
  "linux"
1787
1804
  ]
1788
1805
  },
1806
+ "node_modules/@tanstack/react-virtual": {
1807
+ "version": "3.2.1",
1808
+ "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.2.1.tgz",
1809
+ "integrity": "sha512-i9Nt0ssIh2bSjomJZlr6Iq5usT/9+ewo2/fKHRNk6kjVKS8jrhXbnO8NEawarCuBx/efv0xpoUUKKGxa0cQb4Q==",
1810
+ "dependencies": {
1811
+ "@tanstack/virtual-core": "3.2.1"
1812
+ },
1813
+ "funding": {
1814
+ "type": "github",
1815
+ "url": "https://github.com/sponsors/tannerlinsley"
1816
+ },
1817
+ "peerDependencies": {
1818
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
1819
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
1820
+ }
1821
+ },
1822
+ "node_modules/@tanstack/virtual-core": {
1823
+ "version": "3.2.1",
1824
+ "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.2.1.tgz",
1825
+ "integrity": "sha512-nO0d4vRzsmpBQCJYyClNHPPoUMI4nXNfrm6IcCRL33ncWMoNVpURh9YebEHPw8KrtsP2VSJIHE4gf4XFGk1OGg==",
1826
+ "funding": {
1827
+ "type": "github",
1828
+ "url": "https://github.com/sponsors/tannerlinsley"
1829
+ }
1830
+ },
1789
1831
  "node_modules/@tscircuit/builder": {
1790
1832
  "version": "1.5.53",
1791
1833
  "resolved": "https://registry.npmjs.org/@tscircuit/builder/-/builder-1.5.53.tgz",
@@ -1825,9 +1867,9 @@
1825
1867
  }
1826
1868
  },
1827
1869
  "node_modules/@tscircuit/pcb-viewer": {
1828
- "version": "1.2.23",
1829
- "resolved": "https://registry.npmjs.org/@tscircuit/pcb-viewer/-/pcb-viewer-1.2.23.tgz",
1830
- "integrity": "sha512-GV9UcKu1JEHsqF5xHjSbg4Y+pDqVjeJdH0BMLOXAQOFpPelTuS5MWwdby6qthfqtPoPfFGzJlTKrTSfC3QTFqw==",
1870
+ "version": "1.2.24",
1871
+ "resolved": "https://registry.npmjs.org/@tscircuit/pcb-viewer/-/pcb-viewer-1.2.24.tgz",
1872
+ "integrity": "sha512-T1ohSL9vVI2nPxeXiYnSDJHMVV55Zspa9MqcLCfb4MDFhm8kf/Ba/kMSkmvwkzv8jLFJkdS+HkEcEu9yfncl2Q==",
1831
1873
  "dependencies": {
1832
1874
  "react-supergrid": "^1.0.7",
1833
1875
  "transformation-matrix": "^2.13.0"
@@ -2550,6 +2592,11 @@
2550
2592
  "node": ">=6"
2551
2593
  }
2552
2594
  },
2595
+ "node_modules/client-only": {
2596
+ "version": "0.0.1",
2597
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
2598
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
2599
+ },
2553
2600
  "node_modules/clsx": {
2554
2601
  "version": "2.1.0",
2555
2602
  "license": "MIT",
@@ -4271,7 +4318,8 @@
4271
4318
  },
4272
4319
  "node_modules/react-query": {
4273
4320
  "version": "3.39.3",
4274
- "license": "MIT",
4321
+ "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz",
4322
+ "integrity": "sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==",
4275
4323
  "dependencies": {
4276
4324
  "@babel/runtime": "^7.5.5",
4277
4325
  "broadcast-channel": "^3.4.1",
@@ -31,7 +31,7 @@
31
31
  "@radix-ui/react-toggle-group": "^1.0.4",
32
32
  "@radix-ui/react-tooltip": "^1.0.7",
33
33
  "@tscircuit/builder": "latest",
34
- "@tscircuit/pcb-viewer": "^1.2.23",
34
+ "@tscircuit/pcb-viewer": "^1.2.24",
35
35
  "@tscircuit/schematic-viewer": "^1.1.22",
36
36
  "axios": "^1.6.7",
37
37
  "class-variance-authority": "^0.7.0",
@@ -25,7 +25,9 @@ export const ExampleContentView = () => {
25
25
  })
26
26
  .then((r) => r.data.dev_package_example),
27
27
  {
28
+ refetchInterval: 5_000,
28
29
  refetchIntervalInBackground: true,
30
+ refetchOnWindowFocus: true,
29
31
  retry: false,
30
32
  }
31
33
  )
@@ -45,14 +45,51 @@ export const useGerberExportDialog = () => {
45
45
  setExportError(null)
46
46
  setIsExporting(true)
47
47
  try {
48
- await axios.post("/api/export_requests/create", {
49
- example_file_path: activeDevExamplePackage.file_path,
50
- export_name: activeDevExamplePackage.export_name,
51
- export_parameters: {
52
- should_export_gerber_zip: true,
53
- gerbers_zip_file_name: outputName,
54
- },
55
- })
48
+ let export_request = await axios
49
+ .post("/api/export_requests/create", {
50
+ example_file_path: activeDevExamplePackage.file_path,
51
+ export_name: activeDevExamplePackage.export_name,
52
+ export_parameters: {
53
+ should_export_gerber_zip: true,
54
+ gerbers_zip_file_name: outputName,
55
+ },
56
+ })
57
+ .then((r) => r.data.export_request)
58
+
59
+ const pollExportRequest = async () => {
60
+ while (!export_request.is_complete) {
61
+ try {
62
+ export_request = await axios
63
+ .post("/api/export_requests/get", {
64
+ export_request_id: export_request.export_request_id,
65
+ })
66
+ .then((r) => r.data.export_request)
67
+ } catch (e: any) {
68
+ console.error(e)
69
+ setExportError(
70
+ `${e.toString()}\n\n${e.response?.data?.error?.message}`
71
+ )
72
+ setIsExporting(false)
73
+ return
74
+ }
75
+ await new Promise((resolve) => setTimeout(resolve, 100))
76
+ }
77
+ setIsExporting(false)
78
+ }
79
+
80
+ await pollExportRequest()
81
+
82
+ // open /api/export_files/download?export_file_id=... in new tab
83
+
84
+ const export_file_id =
85
+ export_request.file_summary[0].export_file_id
86
+
87
+ window.open(
88
+ `/api/export_files/download?export_file_id=${export_file_id}`,
89
+ "_blank"
90
+ )
91
+
92
+ setIsExporting(false)
56
93
  } catch (e: any) {
57
94
  console.error(e)
58
95
  setExportError(