@tscircuit/cli 0.0.394 → 0.1.2

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 (246) 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 +33 -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/clone/register.ts +99 -0
  13. package/cli/config/print/register.ts +12 -0
  14. package/cli/config/register.ts +5 -0
  15. package/cli/dev/register.ts +111 -0
  16. package/cli/main.ts +33 -0
  17. package/dist/main.js +537 -0
  18. package/docs/file-server-api-usage.md +57 -0
  19. package/docs/run-frame-usage.md +14 -0
  20. package/example-dir/manual-edits.json +1 -0
  21. package/example-dir/snippet.d.ts +13 -0
  22. package/example-dir/snippet.tsx +20 -0
  23. package/example-dir/types.d.ts +11 -0
  24. package/lib/cli-config/TypedConfigStore.ts +50 -0
  25. package/lib/cli-config/index.ts +16 -0
  26. package/lib/dependency-analysis/DependencyAnalyzer.ts +129 -0
  27. package/lib/dependency-analysis/getLocalFileDependencies.ts +101 -0
  28. package/lib/dependency-analysis/installNodeModuleTypes.ts +74 -0
  29. package/lib/index.ts +2 -0
  30. package/lib/project-config/index.ts +5 -0
  31. package/lib/registry-api/endpoint-types.ts +20 -0
  32. package/lib/registry-api/get-ky.ts +30 -0
  33. package/lib/server/EventsWatcher.ts +75 -0
  34. package/lib/server/createServer.ts +62 -0
  35. package/lib/site/getIndex.ts +18 -0
  36. package/package.json +27 -144
  37. package/tsconfig.json +25 -22
  38. package/.github/workflows/formatbot.yml +0 -63
  39. package/.github/workflows/release.yml +0 -40
  40. package/.github/workflows/test.yml +0 -32
  41. package/.github/workflows/windows-tests.yml +0 -32
  42. package/.prettierrc +0 -1
  43. package/DEVELOPMENT.md +0 -7
  44. package/api/README.md +0 -3
  45. package/api/db/generic-json-level.ts +0 -123
  46. package/api/db/get-db.ts +0 -26
  47. package/api/db/schema.ts +0 -65
  48. package/api/db/zod-level-db.ts +0 -148
  49. package/api/index.ts +0 -4
  50. package/api/lib/middlewares/with-db.ts +0 -18
  51. package/api/lib/middlewares/with-debug-request-logging.ts +0 -13
  52. package/api/lib/middlewares/with-error-response.ts +0 -37
  53. package/api/lib/with-winter-spec.ts +0 -9
  54. package/api/lib/zod/export_parameters.ts +0 -25
  55. package/api/routes/api/db/download.ts +0 -25
  56. package/api/routes/api/dev_package_examples/create.ts +0 -43
  57. package/api/routes/api/dev_package_examples/get.ts +0 -46
  58. package/api/routes/api/dev_package_examples/list.ts +0 -36
  59. package/api/routes/api/dev_package_examples/update.ts +0 -59
  60. package/api/routes/api/dev_server/reset.ts +0 -13
  61. package/api/routes/api/export_files/create.ts +0 -27
  62. package/api/routes/api/export_files/download.ts +0 -25
  63. package/api/routes/api/export_requests/create.ts +0 -30
  64. package/api/routes/api/export_requests/get.ts +0 -43
  65. package/api/routes/api/export_requests/list.ts +0 -26
  66. package/api/routes/api/export_requests/update.ts +0 -34
  67. package/api/routes/api/health.ts +0 -11
  68. package/api/routes/api/package_info/create.ts +0 -26
  69. package/api/routes/api/package_info/get.ts +0 -16
  70. package/api/routes/health.ts +0 -11
  71. package/api/routes/index.ts +0 -16
  72. package/api/server.ts +0 -20
  73. package/api/static-routes.ts +0 -24
  74. package/api/tests/fixtures/get-test-server.ts +0 -31
  75. package/api/tests/fixtures/start-server.ts +0 -41
  76. package/api/tests/routes/dev_package_examples/create.test.ts +0 -19
  77. package/api/tests/routes/dev_package_examples/get.test.ts +0 -25
  78. package/api/tests/routes/dev_package_examples/list.test.ts +0 -32
  79. package/api/tests/routes/dev_package_examples/update.test.ts +0 -38
  80. package/api/tests/routes/export_files/create.test.ts +0 -18
  81. package/api/tests/routes/export_files/download.test.ts +0 -29
  82. package/api/tests/routes/export_requests/create.test.ts +0 -24
  83. package/api/tests/routes/export_requests/get.test.ts +0 -41
  84. package/api/tests/routes/export_requests/list.test.ts +0 -35
  85. package/api/tests/routes/export_requests/update.test.ts +0 -50
  86. package/api/tests/routes/health.test.ts +0 -10
  87. package/bunfig.toml +0 -2
  88. package/cli/cli.ts +0 -13
  89. package/cli/lib/cmd-fns/add.ts +0 -34
  90. package/cli/lib/cmd-fns/auth-login.ts +0 -59
  91. package/cli/lib/cmd-fns/auth-logout.ts +0 -7
  92. package/cli/lib/cmd-fns/auth-sessions-create.ts +0 -3
  93. package/cli/lib/cmd-fns/auth-sessions-get.ts +0 -3
  94. package/cli/lib/cmd-fns/auth-sessions-list.ts +0 -5
  95. package/cli/lib/cmd-fns/config-clear.ts +0 -5
  96. package/cli/lib/cmd-fns/config-print-config.ts +0 -6
  97. package/cli/lib/cmd-fns/config-reveal-location.ts +0 -5
  98. package/cli/lib/cmd-fns/config-set-log-requests.ts +0 -7
  99. package/cli/lib/cmd-fns/config-set-registry.ts +0 -9
  100. package/cli/lib/cmd-fns/config-set-runtime.ts +0 -7
  101. package/cli/lib/cmd-fns/config-set-session.ts +0 -7
  102. package/cli/lib/cmd-fns/dev/check-if-initialized.ts +0 -22
  103. package/cli/lib/cmd-fns/dev/derive-selector-from-pcb-component-id.ts +0 -23
  104. package/cli/lib/cmd-fns/dev/dev-server-request-handler.ts +0 -61
  105. package/cli/lib/cmd-fns/dev/find-available-port.ts +0 -32
  106. package/cli/lib/cmd-fns/dev/fulfill-export-requests.ts +0 -162
  107. package/cli/lib/cmd-fns/dev/get-dev-server-axios.ts +0 -29
  108. package/cli/lib/cmd-fns/dev/index.ts +0 -168
  109. package/cli/lib/cmd-fns/dev/infer-export-name-from-source.ts +0 -17
  110. package/cli/lib/cmd-fns/dev/mark-all-examples-loading.ts +0 -18
  111. package/cli/lib/cmd-fns/dev/soupify-and-upload-example-file.ts +0 -62
  112. package/cli/lib/cmd-fns/dev/start-dev-server.ts +0 -34
  113. package/cli/lib/cmd-fns/dev/start-edit-event-watcher.ts +0 -347
  114. package/cli/lib/cmd-fns/dev/start-export-request-watcher.ts +0 -33
  115. package/cli/lib/cmd-fns/dev/start-fs-watcher.ts +0 -54
  116. package/cli/lib/cmd-fns/dev/upload-examples-from-directory.ts +0 -42
  117. package/cli/lib/cmd-fns/dev-server-fulfill-export-requests.ts +0 -43
  118. package/cli/lib/cmd-fns/dev-server-upload.ts +0 -56
  119. package/cli/lib/cmd-fns/export-gerbers.ts +0 -28
  120. package/cli/lib/cmd-fns/export-kicad-pcb.ts +0 -36
  121. package/cli/lib/cmd-fns/export-pnp-csv.ts +0 -32
  122. package/cli/lib/cmd-fns/gen-jlcpcb-component.ts +0 -64
  123. package/cli/lib/cmd-fns/go.ts +0 -14
  124. package/cli/lib/cmd-fns/index.ts +0 -46
  125. package/cli/lib/cmd-fns/init/create-or-modify-npmrc.ts +0 -21
  126. package/cli/lib/cmd-fns/init/get-generated-npmrc.ts +0 -8
  127. package/cli/lib/cmd-fns/init/get-generated-readme.ts +0 -41
  128. package/cli/lib/cmd-fns/init/get-generated-tsconfig.ts +0 -34
  129. package/cli/lib/cmd-fns/init/index.ts +0 -193
  130. package/cli/lib/cmd-fns/install.ts +0 -34
  131. package/cli/lib/cmd-fns/lint.ts +0 -43
  132. package/cli/lib/cmd-fns/open.ts +0 -19
  133. package/cli/lib/cmd-fns/package-examples-create.ts +0 -36
  134. package/cli/lib/cmd-fns/package-examples-get.ts +0 -20
  135. package/cli/lib/cmd-fns/package-examples-list.ts +0 -18
  136. package/cli/lib/cmd-fns/package-files-create.ts +0 -31
  137. package/cli/lib/cmd-fns/package-files-download.ts +0 -29
  138. package/cli/lib/cmd-fns/package-files-get.ts +0 -3
  139. package/cli/lib/cmd-fns/package-files-list.ts +0 -28
  140. package/cli/lib/cmd-fns/package-files-upload-directory.ts +0 -6
  141. package/cli/lib/cmd-fns/package-releases-create.ts +0 -35
  142. package/cli/lib/cmd-fns/package-releases-get.ts +0 -3
  143. package/cli/lib/cmd-fns/package-releases-list.ts +0 -32
  144. package/cli/lib/cmd-fns/package-releases-update.ts +0 -45
  145. package/cli/lib/cmd-fns/packages-create.ts +0 -16
  146. package/cli/lib/cmd-fns/packages-get.ts +0 -16
  147. package/cli/lib/cmd-fns/packages-list.ts +0 -16
  148. package/cli/lib/cmd-fns/publish/index.ts +0 -336
  149. package/cli/lib/cmd-fns/remove.ts +0 -31
  150. package/cli/lib/cmd-fns/render.ts +0 -45
  151. package/cli/lib/cmd-fns/soupify.ts +0 -31
  152. package/cli/lib/cmd-fns/uninstall.ts +0 -31
  153. package/cli/lib/cmd-fns/version.ts +0 -38
  154. package/cli/lib/create-config-manager.ts +0 -97
  155. package/cli/lib/export-fns/export-bom-csv.ts +0 -32
  156. package/cli/lib/export-fns/export-gerbers.ts +0 -108
  157. package/cli/lib/export-fns/export-kicad-pcb.ts +0 -32
  158. package/cli/lib/export-fns/export-pnp-csv.ts +0 -31
  159. package/cli/lib/get-program.ts +0 -387
  160. package/cli/lib/param-handlers/index.ts +0 -21
  161. package/cli/lib/param-handlers/interact-for-local-directory.ts +0 -58
  162. package/cli/lib/param-handlers/interact-for-local-file.ts +0 -59
  163. package/cli/lib/param-handlers/interact-for-package-example-id.ts +0 -25
  164. package/cli/lib/param-handlers/interact-for-package-name-with-version.ts +0 -63
  165. package/cli/lib/param-handlers/interact-for-package-name.ts +0 -45
  166. package/cli/lib/param-handlers/interact-for-package-release-id.ts +0 -15
  167. package/cli/lib/param-handlers/interact-for-registry-url.ts +0 -27
  168. package/cli/lib/param-handlers/interact-for-runtime.ts +0 -33
  169. package/cli/lib/param-handlers/param-handler-type.ts +0 -7
  170. package/cli/lib/posthog.ts +0 -23
  171. package/cli/lib/soupify/get-export-name-from-file.ts +0 -29
  172. package/cli/lib/soupify/get-tmp-entrpoint-filepath.ts +0 -15
  173. package/cli/lib/soupify/index.ts +0 -1
  174. package/cli/lib/soupify/run-entrypoint-file.ts +0 -59
  175. package/cli/lib/soupify/soupify-with-core.ts +0 -74
  176. package/cli/lib/soupify/soupify.ts +0 -6
  177. package/cli/lib/util/app-context.ts +0 -17
  178. package/cli/lib/util/create-context-and-run-program.ts +0 -168
  179. package/cli/lib/util/get-all-package-files.ts +0 -66
  180. package/cli/lib/util/lint-project.ts +0 -137
  181. package/cli/tests/export-gerber-keyboard.test.ts +0 -16
  182. package/cli/tests/export-gerber.test.ts +0 -49
  183. package/cli/tests/export-kicad-pcb.test.ts +0 -23
  184. package/cli/tests/export-pnp-csv.test.ts +0 -24
  185. package/cli/tests/fixtures/preload.ts +0 -54
  186. package/cli/tests/init.test.ts +0 -9
  187. package/cli/tests/open.test.ts +0 -9
  188. package/cli/tests/soupify-builder.test.ts +0 -9
  189. package/cli/tests/soupify-core.test.ts +0 -9
  190. package/dist/cli.js +0 -3676
  191. package/docs/EDIT_EVENT_PIPELINE.md +0 -34
  192. package/example-project/README.md +0 -18
  193. package/example-project/examples/basic-capacitor.tsx +0 -5
  194. package/example-project/examples/basic-chip.tsx +0 -26
  195. package/example-project/examples/basic-resistor.tsx +0 -3
  196. package/example-project/examples/macrokeypad.tsx +0 -59
  197. package/example-project/index.ts +0 -1
  198. package/example-project/package.json +0 -5
  199. package/example-project/src/ArduinoProMicroBreakout.tsx +0 -37
  200. package/example-project/src/Key.tsx +0 -46
  201. package/example-project/src/Keyswitch.tsx +0 -26
  202. package/example-project/src/KeyswitchSocket.tsx +0 -56
  203. package/example-project/src/MyCircuit.tsx +0 -38
  204. package/example-project/src/manual-edits.ts +0 -93
  205. package/frontend/README.md +0 -3
  206. package/frontend/bun.lockb +0 -0
  207. package/frontend/components/command-k.tsx +0 -86
  208. package/frontend/components/dialogs/generic-export-dialog.tsx +0 -189
  209. package/frontend/components/dialogs/gerber-export-dialog.tsx +0 -168
  210. package/frontend/components/global-context-providers.tsx +0 -11
  211. package/frontend/components/select-example-search.tsx +0 -118
  212. package/frontend/components/ui/alert-dialog.tsx +0 -139
  213. package/frontend/components/ui/alert.tsx +0 -59
  214. package/frontend/components/ui/breadcrumb.tsx +0 -115
  215. package/frontend/components/ui/button.tsx +0 -57
  216. package/frontend/components/ui/card.tsx +0 -76
  217. package/frontend/components/ui/command.tsx +0 -153
  218. package/frontend/components/ui/context-menu.tsx +0 -202
  219. package/frontend/components/ui/dialog.tsx +0 -120
  220. package/frontend/components/ui/menubar.tsx +0 -238
  221. package/frontend/components/ui/navigation-menu.tsx +0 -128
  222. package/frontend/components/ui/popover.tsx +0 -31
  223. package/frontend/components/ui/select.tsx +0 -162
  224. package/frontend/components/ui/tabs.tsx +0 -53
  225. package/frontend/components/ui/toggle-group.tsx +0 -59
  226. package/frontend/components/ui/toggle.tsx +0 -43
  227. package/frontend/components/ui/tooltip.tsx +0 -28
  228. package/frontend/components.json +0 -17
  229. package/frontend/hooks/toast-if-api-not-connected.ts +0 -23
  230. package/frontend/hooks/use-active-dev-package-example-lite.ts +0 -39
  231. package/frontend/hooks/use-dev-package-examples.tsx +0 -18
  232. package/frontend/hooks/use-global-store.ts +0 -42
  233. package/frontend/index.css +0 -76
  234. package/frontend/index.html +0 -13
  235. package/frontend/lib/utils.ts +0 -6
  236. package/frontend/main.tsx +0 -13
  237. package/frontend/tailwind.config.js +0 -74
  238. package/frontend/views/App.tsx +0 -22
  239. package/frontend/views/Header.tsx +0 -55
  240. package/frontend/views/HeaderMenu.tsx +0 -326
  241. package/frontend/views/MainContentView.tsx +0 -172
  242. package/frontend/vite-env.d.ts +0 -1
  243. package/frontend/vite.config.ts +0 -50
  244. package/renovate.json +0 -16
  245. package/scripts/build-cli.ts +0 -12
  246. package/tsup.config.ts +0 -7
