@tscircuit/cli 0.0.394 → 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 -16
  244. package/scripts/build-cli.ts +0 -12
  245. package/tsup.config.ts +0 -7
package/dist/main.js ADDED
@@ -0,0 +1,473 @@
1
+ #!/usr/bin/env node
2
+
3
+ // cli/main.ts
4
+ import { Command } from "commander";
5
+
6
+ // cli/dev/register.ts
7
+ import * as path4 from "node:path";
8
+ import * as chokidar from "chokidar";
9
+ import * as fs4 from "node:fs";
10
+
11
+ // lib/server/createServer.ts
12
+ import * as http from "node:http";
13
+ import * as fs from "node:fs";
14
+ import * as path from "node:path";
15
+ import { getNodeHandler } from "winterspec/adapters/node";
16
+ import winterspecBundle from "@tscircuit/file-server/dist/bundle.js";
17
+
18
+ // lib/site/getIndex.ts
19
+ var getIndex = async () => {
20
+ return `<html>
21
+ <head>
22
+ </head>
23
+ <body>
24
+ <script src="https://cdn.tailwindcss.com"></script>
25
+ <div id="root">loading...</div>
26
+ <script>
27
+ globalThis.process = { env: { NODE_ENV: "production" } }
28
+ </script>
29
+ <script src="/standalone.min.js"></script>
30
+ </body>
31
+ </html>`;
32
+ };
33
+
34
+ // lib/server/createServer.ts
35
+ var createServer2 = async (port = 3e3) => {
36
+ const fileServerHandler = getNodeHandler(winterspecBundle, {});
37
+ const server = http.createServer(async (req, res) => {
38
+ const url = new URL(req.url, `http://${req.headers.host}`);
39
+ if (url.pathname === "/standalone.min.js") {
40
+ const standaloneFilePath = process.env.RUNFRAME_STANDALONE_FILE_PATH || path.resolve(
41
+ process.cwd(),
42
+ "node_modules",
43
+ "@tscircuit/runframe/dist/standalone.min.js"
44
+ );
45
+ try {
46
+ const content = fs.readFileSync(standaloneFilePath, "utf8");
47
+ res.writeHead(200, {
48
+ "Content-Type": "application/javascript; charset=utf-8"
49
+ });
50
+ res.end(content);
51
+ return;
52
+ } catch (error) {
53
+ console.error("Error serving standalone.min.js:", error);
54
+ res.writeHead(404);
55
+ res.end("File not found");
56
+ return;
57
+ }
58
+ }
59
+ if (url.pathname === "/") {
60
+ const html = await getIndex();
61
+ res.writeHead(200, { "Content-Type": "text/html" });
62
+ res.end(html);
63
+ return;
64
+ }
65
+ if (url.pathname.startsWith("/api/")) {
66
+ req.url = req.url.replace("/api/", "/");
67
+ fileServerHandler(req, res);
68
+ return;
69
+ }
70
+ res.writeHead(404);
71
+ res.end("Not found");
72
+ });
73
+ return new Promise((resolve4) => {
74
+ server.listen(port, () => {
75
+ console.log(`Server running at http://localhost:${port}`);
76
+ resolve4();
77
+ });
78
+ });
79
+ };
80
+
81
+ // lib/dependency-analysis/getLocalFileDependencies.ts
82
+ import * as ts from "typescript";
83
+ import * as path2 from "path";
84
+ import * as fs2 from "fs";
85
+ function getLocalFileDependencies(pathToTsxFile) {
86
+ const absolutePath = path2.resolve(pathToTsxFile);
87
+ const baseDir = path2.dirname(absolutePath);
88
+ const content = fs2.readFileSync(absolutePath, "utf-8");
89
+ const sourceFile = ts.createSourceFile(
90
+ absolutePath,
91
+ content,
92
+ ts.ScriptTarget.Latest,
93
+ true
94
+ );
95
+ const dependencies = /* @__PURE__ */ new Set();
96
+ function visit(node) {
97
+ if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
98
+ const moduleSpecifier = node.moduleSpecifier;
99
+ if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
100
+ const importPath = moduleSpecifier.text;
101
+ if (importPath.startsWith(".")) {
102
+ resolveAndAddDependency(importPath);
103
+ }
104
+ }
105
+ }
106
+ if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
107
+ const argument = node.arguments[0];
108
+ if (argument && ts.isStringLiteral(argument)) {
109
+ const importPath = argument.text;
110
+ if (importPath.startsWith(".")) {
111
+ resolveAndAddDependency(importPath);
112
+ }
113
+ }
114
+ }
115
+ ts.forEachChild(node, visit);
116
+ }
117
+ function resolveAndAddDependency(importPath) {
118
+ const extensions = [
119
+ ".tsx",
120
+ ".ts",
121
+ ".jsx",
122
+ ".js",
123
+ ".css",
124
+ ".scss",
125
+ ".sass",
126
+ ".less"
127
+ ];
128
+ let resolvedPath = path2.resolve(baseDir, importPath);
129
+ if (fs2.existsSync(resolvedPath)) {
130
+ dependencies.add(resolvedPath);
131
+ return;
132
+ }
133
+ for (const ext of extensions) {
134
+ const pathWithExt = resolvedPath + ext;
135
+ if (fs2.existsSync(pathWithExt)) {
136
+ dependencies.add(pathWithExt);
137
+ return;
138
+ }
139
+ }
140
+ if (fs2.existsSync(resolvedPath) && fs2.statSync(resolvedPath).isDirectory()) {
141
+ for (const ext of extensions) {
142
+ const indexPath = path2.join(resolvedPath, `index${ext}`);
143
+ if (fs2.existsSync(indexPath)) {
144
+ dependencies.add(indexPath);
145
+ return;
146
+ }
147
+ }
148
+ }
149
+ }
150
+ visit(sourceFile);
151
+ return Array.from(dependencies);
152
+ }
153
+
154
+ // lib/dependency-analysis/installNodeModuleTypes.ts
155
+ import * as fs3 from "node:fs";
156
+ import * as path3 from "node:path";
157
+ import * as ts2 from "typescript";
158
+ async function installTypes(snippetPath) {
159
+ const content = fs3.readFileSync(snippetPath, "utf-8");
160
+ const sourceFile = ts2.createSourceFile(
161
+ snippetPath,
162
+ content,
163
+ ts2.ScriptTarget.Latest,
164
+ true
165
+ );
166
+ const imports = [];
167
+ function visit(node) {
168
+ if (ts2.isImportDeclaration(node)) {
169
+ const moduleSpecifier = node.moduleSpecifier;
170
+ if (moduleSpecifier && ts2.isStringLiteral(moduleSpecifier)) {
171
+ const importPath = moduleSpecifier.text;
172
+ if (importPath.startsWith("@tsci/")) {
173
+ imports.push(importPath);
174
+ }
175
+ }
176
+ }
177
+ ts2.forEachChild(node, visit);
178
+ }
179
+ visit(sourceFile);
180
+ let projectRoot = path3.dirname(snippetPath);
181
+ while (projectRoot !== path3.parse(projectRoot).root) {
182
+ if (fs3.existsSync(path3.join(projectRoot, "package.json"))) {
183
+ break;
184
+ }
185
+ projectRoot = path3.dirname(projectRoot);
186
+ }
187
+ for (const importPath of imports) {
188
+ const [owner, name] = importPath.replace("@tsci/", "").split(".");
189
+ try {
190
+ const response = await fetch(
191
+ `https://registry-api.tscircuit.com/snippets/get?owner_name=${owner}&unscoped_name=${name}`
192
+ );
193
+ if (!response.ok) {
194
+ console.warn(`Failed to fetch types for ${importPath}`);
195
+ continue;
196
+ }
197
+ const data = await response.json();
198
+ if (data.snippet.dts) {
199
+ const packageDir = path3.join(
200
+ projectRoot,
201
+ "node_modules",
202
+ "@tsci",
203
+ `${owner}.${name}`
204
+ );
205
+ fs3.mkdirSync(packageDir, { recursive: true });
206
+ fs3.writeFileSync(path3.join(packageDir, "index.d.ts"), data.snippet.dts);
207
+ }
208
+ } catch (error) {
209
+ console.warn(`Error fetching types for ${importPath}:`, error);
210
+ }
211
+ }
212
+ }
213
+
214
+ // lib/server/EventsWatcher.ts
215
+ import { EventEmitter } from "events";
216
+ var EventsWatcher = class extends EventEmitter {
217
+ lastPollTime;
218
+ pollInterval;
219
+ baseUrl;
220
+ polling = false;
221
+ timeoutId;
222
+ constructor(baseUrl = "http://localhost:3000", pollInterval = 1e3) {
223
+ super();
224
+ this.baseUrl = baseUrl;
225
+ this.pollInterval = pollInterval;
226
+ this.lastPollTime = (/* @__PURE__ */ new Date()).toISOString();
227
+ }
228
+ async start() {
229
+ if (this.polling) return;
230
+ this.polling = true;
231
+ await this.poll();
232
+ }
233
+ stop() {
234
+ this.polling = false;
235
+ if (this.timeoutId) {
236
+ clearTimeout(this.timeoutId);
237
+ }
238
+ }
239
+ async poll() {
240
+ if (!this.polling) return;
241
+ try {
242
+ const response = await fetch(
243
+ `${this.baseUrl}/api/events/list?since=${encodeURIComponent(this.lastPollTime)}`
244
+ );
245
+ if (!response.ok) {
246
+ throw new Error(`HTTP error! status: ${response.status}`);
247
+ }
248
+ const data = await response.json();
249
+ const latestEvent = data.event_list[data.event_list.length - 1];
250
+ this.lastPollTime = latestEvent ? latestEvent.created_at : (/* @__PURE__ */ new Date()).toISOString();
251
+ data.event_list.forEach((event) => {
252
+ this.emit(event.event_type, event);
253
+ this.emit("*", event);
254
+ });
255
+ } catch (error) {
256
+ this.emit("error", error);
257
+ }
258
+ this.timeoutId = globalThis.setTimeout(
259
+ () => this.poll(),
260
+ this.pollInterval
261
+ );
262
+ }
263
+ };
264
+
265
+ // cli/dev/register.ts
266
+ var registerDev = (program2) => {
267
+ program2.command("dev").description("Start development server for a snippet").argument("<file>", "Path to the snippet file").option("-p, --port <number>", "Port to run server on", "3000").action(async (file, options) => {
268
+ const absolutePath = path4.resolve(file);
269
+ const fileDir = path4.dirname(absolutePath);
270
+ const port = parseInt(options.port);
271
+ try {
272
+ console.log("Installing types for imported snippets...");
273
+ await installTypes(absolutePath);
274
+ console.log("Types installed successfully");
275
+ } catch (error) {
276
+ console.warn("Failed to install types:", error);
277
+ }
278
+ await createServer2(port);
279
+ const eventsWatcher = new EventsWatcher(`http://localhost:${port}`);
280
+ eventsWatcher.start();
281
+ await fetch(`http://localhost:${port}/api/files/upsert`, {
282
+ method: "POST",
283
+ headers: { "Content-Type": "application/json" },
284
+ body: JSON.stringify({
285
+ file_path: "entrypoint.tsx",
286
+ text_content: `
287
+ import MyCircuit from "./snippet.tsx"
288
+
289
+ circuit.add(<MyCircuit />)
290
+ `
291
+ })
292
+ });
293
+ const updateFile = async (filePath) => {
294
+ try {
295
+ const content = await fs4.promises.readFile(filePath, "utf-8");
296
+ const response = await fetch(
297
+ `http://localhost:${port}/api/files/upsert`,
298
+ {
299
+ method: "POST",
300
+ headers: { "Content-Type": "application/json" },
301
+ body: JSON.stringify({
302
+ file_path: path4.relative(fileDir, filePath),
303
+ text_content: content
304
+ })
305
+ }
306
+ );
307
+ if (!response.ok) {
308
+ console.error(`Failed to update ${filePath}`);
309
+ }
310
+ } catch (error) {
311
+ console.error(`Error updating ${filePath}:`, error);
312
+ }
313
+ };
314
+ const dependencies = /* @__PURE__ */ new Set([absolutePath]);
315
+ try {
316
+ const deps = getLocalFileDependencies(absolutePath);
317
+ deps.forEach((dep) => dependencies.add(dep));
318
+ } catch (error) {
319
+ console.warn("Failed to analyze dependencies:", error);
320
+ }
321
+ const filesystemWatcher = chokidar.watch(Array.from(dependencies), {
322
+ persistent: true,
323
+ ignoreInitial: false
324
+ });
325
+ filesystemWatcher.on("change", async (filePath) => {
326
+ console.log(`File ${filePath} changed`);
327
+ await updateFile(filePath);
328
+ });
329
+ filesystemWatcher.on("add", async (filePath) => {
330
+ console.log(`File ${filePath} added`);
331
+ await updateFile(filePath);
332
+ });
333
+ eventsWatcher.on("FILE_UPDATED", async (ev) => {
334
+ if (ev.file_path === "manual-edits.json") {
335
+ console.log("Manual edits updated, updating on filesystem...");
336
+ const { file: file2 } = await fetch(
337
+ `http://localhost:${port}/api/files/get?file_path=manual-edits.json`
338
+ ).then((r) => r.json());
339
+ fs4.writeFileSync(
340
+ path4.join(fileDir, "manual-edits.json"),
341
+ file2.text_content
342
+ );
343
+ }
344
+ });
345
+ console.log(`Watching ${file} and its dependencies...`);
346
+ });
347
+ };
348
+
349
+ // lib/cli-config/index.ts
350
+ import Configstore from "configstore";
351
+ var cliConfig = new Configstore(
352
+ "tscircuit"
353
+ );
354
+ var getRegistryApiUrl = () => {
355
+ return cliConfig.get("registryApiUrl") ?? "https://registry-api.tscircuit.com";
356
+ };
357
+
358
+ // cli/auth/login/register.ts
359
+ import delay from "delay";
360
+
361
+ // lib/registry-api/get-ky.ts
362
+ import ky from "ky";
363
+ var prettyResponseErrorHook = async (_request, _options, response) => {
364
+ if (!response.ok) {
365
+ try {
366
+ const errorData = await response.json();
367
+ throw new Error(
368
+ `FAIL [${response.status}]: ${_request.method} ${new URL(_request.url).pathname}
369
+
370
+ ${JSON.stringify(errorData, null, 2)}`
371
+ );
372
+ } catch (e) {
373
+ }
374
+ }
375
+ };
376
+ var getKy = () => {
377
+ return ky.create({
378
+ prefixUrl: getRegistryApiUrl(),
379
+ hooks: {
380
+ afterResponse: [prettyResponseErrorHook]
381
+ }
382
+ });
383
+ };
384
+
385
+ // cli/auth/login/register.ts
386
+ var registerAuthLogin = (program2) => {
387
+ program2.commands.find((c) => c.name() === "auth").command("login").description("Authenticate CLI, login to registry").action(async (args) => {
388
+ const ky2 = getKy();
389
+ const { login_page } = await ky2.post(
390
+ "sessions/login_page/create",
391
+ {
392
+ json: {}
393
+ }
394
+ ).json();
395
+ console.log("Please visit the following URL to log in:");
396
+ console.log(login_page.url);
397
+ while (true) {
398
+ const { login_page: new_login_page } = await ky2.post(
399
+ "sessions/login_page/get",
400
+ {
401
+ json: {
402
+ login_page_id: login_page.login_page_id
403
+ },
404
+ headers: {
405
+ Authorization: `Bearer ${login_page.login_page_auth_token}`
406
+ }
407
+ }
408
+ ).json();
409
+ if (new_login_page.was_login_successful) {
410
+ console.log("Logged in! Generating token...");
411
+ break;
412
+ }
413
+ if (new_login_page.is_expired) {
414
+ throw new Error("Login page expired");
415
+ }
416
+ await delay(1e3);
417
+ }
418
+ const { session } = await ky2.post(
419
+ "sessions/login_page/exchange_for_cli_session",
420
+ {
421
+ json: {
422
+ login_page_id: login_page.login_page_id
423
+ },
424
+ headers: {
425
+ Authorization: `Bearer ${login_page.login_page_auth_token}`
426
+ }
427
+ }
428
+ ).json();
429
+ cliConfig.set("sessionToken", session.token);
430
+ console.log("Ready to use!");
431
+ });
432
+ };
433
+
434
+ // cli/auth/logout/register.ts
435
+ var registerAuthLogout = (program2) => {
436
+ program2.commands.find((c) => c.name() === "auth").command("logout").description("Logout from registry").action((args) => {
437
+ console.log("logout");
438
+ });
439
+ };
440
+
441
+ // cli/auth/register.ts
442
+ var registerAuth = (program2) => {
443
+ program2.command("auth").description("Login/logout");
444
+ };
445
+
446
+ // cli/config/register.ts
447
+ var registerConfig = (program2) => {
448
+ program2.command("config").description("Manage tscircuit CLI configuration");
449
+ };
450
+
451
+ // cli/config/print/register.ts
452
+ var registerConfigPrint = (program2) => {
453
+ program2.commands.find((c) => c.name() === "config").command("print").description("Print the current config").action(() => {
454
+ console.log(JSON.stringify(cliConfig.all, null, 2));
455
+ });
456
+ };
457
+
458
+ // cli/main.ts
459
+ import { perfectCli } from "perfect-cli";
460
+ var program = new Command();
461
+ program.name("tsci").description("CLI for developing tscircuit snippets").version("1.0.0");
462
+ registerDev(program);
463
+ registerAuth(program);
464
+ registerAuthLogin(program);
465
+ registerAuthLogout(program);
466
+ registerConfig(program);
467
+ registerConfigPrint(program);
468
+ if (process.argv.length === 2) {
469
+ perfectCli(program, process.argv);
470
+ } else {
471
+ program.parse();
472
+ }
473
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vY2xpL21haW4udHMiLCAiLi4vY2xpL2Rldi9yZWdpc3Rlci50cyIsICIuLi9saWIvc2VydmVyL2NyZWF0ZVNlcnZlci50cyIsICIuLi9saWIvc2l0ZS9nZXRJbmRleC50cyIsICIuLi9saWIvZGVwZW5kZW5jeS1hbmFseXNpcy9nZXRMb2NhbEZpbGVEZXBlbmRlbmNpZXMudHMiLCAiLi4vbGliL2RlcGVuZGVuY3ktYW5hbHlzaXMvaW5zdGFsbE5vZGVNb2R1bGVUeXBlcy50cyIsICIuLi9saWIvc2VydmVyL0V2ZW50c1dhdGNoZXIudHMiLCAiLi4vbGliL2NsaS1jb25maWcvaW5kZXgudHMiLCAiLi4vY2xpL2F1dGgvbG9naW4vcmVnaXN0ZXIudHMiLCAiLi4vbGliL3JlZ2lzdHJ5LWFwaS9nZXQta3kudHMiLCAiLi4vY2xpL2F1dGgvbG9nb3V0L3JlZ2lzdGVyLnRzIiwgIi4uL2NsaS9hdXRoL3JlZ2lzdGVyLnRzIiwgIi4uL2NsaS9jb25maWcvcmVnaXN0ZXIudHMiLCAiLi4vY2xpL2NvbmZpZy9wcmludC9yZWdpc3Rlci50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuaW1wb3J0IHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJEZXYgfSBmcm9tIFwiLi9kZXYvcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJBdXRoTG9naW4gfSBmcm9tIFwiLi9hdXRoL2xvZ2luL3JlZ2lzdGVyXCJcbmltcG9ydCB7IHJlZ2lzdGVyQXV0aExvZ291dCB9IGZyb20gXCIuL2F1dGgvbG9nb3V0L3JlZ2lzdGVyXCJcbmltcG9ydCB7IHJlZ2lzdGVyQXV0aCB9IGZyb20gXCIuL2F1dGgvcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJDb25maWcgfSBmcm9tIFwiLi9jb25maWcvcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJDb25maWdQcmludCB9IGZyb20gXCIuL2NvbmZpZy9wcmludC9yZWdpc3RlclwiXG5pbXBvcnQgeyBwZXJmZWN0Q2xpIH0gZnJvbSBcInBlcmZlY3QtY2xpXCJcblxuY29uc3QgcHJvZ3JhbSA9IG5ldyBDb21tYW5kKClcblxucHJvZ3JhbVxuICAubmFtZShcInRzY2lcIilcbiAgLmRlc2NyaXB0aW9uKFwiQ0xJIGZvciBkZXZlbG9waW5nIHRzY2lyY3VpdCBzbmlwcGV0c1wiKVxuICAudmVyc2lvbihcIjEuMC4wXCIpXG5cbnJlZ2lzdGVyRGV2KHByb2dyYW0pXG5cbnJlZ2lzdGVyQXV0aChwcm9ncmFtKVxucmVnaXN0ZXJBdXRoTG9naW4ocHJvZ3JhbSlcbnJlZ2lzdGVyQXV0aExvZ291dChwcm9ncmFtKVxuXG5yZWdpc3RlckNvbmZpZyhwcm9ncmFtKVxucmVnaXN0ZXJDb25maWdQcmludChwcm9ncmFtKVxuXG5pZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PT0gMikge1xuICBwZXJmZWN0Q2xpKHByb2dyYW0sIHByb2Nlc3MuYXJndilcbn0gZWxzZSB7XG4gIHByb2dyYW0ucGFyc2UoKVxufVxuIiwgImltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCAqIGFzIGNob2tpZGFyIGZyb20gXCJjaG9raWRhclwiXG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwibm9kZTpmc1wiXG5pbXBvcnQgeyBjcmVhdGVTZXJ2ZXIgfSBmcm9tIFwibGliL3NlcnZlci9jcmVhdGVTZXJ2ZXJcIlxuaW1wb3J0IHsgZ2V0TG9jYWxGaWxlRGVwZW5kZW5jaWVzIH0gZnJvbSBcImxpYi9kZXBlbmRlbmN5LWFuYWx5c2lzL2dldExvY2FsRmlsZURlcGVuZGVuY2llc1wiXG5pbXBvcnQgeyBpbnN0YWxsVHlwZXMgfSBmcm9tIFwiLi4vLi4vbGliL2RlcGVuZGVuY3ktYW5hbHlzaXMvaW5zdGFsbE5vZGVNb2R1bGVUeXBlc1wiXG5pbXBvcnQgeyBFdmVudHNXYXRjaGVyIH0gZnJvbSBcIi4uLy4uL2xpYi9zZXJ2ZXIvRXZlbnRzV2F0Y2hlclwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckRldiA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW1cbiAgICAuY29tbWFuZChcImRldlwiKVxuICAgIC5kZXNjcmlwdGlvbihcIlN0YXJ0IGRldmVsb3BtZW50IHNlcnZlciBmb3IgYSBzbmlwcGV0XCIpXG4gICAgLmFyZ3VtZW50KFwiPGZpbGU+XCIsIFwiUGF0aCB0byB0aGUgc25pcHBldCBmaWxlXCIpXG4gICAgLm9wdGlvbihcIi1wLCAtLXBvcnQgPG51bWJlcj5cIiwgXCJQb3J0IHRvIHJ1biBzZXJ2ZXIgb25cIiwgXCIzMDAwXCIpXG4gICAgLmFjdGlvbihhc3luYyAoZmlsZTogc3RyaW5nLCBvcHRpb25zOiB7IHBvcnQ6IHN0cmluZyB9KSA9PiB7XG4gICAgICBjb25zdCBhYnNvbHV0ZVBhdGggPSBwYXRoLnJlc29sdmUoZmlsZSlcbiAgICAgIGNvbnN0IGZpbGVEaXIgPSBwYXRoLmRpcm5hbWUoYWJzb2x1dGVQYXRoKVxuICAgICAgY29uc3QgcG9ydCA9IHBhcnNlSW50KG9wdGlvbnMucG9ydClcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc29sZS5sb2coXCJJbnN0YWxsaW5nIHR5cGVzIGZvciBpbXBvcnRlZCBzbmlwcGV0cy4uLlwiKVxuICAgICAgICBhd2FpdCBpbnN0YWxsVHlwZXMoYWJzb2x1dGVQYXRoKVxuICAgICAgICBjb25zb2xlLmxvZyhcIlR5cGVzIGluc3RhbGxlZCBzdWNjZXNzZnVsbHlcIilcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIkZhaWxlZCB0byBpbnN0YWxsIHR5cGVzOlwiLCBlcnJvcilcbiAgICAgIH1cblxuICAgICAgLy8gU3RhcnQgdGhlIHNlcnZlclxuICAgICAgYXdhaXQgY3JlYXRlU2VydmVyKHBvcnQpXG5cbiAgICAgIGNvbnN0IGV2ZW50c1dhdGNoZXIgPSBuZXcgRXZlbnRzV2F0Y2hlcihgaHR0cDovL2xvY2FsaG9zdDoke3BvcnR9YClcbiAgICAgIGV2ZW50c1dhdGNoZXIuc3RhcnQoKVxuXG4gICAgICBhd2FpdCBmZXRjaChgaHR0cDovL2xvY2FsaG9zdDoke3BvcnR9L2FwaS9maWxlcy91cHNlcnRgLCB7XG4gICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgIGhlYWRlcnM6IHsgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfSxcbiAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIGZpbGVfcGF0aDogXCJlbnRyeXBvaW50LnRzeFwiLFxuICAgICAgICAgIHRleHRfY29udGVudDogYFxuaW1wb3J0IE15Q2lyY3VpdCBmcm9tIFwiLi9zbmlwcGV0LnRzeFwiXG5cbmNpcmN1aXQuYWRkKDxNeUNpcmN1aXQgLz4pXG5gLFxuICAgICAgICB9KSxcbiAgICAgIH0pXG5cbiAgICAgIC8vIEZ1bmN0aW9uIHRvIHVwZGF0ZSBmaWxlIGNvbnRlbnRcbiAgICAgIGNvbnN0IHVwZGF0ZUZpbGUgPSBhc3luYyAoZmlsZVBhdGg6IHN0cmluZykgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5wcm9taXNlcy5yZWFkRmlsZShmaWxlUGF0aCwgXCJ1dGYtOFwiKVxuICAgICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goXG4gICAgICAgICAgICBgaHR0cDovL2xvY2FsaG9zdDoke3BvcnR9L2FwaS9maWxlcy91cHNlcnRgLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICAgICAgICBoZWFkZXJzOiB7IFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiIH0sXG4gICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICBmaWxlX3BhdGg6IHBhdGgucmVsYXRpdmUoZmlsZURpciwgZmlsZVBhdGgpLFxuICAgICAgICAgICAgICAgIHRleHRfY29udGVudDogY29udGVudCxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIClcbiAgICAgICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gdXBkYXRlICR7ZmlsZVBhdGh9YClcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3IgdXBkYXRpbmcgJHtmaWxlUGF0aH06YCwgZXJyb3IpXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gR2V0IGluaXRpYWwgZGVwZW5kZW5jaWVzXG4gICAgICBjb25zdCBkZXBlbmRlbmNpZXMgPSBuZXcgU2V0KFthYnNvbHV0ZVBhdGhdKVxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZGVwcyA9IGdldExvY2FsRmlsZURlcGVuZGVuY2llcyhhYnNvbHV0ZVBhdGgpXG4gICAgICAgIGRlcHMuZm9yRWFjaCgoZGVwKSA9PiBkZXBlbmRlbmNpZXMuYWRkKGRlcCkpXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLndhcm4oXCJGYWlsZWQgdG8gYW5hbHl6ZSBkZXBlbmRlbmNpZXM6XCIsIGVycm9yKVxuICAgICAgfVxuXG4gICAgICAvLyBXYXRjaCB0aGUgbWFpbiBmaWxlIGFuZCBpdHMgZGVwZW5kZW5jaWVzXG4gICAgICBjb25zdCBmaWxlc3lzdGVtV2F0Y2hlciA9IGNob2tpZGFyLndhdGNoKEFycmF5LmZyb20oZGVwZW5kZW5jaWVzKSwge1xuICAgICAgICBwZXJzaXN0ZW50OiB0cnVlLFxuICAgICAgICBpZ25vcmVJbml0aWFsOiBmYWxzZSxcbiAgICAgIH0pXG5cbiAgICAgIGZpbGVzeXN0ZW1XYXRjaGVyLm9uKFwiY2hhbmdlXCIsIGFzeW5jIChmaWxlUGF0aCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZyhgRmlsZSAke2ZpbGVQYXRofSBjaGFuZ2VkYClcbiAgICAgICAgYXdhaXQgdXBkYXRlRmlsZShmaWxlUGF0aClcbiAgICAgIH0pXG5cbiAgICAgIGZpbGVzeXN0ZW1XYXRjaGVyLm9uKFwiYWRkXCIsIGFzeW5jIChmaWxlUGF0aCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZyhgRmlsZSAke2ZpbGVQYXRofSBhZGRlZGApXG4gICAgICAgIGF3YWl0IHVwZGF0ZUZpbGUoZmlsZVBhdGgpXG4gICAgICB9KVxuXG4gICAgICBldmVudHNXYXRjaGVyLm9uKFwiRklMRV9VUERBVEVEXCIsIGFzeW5jIChldikgPT4ge1xuICAgICAgICBpZiAoZXYuZmlsZV9wYXRoID09PSBcIm1hbnVhbC1lZGl0cy5qc29uXCIpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhcIk1hbnVhbCBlZGl0cyB1cGRhdGVkLCB1cGRhdGluZyBvbiBmaWxlc3lzdGVtLi4uXCIpXG4gICAgICAgICAgY29uc3QgeyBmaWxlIH0gPSBhd2FpdCBmZXRjaChcbiAgICAgICAgICAgIGBodHRwOi8vbG9jYWxob3N0OiR7cG9ydH0vYXBpL2ZpbGVzL2dldD9maWxlX3BhdGg9bWFudWFsLWVkaXRzLmpzb25gLFxuICAgICAgICAgICkudGhlbigocikgPT4gci5qc29uKCkpXG4gICAgICAgICAgZnMud3JpdGVGaWxlU3luYyhcbiAgICAgICAgICAgIHBhdGguam9pbihmaWxlRGlyLCBcIm1hbnVhbC1lZGl0cy5qc29uXCIpLFxuICAgICAgICAgICAgZmlsZS50ZXh0X2NvbnRlbnQsXG4gICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICB9KVxuXG4gICAgICBjb25zb2xlLmxvZyhgV2F0Y2hpbmcgJHtmaWxlfSBhbmQgaXRzIGRlcGVuZGVuY2llcy4uLmApXG4gICAgfSlcbn1cbiIsICJpbXBvcnQgKiBhcyBodHRwIGZyb20gXCJub2RlOmh0dHBcIlxuaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnNcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCB7IGdldE5vZGVIYW5kbGVyIH0gZnJvbSBcIndpbnRlcnNwZWMvYWRhcHRlcnMvbm9kZVwiXG4vLyBAdHMtaWdub3JlXG5pbXBvcnQgd2ludGVyc3BlY0J1bmRsZSBmcm9tIFwiQHRzY2lyY3VpdC9maWxlLXNlcnZlci9kaXN0L2J1bmRsZS5qc1wiXG5pbXBvcnQgeyBnZXRJbmRleCB9IGZyb20gXCIuLi9zaXRlL2dldEluZGV4XCJcblxuZXhwb3J0IGNvbnN0IGNyZWF0ZVNlcnZlciA9IGFzeW5jIChwb3J0OiBudW1iZXIgPSAzMDAwKSA9PiB7XG4gIGNvbnN0IGZpbGVTZXJ2ZXJIYW5kbGVyID0gZ2V0Tm9kZUhhbmRsZXIod2ludGVyc3BlY0J1bmRsZSBhcyBhbnksIHt9KVxuXG4gIGNvbnN0IHNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLnVybCEsIGBodHRwOi8vJHtyZXEuaGVhZGVycy5ob3N0fWApXG5cbiAgICBpZiAodXJsLnBhdGhuYW1lID09PSBcIi9zdGFuZGFsb25lLm1pbi5qc1wiKSB7XG4gICAgICBjb25zdCBzdGFuZGFsb25lRmlsZVBhdGggPVxuICAgICAgICBwcm9jZXNzLmVudi5SVU5GUkFNRV9TVEFOREFMT05FX0ZJTEVfUEFUSCB8fFxuICAgICAgICBwYXRoLnJlc29sdmUoXG4gICAgICAgICAgcHJvY2Vzcy5jd2QoKSxcbiAgICAgICAgICBcIm5vZGVfbW9kdWxlc1wiLFxuICAgICAgICAgIFwiQHRzY2lyY3VpdC9ydW5mcmFtZS9kaXN0L3N0YW5kYWxvbmUubWluLmpzXCIsXG4gICAgICAgIClcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhzdGFuZGFsb25lRmlsZVBhdGgsIFwidXRmOFwiKVxuICAgICAgICByZXMud3JpdGVIZWFkKDIwMCwge1xuICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vamF2YXNjcmlwdDsgY2hhcnNldD11dGYtOFwiLFxuICAgICAgICB9KVxuICAgICAgICByZXMuZW5kKGNvbnRlbnQpXG4gICAgICAgIHJldHVyblxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIHNlcnZpbmcgc3RhbmRhbG9uZS5taW4uanM6XCIsIGVycm9yKVxuICAgICAgICByZXMud3JpdGVIZWFkKDQwNClcbiAgICAgICAgcmVzLmVuZChcIkZpbGUgbm90IGZvdW5kXCIpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh1cmwucGF0aG5hbWUgPT09IFwiL1wiKSB7XG4gICAgICBjb25zdCBodG1sID0gYXdhaXQgZ2V0SW5kZXgoKVxuICAgICAgcmVzLndyaXRlSGVhZCgyMDAsIHsgXCJDb250ZW50LVR5cGVcIjogXCJ0ZXh0L2h0bWxcIiB9KVxuICAgICAgcmVzLmVuZChodG1sKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgaWYgKHVybC5wYXRobmFtZS5zdGFydHNXaXRoKFwiL2FwaS9cIikpIHtcbiAgICAgIHJlcS51cmwgPSByZXEudXJsIS5yZXBsYWNlKFwiL2FwaS9cIiwgXCIvXCIpXG4gICAgICBmaWxlU2VydmVySGFuZGxlcihyZXEsIHJlcylcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHJlcy53cml0ZUhlYWQoNDA0KVxuICAgIHJlcy5lbmQoXCJOb3QgZm91bmRcIilcbiAgfSlcblxuICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICBzZXJ2ZXIubGlzdGVuKHBvcnQsICgpID0+IHtcbiAgICAgIGNvbnNvbGUubG9nKGBTZXJ2ZXIgcnVubmluZyBhdCBodHRwOi8vbG9jYWxob3N0OiR7cG9ydH1gKVxuICAgICAgcmVzb2x2ZSgpXG4gICAgfSlcbiAgfSlcbn1cbiIsICJpbXBvcnQgcGtnIGZyb20gXCIuLi8uLi9wYWNrYWdlLmpzb25cIlxuXG5leHBvcnQgY29uc3QgZ2V0SW5kZXggPSBhc3luYyAoKSA9PiB7XG4gIHJldHVybiBgPGh0bWw+XG4gICAgPGhlYWQ+XG4gICAgPC9oZWFkPlxuICAgIDxib2R5PlxuICAgICAgPHNjcmlwdCBzcmM9XCJodHRwczovL2Nkbi50YWlsd2luZGNzcy5jb21cIj48L3NjcmlwdD5cbiAgICAgIDxkaXYgaWQ9XCJyb290XCI+bG9hZGluZy4uLjwvZGl2PlxuICAgICAgPHNjcmlwdD5cbiAgICAgIGdsb2JhbFRoaXMucHJvY2VzcyA9IHsgZW52OiB7IE5PREVfRU5WOiBcInByb2R1Y3Rpb25cIiB9IH1cbiAgICAgIDwvc2NyaXB0PlxuICAgICAgPHNjcmlwdCBzcmM9XCIvc3RhbmRhbG9uZS5taW4uanNcIj48L3NjcmlwdD5cbiAgICA8L2JvZHk+XG4gIDwvaHRtbD5gXG59XG5cbi8vIDxzY3JpcHQgc3JjPVwiaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AdHNjaXJjdWl0L3J1bmZyYW1lQCR7cGtnLmRlcGVuZGVuY2llc1tcIkB0c2NpcmN1aXQvcnVuZnJhbWVcIl0ucmVwbGFjZSgvXlteMC05XSsvLCBcIlwiKX0vZGlzdC9zdGFuZGFsb25lLm1pbi5qc1wiPjwvc2NyaXB0PlxuIiwgImltcG9ydCAqIGFzIHRzIGZyb20gXCJ0eXBlc2NyaXB0XCJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIlxuaW1wb3J0ICogYXMgZnMgZnJvbSBcImZzXCJcblxuZnVuY3Rpb24gZ2V0TG9jYWxGaWxlRGVwZW5kZW5jaWVzKHBhdGhUb1RzeEZpbGU6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgLy8gRW5zdXJlIGFic29sdXRlIHBhdGhcbiAgY29uc3QgYWJzb2x1dGVQYXRoID0gcGF0aC5yZXNvbHZlKHBhdGhUb1RzeEZpbGUpXG4gIGNvbnN0IGJhc2VEaXIgPSBwYXRoLmRpcm5hbWUoYWJzb2x1dGVQYXRoKVxuXG4gIC8vIFJlYWQgYW5kIHBhcnNlIHRoZSBmaWxlXG4gIGNvbnN0IGNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmMoYWJzb2x1dGVQYXRoLCBcInV0Zi04XCIpXG4gIGNvbnN0IHNvdXJjZUZpbGUgPSB0cy5jcmVhdGVTb3VyY2VGaWxlKFxuICAgIGFic29sdXRlUGF0aCxcbiAgICBjb250ZW50LFxuICAgIHRzLlNjcmlwdFRhcmdldC5MYXRlc3QsXG4gICAgdHJ1ZSxcbiAgKVxuXG4gIGNvbnN0IGRlcGVuZGVuY2llcyA9IG5ldyBTZXQ8c3RyaW5nPigpXG5cbiAgLy8gUmVjdXJzaXZlbHkgdmlzaXQgbm9kZXMgdG8gZmluZCBpbXBvcnRzXG4gIGZ1bmN0aW9uIHZpc2l0KG5vZGU6IHRzLk5vZGUpIHtcbiAgICBpZiAodHMuaXNJbXBvcnREZWNsYXJhdGlvbihub2RlKSB8fCB0cy5pc0V4cG9ydERlY2xhcmF0aW9uKG5vZGUpKSB7XG4gICAgICBjb25zdCBtb2R1bGVTcGVjaWZpZXIgPSBub2RlLm1vZHVsZVNwZWNpZmllclxuICAgICAgaWYgKG1vZHVsZVNwZWNpZmllciAmJiB0cy5pc1N0cmluZ0xpdGVyYWwobW9kdWxlU3BlY2lmaWVyKSkge1xuICAgICAgICBjb25zdCBpbXBvcnRQYXRoID0gbW9kdWxlU3BlY2lmaWVyLnRleHRcbiAgICAgICAgLy8gT25seSBwcm9jZXNzIGxvY2FsIGltcG9ydHMgKHN0YXJ0aW5nIHdpdGggLiBvciAuLilcbiAgICAgICAgaWYgKGltcG9ydFBhdGguc3RhcnRzV2l0aChcIi5cIikpIHtcbiAgICAgICAgICByZXNvbHZlQW5kQWRkRGVwZW5kZW5jeShpbXBvcnRQYXRoKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIGR5bmFtaWMgaW1wb3J0c1xuICAgIGlmIChcbiAgICAgIHRzLmlzQ2FsbEV4cHJlc3Npb24obm9kZSkgJiZcbiAgICAgIG5vZGUuZXhwcmVzc2lvbi5raW5kID09PSB0cy5TeW50YXhLaW5kLkltcG9ydEtleXdvcmRcbiAgICApIHtcbiAgICAgIGNvbnN0IGFyZ3VtZW50ID0gbm9kZS5hcmd1bWVudHNbMF1cbiAgICAgIGlmIChhcmd1bWVudCAmJiB0cy5pc1N0cmluZ0xpdGVyYWwoYXJndW1lbnQpKSB7XG4gICAgICAgIGNvbnN0IGltcG9ydFBhdGggPSBhcmd1bWVudC50ZXh0XG4gICAgICAgIGlmIChpbXBvcnRQYXRoLnN0YXJ0c1dpdGgoXCIuXCIpKSB7XG4gICAgICAgICAgcmVzb2x2ZUFuZEFkZERlcGVuZGVuY3koaW1wb3J0UGF0aClcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHRzLmZvckVhY2hDaGlsZChub2RlLCB2aXNpdClcbiAgfVxuXG4gIC8vIEhlbHBlciB0byByZXNvbHZlIGFuZCBhZGQgZGVwZW5kZW5jeSBwYXRoc1xuICBmdW5jdGlvbiByZXNvbHZlQW5kQWRkRGVwZW5kZW5jeShpbXBvcnRQYXRoOiBzdHJpbmcpIHtcbiAgICBjb25zdCBleHRlbnNpb25zID0gW1xuICAgICAgXCIudHN4XCIsXG4gICAgICBcIi50c1wiLFxuICAgICAgXCIuanN4XCIsXG4gICAgICBcIi5qc1wiLFxuICAgICAgXCIuY3NzXCIsXG4gICAgICBcIi5zY3NzXCIsXG4gICAgICBcIi5zYXNzXCIsXG4gICAgICBcIi5sZXNzXCIsXG4gICAgXVxuICAgIGxldCByZXNvbHZlZFBhdGggPSBwYXRoLnJlc29sdmUoYmFzZURpciwgaW1wb3J0UGF0aClcblxuICAgIC8vIENoZWNrIGlmIHBhdGggZXhpc3RzIGFzLWlzXG4gICAgaWYgKGZzLmV4aXN0c1N5bmMocmVzb2x2ZWRQYXRoKSkge1xuICAgICAgZGVwZW5kZW5jaWVzLmFkZChyZXNvbHZlZFBhdGgpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyBUcnkgd2l0aCBleHRlbnNpb25zXG4gICAgZm9yIChjb25zdCBleHQgb2YgZXh0ZW5zaW9ucykge1xuICAgICAgY29uc3QgcGF0aFdpdGhFeHQgPSByZXNvbHZlZFBhdGggKyBleHRcbiAgICAgIGlmIChmcy5leGlzdHNTeW5jKHBhdGhXaXRoRXh0KSkge1xuICAgICAgICBkZXBlbmRlbmNpZXMuYWRkKHBhdGhXaXRoRXh0KVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDaGVjayBmb3IgaW5kZXggZmlsZXMgaW4gZGlyZWN0b3JpZXNcbiAgICBpZiAoXG4gICAgICBmcy5leGlzdHNTeW5jKHJlc29sdmVkUGF0aCkgJiZcbiAgICAgIGZzLnN0YXRTeW5jKHJlc29sdmVkUGF0aCkuaXNEaXJlY3RvcnkoKVxuICAgICkge1xuICAgICAgZm9yIChjb25zdCBleHQgb2YgZXh0ZW5zaW9ucykge1xuICAgICAgICBjb25zdCBpbmRleFBhdGggPSBwYXRoLmpvaW4ocmVzb2x2ZWRQYXRoLCBgaW5kZXgke2V4dH1gKVxuICAgICAgICBpZiAoZnMuZXhpc3RzU3luYyhpbmRleFBhdGgpKSB7XG4gICAgICAgICAgZGVwZW5kZW5jaWVzLmFkZChpbmRleFBhdGgpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBTdGFydCB0aGUgdHJhdmVyc2FsXG4gIHZpc2l0KHNvdXJjZUZpbGUpXG5cbiAgcmV0dXJuIEFycmF5LmZyb20oZGVwZW5kZW5jaWVzKVxufVxuXG5leHBvcnQgeyBnZXRMb2NhbEZpbGVEZXBlbmRlbmNpZXMgfVxuIiwgImltcG9ydCAqIGFzIGZzIGZyb20gXCJub2RlOmZzXCJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiXG5pbXBvcnQgKiBhcyB0cyBmcm9tIFwidHlwZXNjcmlwdFwiXG5cbmludGVyZmFjZSBTbmlwcGV0QXBpUmVzcG9uc2Uge1xuICBzbmlwcGV0OiB7XG4gICAgZHRzOiBzdHJpbmdcbiAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5zdGFsbFR5cGVzKHNuaXBwZXRQYXRoOiBzdHJpbmcpIHtcbiAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhzbmlwcGV0UGF0aCwgXCJ1dGYtOFwiKVxuICBjb25zdCBzb3VyY2VGaWxlID0gdHMuY3JlYXRlU291cmNlRmlsZShcbiAgICBzbmlwcGV0UGF0aCxcbiAgICBjb250ZW50LFxuICAgIHRzLlNjcmlwdFRhcmdldC5MYXRlc3QsXG4gICAgdHJ1ZSxcbiAgKVxuXG4gIGNvbnN0IGltcG9ydHM6IHN0cmluZ1tdID0gW11cblxuICBmdW5jdGlvbiB2aXNpdChub2RlOiB0cy5Ob2RlKSB7XG4gICAgaWYgKHRzLmlzSW1wb3J0RGVjbGFyYXRpb24obm9kZSkpIHtcbiAgICAgIGNvbnN0IG1vZHVsZVNwZWNpZmllciA9IG5vZGUubW9kdWxlU3BlY2lmaWVyXG4gICAgICBpZiAobW9kdWxlU3BlY2lmaWVyICYmIHRzLmlzU3RyaW5nTGl0ZXJhbChtb2R1bGVTcGVjaWZpZXIpKSB7XG4gICAgICAgIGNvbnN0IGltcG9ydFBhdGggPSBtb2R1bGVTcGVjaWZpZXIudGV4dFxuICAgICAgICBpZiAoaW1wb3J0UGF0aC5zdGFydHNXaXRoKFwiQHRzY2kvXCIpKSB7XG4gICAgICAgICAgaW1wb3J0cy5wdXNoKGltcG9ydFBhdGgpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgdHMuZm9yRWFjaENoaWxkKG5vZGUsIHZpc2l0KVxuICB9XG5cbiAgdmlzaXQoc291cmNlRmlsZSlcblxuICBsZXQgcHJvamVjdFJvb3QgPSBwYXRoLmRpcm5hbWUoc25pcHBldFBhdGgpXG4gIHdoaWxlIChwcm9qZWN0Um9vdCAhPT0gcGF0aC5wYXJzZShwcm9qZWN0Um9vdCkucm9vdCkge1xuICAgIGlmIChmcy5leGlzdHNTeW5jKHBhdGguam9pbihwcm9qZWN0Um9vdCwgXCJwYWNrYWdlLmpzb25cIikpKSB7XG4gICAgICBicmVha1xuICAgIH1cbiAgICBwcm9qZWN0Um9vdCA9IHBhdGguZGlybmFtZShwcm9qZWN0Um9vdClcbiAgfVxuXG4gIGZvciAoY29uc3QgaW1wb3J0UGF0aCBvZiBpbXBvcnRzKSB7XG4gICAgY29uc3QgW293bmVyLCBuYW1lXSA9IGltcG9ydFBhdGgucmVwbGFjZShcIkB0c2NpL1wiLCBcIlwiKS5zcGxpdChcIi5cIilcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChcbiAgICAgICAgYGh0dHBzOi8vcmVnaXN0cnktYXBpLnRzY2lyY3VpdC5jb20vc25pcHBldHMvZ2V0P293bmVyX25hbWU9JHtvd25lcn0mdW5zY29wZWRfbmFtZT0ke25hbWV9YCxcbiAgICAgIClcblxuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICBjb25zb2xlLndhcm4oYEZhaWxlZCB0byBmZXRjaCB0eXBlcyBmb3IgJHtpbXBvcnRQYXRofWApXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRhdGE6IFNuaXBwZXRBcGlSZXNwb25zZSA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKVxuXG4gICAgICBpZiAoZGF0YS5zbmlwcGV0LmR0cykge1xuICAgICAgICBjb25zdCBwYWNrYWdlRGlyID0gcGF0aC5qb2luKFxuICAgICAgICAgIHByb2plY3RSb290LFxuICAgICAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICAgICAgXCJAdHNjaVwiLFxuICAgICAgICAgIGAke293bmVyfS4ke25hbWV9YCxcbiAgICAgICAgKVxuICAgICAgICBmcy5ta2RpclN5bmMocGFja2FnZURpciwgeyByZWN1cnNpdmU6IHRydWUgfSlcblxuICAgICAgICBmcy53cml0ZUZpbGVTeW5jKHBhdGguam9pbihwYWNrYWdlRGlyLCBcImluZGV4LmQudHNcIiksIGRhdGEuc25pcHBldC5kdHMpXG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUud2FybihgRXJyb3IgZmV0Y2hpbmcgdHlwZXMgZm9yICR7aW1wb3J0UGF0aH06YCwgZXJyb3IpXG4gICAgfVxuICB9XG59XG4iLCAiaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSBcImV2ZW50c1wiXG5cbmludGVyZmFjZSBFdmVudCB7XG4gIGV2ZW50X2lkOiBzdHJpbmdcbiAgY3JlYXRlZF9hdDogc3RyaW5nXG4gIGV2ZW50X3R5cGU6IHN0cmluZ1xuICBba2V5OiBzdHJpbmddOiBhbnlcbn1cblxuaW50ZXJmYWNlIEV2ZW50c1Jlc3BvbnNlIHtcbiAgZXZlbnRfbGlzdDogRXZlbnRbXVxufVxuXG5leHBvcnQgY2xhc3MgRXZlbnRzV2F0Y2hlciBleHRlbmRzIEV2ZW50RW1pdHRlciB7XG4gIHByaXZhdGUgbGFzdFBvbGxUaW1lOiBzdHJpbmdcbiAgcHJpdmF0ZSBwb2xsSW50ZXJ2YWw6IG51bWJlclxuICBwcml2YXRlIGJhc2VVcmw6IHN0cmluZ1xuICBwcml2YXRlIHBvbGxpbmcgPSBmYWxzZVxuICBwcml2YXRlIHRpbWVvdXRJZD86IE5vZGVKUy5UaW1lb3V0XG5cbiAgY29uc3RydWN0b3IoYmFzZVVybCA9IFwiaHR0cDovL2xvY2FsaG9zdDozMDAwXCIsIHBvbGxJbnRlcnZhbCA9IDEwMDApIHtcbiAgICBzdXBlcigpXG4gICAgdGhpcy5iYXNlVXJsID0gYmFzZVVybFxuICAgIHRoaXMucG9sbEludGVydmFsID0gcG9sbEludGVydmFsXG4gICAgdGhpcy5sYXN0UG9sbFRpbWUgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcbiAgfVxuXG4gIGFzeW5jIHN0YXJ0KCkge1xuICAgIGlmICh0aGlzLnBvbGxpbmcpIHJldHVyblxuICAgIHRoaXMucG9sbGluZyA9IHRydWVcbiAgICBhd2FpdCB0aGlzLnBvbGwoKVxuICB9XG5cbiAgc3RvcCgpIHtcbiAgICB0aGlzLnBvbGxpbmcgPSBmYWxzZVxuICAgIGlmICh0aGlzLnRpbWVvdXRJZCkge1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZW91dElkKVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcG9sbCgpIHtcbiAgICBpZiAoIXRoaXMucG9sbGluZykgcmV0dXJuXG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChcbiAgICAgICAgYCR7dGhpcy5iYXNlVXJsfS9hcGkvZXZlbnRzL2xpc3Q/c2luY2U9JHtlbmNvZGVVUklDb21wb25lbnQodGhpcy5sYXN0UG9sbFRpbWUpfWAsXG4gICAgICApXG5cbiAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBIVFRQIGVycm9yISBzdGF0dXM6ICR7cmVzcG9uc2Uuc3RhdHVzfWApXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRhdGE6IEV2ZW50c1Jlc3BvbnNlID0gYXdhaXQgcmVzcG9uc2UuanNvbigpXG5cbiAgICAgIC8vIFVwZGF0ZSBsYXN0IHBvbGwgdGltZSB0byBsYXRlc3QgZXZlbnQgb3IgY3VycmVudCB0aW1lXG4gICAgICBjb25zdCBsYXRlc3RFdmVudCA9IGRhdGEuZXZlbnRfbGlzdFtkYXRhLmV2ZW50X2xpc3QubGVuZ3RoIC0gMV1cbiAgICAgIHRoaXMubGFzdFBvbGxUaW1lID0gbGF0ZXN0RXZlbnRcbiAgICAgICAgPyBsYXRlc3RFdmVudC5jcmVhdGVkX2F0XG4gICAgICAgIDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpXG5cbiAgICAgIC8vIEVtaXQgZXZlbnRzIGluIGNocm9ub2xvZ2ljYWwgb3JkZXJcbiAgICAgIGRhdGEuZXZlbnRfbGlzdC5mb3JFYWNoKChldmVudCkgPT4ge1xuICAgICAgICB0aGlzLmVtaXQoZXZlbnQuZXZlbnRfdHlwZSwgZXZlbnQpXG4gICAgICAgIHRoaXMuZW1pdChcIipcIiwgZXZlbnQpXG4gICAgICB9KVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmVtaXQoXCJlcnJvclwiLCBlcnJvcilcbiAgICB9XG4gICAgLy8gU2NoZWR1bGUgbmV4dCBwb2xsXG4gICAgdGhpcy50aW1lb3V0SWQgPSBnbG9iYWxUaGlzLnNldFRpbWVvdXQoXG4gICAgICAoKSA9PiB0aGlzLnBvbGwoKSxcbiAgICAgIHRoaXMucG9sbEludGVydmFsLFxuICAgICkgYXMgdW5rbm93biBhcyBOb2RlSlMuVGltZW91dFxuICB9XG59XG4iLCAiaW1wb3J0IENvbmZpZ3N0b3JlIGZyb20gXCJjb25maWdzdG9yZVwiXG5pbXBvcnQgdHlwZSB7IFR5cGVkQ29uZmlnc3RvcmUgfSBmcm9tIFwiLi9UeXBlZENvbmZpZ1N0b3JlXCJcblxuZXhwb3J0IGludGVyZmFjZSBDbGlDb25maWcge1xuICBzZXNzaW9uVG9rZW4/OiBzdHJpbmdcbiAgZ2l0aHViVXNlcm5hbWU/OiBzdHJpbmdcbiAgcmVnaXN0cnlBcGlVcmw/OiBzdHJpbmdcbn1cblxuZXhwb3J0IGNvbnN0IGNsaUNvbmZpZzogVHlwZWRDb25maWdzdG9yZTxDbGlDb25maWc+ID0gbmV3IENvbmZpZ3N0b3JlKFxuICBcInRzY2lyY3VpdFwiLFxuKVxuXG5leHBvcnQgY29uc3QgZ2V0UmVnaXN0cnlBcGlVcmwgPSAoKTogc3RyaW5nID0+IHtcbiAgcmV0dXJuIGNsaUNvbmZpZy5nZXQoXCJyZWdpc3RyeUFwaVVybFwiKSA/PyBcImh0dHBzOi8vcmVnaXN0cnktYXBpLnRzY2lyY3VpdC5jb21cIlxufVxuIiwgImltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuaW1wb3J0IHsgY2xpQ29uZmlnIH0gZnJvbSBcImxpYi9jbGktY29uZmlnXCJcbmltcG9ydCBkZWxheSBmcm9tIFwiZGVsYXlcIlxuaW1wb3J0IHsgZ2V0S3kgfSBmcm9tIFwibGliL3JlZ2lzdHJ5LWFwaS9nZXQta3lcIlxuaW1wb3J0IHR5cGUgeyBFbmRwb2ludFJlc3BvbnNlIH0gZnJvbSBcImxpYi9yZWdpc3RyeS1hcGkvZW5kcG9pbnQtdHlwZXNcIlxuXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJBdXRoTG9naW4gPSAocHJvZ3JhbTogQ29tbWFuZCkgPT4ge1xuICBwcm9ncmFtLmNvbW1hbmRzXG4gICAgLmZpbmQoKGMpID0+IGMubmFtZSgpID09PSBcImF1dGhcIikhXG4gICAgLmNvbW1hbmQoXCJsb2dpblwiKVxuICAgIC5kZXNjcmlwdGlvbihcIkF1dGhlbnRpY2F0ZSBDTEksIGxvZ2luIHRvIHJlZ2lzdHJ5XCIpXG4gICAgLmFjdGlvbihhc3luYyAoYXJncykgPT4ge1xuICAgICAgY29uc3Qga3kgPSBnZXRLeSgpXG5cbiAgICAgIGNvbnN0IHsgbG9naW5fcGFnZSB9ID0gYXdhaXQga3lcbiAgICAgICAgLnBvc3Q8RW5kcG9pbnRSZXNwb25zZVtcInNlc3Npb25zL2xvZ2luX3BhZ2UvY3JlYXRlXCJdPihcbiAgICAgICAgICBcInNlc3Npb25zL2xvZ2luX3BhZ2UvY3JlYXRlXCIsXG4gICAgICAgICAge1xuICAgICAgICAgICAganNvbjoge30sXG4gICAgICAgICAgfSxcbiAgICAgICAgKVxuICAgICAgICAuanNvbigpXG5cbiAgICAgIGNvbnNvbGUubG9nKFwiUGxlYXNlIHZpc2l0IHRoZSBmb2xsb3dpbmcgVVJMIHRvIGxvZyBpbjpcIilcbiAgICAgIGNvbnNvbGUubG9nKGxvZ2luX3BhZ2UudXJsKVxuXG4gICAgICAvLyBXYWl0IHVudGlsIHdlIHJlY2VpdmUgY29uZmlybWF0aW9uXG4gICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBjb25zdCB7IGxvZ2luX3BhZ2U6IG5ld19sb2dpbl9wYWdlIH0gPSBhd2FpdCBreVxuICAgICAgICAgIC5wb3N0PEVuZHBvaW50UmVzcG9uc2VbXCJzZXNzaW9ucy9sb2dpbl9wYWdlL2dldFwiXT4oXG4gICAgICAgICAgICBcInNlc3Npb25zL2xvZ2luX3BhZ2UvZ2V0XCIsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGpzb246IHtcbiAgICAgICAgICAgICAgICBsb2dpbl9wYWdlX2lkOiBsb2dpbl9wYWdlLmxvZ2luX3BhZ2VfaWQsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7bG9naW5fcGFnZS5sb2dpbl9wYWdlX2F1dGhfdG9rZW59YCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgKVxuICAgICAgICAgIC5qc29uKClcblxuICAgICAgICBpZiAobmV3X2xvZ2luX3BhZ2Uud2FzX2xvZ2luX3N1Y2Nlc3NmdWwpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhcIkxvZ2dlZCBpbiEgR2VuZXJhdGluZyB0b2tlbi4uLlwiKVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIH1cblxuICAgICAgICBpZiAobmV3X2xvZ2luX3BhZ2UuaXNfZXhwaXJlZCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkxvZ2luIHBhZ2UgZXhwaXJlZFwiKVxuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgZGVsYXkoMTAwMClcbiAgICAgIH1cblxuICAgICAgY29uc3QgeyBzZXNzaW9uIH0gPSBhd2FpdCBreVxuICAgICAgICAucG9zdDxFbmRwb2ludFJlc3BvbnNlW1wic2Vzc2lvbnMvbG9naW5fcGFnZS9leGNoYW5nZV9mb3JfY2xpX3Nlc3Npb25cIl0+KFxuICAgICAgICAgIFwic2Vzc2lvbnMvbG9naW5fcGFnZS9leGNoYW5nZV9mb3JfY2xpX3Nlc3Npb25cIixcbiAgICAgICAgICB7XG4gICAgICAgICAgICBqc29uOiB7XG4gICAgICAgICAgICAgIGxvZ2luX3BhZ2VfaWQ6IGxvZ2luX3BhZ2UubG9naW5fcGFnZV9pZCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHtsb2dpbl9wYWdlLmxvZ2luX3BhZ2VfYXV0aF90b2tlbn1gLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICApXG4gICAgICAgIC5qc29uKClcblxuICAgICAgY2xpQ29uZmlnLnNldChcInNlc3Npb25Ub2tlblwiLCBzZXNzaW9uLnRva2VuKVxuXG4gICAgICBjb25zb2xlLmxvZyhcIlJlYWR5IHRvIHVzZSFcIilcbiAgICB9KVxufVxuIiwgImltcG9ydCB7IGdldFJlZ2lzdHJ5QXBpVXJsIH0gZnJvbSBcImxpYi9jbGktY29uZmlnXCJcbmltcG9ydCBreSwgeyB0eXBlIEFmdGVyUmVzcG9uc2VIb29rIH0gZnJvbSBcImt5XCJcblxuY29uc3QgcHJldHR5UmVzcG9uc2VFcnJvckhvb2s6IEFmdGVyUmVzcG9uc2VIb29rID0gYXN5bmMgKFxuICBfcmVxdWVzdCxcbiAgX29wdGlvbnMsXG4gIHJlc3BvbnNlLFxuKSA9PiB7XG4gIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZXJyb3JEYXRhID0gYXdhaXQgcmVzcG9uc2UuanNvbigpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBGQUlMIFske3Jlc3BvbnNlLnN0YXR1c31dOiAke19yZXF1ZXN0Lm1ldGhvZH0gJHtcbiAgICAgICAgICBuZXcgVVJMKF9yZXF1ZXN0LnVybCkucGF0aG5hbWVcbiAgICAgICAgfSBcXG5cXG4gJHtKU09OLnN0cmluZ2lmeShlcnJvckRhdGEsIG51bGwsIDIpfWAsXG4gICAgICApXG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgLy9pZ25vcmUsIGFsbG93IHRoZSBlcnJvciB0byBiZSB0aHJvd25cbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGNvbnN0IGdldEt5ID0gKCkgPT4ge1xuICByZXR1cm4ga3kuY3JlYXRlKHtcbiAgICBwcmVmaXhVcmw6IGdldFJlZ2lzdHJ5QXBpVXJsKCksXG4gICAgaG9va3M6IHtcbiAgICAgIGFmdGVyUmVzcG9uc2U6IFtwcmV0dHlSZXNwb25zZUVycm9ySG9va10sXG4gICAgfSxcbiAgfSlcbn1cbiIsICJpbXBvcnQgdHlwZSB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCJcblxuZXhwb3J0IGNvbnN0IHJlZ2lzdGVyQXV0aExvZ291dCA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW0uY29tbWFuZHNcbiAgICAuZmluZCgoYykgPT4gYy5uYW1lKCkgPT09IFwiYXV0aFwiKSFcbiAgICAuY29tbWFuZChcImxvZ291dFwiKVxuICAgIC5kZXNjcmlwdGlvbihcIkxvZ291dCBmcm9tIHJlZ2lzdHJ5XCIpXG4gICAgLmFjdGlvbigoYXJncykgPT4ge1xuICAgICAgY29uc29sZS5sb2coXCJsb2dvdXRcIilcbiAgICB9KVxufVxuIiwgImltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJBdXRoID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbS5jb21tYW5kKFwiYXV0aFwiKS5kZXNjcmlwdGlvbihcIkxvZ2luL2xvZ291dFwiKVxufVxuIiwgImltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJDb25maWcgPSAocHJvZ3JhbTogQ29tbWFuZCkgPT4ge1xuICBwcm9ncmFtLmNvbW1hbmQoXCJjb25maWdcIikuZGVzY3JpcHRpb24oXCJNYW5hZ2UgdHNjaXJjdWl0IENMSSBjb25maWd1cmF0aW9uXCIpXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5pbXBvcnQgeyBjbGlDb25maWcgfSBmcm9tIFwibGliL2NsaS1jb25maWdcIlxuXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJDb25maWdQcmludCA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW0uY29tbWFuZHNcbiAgICAuZmluZCgoYykgPT4gYy5uYW1lKCkgPT09IFwiY29uZmlnXCIpIVxuICAgIC5jb21tYW5kKFwicHJpbnRcIilcbiAgICAuZGVzY3JpcHRpb24oXCJQcmludCB0aGUgY3VycmVudCBjb25maWdcIilcbiAgICAuYWN0aW9uKCgpID0+IHtcbiAgICAgIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGNsaUNvbmZpZy5hbGwsIG51bGwsIDIpKVxuICAgIH0pXG59XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7QUFDQSxTQUFTLGVBQWU7OztBQ0F4QixZQUFZQSxXQUFVO0FBQ3RCLFlBQVksY0FBYztBQUMxQixZQUFZQyxTQUFROzs7QUNIcEIsWUFBWSxVQUFVO0FBQ3RCLFlBQVksUUFBUTtBQUNwQixZQUFZLFVBQVU7QUFDdEIsU0FBUyxzQkFBc0I7QUFFL0IsT0FBTyxzQkFBc0I7OztBQ0h0QixJQUFNLFdBQVcsWUFBWTtBQUNsQyxTQUFPO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQVlUOzs7QURQTyxJQUFNQyxnQkFBZSxPQUFPLE9BQWUsUUFBUztBQUN6RCxRQUFNLG9CQUFvQixlQUFlLGtCQUF5QixDQUFDLENBQUM7QUFFcEUsUUFBTSxTQUFjLGtCQUFhLE9BQU8sS0FBSyxRQUFRO0FBQ25ELFVBQU0sTUFBTSxJQUFJLElBQUksSUFBSSxLQUFNLFVBQVUsSUFBSSxRQUFRLElBQUksRUFBRTtBQUUxRCxRQUFJLElBQUksYUFBYSxzQkFBc0I7QUFDekMsWUFBTSxxQkFDSixRQUFRLElBQUksaUNBQ1A7QUFBQSxRQUNILFFBQVEsSUFBSTtBQUFBLFFBQ1o7QUFBQSxRQUNBO0FBQUEsTUFDRjtBQUVGLFVBQUk7QUFDRixjQUFNLFVBQWEsZ0JBQWEsb0JBQW9CLE1BQU07QUFDMUQsWUFBSSxVQUFVLEtBQUs7QUFBQSxVQUNqQixnQkFBZ0I7QUFBQSxRQUNsQixDQUFDO0FBQ0QsWUFBSSxJQUFJLE9BQU87QUFDZjtBQUFBLE1BQ0YsU0FBUyxPQUFPO0FBQ2QsZ0JBQVEsTUFBTSxvQ0FBb0MsS0FBSztBQUN2RCxZQUFJLFVBQVUsR0FBRztBQUNqQixZQUFJLElBQUksZ0JBQWdCO0FBQ3hCO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFFQSxRQUFJLElBQUksYUFBYSxLQUFLO0FBQ3hCLFlBQU0sT0FBTyxNQUFNLFNBQVM7QUFDNUIsVUFBSSxVQUFVLEtBQUssRUFBRSxnQkFBZ0IsWUFBWSxDQUFDO0FBQ2xELFVBQUksSUFBSSxJQUFJO0FBQ1o7QUFBQSxJQUNGO0FBRUEsUUFBSSxJQUFJLFNBQVMsV0FBVyxPQUFPLEdBQUc7QUFDcEMsVUFBSSxNQUFNLElBQUksSUFBSyxRQUFRLFNBQVMsR0FBRztBQUN2Qyx3QkFBa0IsS0FBSyxHQUFHO0FBQzFCO0FBQUEsSUFDRjtBQUVBLFFBQUksVUFBVSxHQUFHO0FBQ2pCLFFBQUksSUFBSSxXQUFXO0FBQUEsRUFDckIsQ0FBQztBQUVELFNBQU8sSUFBSSxRQUFjLENBQUNDLGFBQVk7QUFDcEMsV0FBTyxPQUFPLE1BQU0sTUFBTTtBQUN4QixjQUFRLElBQUksc0NBQXNDLElBQUksRUFBRTtBQUN4RCxNQUFBQSxTQUFRO0FBQUEsSUFDVixDQUFDO0FBQUEsRUFDSCxDQUFDO0FBQ0g7OztBRTdEQSxZQUFZLFFBQVE7QUFDcEIsWUFBWUMsV0FBVTtBQUN0QixZQUFZQyxTQUFRO0FBRXBCLFNBQVMseUJBQXlCLGVBQWlDO0FBRWpFLFFBQU0sZUFBb0IsY0FBUSxhQUFhO0FBQy9DLFFBQU0sVUFBZSxjQUFRLFlBQVk7QUFHekMsUUFBTSxVQUFhLGlCQUFhLGNBQWMsT0FBTztBQUNyRCxRQUFNLGFBQWdCO0FBQUEsSUFDcEI7QUFBQSxJQUNBO0FBQUEsSUFDRyxnQkFBYTtBQUFBLElBQ2hCO0FBQUEsRUFDRjtBQUVBLFFBQU0sZUFBZSxvQkFBSSxJQUFZO0FBR3JDLFdBQVMsTUFBTSxNQUFlO0FBQzVCLFFBQU8sdUJBQW9CLElBQUksS0FBUSx1QkFBb0IsSUFBSSxHQUFHO0FBQ2hFLFlBQU0sa0JBQWtCLEtBQUs7QUFDN0IsVUFBSSxtQkFBc0IsbUJBQWdCLGVBQWUsR0FBRztBQUMxRCxjQUFNLGFBQWEsZ0JBQWdCO0FBRW5DLFlBQUksV0FBVyxXQUFXLEdBQUcsR0FBRztBQUM5QixrQ0FBd0IsVUFBVTtBQUFBLFFBQ3BDO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFHQSxRQUNLLG9CQUFpQixJQUFJLEtBQ3hCLEtBQUssV0FBVyxTQUFZLGNBQVcsZUFDdkM7QUFDQSxZQUFNLFdBQVcsS0FBSyxVQUFVLENBQUM7QUFDakMsVUFBSSxZQUFlLG1CQUFnQixRQUFRLEdBQUc7QUFDNUMsY0FBTSxhQUFhLFNBQVM7QUFDNUIsWUFBSSxXQUFXLFdBQVcsR0FBRyxHQUFHO0FBQzlCLGtDQUF3QixVQUFVO0FBQUEsUUFDcEM7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUVBLElBQUcsZ0JBQWEsTUFBTSxLQUFLO0FBQUEsRUFDN0I7QUFHQSxXQUFTLHdCQUF3QixZQUFvQjtBQUNuRCxVQUFNLGFBQWE7QUFBQSxNQUNqQjtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxJQUNGO0FBQ0EsUUFBSSxlQUFvQixjQUFRLFNBQVMsVUFBVTtBQUduRCxRQUFPLGVBQVcsWUFBWSxHQUFHO0FBQy9CLG1CQUFhLElBQUksWUFBWTtBQUM3QjtBQUFBLElBQ0Y7QUFHQSxlQUFXLE9BQU8sWUFBWTtBQUM1QixZQUFNLGNBQWMsZUFBZTtBQUNuQyxVQUFPLGVBQVcsV0FBVyxHQUFHO0FBQzlCLHFCQUFhLElBQUksV0FBVztBQUM1QjtBQUFBLE1BQ0Y7QUFBQSxJQUNGO0FBR0EsUUFDSyxlQUFXLFlBQVksS0FDdkIsYUFBUyxZQUFZLEVBQUUsWUFBWSxHQUN0QztBQUNBLGlCQUFXLE9BQU8sWUFBWTtBQUM1QixjQUFNLFlBQWlCLFdBQUssY0FBYyxRQUFRLEdBQUcsRUFBRTtBQUN2RCxZQUFPLGVBQVcsU0FBUyxHQUFHO0FBQzVCLHVCQUFhLElBQUksU0FBUztBQUMxQjtBQUFBLFFBQ0Y7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFHQSxRQUFNLFVBQVU7QUFFaEIsU0FBTyxNQUFNLEtBQUssWUFBWTtBQUNoQzs7O0FDbEdBLFlBQVlDLFNBQVE7QUFDcEIsWUFBWUMsV0FBVTtBQUN0QixZQUFZQyxTQUFRO0FBUXBCLGVBQXNCLGFBQWEsYUFBcUI7QUFDdEQsUUFBTSxVQUFhLGlCQUFhLGFBQWEsT0FBTztBQUNwRCxRQUFNLGFBQWdCO0FBQUEsSUFDcEI7QUFBQSxJQUNBO0FBQUEsSUFDRyxpQkFBYTtBQUFBLElBQ2hCO0FBQUEsRUFDRjtBQUVBLFFBQU0sVUFBb0IsQ0FBQztBQUUzQixXQUFTLE1BQU0sTUFBZTtBQUM1QixRQUFPLHdCQUFvQixJQUFJLEdBQUc7QUFDaEMsWUFBTSxrQkFBa0IsS0FBSztBQUM3QixVQUFJLG1CQUFzQixvQkFBZ0IsZUFBZSxHQUFHO0FBQzFELGNBQU0sYUFBYSxnQkFBZ0I7QUFDbkMsWUFBSSxXQUFXLFdBQVcsUUFBUSxHQUFHO0FBQ25DLGtCQUFRLEtBQUssVUFBVTtBQUFBLFFBQ3pCO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFDQSxJQUFHLGlCQUFhLE1BQU0sS0FBSztBQUFBLEVBQzdCO0FBRUEsUUFBTSxVQUFVO0FBRWhCLE1BQUksY0FBbUIsY0FBUSxXQUFXO0FBQzFDLFNBQU8sZ0JBQXFCLFlBQU0sV0FBVyxFQUFFLE1BQU07QUFDbkQsUUFBTyxlQUFnQixXQUFLLGFBQWEsY0FBYyxDQUFDLEdBQUc7QUFDekQ7QUFBQSxJQUNGO0FBQ0Esa0JBQW1CLGNBQVEsV0FBVztBQUFBLEVBQ3hDO0FBRUEsYUFBVyxjQUFjLFNBQVM7QUFDaEMsVUFBTSxDQUFDLE9BQU8sSUFBSSxJQUFJLFdBQVcsUUFBUSxVQUFVLEVBQUUsRUFBRSxNQUFNLEdBQUc7QUFDaEUsUUFBSTtBQUNGLFlBQU0sV0FBVyxNQUFNO0FBQUEsUUFDckIsOERBQThELEtBQUssa0JBQWtCLElBQUk7QUFBQSxNQUMzRjtBQUVBLFVBQUksQ0FBQyxTQUFTLElBQUk7QUFDaEIsZ0JBQVEsS0FBSyw2QkFBNkIsVUFBVSxFQUFFO0FBQ3REO0FBQUEsTUFDRjtBQUVBLFlBQU0sT0FBMkIsTUFBTSxTQUFTLEtBQUs7QUFFckQsVUFBSSxLQUFLLFFBQVEsS0FBSztBQUNwQixjQUFNLGFBQWtCO0FBQUEsVUFDdEI7QUFBQSxVQUNBO0FBQUEsVUFDQTtBQUFBLFVBQ0EsR0FBRyxLQUFLLElBQUksSUFBSTtBQUFBLFFBQ2xCO0FBQ0EsUUFBRyxjQUFVLFlBQVksRUFBRSxXQUFXLEtBQUssQ0FBQztBQUU1QyxRQUFHLGtCQUFtQixXQUFLLFlBQVksWUFBWSxHQUFHLEtBQUssUUFBUSxHQUFHO0FBQUEsTUFDeEU7QUFBQSxJQUNGLFNBQVMsT0FBTztBQUNkLGNBQVEsS0FBSyw0QkFBNEIsVUFBVSxLQUFLLEtBQUs7QUFBQSxJQUMvRDtBQUFBLEVBQ0Y7QUFDRjs7O0FDekVBLFNBQVMsb0JBQW9CO0FBYXRCLElBQU0sZ0JBQU4sY0FBNEIsYUFBYTtBQUFBLEVBQ3RDO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBLFVBQVU7QUFBQSxFQUNWO0FBQUEsRUFFUixZQUFZLFVBQVUseUJBQXlCLGVBQWUsS0FBTTtBQUNsRSxVQUFNO0FBQ04sU0FBSyxVQUFVO0FBQ2YsU0FBSyxlQUFlO0FBQ3BCLFNBQUssZ0JBQWUsb0JBQUksS0FBSyxHQUFFLFlBQVk7QUFBQSxFQUM3QztBQUFBLEVBRUEsTUFBTSxRQUFRO0FBQ1osUUFBSSxLQUFLLFFBQVM7QUFDbEIsU0FBSyxVQUFVO0FBQ2YsVUFBTSxLQUFLLEtBQUs7QUFBQSxFQUNsQjtBQUFBLEVBRUEsT0FBTztBQUNMLFNBQUssVUFBVTtBQUNmLFFBQUksS0FBSyxXQUFXO0FBQ2xCLG1CQUFhLEtBQUssU0FBUztBQUFBLElBQzdCO0FBQUEsRUFDRjtBQUFBLEVBRUEsTUFBYyxPQUFPO0FBQ25CLFFBQUksQ0FBQyxLQUFLLFFBQVM7QUFFbkIsUUFBSTtBQUNGLFlBQU0sV0FBVyxNQUFNO0FBQUEsUUFDckIsR0FBRyxLQUFLLE9BQU8sMEJBQTBCLG1CQUFtQixLQUFLLFlBQVksQ0FBQztBQUFBLE1BQ2hGO0FBRUEsVUFBSSxDQUFDLFNBQVMsSUFBSTtBQUNoQixjQUFNLElBQUksTUFBTSx1QkFBdUIsU0FBUyxNQUFNLEVBQUU7QUFBQSxNQUMxRDtBQUVBLFlBQU0sT0FBdUIsTUFBTSxTQUFTLEtBQUs7QUFHakQsWUFBTSxjQUFjLEtBQUssV0FBVyxLQUFLLFdBQVcsU0FBUyxDQUFDO0FBQzlELFdBQUssZUFBZSxjQUNoQixZQUFZLGNBQ1osb0JBQUksS0FBSyxHQUFFLFlBQVk7QUFHM0IsV0FBSyxXQUFXLFFBQVEsQ0FBQyxVQUFVO0FBQ2pDLGFBQUssS0FBSyxNQUFNLFlBQVksS0FBSztBQUNqQyxhQUFLLEtBQUssS0FBSyxLQUFLO0FBQUEsTUFDdEIsQ0FBQztBQUFBLElBQ0gsU0FBUyxPQUFPO0FBQ2QsV0FBSyxLQUFLLFNBQVMsS0FBSztBQUFBLElBQzFCO0FBRUEsU0FBSyxZQUFZLFdBQVc7QUFBQSxNQUMxQixNQUFNLEtBQUssS0FBSztBQUFBLE1BQ2hCLEtBQUs7QUFBQSxJQUNQO0FBQUEsRUFDRjtBQUNGOzs7QUxqRU8sSUFBTSxjQUFjLENBQUNDLGFBQXFCO0FBQy9DLEVBQUFBLFNBQ0csUUFBUSxLQUFLLEVBQ2IsWUFBWSx3Q0FBd0MsRUFDcEQsU0FBUyxVQUFVLDBCQUEwQixFQUM3QyxPQUFPLHVCQUF1Qix5QkFBeUIsTUFBTSxFQUM3RCxPQUFPLE9BQU8sTUFBYyxZQUE4QjtBQUN6RCxVQUFNLGVBQW9CLGNBQVEsSUFBSTtBQUN0QyxVQUFNLFVBQWUsY0FBUSxZQUFZO0FBQ3pDLFVBQU0sT0FBTyxTQUFTLFFBQVEsSUFBSTtBQUVsQyxRQUFJO0FBQ0YsY0FBUSxJQUFJLDJDQUEyQztBQUN2RCxZQUFNLGFBQWEsWUFBWTtBQUMvQixjQUFRLElBQUksOEJBQThCO0FBQUEsSUFDNUMsU0FBUyxPQUFPO0FBQ2QsY0FBUSxLQUFLLDRCQUE0QixLQUFLO0FBQUEsSUFDaEQ7QUFHQSxVQUFNQyxjQUFhLElBQUk7QUFFdkIsVUFBTSxnQkFBZ0IsSUFBSSxjQUFjLG9CQUFvQixJQUFJLEVBQUU7QUFDbEUsa0JBQWMsTUFBTTtBQUVwQixVQUFNLE1BQU0sb0JBQW9CLElBQUkscUJBQXFCO0FBQUEsTUFDdkQsUUFBUTtBQUFBLE1BQ1IsU0FBUyxFQUFFLGdCQUFnQixtQkFBbUI7QUFBQSxNQUM5QyxNQUFNLEtBQUssVUFBVTtBQUFBLFFBQ25CLFdBQVc7QUFBQSxRQUNYLGNBQWM7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BS2hCLENBQUM7QUFBQSxJQUNILENBQUM7QUFHRCxVQUFNLGFBQWEsT0FBTyxhQUFxQjtBQUM3QyxVQUFJO0FBQ0YsY0FBTSxVQUFVLE1BQVMsYUFBUyxTQUFTLFVBQVUsT0FBTztBQUM1RCxjQUFNLFdBQVcsTUFBTTtBQUFBLFVBQ3JCLG9CQUFvQixJQUFJO0FBQUEsVUFDeEI7QUFBQSxZQUNFLFFBQVE7QUFBQSxZQUNSLFNBQVMsRUFBRSxnQkFBZ0IsbUJBQW1CO0FBQUEsWUFDOUMsTUFBTSxLQUFLLFVBQVU7QUFBQSxjQUNuQixXQUFnQixlQUFTLFNBQVMsUUFBUTtBQUFBLGNBQzFDLGNBQWM7QUFBQSxZQUNoQixDQUFDO0FBQUEsVUFDSDtBQUFBLFFBQ0Y7QUFDQSxZQUFJLENBQUMsU0FBUyxJQUFJO0FBQ2hCLGtCQUFRLE1BQU0sb0JBQW9CLFFBQVEsRUFBRTtBQUFBLFFBQzlDO0FBQUEsTUFDRixTQUFTLE9BQU87QUFDZCxnQkFBUSxNQUFNLGtCQUFrQixRQUFRLEtBQUssS0FBSztBQUFBLE1BQ3BEO0FBQUEsSUFDRjtBQUdBLFVBQU0sZUFBZSxvQkFBSSxJQUFJLENBQUMsWUFBWSxDQUFDO0FBQzNDLFFBQUk7QUFDRixZQUFNLE9BQU8seUJBQXlCLFlBQVk7QUFDbEQsV0FBSyxRQUFRLENBQUMsUUFBUSxhQUFhLElBQUksR0FBRyxDQUFDO0FBQUEsSUFDN0MsU0FBUyxPQUFPO0FBQ2QsY0FBUSxLQUFLLG1DQUFtQyxLQUFLO0FBQUEsSUFDdkQ7QUFHQSxVQUFNLG9CQUE2QixlQUFNLE1BQU0sS0FBSyxZQUFZLEdBQUc7QUFBQSxNQUNqRSxZQUFZO0FBQUEsTUFDWixlQUFlO0FBQUEsSUFDakIsQ0FBQztBQUVELHNCQUFrQixHQUFHLFVBQVUsT0FBTyxhQUFhO0FBQ2pELGNBQVEsSUFBSSxRQUFRLFFBQVEsVUFBVTtBQUN0QyxZQUFNLFdBQVcsUUFBUTtBQUFBLElBQzNCLENBQUM7QUFFRCxzQkFBa0IsR0FBRyxPQUFPLE9BQU8sYUFBYTtBQUM5QyxjQUFRLElBQUksUUFBUSxRQUFRLFFBQVE7QUFDcEMsWUFBTSxXQUFXLFFBQVE7QUFBQSxJQUMzQixDQUFDO0FBRUQsa0JBQWMsR0FBRyxnQkFBZ0IsT0FBTyxPQUFPO0FBQzdDLFVBQUksR0FBRyxjQUFjLHFCQUFxQjtBQUN4QyxnQkFBUSxJQUFJLGlEQUFpRDtBQUM3RCxjQUFNLEVBQUUsTUFBQUMsTUFBSyxJQUFJLE1BQU07QUFBQSxVQUNyQixvQkFBb0IsSUFBSTtBQUFBLFFBQzFCLEVBQUUsS0FBSyxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUM7QUFDdEIsUUFBRztBQUFBLFVBQ0ksV0FBSyxTQUFTLG1CQUFtQjtBQUFBLFVBQ3RDQSxNQUFLO0FBQUEsUUFDUDtBQUFBLE1BQ0Y7QUFBQSxJQUNGLENBQUM7QUFFRCxZQUFRLElBQUksWUFBWSxJQUFJLDBCQUEwQjtBQUFBLEVBQ3hELENBQUM7QUFDTDs7O0FNOUdBLE9BQU8saUJBQWlCO0FBU2pCLElBQU0sWUFBeUMsSUFBSTtBQUFBLEVBQ3hEO0FBQ0Y7QUFFTyxJQUFNLG9CQUFvQixNQUFjO0FBQzdDLFNBQU8sVUFBVSxJQUFJLGdCQUFnQixLQUFLO0FBQzVDOzs7QUNiQSxPQUFPLFdBQVc7OztBQ0RsQixPQUFPLFFBQW9DO0FBRTNDLElBQU0sMEJBQTZDLE9BQ2pELFVBQ0EsVUFDQSxhQUNHO0FBQ0gsTUFBSSxDQUFDLFNBQVMsSUFBSTtBQUNoQixRQUFJO0FBQ0YsWUFBTSxZQUFZLE1BQU0sU0FBUyxLQUFLO0FBQ3RDLFlBQU0sSUFBSTtBQUFBLFFBQ1IsU0FBUyxTQUFTLE1BQU0sTUFBTSxTQUFTLE1BQU0sSUFDM0MsSUFBSSxJQUFJLFNBQVMsR0FBRyxFQUFFLFFBQ3hCO0FBQUE7QUFBQSxHQUFTLEtBQUssVUFBVSxXQUFXLE1BQU0sQ0FBQyxDQUFDO0FBQUEsTUFDN0M7QUFBQSxJQUNGLFNBQVMsR0FBRztBQUFBLElBRVo7QUFBQSxFQUNGO0FBQ0Y7QUFFTyxJQUFNLFFBQVEsTUFBTTtBQUN6QixTQUFPLEdBQUcsT0FBTztBQUFBLElBQ2YsV0FBVyxrQkFBa0I7QUFBQSxJQUM3QixPQUFPO0FBQUEsTUFDTCxlQUFlLENBQUMsdUJBQXVCO0FBQUEsSUFDekM7QUFBQSxFQUNGLENBQUM7QUFDSDs7O0FEdkJPLElBQU0sb0JBQW9CLENBQUNDLGFBQXFCO0FBQ3JELEVBQUFBLFNBQVEsU0FDTCxLQUFLLENBQUMsTUFBTSxFQUFFLEtBQUssTUFBTSxNQUFNLEVBQy9CLFFBQVEsT0FBTyxFQUNmLFlBQVkscUNBQXFDLEVBQ2pELE9BQU8sT0FBTyxTQUFTO0FBQ3RCLFVBQU1DLE1BQUssTUFBTTtBQUVqQixVQUFNLEVBQUUsV0FBVyxJQUFJLE1BQU1BLElBQzFCO0FBQUEsTUFDQztBQUFBLE1BQ0E7QUFBQSxRQUNFLE1BQU0sQ0FBQztBQUFBLE1BQ1Q7QUFBQSxJQUNGLEVBQ0MsS0FBSztBQUVSLFlBQVEsSUFBSSwyQ0FBMkM7QUFDdkQsWUFBUSxJQUFJLFdBQVcsR0FBRztBQUcxQixXQUFPLE1BQU07QUFDWCxZQUFNLEVBQUUsWUFBWSxlQUFlLElBQUksTUFBTUEsSUFDMUM7QUFBQSxRQUNDO0FBQUEsUUFDQTtBQUFBLFVBQ0UsTUFBTTtBQUFBLFlBQ0osZUFBZSxXQUFXO0FBQUEsVUFDNUI7QUFBQSxVQUNBLFNBQVM7QUFBQSxZQUNQLGVBQWUsVUFBVSxXQUFXLHFCQUFxQjtBQUFBLFVBQzNEO0FBQUEsUUFDRjtBQUFBLE1BQ0YsRUFDQyxLQUFLO0FBRVIsVUFBSSxlQUFlLHNCQUFzQjtBQUN2QyxnQkFBUSxJQUFJLGdDQUFnQztBQUM1QztBQUFBLE1BQ0Y7QUFFQSxVQUFJLGVBQWUsWUFBWTtBQUM3QixjQUFNLElBQUksTUFBTSxvQkFBb0I7QUFBQSxNQUN0QztBQUVBLFlBQU0sTUFBTSxHQUFJO0FBQUEsSUFDbEI7QUFFQSxVQUFNLEVBQUUsUUFBUSxJQUFJLE1BQU1BLElBQ3ZCO0FBQUEsTUFDQztBQUFBLE1BQ0E7QUFBQSxRQUNFLE1BQU07QUFBQSxVQUNKLGVBQWUsV0FBVztBQUFBLFFBQzVCO0FBQUEsUUFDQSxTQUFTO0FBQUEsVUFDUCxlQUFlLFVBQVUsV0FBVyxxQkFBcUI7QUFBQSxRQUMzRDtBQUFBLE1BQ0Y7QUFBQSxJQUNGLEVBQ0MsS0FBSztBQUVSLGNBQVUsSUFBSSxnQkFBZ0IsUUFBUSxLQUFLO0FBRTNDLFlBQVEsSUFBSSxlQUFlO0FBQUEsRUFDN0IsQ0FBQztBQUNMOzs7QUV0RU8sSUFBTSxxQkFBcUIsQ0FBQ0MsYUFBcUI7QUFDdEQsRUFBQUEsU0FBUSxTQUNMLEtBQUssQ0FBQyxNQUFNLEVBQUUsS0FBSyxNQUFNLE1BQU0sRUFDL0IsUUFBUSxRQUFRLEVBQ2hCLFlBQVksc0JBQXNCLEVBQ2xDLE9BQU8sQ0FBQyxTQUFTO0FBQ2hCLFlBQVEsSUFBSSxRQUFRO0FBQUEsRUFDdEIsQ0FBQztBQUNMOzs7QUNSTyxJQUFNLGVBQWUsQ0FBQ0MsYUFBcUI7QUFDaEQsRUFBQUEsU0FBUSxRQUFRLE1BQU0sRUFBRSxZQUFZLGNBQWM7QUFDcEQ7OztBQ0ZPLElBQU0saUJBQWlCLENBQUNDLGFBQXFCO0FBQ2xELEVBQUFBLFNBQVEsUUFBUSxRQUFRLEVBQUUsWUFBWSxvQ0FBb0M7QUFDNUU7OztBQ0RPLElBQU0sc0JBQXNCLENBQUNDLGFBQXFCO0FBQ3ZELEVBQUFBLFNBQVEsU0FDTCxLQUFLLENBQUMsTUFBTSxFQUFFLEtBQUssTUFBTSxRQUFRLEVBQ2pDLFFBQVEsT0FBTyxFQUNmLFlBQVksMEJBQTBCLEVBQ3RDLE9BQU8sTUFBTTtBQUNaLFlBQVEsSUFBSSxLQUFLLFVBQVUsVUFBVSxLQUFLLE1BQU0sQ0FBQyxDQUFDO0FBQUEsRUFDcEQsQ0FBQztBQUNMOzs7QWJIQSxTQUFTLGtCQUFrQjtBQUUzQixJQUFNLFVBQVUsSUFBSSxRQUFRO0FBRTVCLFFBQ0csS0FBSyxNQUFNLEVBQ1gsWUFBWSx1Q0FBdUMsRUFDbkQsUUFBUSxPQUFPO0FBRWxCLFlBQVksT0FBTztBQUVuQixhQUFhLE9BQU87QUFDcEIsa0JBQWtCLE9BQU87QUFDekIsbUJBQW1CLE9BQU87QUFFMUIsZUFBZSxPQUFPO0FBQ3RCLG9CQUFvQixPQUFPO0FBRTNCLElBQUksUUFBUSxLQUFLLFdBQVcsR0FBRztBQUM3QixhQUFXLFNBQVMsUUFBUSxJQUFJO0FBQ2xDLE9BQU87QUFDTCxVQUFRLE1BQU07QUFDaEI7IiwKICAibmFtZXMiOiBbInBhdGgiLCAiZnMiLCAiY3JlYXRlU2VydmVyIiwgInJlc29sdmUiLCAicGF0aCIsICJmcyIsICJmcyIsICJwYXRoIiwgInRzIiwgInByb2dyYW0iLCAiY3JlYXRlU2VydmVyIiwgImZpbGUiLCAicHJvZ3JhbSIsICJreSIsICJwcm9ncmFtIiwgInByb2dyYW0iLCAicHJvZ3JhbSIsICJwcm9ncmFtIl0KfQo=
@@ -0,0 +1,57 @@
1
+ # File Server API Usage
2
+
3
+ The file server is a simple API that allows you to upload files and get their contents.
4
+
5
+ It emits events whenever a file is updated.
6
+
7
+ The browser preview will typically poll for event
8
+ changes.
9
+
10
+ ```
11
+ POST /files/upsert
12
+ REQUEST: { file_id?, text_content, file_path }
13
+ RESPONSE: { file: { file_id, file_path, text_content } }
14
+
15
+ GET /files/get?file_id?&file_path?
16
+ RESPONSE: { file: { file_id, file_path, text_content } }
17
+
18
+ GET /files/list
19
+ RESPONSE { file_list: Array<{ file_id, file_path } }
20
+
21
+ GET /events/list?since=<iso timestamp>
22
+ RESPONSE { event_list: Array<{ event_id, created_at, event_type, ... }> }
23
+
24
+ POST /events/create
25
+ REQUEST { event_type: "..." }
26
+ RESPONSE { event: { event_id, ... } }
27
+ ```
28
+
29
+ ## Starting the File Server
30
+
31
+ Here's an example of how to start the file server from a vite plugin that starts the file server:
32
+
33
+ ```tsx
34
+ import { defineConfig, type Plugin } from "vite"
35
+ import react from "@vitejs/plugin-react"
36
+ import { resolve } from "node:path"
37
+ import winterspecBundle from "@tscircuit/file-server/dist/bundle"
38
+ import { getNodeHandler } from "winterspec/adapters/node"
39
+
40
+ const fakeHandler = getNodeHandler(winterspecBundle as any, {})
41
+
42
+ function apiServerPlugin(): Plugin {
43
+ return {
44
+ name: "api-server",
45
+ configureServer(server) {
46
+ server.middlewares.use(async (req, res, next) => {
47
+ if (req.url?.startsWith("/api/")) {
48
+ req.url = req.url.replace("/api/", "/")
49
+ fakeHandler(req, res)
50
+ } else {
51
+ next()
52
+ }
53
+ })
54
+ },
55
+ }
56
+ }
57
+ ```
@@ -0,0 +1,14 @@
1
+ # RunFrame Usage
2
+
3
+ RunFrame provides a standalone JS file that automatically loads a runframe into an element with the id "root"
4
+
5
+ This is essentially the code that the "standalone.js" file contains (prior to compilation):
6
+
7
+ ```tsx
8
+ import { createRoot } from "react-dom/client"
9
+ import { RunFrameWithApi } from "./index"
10
+
11
+ const root = createRoot(document.getElementById("root")!)
12
+
13
+ root.render(<RunFrameWithApi />)
14
+ ```
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,13 @@
1
+ declare module "@tsci/seveibar.red-led" {
2
+ export function useRedLed(name: string): any
3
+ }
4
+
5
+ declare module "@tsci/seveibar.push-button" {
6
+ export function usePushButton(name: string): any
7
+ }
8
+
9
+ declare module "@tsci/seveibar.smd-usb-c" {
10
+ export function useUsbC(name: string): any
11
+ }
12
+
13
+ import "@tscircuit/core"
@@ -0,0 +1,20 @@
1
+ import "@tscircuit/core"
2
+ import { useRedLed } from "@tsci/seveibar.red-led"
3
+ import { usePushButton } from "@tsci/seveibar.push-button"
4
+ import { useUsbC } from "@tsci/seveibar.smd-usb-c"
5
+ import manualEdits from "./manual-edits.json"
6
+
7
+ export default () => {
8
+ const USBC = useUsbC("USBC")
9
+ const Button = usePushButton("SW1")
10
+ const Led = useRedLed("LED")
11
+ return (
12
+ <board width="12mm" height="30mm" manualEdits={manualEdits}>
13
+ <USBC GND="net.GND" pcbY={-10} VBUS1="net.VBUS" />
14
+ <Led neg="net.GND" pcbY={12} />
15
+ <Button pcbY={0} pin2=".R1 > .pos" pin3="net.VBUS" />
16
+ <resistor name="R1" footprint="0603" resistance="1k" pcbY={7} />
17
+ <trace from=".R1 > .neg" to={Led.pos} />
18
+ </board>
19
+ )
20
+ }
@@ -0,0 +1,11 @@
1
+ declare module "@tsci/seveibar.red-led" {
2
+ export function useRedLed(name: string): any
3
+ }
4
+
5
+ declare module "@tsci/seveibar.push-button" {
6
+ export function usePushButton(name: string): any
7
+ }
8
+
9
+ declare module "@tsci/seveibar.smd-usb-c" {
10
+ export function useUsbC(name: string): any
11
+ }