@tscircuit/cli 0.0.393 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/bun-formatcheck.yml +26 -0
- package/.github/workflows/bun-pver-release.yml +25 -0
- package/.github/workflows/{typecheck.yml → bun-typecheck.yml} +0 -3
- package/LICENSE +21 -0
- package/README.md +30 -36
- package/biome.json +9 -9
- package/bun.lockb +0 -0
- package/cli/CliContext.ts +8 -0
- package/cli/auth/login/register.ts +73 -0
- package/cli/auth/logout/register.ts +11 -0
- package/cli/auth/register.ts +5 -0
- package/cli/config/print/register.ts +12 -0
- package/cli/config/register.ts +5 -0
- package/cli/dev/register.ts +111 -0
- package/cli/main.ts +31 -0
- package/dist/main.js +473 -0
- package/docs/file-server-api-usage.md +57 -0
- package/docs/run-frame-usage.md +14 -0
- package/example-dir/manual-edits.json +1 -0
- package/example-dir/snippet.d.ts +13 -0
- package/example-dir/snippet.tsx +20 -0
- package/example-dir/types.d.ts +11 -0
- package/lib/cli-config/TypedConfigStore.ts +50 -0
- package/lib/cli-config/index.ts +16 -0
- package/lib/dependency-analysis/DependencyAnalyzer.ts +129 -0
- package/lib/dependency-analysis/getLocalFileDependencies.ts +101 -0
- package/lib/dependency-analysis/installNodeModuleTypes.ts +74 -0
- package/lib/index.ts +2 -0
- package/lib/project-config/index.ts +5 -0
- package/lib/registry-api/endpoint-types.ts +20 -0
- package/lib/registry-api/get-ky.ts +30 -0
- package/lib/server/EventsWatcher.ts +75 -0
- package/lib/server/createServer.ts +62 -0
- package/lib/site/getIndex.ts +18 -0
- package/package.json +27 -144
- package/tsconfig.json +25 -22
- package/.github/workflows/formatbot.yml +0 -63
- package/.github/workflows/release.yml +0 -40
- package/.github/workflows/test.yml +0 -32
- package/.github/workflows/windows-tests.yml +0 -32
- package/.prettierrc +0 -1
- package/DEVELOPMENT.md +0 -7
- package/api/README.md +0 -3
- package/api/db/generic-json-level.ts +0 -123
- package/api/db/get-db.ts +0 -26
- package/api/db/schema.ts +0 -65
- package/api/db/zod-level-db.ts +0 -148
- package/api/index.ts +0 -4
- package/api/lib/middlewares/with-db.ts +0 -18
- package/api/lib/middlewares/with-debug-request-logging.ts +0 -13
- package/api/lib/middlewares/with-error-response.ts +0 -37
- package/api/lib/with-winter-spec.ts +0 -9
- package/api/lib/zod/export_parameters.ts +0 -25
- package/api/routes/api/db/download.ts +0 -25
- package/api/routes/api/dev_package_examples/create.ts +0 -43
- package/api/routes/api/dev_package_examples/get.ts +0 -46
- package/api/routes/api/dev_package_examples/list.ts +0 -36
- package/api/routes/api/dev_package_examples/update.ts +0 -59
- package/api/routes/api/dev_server/reset.ts +0 -13
- package/api/routes/api/export_files/create.ts +0 -27
- package/api/routes/api/export_files/download.ts +0 -25
- package/api/routes/api/export_requests/create.ts +0 -30
- package/api/routes/api/export_requests/get.ts +0 -43
- package/api/routes/api/export_requests/list.ts +0 -26
- package/api/routes/api/export_requests/update.ts +0 -34
- package/api/routes/api/health.ts +0 -11
- package/api/routes/api/package_info/create.ts +0 -26
- package/api/routes/api/package_info/get.ts +0 -16
- package/api/routes/health.ts +0 -11
- package/api/routes/index.ts +0 -16
- package/api/server.ts +0 -20
- package/api/static-routes.ts +0 -24
- package/api/tests/fixtures/get-test-server.ts +0 -31
- package/api/tests/fixtures/start-server.ts +0 -41
- package/api/tests/routes/dev_package_examples/create.test.ts +0 -19
- package/api/tests/routes/dev_package_examples/get.test.ts +0 -25
- package/api/tests/routes/dev_package_examples/list.test.ts +0 -32
- package/api/tests/routes/dev_package_examples/update.test.ts +0 -38
- package/api/tests/routes/export_files/create.test.ts +0 -18
- package/api/tests/routes/export_files/download.test.ts +0 -29
- package/api/tests/routes/export_requests/create.test.ts +0 -24
- package/api/tests/routes/export_requests/get.test.ts +0 -41
- package/api/tests/routes/export_requests/list.test.ts +0 -35
- package/api/tests/routes/export_requests/update.test.ts +0 -50
- package/api/tests/routes/health.test.ts +0 -10
- package/bunfig.toml +0 -2
- package/cli/cli.ts +0 -13
- package/cli/lib/cmd-fns/add.ts +0 -34
- package/cli/lib/cmd-fns/auth-login.ts +0 -59
- package/cli/lib/cmd-fns/auth-logout.ts +0 -7
- package/cli/lib/cmd-fns/auth-sessions-create.ts +0 -3
- package/cli/lib/cmd-fns/auth-sessions-get.ts +0 -3
- package/cli/lib/cmd-fns/auth-sessions-list.ts +0 -5
- package/cli/lib/cmd-fns/config-clear.ts +0 -5
- package/cli/lib/cmd-fns/config-print-config.ts +0 -6
- package/cli/lib/cmd-fns/config-reveal-location.ts +0 -5
- package/cli/lib/cmd-fns/config-set-log-requests.ts +0 -7
- package/cli/lib/cmd-fns/config-set-registry.ts +0 -9
- package/cli/lib/cmd-fns/config-set-runtime.ts +0 -7
- package/cli/lib/cmd-fns/config-set-session.ts +0 -7
- package/cli/lib/cmd-fns/dev/check-if-initialized.ts +0 -22
- package/cli/lib/cmd-fns/dev/derive-selector-from-pcb-component-id.ts +0 -23
- package/cli/lib/cmd-fns/dev/dev-server-request-handler.ts +0 -61
- package/cli/lib/cmd-fns/dev/find-available-port.ts +0 -32
- package/cli/lib/cmd-fns/dev/fulfill-export-requests.ts +0 -162
- package/cli/lib/cmd-fns/dev/get-dev-server-axios.ts +0 -29
- package/cli/lib/cmd-fns/dev/index.ts +0 -168
- package/cli/lib/cmd-fns/dev/infer-export-name-from-source.ts +0 -17
- package/cli/lib/cmd-fns/dev/mark-all-examples-loading.ts +0 -18
- package/cli/lib/cmd-fns/dev/soupify-and-upload-example-file.ts +0 -62
- package/cli/lib/cmd-fns/dev/start-dev-server.ts +0 -34
- package/cli/lib/cmd-fns/dev/start-edit-event-watcher.ts +0 -347
- package/cli/lib/cmd-fns/dev/start-export-request-watcher.ts +0 -33
- package/cli/lib/cmd-fns/dev/start-fs-watcher.ts +0 -54
- package/cli/lib/cmd-fns/dev/upload-examples-from-directory.ts +0 -42
- package/cli/lib/cmd-fns/dev-server-fulfill-export-requests.ts +0 -43
- package/cli/lib/cmd-fns/dev-server-upload.ts +0 -56
- package/cli/lib/cmd-fns/export-gerbers.ts +0 -28
- package/cli/lib/cmd-fns/export-kicad-pcb.ts +0 -36
- package/cli/lib/cmd-fns/export-pnp-csv.ts +0 -32
- package/cli/lib/cmd-fns/gen-jlcpcb-component.ts +0 -64
- package/cli/lib/cmd-fns/go.ts +0 -14
- package/cli/lib/cmd-fns/index.ts +0 -46
- package/cli/lib/cmd-fns/init/create-or-modify-npmrc.ts +0 -21
- package/cli/lib/cmd-fns/init/get-generated-npmrc.ts +0 -8
- package/cli/lib/cmd-fns/init/get-generated-readme.ts +0 -41
- package/cli/lib/cmd-fns/init/get-generated-tsconfig.ts +0 -34
- package/cli/lib/cmd-fns/init/index.ts +0 -193
- package/cli/lib/cmd-fns/install.ts +0 -34
- package/cli/lib/cmd-fns/lint.ts +0 -43
- package/cli/lib/cmd-fns/open.ts +0 -19
- package/cli/lib/cmd-fns/package-examples-create.ts +0 -36
- package/cli/lib/cmd-fns/package-examples-get.ts +0 -20
- package/cli/lib/cmd-fns/package-examples-list.ts +0 -18
- package/cli/lib/cmd-fns/package-files-create.ts +0 -31
- package/cli/lib/cmd-fns/package-files-download.ts +0 -29
- package/cli/lib/cmd-fns/package-files-get.ts +0 -3
- package/cli/lib/cmd-fns/package-files-list.ts +0 -28
- package/cli/lib/cmd-fns/package-files-upload-directory.ts +0 -6
- package/cli/lib/cmd-fns/package-releases-create.ts +0 -35
- package/cli/lib/cmd-fns/package-releases-get.ts +0 -3
- package/cli/lib/cmd-fns/package-releases-list.ts +0 -32
- package/cli/lib/cmd-fns/package-releases-update.ts +0 -45
- package/cli/lib/cmd-fns/packages-create.ts +0 -16
- package/cli/lib/cmd-fns/packages-get.ts +0 -16
- package/cli/lib/cmd-fns/packages-list.ts +0 -16
- package/cli/lib/cmd-fns/publish/index.ts +0 -336
- package/cli/lib/cmd-fns/remove.ts +0 -31
- package/cli/lib/cmd-fns/render.ts +0 -45
- package/cli/lib/cmd-fns/soupify.ts +0 -31
- package/cli/lib/cmd-fns/uninstall.ts +0 -31
- package/cli/lib/cmd-fns/version.ts +0 -38
- package/cli/lib/create-config-manager.ts +0 -97
- package/cli/lib/export-fns/export-bom-csv.ts +0 -32
- package/cli/lib/export-fns/export-gerbers.ts +0 -108
- package/cli/lib/export-fns/export-kicad-pcb.ts +0 -32
- package/cli/lib/export-fns/export-pnp-csv.ts +0 -31
- package/cli/lib/get-program.ts +0 -387
- package/cli/lib/param-handlers/index.ts +0 -21
- package/cli/lib/param-handlers/interact-for-local-directory.ts +0 -58
- package/cli/lib/param-handlers/interact-for-local-file.ts +0 -59
- package/cli/lib/param-handlers/interact-for-package-example-id.ts +0 -25
- package/cli/lib/param-handlers/interact-for-package-name-with-version.ts +0 -63
- package/cli/lib/param-handlers/interact-for-package-name.ts +0 -45
- package/cli/lib/param-handlers/interact-for-package-release-id.ts +0 -15
- package/cli/lib/param-handlers/interact-for-registry-url.ts +0 -27
- package/cli/lib/param-handlers/interact-for-runtime.ts +0 -33
- package/cli/lib/param-handlers/param-handler-type.ts +0 -7
- package/cli/lib/posthog.ts +0 -23
- package/cli/lib/soupify/get-export-name-from-file.ts +0 -29
- package/cli/lib/soupify/get-tmp-entrpoint-filepath.ts +0 -15
- package/cli/lib/soupify/index.ts +0 -1
- package/cli/lib/soupify/run-entrypoint-file.ts +0 -59
- package/cli/lib/soupify/soupify-with-core.ts +0 -74
- package/cli/lib/soupify/soupify.ts +0 -6
- package/cli/lib/util/app-context.ts +0 -17
- package/cli/lib/util/create-context-and-run-program.ts +0 -168
- package/cli/lib/util/get-all-package-files.ts +0 -66
- package/cli/lib/util/lint-project.ts +0 -137
- package/cli/tests/export-gerber-keyboard.test.ts +0 -16
- package/cli/tests/export-gerber.test.ts +0 -49
- package/cli/tests/export-kicad-pcb.test.ts +0 -23
- package/cli/tests/export-pnp-csv.test.ts +0 -24
- package/cli/tests/fixtures/preload.ts +0 -54
- package/cli/tests/init.test.ts +0 -9
- package/cli/tests/open.test.ts +0 -9
- package/cli/tests/soupify-builder.test.ts +0 -9
- package/cli/tests/soupify-core.test.ts +0 -9
- package/dist/cli.js +0 -3676
- package/docs/EDIT_EVENT_PIPELINE.md +0 -34
- package/example-project/README.md +0 -18
- package/example-project/examples/basic-capacitor.tsx +0 -5
- package/example-project/examples/basic-chip.tsx +0 -26
- package/example-project/examples/basic-resistor.tsx +0 -3
- package/example-project/examples/macrokeypad.tsx +0 -59
- package/example-project/index.ts +0 -1
- package/example-project/package.json +0 -5
- package/example-project/src/ArduinoProMicroBreakout.tsx +0 -37
- package/example-project/src/Key.tsx +0 -46
- package/example-project/src/Keyswitch.tsx +0 -26
- package/example-project/src/KeyswitchSocket.tsx +0 -56
- package/example-project/src/MyCircuit.tsx +0 -38
- package/example-project/src/manual-edits.ts +0 -93
- package/frontend/README.md +0 -3
- package/frontend/bun.lockb +0 -0
- package/frontend/components/command-k.tsx +0 -86
- package/frontend/components/dialogs/generic-export-dialog.tsx +0 -189
- package/frontend/components/dialogs/gerber-export-dialog.tsx +0 -168
- package/frontend/components/global-context-providers.tsx +0 -11
- package/frontend/components/select-example-search.tsx +0 -118
- package/frontend/components/ui/alert-dialog.tsx +0 -139
- package/frontend/components/ui/alert.tsx +0 -59
- package/frontend/components/ui/breadcrumb.tsx +0 -115
- package/frontend/components/ui/button.tsx +0 -57
- package/frontend/components/ui/card.tsx +0 -76
- package/frontend/components/ui/command.tsx +0 -153
- package/frontend/components/ui/context-menu.tsx +0 -202
- package/frontend/components/ui/dialog.tsx +0 -120
- package/frontend/components/ui/menubar.tsx +0 -238
- package/frontend/components/ui/navigation-menu.tsx +0 -128
- package/frontend/components/ui/popover.tsx +0 -31
- package/frontend/components/ui/select.tsx +0 -162
- package/frontend/components/ui/tabs.tsx +0 -53
- package/frontend/components/ui/toggle-group.tsx +0 -59
- package/frontend/components/ui/toggle.tsx +0 -43
- package/frontend/components/ui/tooltip.tsx +0 -28
- package/frontend/components.json +0 -17
- package/frontend/hooks/toast-if-api-not-connected.ts +0 -23
- package/frontend/hooks/use-active-dev-package-example-lite.ts +0 -39
- package/frontend/hooks/use-dev-package-examples.tsx +0 -18
- package/frontend/hooks/use-global-store.ts +0 -42
- package/frontend/index.css +0 -76
- package/frontend/index.html +0 -13
- package/frontend/lib/utils.ts +0 -6
- package/frontend/main.tsx +0 -13
- package/frontend/tailwind.config.js +0 -74
- package/frontend/views/App.tsx +0 -22
- package/frontend/views/Header.tsx +0 -55
- package/frontend/views/HeaderMenu.tsx +0 -326
- package/frontend/views/MainContentView.tsx +0 -172
- package/frontend/vite-env.d.ts +0 -1
- package/frontend/vite.config.ts +0 -50
- package/renovate.json +0 -15
- package/scripts/build-cli.ts +0 -12
- 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+IHtcbiAgICAgIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGNsaUNvbmZpZy5hbGwsIG51bGwsIDIpKVxuICAgIH0pXG59XG4iXSwKICAibWFwcGluZ3Mi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RDtBQUFBLE1BQ0Y7QUFBQSxJQUNGLEVBQ0MsS0FBSztBQUVSLGNBQVUsSUFBSSxnQkFBZ0IsUUFBUSxLQUFLO0FBRTNDLFlBQVEsSUFBSSxlQUFlO0FBQUEsRUFDN0IsQ0FBQztBQUNMOzs7QUV0RU8sSUFBTSxxQkFBcUIsQ0FBQ0MsYUFBcUI7QUFDdEQsRUFBQUEsU0FBUSxTQUNMLEtBQUssQ0FBQyxNQUFNLEVBQUUsS0FBSyxNQUFNLE1BQU0sRUFDL0IsUUFBUSxRQUFRLEVBQ2hCLFlBQVksc0JBQXNCLEVBQ2xDLE9BQU8sQ0FBQyxTQUFTO0FBQ2hCLFlBQVEsSUFBSSxRQUFRO0FBQUEsRUFDdEIsQ0FBQztBQUNMOzs7QUNSTyxJQUFNLGVBQWUsQ0FBQ0MsYUFBcUI7QUFDaEQsRUFBQUEsU0FBUSxRQUFRLE1BQU0sRUFBRSxZQUFZLGNBQWM7QUFDcEQ7OztBQ0ZPLElBQU0saUJBQWlCLENBQUNDLGFBQXFCO0FBQ2xELEVBQUFBLFNBQVEsUUFBUSxRQUFRLEVBQUUsWUFBWSxvQ0FBb0M7QUFDNUU7OztBQ0RPLElBQU0sc0JBQXNCLENBQUNDLGFBQXFCO0FBQ3ZELEVBQUFBLFNBQVEsU0FDTCxLQUFLLENBQUMsTUFBTSxFQUFFLEtBQUssTUFBTSxRQUFRLEVBQ2pDLFFBQVEsT0FBTyxFQUNmLFlBQVksMEJBQTBCLEVBQ3RDLE9BQU8sTUFBTTtBQUNaLFlBQVEsSUFBSSxLQUFLLFVBQVUsVUFBVSxLQUFLLE1BQU0sQ0FBQyxDQUFDO0FBQUEsRUFDcEQsQ0FBQztBQUNMOzs7QWJIQSxTQUFTLGtCQUFrQjtBQUUzQixJQUFNLFVBQVUsSUFBSSxRQUFRO0FBRTVCLFFBQ0csS0FBSyxNQUFNLEVBQ1gsWUFBWSx1Q0FBdUMsRUFDbkQsUUFBUSxPQUFPO0FBRWxCLFlBQVksT0FBTztBQUVuQixhQUFhLE9BQU87QUFDcEIsa0JBQWtCLE9BQU87QUFDekIsbUJBQW1CLE9BQU87QUFFMUIsZUFBZSxPQUFPO0FBQ3RCLG9CQUFvQixPQUFPO0FBRTNCLElBQUksUUFBUSxLQUFLLFdBQVcsR0FBRztBQUM3QixhQUFXLFNBQVMsUUFBUSxJQUFJO0FBQ2xDLE9BQU87QUFDTCxVQUFRLE1BQU07QUFDaEI7IiwKICAibmFtZXMiOiBbInBhdGgiLCAiZnMiLCAiY3JlYXRlU2VydmVyIiwgInJlc29sdmUiLCAicGF0aCIsICJmcyIsICJmcyIsICJwYXRoIiwgInRzIiwgInByb2dyYW0iLCAiY3JlYXRlU2VydmVyIiwgImZpbGUiLCAicHJvZ3JhbSIsICJreSIsICJwcm9ncmFtIiwgInByb2dyYW0iLCAicHJvZ3JhbSIsICJwcm9ncmFtIl0KfQo=
|
|
@@ -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
|
+
}
|