@tscircuit/cli 0.0.393 → 0.1.1

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 (245) hide show
  1. package/.github/workflows/bun-formatcheck.yml +26 -0
  2. package/.github/workflows/bun-pver-release.yml +25 -0
  3. package/.github/workflows/{typecheck.yml → bun-typecheck.yml} +0 -3
  4. package/LICENSE +21 -0
  5. package/README.md +30 -36
  6. package/biome.json +9 -9
  7. package/bun.lockb +0 -0
  8. package/cli/CliContext.ts +8 -0
  9. package/cli/auth/login/register.ts +73 -0
  10. package/cli/auth/logout/register.ts +11 -0
  11. package/cli/auth/register.ts +5 -0
  12. package/cli/config/print/register.ts +12 -0
  13. package/cli/config/register.ts +5 -0
  14. package/cli/dev/register.ts +111 -0
  15. package/cli/main.ts +31 -0
  16. package/dist/main.js +473 -0
  17. package/docs/file-server-api-usage.md +57 -0
  18. package/docs/run-frame-usage.md +14 -0
  19. package/example-dir/manual-edits.json +1 -0
  20. package/example-dir/snippet.d.ts +13 -0
  21. package/example-dir/snippet.tsx +20 -0
  22. package/example-dir/types.d.ts +11 -0
  23. package/lib/cli-config/TypedConfigStore.ts +50 -0
  24. package/lib/cli-config/index.ts +16 -0
  25. package/lib/dependency-analysis/DependencyAnalyzer.ts +129 -0
  26. package/lib/dependency-analysis/getLocalFileDependencies.ts +101 -0
  27. package/lib/dependency-analysis/installNodeModuleTypes.ts +74 -0
  28. package/lib/index.ts +2 -0
  29. package/lib/project-config/index.ts +5 -0
  30. package/lib/registry-api/endpoint-types.ts +20 -0
  31. package/lib/registry-api/get-ky.ts +30 -0
  32. package/lib/server/EventsWatcher.ts +75 -0
  33. package/lib/server/createServer.ts +62 -0
  34. package/lib/site/getIndex.ts +18 -0
  35. package/package.json +27 -144
  36. package/tsconfig.json +25 -22
  37. package/.github/workflows/formatbot.yml +0 -63
  38. package/.github/workflows/release.yml +0 -40
  39. package/.github/workflows/test.yml +0 -32
  40. package/.github/workflows/windows-tests.yml +0 -32
  41. package/.prettierrc +0 -1
  42. package/DEVELOPMENT.md +0 -7
  43. package/api/README.md +0 -3
  44. package/api/db/generic-json-level.ts +0 -123
  45. package/api/db/get-db.ts +0 -26
  46. package/api/db/schema.ts +0 -65
  47. package/api/db/zod-level-db.ts +0 -148
  48. package/api/index.ts +0 -4
  49. package/api/lib/middlewares/with-db.ts +0 -18
  50. package/api/lib/middlewares/with-debug-request-logging.ts +0 -13
  51. package/api/lib/middlewares/with-error-response.ts +0 -37
  52. package/api/lib/with-winter-spec.ts +0 -9
  53. package/api/lib/zod/export_parameters.ts +0 -25
  54. package/api/routes/api/db/download.ts +0 -25
  55. package/api/routes/api/dev_package_examples/create.ts +0 -43
  56. package/api/routes/api/dev_package_examples/get.ts +0 -46
  57. package/api/routes/api/dev_package_examples/list.ts +0 -36
  58. package/api/routes/api/dev_package_examples/update.ts +0 -59
  59. package/api/routes/api/dev_server/reset.ts +0 -13
  60. package/api/routes/api/export_files/create.ts +0 -27
  61. package/api/routes/api/export_files/download.ts +0 -25
  62. package/api/routes/api/export_requests/create.ts +0 -30
  63. package/api/routes/api/export_requests/get.ts +0 -43
  64. package/api/routes/api/export_requests/list.ts +0 -26
  65. package/api/routes/api/export_requests/update.ts +0 -34
  66. package/api/routes/api/health.ts +0 -11
  67. package/api/routes/api/package_info/create.ts +0 -26
  68. package/api/routes/api/package_info/get.ts +0 -16
  69. package/api/routes/health.ts +0 -11
  70. package/api/routes/index.ts +0 -16
  71. package/api/server.ts +0 -20
  72. package/api/static-routes.ts +0 -24
  73. package/api/tests/fixtures/get-test-server.ts +0 -31
  74. package/api/tests/fixtures/start-server.ts +0 -41
  75. package/api/tests/routes/dev_package_examples/create.test.ts +0 -19
  76. package/api/tests/routes/dev_package_examples/get.test.ts +0 -25
  77. package/api/tests/routes/dev_package_examples/list.test.ts +0 -32
  78. package/api/tests/routes/dev_package_examples/update.test.ts +0 -38
  79. package/api/tests/routes/export_files/create.test.ts +0 -18
  80. package/api/tests/routes/export_files/download.test.ts +0 -29
  81. package/api/tests/routes/export_requests/create.test.ts +0 -24
  82. package/api/tests/routes/export_requests/get.test.ts +0 -41
  83. package/api/tests/routes/export_requests/list.test.ts +0 -35
  84. package/api/tests/routes/export_requests/update.test.ts +0 -50
  85. package/api/tests/routes/health.test.ts +0 -10
  86. package/bunfig.toml +0 -2
  87. package/cli/cli.ts +0 -13
  88. package/cli/lib/cmd-fns/add.ts +0 -34
  89. package/cli/lib/cmd-fns/auth-login.ts +0 -59
  90. package/cli/lib/cmd-fns/auth-logout.ts +0 -7
  91. package/cli/lib/cmd-fns/auth-sessions-create.ts +0 -3
  92. package/cli/lib/cmd-fns/auth-sessions-get.ts +0 -3
  93. package/cli/lib/cmd-fns/auth-sessions-list.ts +0 -5
  94. package/cli/lib/cmd-fns/config-clear.ts +0 -5
  95. package/cli/lib/cmd-fns/config-print-config.ts +0 -6
  96. package/cli/lib/cmd-fns/config-reveal-location.ts +0 -5
  97. package/cli/lib/cmd-fns/config-set-log-requests.ts +0 -7
  98. package/cli/lib/cmd-fns/config-set-registry.ts +0 -9
  99. package/cli/lib/cmd-fns/config-set-runtime.ts +0 -7
  100. package/cli/lib/cmd-fns/config-set-session.ts +0 -7
  101. package/cli/lib/cmd-fns/dev/check-if-initialized.ts +0 -22
  102. package/cli/lib/cmd-fns/dev/derive-selector-from-pcb-component-id.ts +0 -23
  103. package/cli/lib/cmd-fns/dev/dev-server-request-handler.ts +0 -61
  104. package/cli/lib/cmd-fns/dev/find-available-port.ts +0 -32
  105. package/cli/lib/cmd-fns/dev/fulfill-export-requests.ts +0 -162
  106. package/cli/lib/cmd-fns/dev/get-dev-server-axios.ts +0 -29
  107. package/cli/lib/cmd-fns/dev/index.ts +0 -168
  108. package/cli/lib/cmd-fns/dev/infer-export-name-from-source.ts +0 -17
  109. package/cli/lib/cmd-fns/dev/mark-all-examples-loading.ts +0 -18
  110. package/cli/lib/cmd-fns/dev/soupify-and-upload-example-file.ts +0 -62
  111. package/cli/lib/cmd-fns/dev/start-dev-server.ts +0 -34
  112. package/cli/lib/cmd-fns/dev/start-edit-event-watcher.ts +0 -347
  113. package/cli/lib/cmd-fns/dev/start-export-request-watcher.ts +0 -33
  114. package/cli/lib/cmd-fns/dev/start-fs-watcher.ts +0 -54
  115. package/cli/lib/cmd-fns/dev/upload-examples-from-directory.ts +0 -42
  116. package/cli/lib/cmd-fns/dev-server-fulfill-export-requests.ts +0 -43
  117. package/cli/lib/cmd-fns/dev-server-upload.ts +0 -56
  118. package/cli/lib/cmd-fns/export-gerbers.ts +0 -28
  119. package/cli/lib/cmd-fns/export-kicad-pcb.ts +0 -36
  120. package/cli/lib/cmd-fns/export-pnp-csv.ts +0 -32
  121. package/cli/lib/cmd-fns/gen-jlcpcb-component.ts +0 -64
  122. package/cli/lib/cmd-fns/go.ts +0 -14
  123. package/cli/lib/cmd-fns/index.ts +0 -46
  124. package/cli/lib/cmd-fns/init/create-or-modify-npmrc.ts +0 -21
  125. package/cli/lib/cmd-fns/init/get-generated-npmrc.ts +0 -8
  126. package/cli/lib/cmd-fns/init/get-generated-readme.ts +0 -41
  127. package/cli/lib/cmd-fns/init/get-generated-tsconfig.ts +0 -34
  128. package/cli/lib/cmd-fns/init/index.ts +0 -193
  129. package/cli/lib/cmd-fns/install.ts +0 -34
  130. package/cli/lib/cmd-fns/lint.ts +0 -43
  131. package/cli/lib/cmd-fns/open.ts +0 -19
  132. package/cli/lib/cmd-fns/package-examples-create.ts +0 -36
  133. package/cli/lib/cmd-fns/package-examples-get.ts +0 -20
  134. package/cli/lib/cmd-fns/package-examples-list.ts +0 -18
  135. package/cli/lib/cmd-fns/package-files-create.ts +0 -31
  136. package/cli/lib/cmd-fns/package-files-download.ts +0 -29
  137. package/cli/lib/cmd-fns/package-files-get.ts +0 -3
  138. package/cli/lib/cmd-fns/package-files-list.ts +0 -28
  139. package/cli/lib/cmd-fns/package-files-upload-directory.ts +0 -6
  140. package/cli/lib/cmd-fns/package-releases-create.ts +0 -35
  141. package/cli/lib/cmd-fns/package-releases-get.ts +0 -3
  142. package/cli/lib/cmd-fns/package-releases-list.ts +0 -32
  143. package/cli/lib/cmd-fns/package-releases-update.ts +0 -45
  144. package/cli/lib/cmd-fns/packages-create.ts +0 -16
  145. package/cli/lib/cmd-fns/packages-get.ts +0 -16
  146. package/cli/lib/cmd-fns/packages-list.ts +0 -16
  147. package/cli/lib/cmd-fns/publish/index.ts +0 -336
  148. package/cli/lib/cmd-fns/remove.ts +0 -31
  149. package/cli/lib/cmd-fns/render.ts +0 -45
  150. package/cli/lib/cmd-fns/soupify.ts +0 -31
  151. package/cli/lib/cmd-fns/uninstall.ts +0 -31
  152. package/cli/lib/cmd-fns/version.ts +0 -38
  153. package/cli/lib/create-config-manager.ts +0 -97
  154. package/cli/lib/export-fns/export-bom-csv.ts +0 -32
  155. package/cli/lib/export-fns/export-gerbers.ts +0 -108
  156. package/cli/lib/export-fns/export-kicad-pcb.ts +0 -32
  157. package/cli/lib/export-fns/export-pnp-csv.ts +0 -31
  158. package/cli/lib/get-program.ts +0 -387
  159. package/cli/lib/param-handlers/index.ts +0 -21
  160. package/cli/lib/param-handlers/interact-for-local-directory.ts +0 -58
  161. package/cli/lib/param-handlers/interact-for-local-file.ts +0 -59
  162. package/cli/lib/param-handlers/interact-for-package-example-id.ts +0 -25
  163. package/cli/lib/param-handlers/interact-for-package-name-with-version.ts +0 -63
  164. package/cli/lib/param-handlers/interact-for-package-name.ts +0 -45
  165. package/cli/lib/param-handlers/interact-for-package-release-id.ts +0 -15
  166. package/cli/lib/param-handlers/interact-for-registry-url.ts +0 -27
  167. package/cli/lib/param-handlers/interact-for-runtime.ts +0 -33
  168. package/cli/lib/param-handlers/param-handler-type.ts +0 -7
  169. package/cli/lib/posthog.ts +0 -23
  170. package/cli/lib/soupify/get-export-name-from-file.ts +0 -29
  171. package/cli/lib/soupify/get-tmp-entrpoint-filepath.ts +0 -15
  172. package/cli/lib/soupify/index.ts +0 -1
  173. package/cli/lib/soupify/run-entrypoint-file.ts +0 -59
  174. package/cli/lib/soupify/soupify-with-core.ts +0 -74
  175. package/cli/lib/soupify/soupify.ts +0 -6
  176. package/cli/lib/util/app-context.ts +0 -17
  177. package/cli/lib/util/create-context-and-run-program.ts +0 -168
  178. package/cli/lib/util/get-all-package-files.ts +0 -66
  179. package/cli/lib/util/lint-project.ts +0 -137
  180. package/cli/tests/export-gerber-keyboard.test.ts +0 -16
  181. package/cli/tests/export-gerber.test.ts +0 -49
  182. package/cli/tests/export-kicad-pcb.test.ts +0 -23
  183. package/cli/tests/export-pnp-csv.test.ts +0 -24
  184. package/cli/tests/fixtures/preload.ts +0 -54
  185. package/cli/tests/init.test.ts +0 -9
  186. package/cli/tests/open.test.ts +0 -9
  187. package/cli/tests/soupify-builder.test.ts +0 -9
  188. package/cli/tests/soupify-core.test.ts +0 -9
  189. package/dist/cli.js +0 -3676
  190. package/docs/EDIT_EVENT_PIPELINE.md +0 -34
  191. package/example-project/README.md +0 -18
  192. package/example-project/examples/basic-capacitor.tsx +0 -5
  193. package/example-project/examples/basic-chip.tsx +0 -26
  194. package/example-project/examples/basic-resistor.tsx +0 -3
  195. package/example-project/examples/macrokeypad.tsx +0 -59
  196. package/example-project/index.ts +0 -1
  197. package/example-project/package.json +0 -5
  198. package/example-project/src/ArduinoProMicroBreakout.tsx +0 -37
  199. package/example-project/src/Key.tsx +0 -46
  200. package/example-project/src/Keyswitch.tsx +0 -26
  201. package/example-project/src/KeyswitchSocket.tsx +0 -56
  202. package/example-project/src/MyCircuit.tsx +0 -38
  203. package/example-project/src/manual-edits.ts +0 -93
  204. package/frontend/README.md +0 -3
  205. package/frontend/bun.lockb +0 -0
  206. package/frontend/components/command-k.tsx +0 -86
  207. package/frontend/components/dialogs/generic-export-dialog.tsx +0 -189
  208. package/frontend/components/dialogs/gerber-export-dialog.tsx +0 -168
  209. package/frontend/components/global-context-providers.tsx +0 -11
  210. package/frontend/components/select-example-search.tsx +0 -118
  211. package/frontend/components/ui/alert-dialog.tsx +0 -139
  212. package/frontend/components/ui/alert.tsx +0 -59
  213. package/frontend/components/ui/breadcrumb.tsx +0 -115
  214. package/frontend/components/ui/button.tsx +0 -57
  215. package/frontend/components/ui/card.tsx +0 -76
  216. package/frontend/components/ui/command.tsx +0 -153
  217. package/frontend/components/ui/context-menu.tsx +0 -202
  218. package/frontend/components/ui/dialog.tsx +0 -120
  219. package/frontend/components/ui/menubar.tsx +0 -238
  220. package/frontend/components/ui/navigation-menu.tsx +0 -128
  221. package/frontend/components/ui/popover.tsx +0 -31
  222. package/frontend/components/ui/select.tsx +0 -162
  223. package/frontend/components/ui/tabs.tsx +0 -53
  224. package/frontend/components/ui/toggle-group.tsx +0 -59
  225. package/frontend/components/ui/toggle.tsx +0 -43
  226. package/frontend/components/ui/tooltip.tsx +0 -28
  227. package/frontend/components.json +0 -17
  228. package/frontend/hooks/toast-if-api-not-connected.ts +0 -23
  229. package/frontend/hooks/use-active-dev-package-example-lite.ts +0 -39
  230. package/frontend/hooks/use-dev-package-examples.tsx +0 -18
  231. package/frontend/hooks/use-global-store.ts +0 -42
  232. package/frontend/index.css +0 -76
  233. package/frontend/index.html +0 -13
  234. package/frontend/lib/utils.ts +0 -6
  235. package/frontend/main.tsx +0 -13
  236. package/frontend/tailwind.config.js +0 -74
  237. package/frontend/views/App.tsx +0 -22
  238. package/frontend/views/Header.tsx +0 -55
  239. package/frontend/views/HeaderMenu.tsx +0 -326
  240. package/frontend/views/MainContentView.tsx +0 -172
  241. package/frontend/vite-env.d.ts +0 -1
  242. package/frontend/vite.config.ts +0 -50
  243. package/renovate.json +0 -15
  244. package/scripts/build-cli.ts +0 -12
  245. package/tsup.config.ts +0 -7