package/dist/main.js ADDED
@@ -0,0 +1,537 @@
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/clone/register.ts
459
+ import * as fs5 from "node:fs";
460
+ import * as path5 from "node:path";
461
+ var registerClone = (program2) => {
462
+ program2.command("clone").description("Clone a snippet from the registry").argument("<snippet>", "Snippet to clone (e.g. author/snippetName)").action(async (snippetPath) => {
463
+ let author;
464
+ let snippetName;
465
+ if (!snippetPath.startsWith("@tsci/") && snippetPath.includes("/")) {
466
+ ;
467
+ [author, snippetName] = snippetPath.split("/");
468
+ } else {
469
+ const trimmedPath = snippetPath.replace("@tsci/", "");
470
+ const firstDotIndex = trimmedPath.indexOf(".");
471
+ author = trimmedPath.slice(0, firstDotIndex);
472
+ snippetName = trimmedPath.slice(firstDotIndex + 1);
473
+ }
474
+ if (!author || !snippetName) {
475
+ console.error(
476
+ "Invalid snippet path. Use format: author/snippetName, author.snippetName or @tsci/author.snippetName"
477
+ );
478
+ process.exit(1);
479
+ }
480
+ const ky2 = getKy();
481
+ try {
482
+ console.log(`Cloning ${author}/${snippetName}...`);
483
+ const packageFileList = await ky2.post("package_files/list", {
484
+ json: {
485
+ package_name: `${author}/${snippetName}`,
486
+ use_latest_version: true
487
+ }
488
+ }).json();
489
+ const dirPath = `./${author}.${snippetName}`;
490
+ if (!fs5.existsSync(dirPath)) {
491
+ fs5.mkdirSync(dirPath);
492
+ }
493
+ for (const fileInfo of packageFileList.package_files) {
494
+ const filePath = fileInfo.file_path.startsWith("/") ? fileInfo.file_path.slice(1) : fileInfo.file_path;
495
+ if (filePath.startsWith("dist/")) continue;
496
+ const fileContent = await ky2.post("package_files/get", {
497
+ json: {
498
+ package_name: `${author}/${snippetName}`,
499
+ file_path: fileInfo.file_path
500
+ }
501
+ }).json();
502
+ const fullPath = path5.join(dirPath, filePath);
503
+ const dirName = path5.dirname(fullPath);
504
+ if (!fs5.existsSync(dirName)) {
505
+ fs5.mkdirSync(dirName, { recursive: true });
506
+ }
507
+ fs5.writeFileSync(fullPath, fileContent.package_file.content_text);
508
+ }
509
+ console.log(`Successfully cloned to ./${author}.${snippetName}/`);
510
+ } catch (error) {
511
+ if (error instanceof Error) {
512
+ console.error("Failed to clone snippet:", error.message);
513
+ } else {
514
+ console.error("Failed to clone snippet:", error);
515
+ }
516
+ process.exit(1);
517
+ }
518
+ });
519
+ };
520
+
521
+ // cli/main.ts
522
+ import { perfectCli } from "perfect-cli";
523
+ var program = new Command();
524
+ program.name("tsci").description("CLI for developing tscircuit snippets").version("1.0.0");
525
+ registerDev(program);
526
+ registerClone(program);
527
+ registerAuth(program);
528
+ registerAuthLogin(program);
529
+ registerAuthLogout(program);
530
+ registerConfig(program);
531
+ registerConfigPrint(program);
532
+ if (process.argv.length === 2) {
533
+ perfectCli(program, process.argv);
534
+ } else {
535
+ program.parse();
536
+ }
537
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vY2xpL21haW4udHMiLCAiLi4vY2xpL2Rldi9yZWdpc3Rlci50cyIsICIuLi9saWIvc2VydmVyL2NyZWF0ZVNlcnZlci50cyIsICIuLi9saWIvc2l0ZS9nZXRJbmRleC50cyIsICIuLi9saWIvZGVwZW5kZW5jeS1hbmFseXNpcy9nZXRMb2NhbEZpbGVEZXBlbmRlbmNpZXMudHMiLCAiLi4vbGliL2RlcGVuZGVuY3ktYW5hbHlzaXMvaW5zdGFsbE5vZGVNb2R1bGVUeXBlcy50cyIsICIuLi9saWIvc2VydmVyL0V2ZW50c1dhdGNoZXIudHMiLCAiLi4vbGliL2NsaS1jb25maWcvaW5kZXgudHMiLCAiLi4vY2xpL2F1dGgvbG9naW4vcmVnaXN0ZXIudHMiLCAiLi4vbGliL3JlZ2lzdHJ5LWFwaS9nZXQta3kudHMiLCAiLi4vY2xpL2F1dGgvbG9nb3V0L3JlZ2lzdGVyLnRzIiwgIi4uL2NsaS9hdXRoL3JlZ2lzdGVyLnRzIiwgIi4uL2NsaS9jb25maWcvcmVnaXN0ZXIudHMiLCAiLi4vY2xpL2NvbmZpZy9wcmludC9yZWdpc3Rlci50cyIsICIuLi9jbGkvY2xvbmUvcmVnaXN0ZXIudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIiMhL3Vzci9iaW4vZW52IG5vZGVcbmltcG9ydCB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCJcbmltcG9ydCB7IHJlZ2lzdGVyRGV2IH0gZnJvbSBcIi4vZGV2L3JlZ2lzdGVyXCJcbmltcG9ydCB7IHJlZ2lzdGVyQXV0aExvZ2luIH0gZnJvbSBcIi4vYXV0aC9sb2dpbi9yZWdpc3RlclwiXG5pbXBvcnQgeyByZWdpc3RlckF1dGhMb2dvdXQgfSBmcm9tIFwiLi9hdXRoL2xvZ291dC9yZWdpc3RlclwiXG5pbXBvcnQgeyByZWdpc3RlckF1dGggfSBmcm9tIFwiLi9hdXRoL3JlZ2lzdGVyXCJcbmltcG9ydCB7IHJlZ2lzdGVyQ29uZmlnIH0gZnJvbSBcIi4vY29uZmlnL3JlZ2lzdGVyXCJcbmltcG9ydCB7IHJlZ2lzdGVyQ29uZmlnUHJpbnQgfSBmcm9tIFwiLi9jb25maWcvcHJpbnQvcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJDbG9uZSB9IGZyb20gXCIuL2Nsb25lL3JlZ2lzdGVyXCJcbmltcG9ydCB7IHBlcmZlY3RDbGkgfSBmcm9tIFwicGVyZmVjdC1jbGlcIlxuXG5jb25zdCBwcm9ncmFtID0gbmV3IENvbW1hbmQoKVxuXG5wcm9ncmFtXG4gIC5uYW1lKFwidHNjaVwiKVxuICAuZGVzY3JpcHRpb24oXCJDTEkgZm9yIGRldmVsb3BpbmcgdHNjaXJjdWl0IHNuaXBwZXRzXCIpXG4gIC52ZXJzaW9uKFwiMS4wLjBcIilcblxucmVnaXN0ZXJEZXYocHJvZ3JhbSlcbnJlZ2lzdGVyQ2xvbmUocHJvZ3JhbSlcblxucmVnaXN0ZXJBdXRoKHByb2dyYW0pXG5yZWdpc3RlckF1dGhMb2dpbihwcm9ncmFtKVxucmVnaXN0ZXJBdXRoTG9nb3V0KHByb2dyYW0pXG5cbnJlZ2lzdGVyQ29uZmlnKHByb2dyYW0pXG5yZWdpc3RlckNvbmZpZ1ByaW50KHByb2dyYW0pXG5cbmlmIChwcm9jZXNzLmFyZ3YubGVuZ3RoID09PSAyKSB7XG4gIHBlcmZlY3RDbGkocHJvZ3JhbSwgcHJvY2Vzcy5hcmd2KVxufSBlbHNlIHtcbiAgcHJvZ3JhbS5wYXJzZSgpXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJub2RlOnBhdGhcIlxuaW1wb3J0ICogYXMgY2hva2lkYXIgZnJvbSBcImNob2tpZGFyXCJcbmltcG9ydCAqIGFzIGZzIGZyb20gXCJub2RlOmZzXCJcbmltcG9ydCB7IGNyZWF0ZVNlcnZlciB9IGZyb20gXCJsaWIvc2VydmVyL2NyZWF0ZVNlcnZlclwiXG5pbXBvcnQgeyBnZXRMb2NhbEZpbGVEZXBlbmRlbmNpZXMgfSBmcm9tIFwibGliL2RlcGVuZGVuY3ktYW5hbHlzaXMvZ2V0TG9jYWxGaWxlRGVwZW5kZW5jaWVzXCJcbmltcG9ydCB7IGluc3RhbGxUeXBlcyB9IGZyb20gXCIuLi8uLi9saWIvZGVwZW5kZW5jeS1hbmFseXNpcy9pbnN0YWxsTm9kZU1vZHVsZVR5cGVzXCJcbmltcG9ydCB7IEV2ZW50c1dhdGNoZXIgfSBmcm9tIFwiLi4vLi4vbGliL3NlcnZlci9FdmVudHNXYXRjaGVyXCJcblxuZXhwb3J0IGNvbnN0IHJlZ2lzdGVyRGV2ID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbVxuICAgIC5jb21tYW5kKFwiZGV2XCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiU3RhcnQgZGV2ZWxvcG1lbnQgc2VydmVyIGZvciBhIHNuaXBwZXRcIilcbiAgICAuYXJndW1lbnQoXCI8ZmlsZT5cIiwgXCJQYXRoIHRvIHRoZSBzbmlwcGV0IGZpbGVcIilcbiAgICAub3B0aW9uKFwiLXAsIC0tcG9ydCA8bnVtYmVyPlwiLCBcIlBvcnQgdG8gcnVuIHNlcnZlciBvblwiLCBcIjMwMDBcIilcbiAgICAuYWN0aW9uKGFzeW5jIChmaWxlOiBzdHJpbmcsIG9wdGlvbnM6IHsgcG9ydDogc3RyaW5nIH0pID0+IHtcbiAgICAgIGNvbnN0IGFic29sdXRlUGF0aCA9IHBhdGgucmVzb2x2ZShmaWxlKVxuICAgICAgY29uc3QgZmlsZURpciA9IHBhdGguZGlybmFtZShhYnNvbHV0ZVBhdGgpXG4gICAgICBjb25zdCBwb3J0ID0gcGFyc2VJbnQob3B0aW9ucy5wb3J0KVxuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zb2xlLmxvZyhcIkluc3RhbGxpbmcgdHlwZXMgZm9yIGltcG9ydGVkIHNuaXBwZXRzLi4uXCIpXG4gICAgICAgIGF3YWl0IGluc3RhbGxUeXBlcyhhYnNvbHV0ZVBhdGgpXG4gICAgICAgIGNvbnNvbGUubG9nKFwiVHlwZXMgaW5zdGFsbGVkIHN1Y2Nlc3NmdWxseVwiKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFwiRmFpbGVkIHRvIGluc3RhbGwgdHlwZXM6XCIsIGVycm9yKVxuICAgICAgfVxuXG4gICAgICAvLyBTdGFydCB0aGUgc2VydmVyXG4gICAgICBhd2FpdCBjcmVhdGVTZXJ2ZXIocG9ydClcblxuICAgICAgY29uc3QgZXZlbnRzV2F0Y2hlciA9IG5ldyBFdmVudHNXYXRjaGVyKGBodHRwOi8vbG9jYWxob3N0OiR7cG9ydH1gKVxuICAgICAgZXZlbnRzV2F0Y2hlci5zdGFydCgpXG5cbiAgICAgIGF3YWl0IGZldGNoKGBodHRwOi8vbG9jYWxob3N0OiR7cG9ydH0vYXBpL2ZpbGVzL3Vwc2VydGAsIHtcbiAgICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgaGVhZGVyczogeyBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIiB9LFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgZmlsZV9wYXRoOiBcImVudHJ5cG9pbnQudHN4XCIsXG4gICAgICAgICAgdGV4dF9jb250ZW50OiBgXG5pbXBvcnQgTXlDaXJjdWl0IGZyb20gXCIuL3NuaXBwZXQudHN4XCJcblxuY2lyY3VpdC5hZGQoPE15Q2lyY3VpdCAvPilcbmAsXG4gICAgICAgIH0pLFxuICAgICAgfSlcblxuICAgICAgLy8gRnVuY3Rpb24gdG8gdXBkYXRlIGZpbGUgY29udGVudFxuICAgICAgY29uc3QgdXBkYXRlRmlsZSA9IGFzeW5jIChmaWxlUGF0aDogc3RyaW5nKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnByb21pc2VzLnJlYWRGaWxlKGZpbGVQYXRoLCBcInV0Zi04XCIpXG4gICAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChcbiAgICAgICAgICAgIGBodHRwOi8vbG9jYWxob3N0OiR7cG9ydH0vYXBpL2ZpbGVzL3Vwc2VydGAsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgICAgICAgIGhlYWRlcnM6IHsgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfSxcbiAgICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgIGZpbGVfcGF0aDogcGF0aC5yZWxhdGl2ZShmaWxlRGlyLCBmaWxlUGF0aCksXG4gICAgICAgICAgICAgICAgdGV4dF9jb250ZW50OiBjb250ZW50LFxuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgKVxuICAgICAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byB1cGRhdGUgJHtmaWxlUGF0aH1gKVxuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvciB1cGRhdGluZyAke2ZpbGVQYXRofTpgLCBlcnJvcilcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBHZXQgaW5pdGlhbCBkZXBlbmRlbmNpZXNcbiAgICAgIGNvbnN0IGRlcGVuZGVuY2llcyA9IG5ldyBTZXQoW2Fic29sdXRlUGF0aF0pXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBkZXBzID0gZ2V0TG9jYWxGaWxlRGVwZW5kZW5jaWVzKGFic29sdXRlUGF0aClcbiAgICAgICAgZGVwcy5mb3JFYWNoKChkZXApID0+IGRlcGVuZGVuY2llcy5hZGQoZGVwKSlcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIkZhaWxlZCB0byBhbmFseXplIGRlcGVuZGVuY2llczpcIiwgZXJyb3IpXG4gICAgICB9XG5cbiAgICAgIC8vIFdhdGNoIHRoZSBtYWluIGZpbGUgYW5kIGl0cyBkZXBlbmRlbmNpZXNcbiAgICAgIGNvbnN0IGZpbGVzeXN0ZW1XYXRjaGVyID0gY2hva2lkYXIud2F0Y2goQXJyYXkuZnJvbShkZXBlbmRlbmNpZXMpLCB7XG4gICAgICAgIHBlcnNpc3RlbnQ6IHRydWUsXG4gICAgICAgIGlnbm9yZUluaXRpYWw6IGZhbHNlLFxuICAgICAgfSlcblxuICAgICAgZmlsZXN5c3RlbVdhdGNoZXIub24oXCJjaGFuZ2VcIiwgYXN5bmMgKGZpbGVQYXRoKSA9PiB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBGaWxlICR7ZmlsZVBhdGh9IGNoYW5nZWRgKVxuICAgICAgICBhd2FpdCB1cGRhdGVGaWxlKGZpbGVQYXRoKVxuICAgICAgfSlcblxuICAgICAgZmlsZXN5c3RlbVdhdGNoZXIub24oXCJhZGRcIiwgYXN5bmMgKGZpbGVQYXRoKSA9PiB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBGaWxlICR7ZmlsZVBhdGh9IGFkZGVkYClcbiAgICAgICAgYXdhaXQgdXBkYXRlRmlsZShmaWxlUGF0aClcbiAgICAgIH0pXG5cbiAgICAgIGV2ZW50c1dhdGNoZXIub24oXCJGSUxFX1VQREFURURcIiwgYXN5bmMgKGV2KSA9PiB7XG4gICAgICAgIGlmIChldi5maWxlX3BhdGggPT09IFwibWFudWFsLWVkaXRzLmpzb25cIikge1xuICAgICAgICAgIGNvbnNvbGUubG9nKFwiTWFudWFsIGVkaXRzIHVwZGF0ZWQsIHVwZGF0aW5nIG9uIGZpbGVzeXN0ZW0uLi5cIilcbiAgICAgICAgICBjb25zdCB7IGZpbGUgfSA9IGF3YWl0IGZldGNoKFxuICAgICAgICAgICAgYGh0dHA6Ly9sb2NhbGhvc3Q6JHtwb3J0fS9hcGkvZmlsZXMvZ2V0P2ZpbGVfcGF0aD1tYW51YWwtZWRpdHMuanNvbmAsXG4gICAgICAgICAgKS50aGVuKChyKSA9PiByLmpzb24oKSlcbiAgICAgICAgICBmcy53cml0ZUZpbGVTeW5jKFxuICAgICAgICAgICAgcGF0aC5qb2luKGZpbGVEaXIsIFwibWFudWFsLWVkaXRzLmpzb25cIiksXG4gICAgICAgICAgICBmaWxlLnRleHRfY29udGVudCxcbiAgICAgICAgICApXG4gICAgICAgIH1cbiAgICAgIH0pXG5cbiAgICAgIGNvbnNvbGUubG9nKGBXYXRjaGluZyAke2ZpbGV9IGFuZCBpdHMgZGVwZW5kZW5jaWVzLi4uYClcbiAgICB9KVxufVxuIiwgImltcG9ydCAqIGFzIGh0dHAgZnJvbSBcIm5vZGU6aHR0cFwiXG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwibm9kZTpmc1wiXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJub2RlOnBhdGhcIlxuaW1wb3J0IHsgZ2V0Tm9kZUhhbmRsZXIgfSBmcm9tIFwid2ludGVyc3BlYy9hZGFwdGVycy9ub2RlXCJcbi8vIEB0cy1pZ25vcmVcbmltcG9ydCB3aW50ZXJzcGVjQnVuZGxlIGZyb20gXCJAdHNjaXJjdWl0L2ZpbGUtc2VydmVyL2Rpc3QvYnVuZGxlLmpzXCJcbmltcG9ydCB7IGdldEluZGV4IH0gZnJvbSBcIi4uL3NpdGUvZ2V0SW5kZXhcIlxuXG5leHBvcnQgY29uc3QgY3JlYXRlU2VydmVyID0gYXN5bmMgKHBvcnQ6IG51bWJlciA9IDMwMDApID0+IHtcbiAgY29uc3QgZmlsZVNlcnZlckhhbmRsZXIgPSBnZXROb2RlSGFuZGxlcih3aW50ZXJzcGVjQnVuZGxlIGFzIGFueSwge30pXG5cbiAgY29uc3Qgc2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChyZXEudXJsISwgYGh0dHA6Ly8ke3JlcS5oZWFkZXJzLmhvc3R9YClcblxuICAgIGlmICh1cmwucGF0aG5hbWUgPT09IFwiL3N0YW5kYWxvbmUubWluLmpzXCIpIHtcbiAgICAgIGNvbnN0IHN0YW5kYWxvbmVGaWxlUGF0aCA9XG4gICAgICAgIHByb2Nlc3MuZW52LlJVTkZSQU1FX1NUQU5EQUxPTkVfRklMRV9QQVRIIHx8XG4gICAgICAgIHBhdGgucmVzb2x2ZShcbiAgICAgICAgICBwcm9jZXNzLmN3ZCgpLFxuICAgICAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICAgICAgXCJAdHNjaXJjdWl0L3J1bmZyYW1lL2Rpc3Qvc3RhbmRhbG9uZS5taW4uanNcIixcbiAgICAgICAgKVxuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjb250ZW50ID0gZnMucmVhZEZpbGVTeW5jKHN0YW5kYWxvbmVGaWxlUGF0aCwgXCJ1dGY4XCIpXG4gICAgICAgIHJlcy53cml0ZUhlYWQoMjAwLCB7XG4gICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qYXZhc2NyaXB0OyBjaGFyc2V0PXV0Zi04XCIsXG4gICAgICAgIH0pXG4gICAgICAgIHJlcy5lbmQoY29udGVudClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3Igc2VydmluZyBzdGFuZGFsb25lLm1pbi5qczpcIiwgZXJyb3IpXG4gICAgICAgIHJlcy53cml0ZUhlYWQoNDA0KVxuICAgICAgICByZXMuZW5kKFwiRmlsZSBub3QgZm91bmRcIilcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHVybC5wYXRobmFtZSA9PT0gXCIvXCIpIHtcbiAgICAgIGNvbnN0IGh0bWwgPSBhd2FpdCBnZXRJbmRleCgpXG4gICAgICByZXMud3JpdGVIZWFkKDIwMCwgeyBcIkNvbnRlbnQtVHlwZVwiOiBcInRleHQvaHRtbFwiIH0pXG4gICAgICByZXMuZW5kKGh0bWwpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBpZiAodXJsLnBhdGhuYW1lLnN0YXJ0c1dpdGgoXCIvYXBpL1wiKSkge1xuICAgICAgcmVxLnVybCA9IHJlcS51cmwhLnJlcGxhY2UoXCIvYXBpL1wiLCBcIi9cIilcbiAgICAgIGZpbGVTZXJ2ZXJIYW5kbGVyKHJlcSwgcmVzKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgcmVzLndyaXRlSGVhZCg0MDQpXG4gICAgcmVzLmVuZChcIk5vdCBmb3VuZFwiKVxuICB9KVxuXG4gIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgIHNlcnZlci5saXN0ZW4ocG9ydCwgKCkgPT4ge1xuICAgICAgY29uc29sZS5sb2coYFNlcnZlciBydW5uaW5nIGF0IGh0dHA6Ly9sb2NhbGhvc3Q6JHtwb3J0fWApXG4gICAgICByZXNvbHZlKClcbiAgICB9KVxuICB9KVxufVxuIiwgImltcG9ydCBwa2cgZnJvbSBcIi4uLy4uL3BhY2thZ2UuanNvblwiXG5cbmV4cG9ydCBjb25zdCBnZXRJbmRleCA9IGFzeW5jICgpID0+IHtcbiAgcmV0dXJuIGA8aHRtbD5cbiAgICA8aGVhZD5cbiAgICA8L2hlYWQ+XG4gICAgPGJvZHk+XG4gICAgICA8c2NyaXB0IHNyYz1cImh0dHBzOi8vY2RuLnRhaWx3aW5kY3NzLmNvbVwiPjwvc2NyaXB0PlxuICAgICAgPGRpdiBpZD1cInJvb3RcIj5sb2FkaW5nLi4uPC9kaXY+XG4gICAgICA8c2NyaXB0PlxuICAgICAgZ2xvYmFsVGhpcy5wcm9jZXNzID0geyBlbnY6IHsgTk9ERV9FTlY6IFwicHJvZHVjdGlvblwiIH0gfVxuICAgICAgPC9zY3JpcHQ+XG4gICAgICA8c2NyaXB0IHNyYz1cIi9zdGFuZGFsb25lLm1pbi5qc1wiPjwvc2NyaXB0PlxuICAgIDwvYm9keT5cbiAgPC9odG1sPmBcbn1cblxuLy8gPHNjcmlwdCBzcmM9XCJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL0B0c2NpcmN1aXQvcnVuZnJhbWVAJHtwa2cuZGVwZW5kZW5jaWVzW1wiQHRzY2lyY3VpdC9ydW5mcmFtZVwiXS5yZXBsYWNlKC9eW14wLTldKy8sIFwiXCIpfS9kaXN0L3N0YW5kYWxvbmUubWluLmpzXCI+PC9zY3JpcHQ+XG4iLCAiaW1wb3J0ICogYXMgdHMgZnJvbSBcInR5cGVzY3JpcHRcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwicGF0aFwiXG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwiZnNcIlxuXG5mdW5jdGlvbiBnZXRMb2NhbEZpbGVEZXBlbmRlbmNpZXMocGF0aFRvVHN4RmlsZTogc3RyaW5nKTogc3RyaW5nW10ge1xuICAvLyBFbnN1cmUgYWJzb2x1dGUgcGF0aFxuICBjb25zdCBhYnNvbHV0ZVBhdGggPSBwYXRoLnJlc29sdmUocGF0aFRvVHN4RmlsZSlcbiAgY29uc3QgYmFzZURpciA9IHBhdGguZGlybmFtZShhYnNvbHV0ZVBhdGgpXG5cbiAgLy8gUmVhZCBhbmQgcGFyc2UgdGhlIGZpbGVcbiAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhhYnNvbHV0ZVBhdGgsIFwidXRmLThcIilcbiAgY29uc3Qgc291cmNlRmlsZSA9IHRzLmNyZWF0ZVNvdXJjZUZpbGUoXG4gICAgYWJzb2x1dGVQYXRoLFxuICAgIGNvbnRlbnQsXG4gICAgdHMuU2NyaXB0VGFyZ2V0LkxhdGVzdCxcbiAgICB0cnVlLFxuICApXG5cbiAgY29uc3QgZGVwZW5kZW5jaWVzID0gbmV3IFNldDxzdHJpbmc+KClcblxuICAvLyBSZWN1cnNpdmVseSB2aXNpdCBub2RlcyB0byBmaW5kIGltcG9ydHNcbiAgZnVuY3Rpb24gdmlzaXQobm9kZTogdHMuTm9kZSkge1xuICAgIGlmICh0cy5pc0ltcG9ydERlY2xhcmF0aW9uKG5vZGUpIHx8IHRzLmlzRXhwb3J0RGVjbGFyYXRpb24obm9kZSkpIHtcbiAgICAgIGNvbnN0IG1vZHVsZVNwZWNpZmllciA9IG5vZGUubW9kdWxlU3BlY2lmaWVyXG4gICAgICBpZiAobW9kdWxlU3BlY2lmaWVyICYmIHRzLmlzU3RyaW5nTGl0ZXJhbChtb2R1bGVTcGVjaWZpZXIpKSB7XG4gICAgICAgIGNvbnN0IGltcG9ydFBhdGggPSBtb2R1bGVTcGVjaWZpZXIudGV4dFxuICAgICAgICAvLyBPbmx5IHByb2Nlc3MgbG9jYWwgaW1wb3J0cyAoc3RhcnRpbmcgd2l0aCAuIG9yIC4uKVxuICAgICAgICBpZiAoaW1wb3J0UGF0aC5zdGFydHNXaXRoKFwiLlwiKSkge1xuICAgICAgICAgIHJlc29sdmVBbmRBZGREZXBlbmRlbmN5KGltcG9ydFBhdGgpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBIYW5kbGUgZHluYW1pYyBpbXBvcnRzXG4gICAgaWYgKFxuICAgICAgdHMuaXNDYWxsRXhwcmVzc2lvbihub2RlKSAmJlxuICAgICAgbm9kZS5leHByZXNzaW9uLmtpbmQgPT09IHRzLlN5bnRheEtpbmQuSW1wb3J0S2V5d29yZFxuICAgICkge1xuICAgICAgY29uc3QgYXJndW1lbnQgPSBub2RlLmFyZ3VtZW50c1swXVxuICAgICAgaWYgKGFyZ3VtZW50ICYmIHRzLmlzU3RyaW5nTGl0ZXJhbChhcmd1bWVudCkpIHtcbiAgICAgICAgY29uc3QgaW1wb3J0UGF0aCA9IGFyZ3VtZW50LnRleHRcbiAgICAgICAgaWYgKGltcG9ydFBhdGguc3RhcnRzV2l0aChcIi5cIikpIHtcbiAgICAgICAgICByZXNvbHZlQW5kQWRkRGVwZW5kZW5jeShpbXBvcnRQYXRoKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdHMuZm9yRWFjaENoaWxkKG5vZGUsIHZpc2l0KVxuICB9XG5cbiAgLy8gSGVscGVyIHRvIHJlc29sdmUgYW5kIGFkZCBkZXBlbmRlbmN5IHBhdGhzXG4gIGZ1bmN0aW9uIHJlc29sdmVBbmRBZGREZXBlbmRlbmN5KGltcG9ydFBhdGg6IHN0cmluZykge1xuICAgIGNvbnN0IGV4dGVuc2lvbnMgPSBbXG4gICAgICBcIi50c3hcIixcbiAgICAgIFwiLnRzXCIsXG4gICAgICBcIi5qc3hcIixcbiAgICAgIFwiLmpzXCIsXG4gICAgICBcIi5jc3NcIixcbiAgICAgIFwiLnNjc3NcIixcbiAgICAgIFwiLnNhc3NcIixcbiAgICAgIFwiLmxlc3NcIixcbiAgICBdXG4gICAgbGV0IHJlc29sdmVkUGF0aCA9IHBhdGgucmVzb2x2ZShiYXNlRGlyLCBpbXBvcnRQYXRoKVxuXG4gICAgLy8gQ2hlY2sgaWYgcGF0aCBleGlzdHMgYXMtaXNcbiAgICBpZiAoZnMuZXhpc3RzU3luYyhyZXNvbHZlZFBhdGgpKSB7XG4gICAgICBkZXBlbmRlbmNpZXMuYWRkKHJlc29sdmVkUGF0aClcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIC8vIFRyeSB3aXRoIGV4dGVuc2lvbnNcbiAgICBmb3IgKGNvbnN0IGV4dCBvZiBleHRlbnNpb25zKSB7XG4gICAgICBjb25zdCBwYXRoV2l0aEV4dCA9IHJlc29sdmVkUGF0aCArIGV4dFxuICAgICAgaWYgKGZzLmV4aXN0c1N5bmMocGF0aFdpdGhFeHQpKSB7XG4gICAgICAgIGRlcGVuZGVuY2llcy5hZGQocGF0aFdpdGhFeHQpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENoZWNrIGZvciBpbmRleCBmaWxlcyBpbiBkaXJlY3Rvcmllc1xuICAgIGlmIChcbiAgICAgIGZzLmV4aXN0c1N5bmMocmVzb2x2ZWRQYXRoKSAmJlxuICAgICAgZnMuc3RhdFN5bmMocmVzb2x2ZWRQYXRoKS5pc0RpcmVjdG9yeSgpXG4gICAgKSB7XG4gICAgICBmb3IgKGNvbnN0IGV4dCBvZiBleHRlbnNpb25zKSB7XG4gICAgICAgIGNvbnN0IGluZGV4UGF0aCA9IHBhdGguam9pbihyZXNvbHZlZFBhdGgsIGBpbmRleCR7ZXh0fWApXG4gICAgICAgIGlmIChmcy5leGlzdHNTeW5jKGluZGV4UGF0aCkpIHtcbiAgICAgICAgICBkZXBlbmRlbmNpZXMuYWRkKGluZGV4UGF0aClcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFN0YXJ0IHRoZSB0cmF2ZXJzYWxcbiAgdmlzaXQoc291cmNlRmlsZSlcblxuICByZXR1cm4gQXJyYXkuZnJvbShkZXBlbmRlbmNpZXMpXG59XG5cbmV4cG9ydCB7IGdldExvY2FsRmlsZURlcGVuZGVuY2llcyB9XG4iLCAiaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnNcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCAqIGFzIHRzIGZyb20gXCJ0eXBlc2NyaXB0XCJcblxuaW50ZXJmYWNlIFNuaXBwZXRBcGlSZXNwb25zZSB7XG4gIHNuaXBwZXQ6IHtcbiAgICBkdHM6IHN0cmluZ1xuICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbnN0YWxsVHlwZXMoc25pcHBldFBhdGg6IHN0cmluZykge1xuICBjb25zdCBjb250ZW50ID0gZnMucmVhZEZpbGVTeW5jKHNuaXBwZXRQYXRoLCBcInV0Zi04XCIpXG4gIGNvbnN0IHNvdXJjZUZpbGUgPSB0cy5jcmVhdGVTb3VyY2VGaWxlKFxuICAgIHNuaXBwZXRQYXRoLFxuICAgIGNvbnRlbnQsXG4gICAgdHMuU2NyaXB0VGFyZ2V0LkxhdGVzdCxcbiAgICB0cnVlLFxuICApXG5cbiAgY29uc3QgaW1wb3J0czogc3RyaW5nW10gPSBbXVxuXG4gIGZ1bmN0aW9uIHZpc2l0KG5vZGU6IHRzLk5vZGUpIHtcbiAgICBpZiAodHMuaXNJbXBvcnREZWNsYXJhdGlvbihub2RlKSkge1xuICAgICAgY29uc3QgbW9kdWxlU3BlY2lmaWVyID0gbm9kZS5tb2R1bGVTcGVjaWZpZXJcbiAgICAgIGlmIChtb2R1bGVTcGVjaWZpZXIgJiYgdHMuaXNTdHJpbmdMaXRlcmFsKG1vZHVsZVNwZWNpZmllcikpIHtcbiAgICAgICAgY29uc3QgaW1wb3J0UGF0aCA9IG1vZHVsZVNwZWNpZmllci50ZXh0XG4gICAgICAgIGlmIChpbXBvcnRQYXRoLnN0YXJ0c1dpdGgoXCJAdHNjaS9cIikpIHtcbiAgICAgICAgICBpbXBvcnRzLnB1c2goaW1wb3J0UGF0aClcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICB0cy5mb3JFYWNoQ2hpbGQobm9kZSwgdmlzaXQpXG4gIH1cblxuICB2aXNpdChzb3VyY2VGaWxlKVxuXG4gIGxldCBwcm9qZWN0Um9vdCA9IHBhdGguZGlybmFtZShzbmlwcGV0UGF0aClcbiAgd2hpbGUgKHByb2plY3RSb290ICE9PSBwYXRoLnBhcnNlKHByb2plY3RSb290KS5yb290KSB7XG4gICAgaWYgKGZzLmV4aXN0c1N5bmMocGF0aC5qb2luKHByb2plY3RSb290LCBcInBhY2thZ2UuanNvblwiKSkpIHtcbiAgICAgIGJyZWFrXG4gICAgfVxuICAgIHByb2plY3RSb290ID0gcGF0aC5kaXJuYW1lKHByb2plY3RSb290KVxuICB9XG5cbiAgZm9yIChjb25zdCBpbXBvcnRQYXRoIG9mIGltcG9ydHMpIHtcbiAgICBjb25zdCBbb3duZXIsIG5hbWVdID0gaW1wb3J0UGF0aC5yZXBsYWNlKFwiQHRzY2kvXCIsIFwiXCIpLnNwbGl0KFwiLlwiKVxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKFxuICAgICAgICBgaHR0cHM6Ly9yZWdpc3RyeS1hcGkudHNjaXJjdWl0LmNvbS9zbmlwcGV0cy9nZXQ/b3duZXJfbmFtZT0ke293bmVyfSZ1bnNjb3BlZF9uYW1lPSR7bmFtZX1gLFxuICAgICAgKVxuXG4gICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgRmFpbGVkIHRvIGZldGNoIHR5cGVzIGZvciAke2ltcG9ydFBhdGh9YClcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YTogU25pcHBldEFwaVJlc3BvbnNlID0gYXdhaXQgcmVzcG9uc2UuanNvbigpXG5cbiAgICAgIGlmIChkYXRhLnNuaXBwZXQuZHRzKSB7XG4gICAgICAgIGNvbnN0IHBhY2thZ2VEaXIgPSBwYXRoLmpvaW4oXG4gICAgICAgICAgcHJvamVjdFJvb3QsXG4gICAgICAgICAgXCJub2RlX21vZHVsZXNcIixcbiAgICAgICAgICBcIkB0c2NpXCIsXG4gICAgICAgICAgYCR7b3duZXJ9LiR7bmFtZX1gLFxuICAgICAgICApXG4gICAgICAgIGZzLm1rZGlyU3luYyhwYWNrYWdlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KVxuXG4gICAgICAgIGZzLndyaXRlRmlsZVN5bmMocGF0aC5qb2luKHBhY2thZ2VEaXIsIFwiaW5kZXguZC50c1wiKSwgZGF0YS5zbmlwcGV0LmR0cylcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS53YXJuKGBFcnJvciBmZXRjaGluZyB0eXBlcyBmb3IgJHtpbXBvcnRQYXRofTpgLCBlcnJvcilcbiAgICB9XG4gIH1cbn1cbiIsICJpbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tIFwiZXZlbnRzXCJcblxuaW50ZXJmYWNlIEV2ZW50IHtcbiAgZXZlbnRfaWQ6IHN0cmluZ1xuICBjcmVhdGVkX2F0OiBzdHJpbmdcbiAgZXZlbnRfdHlwZTogc3RyaW5nXG4gIFtrZXk6IHN0cmluZ106IGFueVxufVxuXG5pbnRlcmZhY2UgRXZlbnRzUmVzcG9uc2Uge1xuICBldmVudF9saXN0OiBFdmVudFtdXG59XG5cbmV4cG9ydCBjbGFzcyBFdmVudHNXYXRjaGVyIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgcHJpdmF0ZSBsYXN0UG9sbFRpbWU6IHN0cmluZ1xuICBwcml2YXRlIHBvbGxJbnRlcnZhbDogbnVtYmVyXG4gIHByaXZhdGUgYmFzZVVybDogc3RyaW5nXG4gIHByaXZhdGUgcG9sbGluZyA9IGZhbHNlXG4gIHByaXZhdGUgdGltZW91dElkPzogTm9kZUpTLlRpbWVvdXRcblxuICBjb25zdHJ1Y3RvcihiYXNlVXJsID0gXCJodHRwOi8vbG9jYWxob3N0OjMwMDBcIiwgcG9sbEludGVydmFsID0gMTAwMCkge1xuICAgIHN1cGVyKClcbiAgICB0aGlzLmJhc2VVcmwgPSBiYXNlVXJsXG4gICAgdGhpcy5wb2xsSW50ZXJ2YWwgPSBwb2xsSW50ZXJ2YWxcbiAgICB0aGlzLmxhc3RQb2xsVGltZSA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKVxuICB9XG5cbiAgYXN5bmMgc3RhcnQoKSB7XG4gICAgaWYgKHRoaXMucG9sbGluZykgcmV0dXJuXG4gICAgdGhpcy5wb2xsaW5nID0gdHJ1ZVxuICAgIGF3YWl0IHRoaXMucG9sbCgpXG4gIH1cblxuICBzdG9wKCkge1xuICAgIHRoaXMucG9sbGluZyA9IGZhbHNlXG4gICAgaWYgKHRoaXMudGltZW91dElkKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0SWQpXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwb2xsKCkge1xuICAgIGlmICghdGhpcy5wb2xsaW5nKSByZXR1cm5cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKFxuICAgICAgICBgJHt0aGlzLmJhc2VVcmx9L2FwaS9ldmVudHMvbGlzdD9zaW5jZT0ke2VuY29kZVVSSUNvbXBvbmVudCh0aGlzLmxhc3RQb2xsVGltZSl9YCxcbiAgICAgIClcblxuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEhUVFAgZXJyb3IhIHN0YXR1czogJHtyZXNwb25zZS5zdGF0dXN9YClcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YTogRXZlbnRzUmVzcG9uc2UgPSBhd2FpdCByZXNwb25zZS5qc29uKClcblxuICAgICAgLy8gVXBkYXRlIGxhc3QgcG9sbCB0aW1lIHRvIGxhdGVzdCBldmVudCBvciBjdXJyZW50IHRpbWVcbiAgICAgIGNvbnN0IGxhdGVzdEV2ZW50ID0gZGF0YS5ldmVudF9saXN0W2RhdGEuZXZlbnRfbGlzdC5sZW5ndGggLSAxXVxuICAgICAgdGhpcy5sYXN0UG9sbFRpbWUgPSBsYXRlc3RFdmVudFxuICAgICAgICA/IGxhdGVzdEV2ZW50LmNyZWF0ZWRfYXRcbiAgICAgICAgOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcblxuICAgICAgLy8gRW1pdCBldmVudHMgaW4gY2hyb25vbG9naWNhbCBvcmRlclxuICAgICAgZGF0YS5ldmVudF9saXN0LmZvckVhY2goKGV2ZW50KSA9PiB7XG4gICAgICAgIHRoaXMuZW1pdChldmVudC5ldmVudF90eXBlLCBldmVudClcbiAgICAgICAgdGhpcy5lbWl0KFwiKlwiLCBldmVudClcbiAgICAgIH0pXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMuZW1pdChcImVycm9yXCIsIGVycm9yKVxuICAgIH1cbiAgICAvLyBTY2hlZHVsZSBuZXh0IHBvbGxcbiAgICB0aGlzLnRpbWVvdXRJZCA9IGdsb2JhbFRoaXMuc2V0VGltZW91dChcbiAgICAgICgpID0+IHRoaXMucG9sbCgpLFxuICAgICAgdGhpcy5wb2xsSW50ZXJ2YWwsXG4gICAgKSBhcyB1bmtub3duIGFzIE5vZGVKUy5UaW1lb3V0XG4gIH1cbn1cbiIsICJpbXBvcnQgQ29uZmlnc3RvcmUgZnJvbSBcImNvbmZpZ3N0b3JlXCJcbmltcG9ydCB0eXBlIHsgVHlwZWRDb25maWdzdG9yZSB9IGZyb20gXCIuL1R5cGVkQ29uZmlnU3RvcmVcIlxuXG5leHBvcnQgaW50ZXJmYWNlIENsaUNvbmZpZyB7XG4gIHNlc3Npb25Ub2tlbj86IHN0cmluZ1xuICBnaXRodWJVc2VybmFtZT86IHN0cmluZ1xuICByZWdpc3RyeUFwaVVybD86IHN0cmluZ1xufVxuXG5leHBvcnQgY29uc3QgY2xpQ29uZmlnOiBUeXBlZENvbmZpZ3N0b3JlPENsaUNvbmZpZz4gPSBuZXcgQ29uZmlnc3RvcmUoXG4gIFwidHNjaXJjdWl0XCIsXG4pXG5cbmV4cG9ydCBjb25zdCBnZXRSZWdpc3RyeUFwaVVybCA9ICgpOiBzdHJpbmcgPT4ge1xuICByZXR1cm4gY2xpQ29uZmlnLmdldChcInJlZ2lzdHJ5QXBpVXJsXCIpID8/IFwiaHR0cHM6Ly9yZWdpc3RyeS1hcGkudHNjaXJjdWl0LmNvbVwiXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5pbXBvcnQgeyBjbGlDb25maWcgfSBmcm9tIFwibGliL2NsaS1jb25maWdcIlxuaW1wb3J0IGRlbGF5IGZyb20gXCJkZWxheVwiXG5pbXBvcnQgeyBnZXRLeSB9IGZyb20gXCJsaWIvcmVnaXN0cnktYXBpL2dldC1reVwiXG5pbXBvcnQgdHlwZSB7IEVuZHBvaW50UmVzcG9uc2UgfSBmcm9tIFwibGliL3JlZ2lzdHJ5LWFwaS9lbmRwb2ludC10eXBlc1wiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckF1dGhMb2dpbiA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW0uY29tbWFuZHNcbiAgICAuZmluZCgoYykgPT4gYy5uYW1lKCkgPT09IFwiYXV0aFwiKSFcbiAgICAuY29tbWFuZChcImxvZ2luXCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiQXV0aGVudGljYXRlIENMSSwgbG9naW4gdG8gcmVnaXN0cnlcIilcbiAgICAuYWN0aW9uKGFzeW5jIChhcmdzKSA9PiB7XG4gICAgICBjb25zdCBreSA9IGdldEt5KClcblxuICAgICAgY29uc3QgeyBsb2dpbl9wYWdlIH0gPSBhd2FpdCBreVxuICAgICAgICAucG9zdDxFbmRwb2ludFJlc3BvbnNlW1wic2Vzc2lvbnMvbG9naW5fcGFnZS9jcmVhdGVcIl0+KFxuICAgICAgICAgIFwic2Vzc2lvbnMvbG9naW5fcGFnZS9jcmVhdGVcIixcbiAgICAgICAgICB7XG4gICAgICAgICAgICBqc29uOiB7fSxcbiAgICAgICAgICB9LFxuICAgICAgICApXG4gICAgICAgIC5qc29uKClcblxuICAgICAgY29uc29sZS5sb2coXCJQbGVhc2UgdmlzaXQgdGhlIGZvbGxvd2luZyBVUkwgdG8gbG9nIGluOlwiKVxuICAgICAgY29uc29sZS5sb2cobG9naW5fcGFnZS51cmwpXG5cbiAgICAgIC8vIFdhaXQgdW50aWwgd2UgcmVjZWl2ZSBjb25maXJtYXRpb25cbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIGNvbnN0IHsgbG9naW5fcGFnZTogbmV3X2xvZ2luX3BhZ2UgfSA9IGF3YWl0IGt5XG4gICAgICAgICAgLnBvc3Q8RW5kcG9pbnRSZXNwb25zZVtcInNlc3Npb25zL2xvZ2luX3BhZ2UvZ2V0XCJdPihcbiAgICAgICAgICAgIFwic2Vzc2lvbnMvbG9naW5fcGFnZS9nZXRcIixcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAganNvbjoge1xuICAgICAgICAgICAgICAgIGxvZ2luX3BhZ2VfaWQ6IGxvZ2luX3BhZ2UubG9naW5fcGFnZV9pZCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHtsb2dpbl9wYWdlLmxvZ2luX3BhZ2VfYXV0aF90b2tlbn1gLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICApXG4gICAgICAgICAgLmpzb24oKVxuXG4gICAgICAgIGlmIChuZXdfbG9naW5fcGFnZS53YXNfbG9naW5fc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKFwiTG9nZ2VkIGluISBHZW5lcmF0aW5nIHRva2VuLi4uXCIpXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChuZXdfbG9naW5fcGFnZS5pc19leHBpcmVkKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTG9naW4gcGFnZSBleHBpcmVkXCIpXG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBkZWxheSgxMDAwKVxuICAgICAgfVxuXG4gICAgICBjb25zdCB7IHNlc3Npb24gfSA9IGF3YWl0IGt5XG4gICAgICAgIC5wb3N0PEVuZHBvaW50UmVzcG9uc2VbXCJzZXNzaW9ucy9sb2dpbl9wYWdlL2V4Y2hhbmdlX2Zvcl9jbGlfc2Vzc2lvblwiXT4oXG4gICAgICAgICAgXCJzZXNzaW9ucy9sb2dpbl9wYWdlL2V4Y2hhbmdlX2Zvcl9jbGlfc2Vzc2lvblwiLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGpzb246IHtcbiAgICAgICAgICAgICAgbG9naW5fcGFnZV9pZDogbG9naW5fcGFnZS5sb2dpbl9wYWdlX2lkLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke2xvZ2luX3BhZ2UubG9naW5fcGFnZV9hdXRoX3Rva2VufWAsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIClcbiAgICAgICAgLmpzb24oKVxuXG4gICAgICBjbGlDb25maWcuc2V0KFwic2Vzc2lvblRva2VuXCIsIHNlc3Npb24udG9rZW4pXG5cbiAgICAgIGNvbnNvbGUubG9nKFwiUmVhZHkgdG8gdXNlIVwiKVxuICAgIH0pXG59XG4iLCAiaW1wb3J0IHsgZ2V0UmVnaXN0cnlBcGlVcmwgfSBmcm9tIFwibGliL2NsaS1jb25maWdcIlxuaW1wb3J0IGt5LCB7IHR5cGUgQWZ0ZXJSZXNwb25zZUhvb2sgfSBmcm9tIFwia3lcIlxuXG5jb25zdCBwcmV0dHlSZXNwb25zZUVycm9ySG9vazogQWZ0ZXJSZXNwb25zZUhvb2sgPSBhc3luYyAoXG4gIF9yZXF1ZXN0LFxuICBfb3B0aW9ucyxcbiAgcmVzcG9uc2UsXG4pID0+IHtcbiAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBlcnJvckRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKClcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEZBSUwgWyR7cmVzcG9uc2Uuc3RhdHVzfV06ICR7X3JlcXVlc3QubWV0aG9kfSAke1xuICAgICAgICAgIG5ldyBVUkwoX3JlcXVlc3QudXJsKS5wYXRobmFtZVxuICAgICAgICB9IFxcblxcbiAke0pTT04uc3RyaW5naWZ5KGVycm9yRGF0YSwgbnVsbCwgMil9YCxcbiAgICAgIClcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvL2lnbm9yZSwgYWxsb3cgdGhlIGVycm9yIHRvIGJlIHRocm93blxuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgY29uc3QgZ2V0S3kgPSAoKSA9PiB7XG4gIHJldHVybiBreS5jcmVhdGUoe1xuICAgIHByZWZpeFVybDogZ2V0UmVnaXN0cnlBcGlVcmwoKSxcbiAgICBob29rczoge1xuICAgICAgYWZ0ZXJSZXNwb25zZTogW3ByZXR0eVJlc3BvbnNlRXJyb3JIb29rXSxcbiAgICB9LFxuICB9KVxufVxuIiwgImltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJBdXRoTG9nb3V0ID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbS5jb21tYW5kc1xuICAgIC5maW5kKChjKSA9PiBjLm5hbWUoKSA9PT0gXCJhdXRoXCIpIVxuICAgIC5jb21tYW5kKFwibG9nb3V0XCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiTG9nb3V0IGZyb20gcmVnaXN0cnlcIilcbiAgICAuYWN0aW9uKChhcmdzKSA9PiB7XG4gICAgICBjb25zb2xlLmxvZyhcImxvZ291dFwiKVxuICAgIH0pXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckF1dGggPSAocHJvZ3JhbTogQ29tbWFuZCkgPT4ge1xuICBwcm9ncmFtLmNvbW1hbmQoXCJhdXRoXCIpLmRlc2NyaXB0aW9uKFwiTG9naW4vbG9nb3V0XCIpXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckNvbmZpZyA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW0uY29tbWFuZChcImNvbmZpZ1wiKS5kZXNjcmlwdGlvbihcIk1hbmFnZSB0c2NpcmN1aXQgQ0xJIGNvbmZpZ3VyYXRpb25cIilcbn1cbiIsICJpbXBvcnQgdHlwZSB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCJcbmltcG9ydCB7IGNsaUNvbmZpZyB9IGZyb20gXCJsaWIvY2xpLWNvbmZpZ1wiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckNvbmZpZ1ByaW50ID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbS5jb21tYW5kc1xuICAgIC5maW5kKChjKSA9PiBjLm5hbWUoKSA9PT0gXCJjb25maWdcIikhXG4gICAgLmNvbW1hbmQoXCJwcmludFwiKVxuICAgIC5kZXNjcmlwdGlvbihcIlByaW50IHRoZSBjdXJyZW50IGNvbmZpZ1wiKVxuICAgIC5hY3Rpb24oKCkgPT4ge1xuICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoY2xpQ29uZmlnLmFsbCwgbnVsbCwgMikpXG4gICAgfSlcbn1cbiIsICJpbXBvcnQgdHlwZSB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCJcbmltcG9ydCB7IGdldEt5IH0gZnJvbSBcImxpYi9yZWdpc3RyeS1hcGkvZ2V0LWt5XCJcbmltcG9ydCAqIGFzIGZzIGZyb20gXCJub2RlOmZzXCJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckNsb25lID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbVxuICAgIC5jb21tYW5kKFwiY2xvbmVcIilcbiAgICAuZGVzY3JpcHRpb24oXCJDbG9uZSBhIHNuaXBwZXQgZnJvbSB0aGUgcmVnaXN0cnlcIilcbiAgICAuYXJndW1lbnQoXCI8c25pcHBldD5cIiwgXCJTbmlwcGV0IHRvIGNsb25lIChlLmcuIGF1dGhvci9zbmlwcGV0TmFtZSlcIilcbiAgICAuYWN0aW9uKGFzeW5jIChzbmlwcGV0UGF0aDogc3RyaW5nKSA9PiB7XG4gICAgICBsZXQgYXV0aG9yOiBzdHJpbmdcbiAgICAgIGxldCBzbmlwcGV0TmFtZTogc3RyaW5nXG4gICAgICBpZiAoIXNuaXBwZXRQYXRoLnN0YXJ0c1dpdGgoXCJAdHNjaS9cIikgJiYgc25pcHBldFBhdGguaW5jbHVkZXMoXCIvXCIpKSB7XG4gICAgICAgIDtbYXV0aG9yLCBzbmlwcGV0TmFtZV0gPSBzbmlwcGV0UGF0aC5zcGxpdChcIi9cIilcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHRyaW1tZWRQYXRoID0gc25pcHBldFBhdGgucmVwbGFjZShcIkB0c2NpL1wiLCBcIlwiKVxuICAgICAgICBjb25zdCBmaXJzdERvdEluZGV4ID0gdHJpbW1lZFBhdGguaW5kZXhPZihcIi5cIilcbiAgICAgICAgYXV0aG9yID0gdHJpbW1lZFBhdGguc2xpY2UoMCwgZmlyc3REb3RJbmRleClcbiAgICAgICAgc25pcHBldE5hbWUgPSB0cmltbWVkUGF0aC5zbGljZShmaXJzdERvdEluZGV4ICsgMSlcbiAgICAgIH1cblxuICAgICAgaWYgKCFhdXRob3IgfHwgIXNuaXBwZXROYW1lKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgXCJJbnZhbGlkIHNuaXBwZXQgcGF0aC4gVXNlIGZvcm1hdDogYXV0aG9yL3NuaXBwZXROYW1lLCBhdXRob3Iuc25pcHBldE5hbWUgb3IgQHRzY2kvYXV0aG9yLnNuaXBwZXROYW1lXCIsXG4gICAgICAgIClcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGt5ID0gZ2V0S3koKVxuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zb2xlLmxvZyhgQ2xvbmluZyAke2F1dGhvcn0vJHtzbmlwcGV0TmFtZX0uLi5gKVxuXG4gICAgICAgIGNvbnN0IHBhY2thZ2VGaWxlTGlzdCA9IGF3YWl0IGt5XG4gICAgICAgICAgLnBvc3Q8e1xuICAgICAgICAgICAgcGFja2FnZV9maWxlczogQXJyYXk8e1xuICAgICAgICAgICAgICBwYWNrYWdlX2ZpbGVfaWQ6IHN0cmluZ1xuICAgICAgICAgICAgICBwYWNrYWdlX3JlbGVhc2VfaWQ6IHN0cmluZ1xuICAgICAgICAgICAgICBmaWxlX3BhdGg6IHN0cmluZ1xuICAgICAgICAgICAgICBjcmVhdGVkX2F0OiBzdHJpbmdcbiAgICAgICAgICAgIH0+XG4gICAgICAgICAgfT4oXCJwYWNrYWdlX2ZpbGVzL2xpc3RcIiwge1xuICAgICAgICAgICAganNvbjoge1xuICAgICAgICAgICAgICBwYWNrYWdlX25hbWU6IGAke2F1dGhvcn0vJHtzbmlwcGV0TmFtZX1gLFxuICAgICAgICAgICAgICB1c2VfbGF0ZXN0X3ZlcnNpb246IHRydWUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pXG4gICAgICAgICAgLmpzb24oKVxuXG4gICAgICAgIC8vIENyZWF0ZSBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdFxuICAgICAgICBjb25zdCBkaXJQYXRoID0gYC4vJHthdXRob3J9LiR7c25pcHBldE5hbWV9YFxuICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZGlyUGF0aCkpIHtcbiAgICAgICAgICBmcy5ta2RpclN5bmMoZGlyUGF0aClcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERvd25sb2FkIGVhY2ggZmlsZSB0aGF0IGRvZXNuJ3Qgc3RhcnQgd2l0aCBkaXN0L1xuICAgICAgICBmb3IgKGNvbnN0IGZpbGVJbmZvIG9mIHBhY2thZ2VGaWxlTGlzdC5wYWNrYWdlX2ZpbGVzKSB7XG4gICAgICAgICAgY29uc3QgZmlsZVBhdGggPSBmaWxlSW5mby5maWxlX3BhdGguc3RhcnRzV2l0aChcIi9cIilcbiAgICAgICAgICAgID8gZmlsZUluZm8uZmlsZV9wYXRoLnNsaWNlKDEpXG4gICAgICAgICAgICA6IGZpbGVJbmZvLmZpbGVfcGF0aFxuXG4gICAgICAgICAgaWYgKGZpbGVQYXRoLnN0YXJ0c1dpdGgoXCJkaXN0L1wiKSkgY29udGludWVcblxuICAgICAgICAgIGNvbnN0IGZpbGVDb250ZW50ID0gYXdhaXQga3lcbiAgICAgICAgICAgIC5wb3N0PHtcbiAgICAgICAgICAgICAgcGFja2FnZV9maWxlOiB7XG4gICAgICAgICAgICAgICAgY29udGVudF90ZXh0OiBzdHJpbmdcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfT4oXCJwYWNrYWdlX2ZpbGVzL2dldFwiLCB7XG4gICAgICAgICAgICAgIGpzb246IHtcbiAgICAgICAgICAgICAgICBwYWNrYWdlX25hbWU6IGAke2F1dGhvcn0vJHtzbmlwcGV0TmFtZX1gLFxuICAgICAgICAgICAgICAgIGZpbGVfcGF0aDogZmlsZUluZm8uZmlsZV9wYXRoLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5qc29uKClcblxuICAgICAgICAgIGNvbnN0IGZ1bGxQYXRoID0gcGF0aC5qb2luKGRpclBhdGgsIGZpbGVQYXRoKVxuICAgICAgICAgIGNvbnN0IGRpck5hbWUgPSBwYXRoLmRpcm5hbWUoZnVsbFBhdGgpXG5cbiAgICAgICAgICAvLyBDcmVhdGUgbmVzdGVkIGRpcmVjdG9yaWVzIGlmIHRoZXkgZG9uJ3QgZXhpc3RcbiAgICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZGlyTmFtZSkpIHtcbiAgICAgICAgICAgIGZzLm1rZGlyU3luYyhkaXJOYW1lLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMoZnVsbFBhdGgsIGZpbGVDb250ZW50LnBhY2thZ2VfZmlsZS5jb250ZW50X3RleHQpXG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmxvZyhgU3VjY2Vzc2Z1bGx5IGNsb25lZCB0byAuLyR7YXV0aG9yfS4ke3NuaXBwZXROYW1lfS9gKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRmFpbGVkIHRvIGNsb25lIHNuaXBwZXQ6XCIsIGVycm9yLm1lc3NhZ2UpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkZhaWxlZCB0byBjbG9uZSBzbmlwcGV0OlwiLCBlcnJvcilcbiAgICAgICAgfVxuICAgICAgICBwcm9jZXNzLmV4aXQoMSlcbiAgICAgIH1cbiAgICB9KVxufVxuIl0sCiAgIm1hcHBpbmdzIjogIjs7O0FBQ0EsU0FBUyxlQUFlOzs7QUNBeEIsWUFBWUEsV0FBVTtBQUN0QixZQUFZLGNBQWM7QUFDMUIsWUFBWUMsU0FBUTs7O0FDSHBCLFlBQVksVUFBVTtBQUN0QixZQUFZLFFBQVE7QUFDcEIsWUFBWSxVQUFVO0FBQ3RCLFNBQVMsc0JBQXNCO0FBRS9CLE9BQU8sc0JBQXNCOzs7QUNIdEIsSUFBTSxXQUFXLFlBQVk7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SSw0QkFBNEIsTUFBTSxJQUFJLFdBQVcsR0FBRztBQUFBLElBQ2xFLFNBQVMsT0FBTztBQUNkLFVBQUksaUJBQWlCLE9BQU87QUFDMUIsZ0JBQVEsTUFBTSw0QkFBNEIsTUFBTSxPQUFPO0FBQUEsTUFDekQsT0FBTztBQUNMLGdCQUFRLE1BQU0sNEJBQTRCLEtBQUs7QUFBQSxNQUNqRDtBQUNBLGNBQVEsS0FBSyxDQUFDO0FBQUEsSUFDaEI7QUFBQSxFQUNGLENBQUM7QUFDTDs7O0FkekZBLFNBQVMsa0JBQWtCO0FBRTNCLElBQU0sVUFBVSxJQUFJLFFBQVE7QUFFNUIsUUFDRyxLQUFLLE1BQU0sRUFDWCxZQUFZLHVDQUF1QyxFQUNuRCxRQUFRLE9BQU87QUFFbEIsWUFBWSxPQUFPO0FBQ25CLGNBQWMsT0FBTztBQUVyQixhQUFhLE9BQU87QUFDcEIsa0JBQWtCLE9BQU87QUFDekIsbUJBQW1CLE9BQU87QUFFMUIsZUFBZSxPQUFPO0FBQ3RCLG9CQUFvQixPQUFPO0FBRTNCLElBQUksUUFBUSxLQUFLLFdBQVcsR0FBRztBQUM3QixhQUFXLFNBQVMsUUFBUSxJQUFJO0FBQ2xDLE9BQU87QUFDTCxVQUFRLE1BQU07QUFDaEI7IiwKICAibmFtZXMiOiBbInBhdGgiLCAiZnMiLCAiY3JlYXRlU2VydmVyIiwgInJlc29sdmUiLCAicGF0aCIsICJmcyIsICJmcyIsICJwYXRoIiwgInRzIiwgInByb2dyYW0iLCAiY3JlYXRlU2VydmVyIiwgImZpbGUiLCAicHJvZ3JhbSIsICJreSIsICJwcm9ncmFtIiwgInByb2dyYW0iLCAicHJvZ3JhbSIsICJwcm9ncmFtIiwgImZzIiwgInBhdGgiLCAicHJvZ3JhbSIsICJreSJdCn0K
@@ -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
+ ```