|
| 1 | +// src/tg-bot-playground/bot-launcher/load.ts |
| 2 | +async function loadWorker() { |
| 3 | + const version = await fetch("./metadata.json", { cache: "no-cache" }).then((_) => _.json()).then((_) => _["web-worker.js"]); |
| 4 | + if (!version) { |
| 5 | + console.warn("Cannot get version from metadata"); |
| 6 | + return; |
| 7 | + } |
| 8 | + ; |
| 9 | + const worker = new Worker(`./scripts/worker/web-worker.js?v=${version}`, { type: "module" }); |
| 10 | + console.log("web worker has been loaded"); |
| 11 | + return worker; |
| 12 | +} |
| 13 | + |
| 14 | +// src/tg-bot-playground/bot-launcher/run.ts |
| 15 | +var makeRunnableBot = (tsTextModel, worker) => (state) => tsTextModel.getJsCode().then((code) => { |
| 16 | + if (!state.bot.token || state.bot.token.length < 10) return; |
| 17 | + if (!code.serialized) { |
| 18 | + console.warn("Serizalized js code not defined"); |
| 19 | + return; |
| 20 | + } |
| 21 | + worker.postMessage({ |
| 22 | + command: "run-bot", |
| 23 | + token: state.bot.token, |
| 24 | + code: code.serialized |
| 25 | + }); |
| 26 | + state.bot.status = "active"; |
| 27 | +}).catch((error) => { |
| 28 | + console.warn("cannot run bot", error); |
| 29 | +}); |
| 30 | +var checkTokenAndRun = (state, runnableBot) => { |
| 31 | + const token = state.bot.token; |
| 32 | + if (!token) return; |
| 33 | + fetch(`https://api.telegram.org/bot${token}/getMe`).then((_) => _.json()).then((info) => { |
| 34 | + if (info.ok) { |
| 35 | + state.bot.name = info.result.first_name; |
| 36 | + console.log("Running bot"); |
| 37 | + runnableBot(state); |
| 38 | + } else { |
| 39 | + state.bot.name = "nameless"; |
| 40 | + } |
| 41 | + }).catch((error) => { |
| 42 | + console.warn("check token error", error); |
| 43 | + }); |
| 44 | +}; |
| 45 | + |
| 46 | +// src/tg-bot-playground/bot-launcher/_main.ts |
| 47 | +var makeBotLauncher = async (tsTextModel) => { |
| 48 | + const worker = await loadWorker(); |
| 49 | + if (!worker) return; |
| 50 | + const runnableBot = makeRunnableBot(tsTextModel, worker); |
| 51 | + return { |
| 52 | + worker, |
| 53 | + runBot: (state) => runnableBot(state), |
| 54 | + checkTokenAndRun: (state) => checkTokenAndRun(state, runnableBot) |
| 55 | + }; |
| 56 | +}; |
| 57 | + |
| 58 | +// src/tg-bot-playground/utils.ts |
| 59 | +var fetchText = (path) => fetch(path).then((_) => _.text()); |
| 60 | +var getMonacoLoader = () => { |
| 61 | + if (!("monaco_loader" in window) || typeof window.monaco_loader != "object" || window.monaco_loader == null) { |
| 62 | + console.warn("monaco loader is not available"); |
| 63 | + return; |
| 64 | + } |
| 65 | + return window.monaco_loader; |
| 66 | +}; |
| 67 | +function getAlpine() { |
| 68 | + if (!("Alpine" in window) || typeof window.Alpine != "object" || window.Alpine == null) { |
| 69 | + console.warn("Alpine is not available"); |
| 70 | + return; |
| 71 | + } |
| 72 | + return window.Alpine; |
| 73 | +} |
| 74 | + |
| 75 | +// src/tg-bot-playground/editor/setup.ts |
| 76 | +var setupDts = async (monaco) => { |
| 77 | + const dts = await fetchText("https://cdn.jsdelivr.net/npm/@effect-ak/[email protected]/dist/index.d.ts"); |
| 78 | + monaco.languages.typescript.typescriptDefaults.setExtraLibs([ |
| 79 | + { |
| 80 | + content: dts, |
| 81 | + filePath: "node_modules/@effect-ak/tg-bot-client/index.d.ts" |
| 82 | + } |
| 83 | + ]); |
| 84 | + monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ |
| 85 | + ...monaco.languages.typescript.typescriptDefaults.getCompilerOptions(), |
| 86 | + moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs, |
| 87 | + typeRoots: [ |
| 88 | + "node_modules" |
| 89 | + ], |
| 90 | + strict: true |
| 91 | + }); |
| 92 | +}; |
| 93 | + |
| 94 | +// src/tg-bot-playground/editor/ts-text-model.ts |
| 95 | +var makeTsTextModel = async (monaco) => { |
| 96 | + const emptyExample = await fetchText("./example/empty.ts"); |
| 97 | + const tsModel = monaco.editor.createModel(emptyExample, "typescript"); |
| 98 | + let cachedWorkerPromise = null; |
| 99 | + const getTsCode = async () => { |
| 100 | + if (!cachedWorkerPromise) { |
| 101 | + cachedWorkerPromise = (async () => { |
| 102 | + const tsWorker = await monaco.languages.typescript.getTypeScriptWorker(); |
| 103 | + return tsWorker(tsModel.uri); |
| 104 | + })(); |
| 105 | + } |
| 106 | + return cachedWorkerPromise.then((_) => _.getEmitOutput(tsModel.uri.toString())); |
| 107 | + }; |
| 108 | + return { |
| 109 | + tsModel, |
| 110 | + getJsCode: async () => { |
| 111 | + const output = await getTsCode(); |
| 112 | + const code = output.outputFiles[0].text; |
| 113 | + const defaultExport = await getDefaultExport(code); |
| 114 | + return { |
| 115 | + defaultExport, |
| 116 | + serialized: serialize(defaultExport?.default) |
| 117 | + }; |
| 118 | + } |
| 119 | + }; |
| 120 | +}; |
| 121 | +async function getDefaultExport(code) { |
| 122 | + try { |
| 123 | + const encodedCode = encodeURIComponent(code); |
| 124 | + const module = await import(`data:text/javascript,${encodedCode}`); |
| 125 | + const result = module.default; |
| 126 | + return { default: result }; |
| 127 | + } catch (e) { |
| 128 | + console.warn("get default error", e); |
| 129 | + return void 0; |
| 130 | + } |
| 131 | +} |
| 132 | +var serialize = (input) => { |
| 133 | + if (typeof input != "object" || !input) { |
| 134 | + return void 0; |
| 135 | + } |
| 136 | + const result = []; |
| 137 | + for (const [key, value] of Object.entries(input)) { |
| 138 | + if (typeof value != "function") { |
| 139 | + continue; |
| 140 | + } |
| 141 | + result.push([key, value.toString()]); |
| 142 | + } |
| 143 | + return JSON.stringify(Object.fromEntries(result)); |
| 144 | +}; |
| 145 | + |
| 146 | +// src/tg-bot-playground/editor/init.ts |
| 147 | +var initEditor = async (loader) => { |
| 148 | + const container = document.getElementById("container"); |
| 149 | + if (!container) { |
| 150 | + console.warn("container not found"); |
| 151 | + return; |
| 152 | + } |
| 153 | + loader.config({ |
| 154 | + paths: { |
| 155 | + vs: "https://cdn.jsdelivr.net/npm/monaco-editor@latest/min/vs" |
| 156 | + } |
| 157 | + }); |
| 158 | + const monaco = await loader.init(); |
| 159 | + const tsTextModel = await makeTsTextModel(monaco); |
| 160 | + const editor = monaco.editor.create(container, { |
| 161 | + model: tsTextModel.tsModel, |
| 162 | + contextmenu: false, |
| 163 | + minimap: { |
| 164 | + enabled: false |
| 165 | + } |
| 166 | + }); |
| 167 | + return { |
| 168 | + tsTextModel, |
| 169 | + editor, |
| 170 | + monaco |
| 171 | + }; |
| 172 | +}; |
| 173 | + |
| 174 | +// src/tg-bot-playground/editor/_editor.ts |
| 175 | +var makeEditor = async (state) => { |
| 176 | + const loader = getMonacoLoader(); |
| 177 | + if (!loader) return; |
| 178 | + const editor = await initEditor(loader); |
| 179 | + if (!editor) return; |
| 180 | + await setupDts(editor.monaco); |
| 181 | + return { |
| 182 | + tsTextModel: editor.tsTextModel, |
| 183 | + loadExample: () => { |
| 184 | + if (!state.selectedExample) return; |
| 185 | + fetchText(`./example/${state.selectedExample}`).then((_) => editor.tsTextModel.tsModel.setValue(_)); |
| 186 | + }, |
| 187 | + onCodeChange: (f) => { |
| 188 | + let timeoutId; |
| 189 | + const debounceDelay = 1e3; |
| 190 | + editor.tsTextModel.tsModel.onDidChangeContent(() => { |
| 191 | + if (timeoutId !== void 0) { |
| 192 | + clearTimeout(timeoutId); |
| 193 | + } |
| 194 | + timeoutId = window.setTimeout(() => { |
| 195 | + const markers = editor.monaco.editor.getModelMarkers({ |
| 196 | + resource: editor.tsTextModel.tsModel.uri |
| 197 | + }); |
| 198 | + const hasError = markers.find((_) => _.severity.valueOf() == 8) != null; |
| 199 | + if (!hasError) { |
| 200 | + f(); |
| 201 | + } else { |
| 202 | + console.debug("Code contains errors"); |
| 203 | + } |
| 204 | + }, debounceDelay); |
| 205 | + }); |
| 206 | + } |
| 207 | + }; |
| 208 | +}; |
| 209 | + |
| 210 | +// src/tg-bot-playground/_main.ts |
| 211 | +var makeGlobalState = (alpine) => { |
| 212 | + const state = alpine.reactive({ |
| 213 | + bot: { |
| 214 | + name: "nameless", |
| 215 | + status: "idle", |
| 216 | + token: "" |
| 217 | + }, |
| 218 | + selectedExample: "empty.ts", |
| 219 | + botUpdates: [] |
| 220 | + }); |
| 221 | + return state; |
| 222 | +}; |
| 223 | +document.addEventListener("alpine:init", async () => { |
| 224 | + const Alpine = getAlpine(); |
| 225 | + if (!Alpine) return; |
| 226 | + Alpine.data("state", () => ({ |
| 227 | + bot: { |
| 228 | + a: 1 |
| 229 | + } |
| 230 | + })); |
| 231 | + const state = makeGlobalState(Alpine); |
| 232 | + Alpine.store("state", state); |
| 233 | + const editor = await makeEditor(state); |
| 234 | + if (!editor) return; |
| 235 | + const botLauncher = await makeBotLauncher(editor.tsTextModel); |
| 236 | + if (!botLauncher) return; |
| 237 | + editor.onCodeChange(() => { |
| 238 | + botLauncher.runBot(state); |
| 239 | + }); |
| 240 | + document.addEventListener("check-token", () => { |
| 241 | + botLauncher.checkTokenAndRun(state); |
| 242 | + }); |
| 243 | + document.addEventListener("change-example", () => { |
| 244 | + editor.loadExample(); |
| 245 | + }); |
| 246 | + botLauncher.worker.onmessage = (event) => { |
| 247 | + const data = event.data; |
| 248 | + console.log("got message from worker", data); |
| 249 | + if (!data) return; |
| 250 | + if (data.botState) { |
| 251 | + Object.assign(state.bot, data.botState); |
| 252 | + } |
| 253 | + state.botUpdates.push(data); |
| 254 | + }; |
| 255 | +}); |
| 256 | +export { |
| 257 | + makeGlobalState |
| 258 | +}; |
0 commit comments