@@ -0,0 +1,50 @@
1
+ export interface TypedConfigstore<T extends Record<string, any>> {
2
+ /**
3
+ * Get the path to the config file. Can be used to show the user
4
+ * where it is, or better, open it for them.
5
+ */
6
+ path: string
7
+
8
+ /**
9
+ * Get all items as an object or replace the current config with an object.
10
+ */
11
+ all: any
12
+
13
+ /**
14
+ * Get the item count
15
+ */
16
+ size: number
17
+
18
+ /**
19
+ * Get an item
20
+ * @param key The string key to get
21
+ * @return The contents of the config from key $key
22
+ */
23
+ get(key: keyof T): any
24
+
25
+ /**
26
+ * Set an item
27
+ * @param key The string key
28
+ * @param val The value to set
29
+ */
30
+ set<K extends keyof T>(key: K, val: T[K]): void
31
+
32
+ /**
33
+ * Determines if a key is present in the config
34
+ * @param key The string key to test for
35
+ * @return True if the key is present
36
+ */
37
+ has(key: keyof T): boolean
38
+
39
+ /**
40
+ * Delete an item.
41
+ * @param key The key to delete
42
+ */
43
+ delete(key: keyof T): void
44
+
45
+ /**
46
+ * Clear the config.
47
+ * Equivalent to <code>Configstore.all = {};</code>
48
+ */
49
+ clear(): void
50
+ }
@@ -0,0 +1,16 @@
1
+ import Configstore from "configstore"
2
+ import type { TypedConfigstore } from "./TypedConfigStore"
3
+
4
+ export interface CliConfig {
5
+ sessionToken?: string
6
+ githubUsername?: string
7
+ registryApiUrl?: string
8
+ }
9
+
10
+ export const cliConfig: TypedConfigstore<CliConfig> = new Configstore(
11
+ "tscircuit",
12
+ )
13
+
14
+ export const getRegistryApiUrl = (): string => {
15
+ return cliConfig.get("registryApiUrl") ?? "https://registry-api.tscircuit.com"
16
+ }
@@ -0,0 +1,129 @@
1
+ import * as ts from "typescript"
2
+ import * as path from "path"
3
+ import * as fs from "fs"
4
+
5
+ interface DependencyAnalyzerOptions {
6
+ baseDir: string
7
+ includeNodeModules?: boolean
8
+ includeCssModules?: boolean
9
+ }
10
+
11
+ class DependencyAnalyzer {
12
+ private readonly baseDir: string
13
+ private readonly includeNodeModules: boolean
14
+ private readonly includeCssModules: boolean
15
+ private readonly cache: Map<string, Set<string>> = new Map()
16
+
17
+ constructor(options: DependencyAnalyzerOptions) {
18
+ this.baseDir = options.baseDir
19
+ this.includeNodeModules = options.includeNodeModules ?? false
20
+ this.includeCssModules = options.includeCssModules ?? true
21
+ }
22
+
23
+ public analyze(filePath: string): Set<string> {
24
+ if (this.cache.has(filePath)) {
25
+ return this.cache.get(filePath)!
26
+ }
27
+
28
+ const dependencies = new Set<string>()
29
+ const sourceFile = this.createSourceFile(filePath)
30
+
31
+ if (!sourceFile) {
32
+ return dependencies
33
+ }
34
+
35
+ this.visitNode(sourceFile, dependencies)
36
+ this.cache.set(filePath, dependencies)
37
+
38
+ return dependencies
39
+ }
40
+
41
+ private createSourceFile(filePath: string): ts.SourceFile | null {
42
+ try {
43
+ const content = fs.readFileSync(filePath, "utf-8")
44
+ return ts.createSourceFile(
45
+ filePath,
46
+ content,
47
+ ts.ScriptTarget.Latest,
48
+ true,
49
+ )
50
+ } catch (error) {
51
+ console.error(`Error reading file ${filePath}:`, error)
52
+ return null
53
+ }
54
+ }
55
+
56
+ private visitNode(node: ts.Node, dependencies: Set<string>): void {
57
+ if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
58
+ const moduleSpecifier = node.moduleSpecifier
59
+ if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
60
+ const importPath = moduleSpecifier.text
61
+ this.addDependency(importPath, dependencies)
62
+ }
63
+ }
64
+
65
+ // Check for dynamic imports
66
+ if (
67
+ ts.isCallExpression(node) &&
68
+ node.expression.kind === ts.SyntaxKind.ImportKeyword
69
+ ) {
70
+ const argument = node.arguments[0]
71
+ if (argument && ts.isStringLiteral(argument)) {
72
+ this.addDependency(argument.text, dependencies)
73
+ }
74
+ }
75
+
76
+ ts.forEachChild(node, (child) => this.visitNode(child, dependencies))
77
+ }
78
+
79
+ private addDependency(importPath: string, dependencies: Set<string>): void {
80
+ // Skip node_modules unless explicitly included
81
+ if (!this.includeNodeModules && importPath.startsWith("node_modules")) {
82
+ return
83
+ }
84
+
85
+ // Handle CSS modules if enabled
86
+ if (this.includeCssModules && importPath.endsWith(".css")) {
87
+ const resolvedPath = this.resolvePath(importPath)
88
+ if (resolvedPath) {
89
+ dependencies.add(resolvedPath)
90
+ }
91
+ return
92
+ }
93
+
94
+ // Resolve relative imports
95
+ if (importPath.startsWith(".")) {
96
+ const resolvedPath = this.resolvePath(importPath)
97
+ if (resolvedPath) {
98
+ dependencies.add(resolvedPath)
99
+ }
100
+ }
101
+ }
102
+
103
+ private resolvePath(importPath: string): string | null {
104
+ try {
105
+ const extensions = [".tsx", ".ts", ".jsx", ".js", ".css"]
106
+ const resolvedPath = path.resolve(this.baseDir, importPath)
107
+
108
+ // Try exact path first
109
+ if (fs.existsSync(resolvedPath)) {
110
+ return resolvedPath
111
+ }
112
+
113
+ // Try with extensions
114
+ for (const ext of extensions) {
115
+ const pathWithExt = resolvedPath + ext
116
+ if (fs.existsSync(pathWithExt)) {
117
+ return pathWithExt
118
+ }
119
+ }
120
+
121
+ return null
122
+ } catch (error) {
123
+ console.error(`Error resolving path ${importPath}:`, error)
124
+ return null
125
+ }
126
+ }
127
+ }
128
+
129
+ export { DependencyAnalyzer, type DependencyAnalyzerOptions }
@@ -0,0 +1,101 @@
1
+ import * as ts from "typescript"
2
+ import * as path from "path"
3
+ import * as fs from "fs"
4
+
5
+ function getLocalFileDependencies(pathToTsxFile: string): string[] {
6
+ // Ensure absolute path
7
+ const absolutePath = path.resolve(pathToTsxFile)
8
+ const baseDir = path.dirname(absolutePath)
9
+
10
+ // Read and parse the file
11
+ const content = fs.readFileSync(absolutePath, "utf-8")
12
+ const sourceFile = ts.createSourceFile(
13
+ absolutePath,
14
+ content,
15
+ ts.ScriptTarget.Latest,
16
+ true,
17
+ )
18
+
19
+ const dependencies = new Set<string>()
20
+
21
+ // Recursively visit nodes to find imports
22
+ function visit(node: ts.Node) {
23
+ if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
24
+ const moduleSpecifier = node.moduleSpecifier
25
+ if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
26
+ const importPath = moduleSpecifier.text
27
+ // Only process local imports (starting with . or ..)
28
+ if (importPath.startsWith(".")) {
29
+ resolveAndAddDependency(importPath)
30
+ }
31
+ }
32
+ }
33
+
34
+ // Handle dynamic imports
35
+ if (
36
+ ts.isCallExpression(node) &&
37
+ node.expression.kind === ts.SyntaxKind.ImportKeyword
38
+ ) {
39
+ const argument = node.arguments[0]
40
+ if (argument && ts.isStringLiteral(argument)) {
41
+ const importPath = argument.text
42
+ if (importPath.startsWith(".")) {
43
+ resolveAndAddDependency(importPath)
44
+ }
45
+ }
46
+ }
47
+
48
+ ts.forEachChild(node, visit)
49
+ }
50
+
51
+ // Helper to resolve and add dependency paths
52
+ function resolveAndAddDependency(importPath: string) {
53
+ const extensions = [
54
+ ".tsx",
55
+ ".ts",
56
+ ".jsx",
57
+ ".js",
58
+ ".css",
59
+ ".scss",
60
+ ".sass",
61
+ ".less",
62
+ ]
63
+ let resolvedPath = path.resolve(baseDir, importPath)
64
+
65
+ // Check if path exists as-is
66
+ if (fs.existsSync(resolvedPath)) {
67
+ dependencies.add(resolvedPath)
68
+ return
69
+ }
70
+
71
+ // Try with extensions
72
+ for (const ext of extensions) {
73
+ const pathWithExt = resolvedPath + ext
74
+ if (fs.existsSync(pathWithExt)) {
75
+ dependencies.add(pathWithExt)
76
+ return
77
+ }
78
+ }
79
+
80
+ // Check for index files in directories
81
+ if (
82
+ fs.existsSync(resolvedPath) &&
83
+ fs.statSync(resolvedPath).isDirectory()
84
+ ) {
85
+ for (const ext of extensions) {
86
+ const indexPath = path.join(resolvedPath, `index${ext}`)
87
+ if (fs.existsSync(indexPath)) {
88
+ dependencies.add(indexPath)
89
+ return
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ // Start the traversal
96
+ visit(sourceFile)
97
+
98
+ return Array.from(dependencies)
99
+ }
100
+
101
+ export { getLocalFileDependencies }
@@ -0,0 +1,74 @@
1
+ import * as fs from "node:fs"
2
+ import * as path from "node:path"
3
+ import * as ts from "typescript"
4
+
5
+ interface SnippetApiResponse {
6
+ snippet: {
7
+ dts: string
8
+ }
9
+ }
10
+
11
+ export async function installTypes(snippetPath: string) {
12
+ const content = fs.readFileSync(snippetPath, "utf-8")
13
+ const sourceFile = ts.createSourceFile(
14
+ snippetPath,
15
+ content,
16
+ ts.ScriptTarget.Latest,
17
+ true,
18
+ )
19
+
20
+ const imports: string[] = []
21
+
22
+ function visit(node: ts.Node) {
23
+ if (ts.isImportDeclaration(node)) {
24
+ const moduleSpecifier = node.moduleSpecifier
25
+ if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
26
+ const importPath = moduleSpecifier.text
27
+ if (importPath.startsWith("@tsci/")) {
28
+ imports.push(importPath)
29
+ }
30
+ }
31
+ }
32
+ ts.forEachChild(node, visit)
33
+ }
34
+
35
+ visit(sourceFile)
36
+
37
+ let projectRoot = path.dirname(snippetPath)
38
+ while (projectRoot !== path.parse(projectRoot).root) {
39
+ if (fs.existsSync(path.join(projectRoot, "package.json"))) {
40
+ break
41
+ }
42
+ projectRoot = path.dirname(projectRoot)
43
+ }
44
+
45
+ for (const importPath of imports) {
46
+ const [owner, name] = importPath.replace("@tsci/", "").split(".")
47
+ try {
48
+ const response = await fetch(
49
+ `https://registry-api.tscircuit.com/snippets/get?owner_name=${owner}&unscoped_name=${name}`,
50
+ )
51
+
52
+ if (!response.ok) {
53
+ console.warn(`Failed to fetch types for ${importPath}`)
54
+ continue
55
+ }
56
+
57
+ const data: SnippetApiResponse = await response.json()
58
+
59
+ if (data.snippet.dts) {
60
+ const packageDir = path.join(
61
+ projectRoot,
62
+ "node_modules",
63
+ "@tsci",
64
+ `${owner}.${name}`,
65
+ )
66
+ fs.mkdirSync(packageDir, { recursive: true })
67
+
68
+ fs.writeFileSync(path.join(packageDir, "index.d.ts"), data.snippet.dts)
69
+ }
70
+ } catch (error) {
71
+ console.warn(`Error fetching types for ${importPath}:`, error)
72
+ }
73
+ }
74
+ }
package/lib/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { createServer } from "./server/createServer"
2
+ export { getLocalFileDependencies } from "./dependency-analysis/getLocalFileDependencies"
@@ -0,0 +1,5 @@
1
+ import { cosmiconfigSync } from "cosmiconfig"
2
+
3
+ const explorer = cosmiconfigSync("tscircuit", {})
4
+
5
+ export const projectConfigSearchResult = explorer.search()
@@ -0,0 +1,20 @@
1
+ export interface EndpointResponse {
2
+ "sessions/login_page/create": {
3
+ login_page: {
4
+ login_page_id: string
5
+ login_page_auth_token: string
6
+ url: string
7
+ }
8
+ }
9
+ "sessions/login_page/get": {
10
+ login_page: {
11
+ was_login_successful: boolean
12
+ is_expired: boolean
13
+ }
14
+ }
15
+ "sessions/login_page/exchange_for_cli_session": {
16
+ session: {
17
+ token: string
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,30 @@
1
+ import { getRegistryApiUrl } from "lib/cli-config"
2
+ import ky, { type AfterResponseHook } from "ky"
3
+
4
+ const prettyResponseErrorHook: AfterResponseHook = async (
5
+ _request,
6
+ _options,
7
+ response,
8
+ ) => {
9
+ if (!response.ok) {
10
+ try {
11
+ const errorData = await response.json()
12
+ throw new Error(
13
+ `FAIL [${response.status}]: ${_request.method} ${
14
+ new URL(_request.url).pathname
15
+ } \n\n ${JSON.stringify(errorData, null, 2)}`,
16
+ )
17
+ } catch (e) {
18
+ //ignore, allow the error to be thrown
19
+ }
20
+ }
21
+ }
22
+
23
+ export const getKy = () => {
24
+ return ky.create({
25
+ prefixUrl: getRegistryApiUrl(),
26
+ hooks: {
27
+ afterResponse: [prettyResponseErrorHook],
28
+ },
29
+ })
30
+ }
@@ -0,0 +1,75 @@
1
+ import { EventEmitter } from "events"
2
+
3
+ interface Event {
4
+ event_id: string
5
+ created_at: string
6
+ event_type: string
7
+ [key: string]: any
8
+ }
9
+
10
+ interface EventsResponse {
11
+ event_list: Event[]
12
+ }
13
+
14
+ export class EventsWatcher extends EventEmitter {
15
+ private lastPollTime: string
16
+ private pollInterval: number
17
+ private baseUrl: string
18
+ private polling = false
19
+ private timeoutId?: NodeJS.Timeout
20
+
21
+ constructor(baseUrl = "http://localhost:3000", pollInterval = 1000) {
22
+ super()
23
+ this.baseUrl = baseUrl
24
+ this.pollInterval = pollInterval
25
+ this.lastPollTime = new Date().toISOString()
26
+ }
27
+
28
+ async start() {
29
+ if (this.polling) return
30
+ this.polling = true
31
+ await this.poll()
32
+ }
33
+
34
+ stop() {
35
+ this.polling = false
36
+ if (this.timeoutId) {
37
+ clearTimeout(this.timeoutId)
38
+ }
39
+ }
40
+
41
+ private async poll() {
42
+ if (!this.polling) return
43
+
44
+ try {
45
+ const response = await fetch(
46
+ `${this.baseUrl}/api/events/list?since=${encodeURIComponent(this.lastPollTime)}`,
47
+ )
48
+
49
+ if (!response.ok) {
50
+ throw new Error(`HTTP error! status: ${response.status}`)
51
+ }
52
+
53
+ const data: EventsResponse = await response.json()
54
+
55
+ // Update last poll time to latest event or current time
56
+ const latestEvent = data.event_list[data.event_list.length - 1]
57
+ this.lastPollTime = latestEvent
58
+ ? latestEvent.created_at
59
+ : new Date().toISOString()
60
+
61
+ // Emit events in chronological order
62
+ data.event_list.forEach((event) => {
63
+ this.emit(event.event_type, event)
64
+ this.emit("*", event)
65
+ })
66
+ } catch (error) {
67
+ this.emit("error", error)
68
+ }
69
+ // Schedule next poll
70
+ this.timeoutId = globalThis.setTimeout(
71
+ () => this.poll(),
72
+ this.pollInterval,
73
+ ) as unknown as NodeJS.Timeout
74
+ }
75
+ }
@@ -0,0 +1,62 @@
1
+ import * as http from "node:http"
2
+ import * as fs from "node:fs"
3
+ import * as path from "node:path"
4
+ import { getNodeHandler } from "winterspec/adapters/node"
5
+ // @ts-ignore
6
+ import winterspecBundle from "@tscircuit/file-server/dist/bundle.js"
7
+ import { getIndex } from "../site/getIndex"
8
+
9
+ export const createServer = async (port: number = 3000) => {
10
+ const fileServerHandler = getNodeHandler(winterspecBundle as any, {})
11
+
12
+ const server = http.createServer(async (req, res) => {
13
+ const url = new URL(req.url!, `http://${req.headers.host}`)
14
+
15
+ if (url.pathname === "/standalone.min.js") {
16
+ const standaloneFilePath =
17
+ process.env.RUNFRAME_STANDALONE_FILE_PATH ||
18
+ path.resolve(
19
+ process.cwd(),
20
+ "node_modules",
21
+ "@tscircuit/runframe/dist/standalone.min.js",
22
+ )
23
+
24
+ try {
25
+ const content = fs.readFileSync(standaloneFilePath, "utf8")
26
+ res.writeHead(200, {
27
+ "Content-Type": "application/javascript; charset=utf-8",
28
+ })
29
+ res.end(content)
30
+ return
31
+ } catch (error) {
32
+ console.error("Error serving standalone.min.js:", error)
33
+ res.writeHead(404)
34
+ res.end("File not found")
35
+ return
36
+ }
37
+ }
38
+
39
+ if (url.pathname === "/") {
40
+ const html = await getIndex()
41
+ res.writeHead(200, { "Content-Type": "text/html" })
42
+ res.end(html)
43
+ return
44
+ }
45
+
46
+ if (url.pathname.startsWith("/api/")) {
47
+ req.url = req.url!.replace("/api/", "/")
48
+ fileServerHandler(req, res)
49
+ return
50
+ }
51
+
52
+ res.writeHead(404)
53
+ res.end("Not found")
54
+ })
55
+
56
+ return new Promise<void>((resolve) => {
57
+ server.listen(port, () => {
58
+ console.log(`Server running at http://localhost:${port}`)
59
+ resolve()
60
+ })
61
+ })
62
+ }
@@ -0,0 +1,18 @@
1
+ import pkg from "../../package.json"
2
+
3
+ export const getIndex = async () => {
4
+ return `<html>
5
+ <head>
6
+ </head>
7
+ <body>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <div id="root">loading...</div>
10
+ <script>
11
+ globalThis.process = { env: { NODE_ENV: "production" } }
12
+ </script>
13
+ <script src="/standalone.min.js"></script>
14
+ </body>
15
+ </html>`
16
+ }
17
+
18
+ // <script src="https://cdn.jsdelivr.net/npm/@tscircuit/runframe@${pkg.dependencies["@tscircuit/runframe"].replace(/^[^0-9]+/, "")}/dist/standalone.min.js"></script>